DASCTFXGFCTF2024四月Re-ezVM(ida调试dll文件)

Z3约束器
VM逆向(虚拟机逆向 or 代码解释器逆向)
ida调试dll文件
DLL文件分析
异或逆运算

  tar = 0;
  memset(Str, 0, 0x20ui64);
  memset(num, 0, 0x40ui64);
  len = 0;
  printf("please input your key:\n");
  scanf("%s", Str);
  len = strlen(Str);
  if ( len == 16 )
  {
    tar = 1;
    for ( j = 0; j < len; ++j )
    {
      if ( Str[j] > 0x39 || Str[j] < 0x30 )     // 输入的key是数字
        tar = 0;
    }
    if ( tar == 1 )
    {
      for ( k = 0; k < 8; ++k )
        vscanf(&Str[2 * k], "%2d");             // 将每两个数字字符串转为整数存入num
      tar = VM(num, v5, v6);                    // 貌似是VM
      if ( tar )
        decodefile(num, v7, v8);                // 这里存在写文件,输入正确的num数组就可以得到正真的dll文件
    }
  }

这里主要是分析vm!

  for ( j = 0; j < 8; ++j )
    data[j] = *(arg1 + 4i64 * j);               // 每三个数据为一组
  do
  {
    if ( opcode[idx] == 160 )
    {
      data[opcode[idx + 1]] = opcode[idx + 2];  // 赋值data = opcode
      idx += 3;
    }
    if ( opcode[idx] == 161 )
    {
      data[opcode[idx + 1]] = data[opcode[idx + 2]];// 赋值data = data
      idx += 3;
    }
    if ( opcode[idx] == 162 )
    {
      data[opcode[idx + 1]] += opcode[idx + 2]; // 加法data+opcode
      idx += 3;
    }
    if ( opcode[idx] == 163 )
    {
      data[opcode[idx + 1]] += data[opcode[idx + 2]];
      idx += 3;
    }
    if ( opcode[idx] == 164 )
    {
      data[opcode[idx + 1]] -= opcode[idx + 2];
      idx += 3;
    }
    if ( opcode[idx] == 165 )
    {
      data[opcode[idx + 1]] -= data[opcode[idx + 2]];
      idx += 3;
    }
    if ( opcode[idx] == 166 )
    {
      data[opcode[idx + 1]] *= opcode[idx + 2];
      idx += 3;
    }
    if ( opcode[idx] == 167 )
    {
      data[opcode[idx + 1]] *= data[opcode[idx + 2]];
      idx += 3;
    }
    if ( opcode[idx] == 176 )
    {
      checktar = data[opcode[idx + 1]] == opcode[idx + 2];
      tar = checktar;
      idx += 3;
    }
    if ( opcode[idx] == 177 )
    {
      checktar = data[opcode[idx + 1]] == data[opcode[idx + 2]];
      tar = checktar;
      idx += 3;
    }
    if ( opcode[idx] == 178 )                   // 检测tar
    {
      if ( !tar )
        return 0i64;
      ++idx;
    }
  }
  while ( opcode[idx] != 192 );

发现关键数据:178是判断tar是否为0,176是对tar进行修改
里面还有一些加减乘除运算,还发现177是多余的!

直接叫chatgpt将c转为python,再改改就好了!
添加输出发现其实就算个简单的多元一次方程,直接上z3就好了!

data[0] += 132
data[8] += data[0]
data[8] += data[1]
判断:data[8] == 316
data[9] += data[1]
data[9] += data[2]
data[9] += data[3]
判断:data[9] == 158
data[4] *= 22
data[0] += data[4]
判断:data[0] == 889
data[5] -= 11
data[8] = data[5]
data[8] += data[6]
判断:data[8] == 38
data[7] += data[6]
判断:data[7] == 96
data[9] = data[1]
data[9] += data[2]
data[9] -= data[5]
判断:data[9] == 111
data[5] *= 7
data[8] = data[0]
data[8] -= data[6]
data[8] += data[5]
判断:data[8] == 859
data[3] += data[4]
判断:data[3] == 706

成功得到key:9787254630123759

动态调试就会发现原dll文件被改为check1.dll,然后将data解密成正真的dll!
直接上chatgpt,问代码!

// 重命名文件 "check.dll" 为 "check1.dll"
rename("check.dll", "check1.dll");

// 打开名为"data"的文件以供读取
hFile = CreateFileW(L"data", 0x80000000, 0, 0i64, 3u, 0x80u, 0i64);

// 获取文件大小
GetFileSizeEx(hFile, &FileSize);

// 确定要读取的字节数
nNumberOfBytesToRead = FileSize.LowPart;

// 创建用于存储文件内容的缓冲区
v14 = newchunk(FileSize.LowPart);
lpBuffer = v14;

// 从文件中读取数据到缓冲区中
ReadFile(hFile, v14, nNumberOfBytesToRead, &NumberOfBytesRead, 0i64);

// 对读取的数据进行修改
for ( j = 0; j < nNumberOfBytesToRead; ++j )
{
  v15 = j;
  // 对缓冲区中的每个字节与指定位置处的字节进行异或操作
  *(lpBuffer + j) ^= *(a1 + 4i64 * (j % 8));
}

// 关闭文件句柄
CloseHandle(hFile);

// 重新打开名为"check.dll"的文件以供写入
hFile = CreateFileW(L"check.dll", 0x40000000u, 0, 0i64, 1u, 0x80u, 0i64);

// 将修改后的数据写回到文件中
WriteFile(hFile, lpBuffer, NumberOfBytesRead, &NumberOfBytesWritten, 0i64);

// 返回文件句柄的关闭情况
return CloseHandle(hFile);

成功解密接下来就是调试解密出来的dll了!

  v5[0] = 0xD;
  v5[1] = 8;
  v5[2] = 26;
  v5[3] = 10;
  v5[4] = 29;
  v5[5] = 15;
  qmemcpy(&v5[6], "2x*{*{|}qdz,{}d(}q,dxx}zd(z}p\x7F(z+~}yy4", 38);
  tar = 1;
  for ( j = 0; j < 44; ++j )
  {
    if ( (*(a1 + j) ^ 0x49) != v5[j] )
      tar = 0;
  }
  return tar;
}

发现是一个超级简单的异或加密!
所以直接dll动态调试提取数据!

更改一下启动文件就好了!

下面是完整的揭秘脚本!

from z3 import *

def VM(arg1,s):
    idx = 0
    tar = 0
    #178是判断tar是否为0,176是对tar进行修改
    opcode = [162, 0, 132, 163, 8, 0, 163, 8, 1, 176,8, 316
              , 178
              , 163, 9, 1, 163, 9, 2, 163, 9, 3, 176, 9, 158
              , 178
              , 166, 4, 22, 163, 0, 4, 176, 0, 889, 178
              , 164, 5, 11, 161, 8, 5, 163, 8, 6, 176, 8, 38
              , 178
              , 163, 7, 6, 176, 7, 96, 178
              , 161, 9, 1, 163, 9, 2, 165, 9, 5, 176, 9, 111
              , 178
              , 166, 5, 7, 161, 8, 0, 165, 8, 6, 163, 8, 5, 176, 8, 859
              , 178
              , 163, 3, 4, 176, 3, 706
              , 178
              , 192]
    data = [0] * 40  # Assuming data is an array of 40 elements

    # Copy initial values into data
    for j in range(8):
        data[j] = arg1[j]

    while opcode[idx] != 192:
        if opcode[idx] == 160:
            data[opcode[idx + 1]] = opcode[idx + 2]
            print("data[{}] = {}".format(opcode[idx + 1],opcode[idx + 2]))
            idx += 3
        elif opcode[idx] == 161:
            data[opcode[idx + 1]] = data[opcode[idx + 2]]
            print("data[{}] = data[{}]".format(opcode[idx + 1],opcode[idx + 2]))
            idx += 3
        elif opcode[idx] == 162:
            data[opcode[idx + 1]] += opcode[idx + 2]
            print("data[{}] += {}".format(opcode[idx + 1],opcode[idx + 2]))
            idx += 3
        elif opcode[idx] == 163:
            data[opcode[idx + 1]] += data[opcode[idx + 2]]
            print("data[{}] += data[{}]".format(opcode[idx + 1],opcode[idx + 2]))
            idx += 3
        elif opcode[idx] == 164:
            data[opcode[idx + 1]] -= opcode[idx + 2]
            print("data[{}] -= {}".format(opcode[idx + 1],opcode[idx + 2]))
            idx += 3
        elif opcode[idx] == 165:
            data[opcode[idx + 1]] -= data[opcode[idx + 2]]
            print("data[{}] -= data[{}]".format(opcode[idx + 1],opcode[idx + 2]))
            idx += 3
        elif opcode[idx] == 166:
            data[opcode[idx + 1]] *= opcode[idx + 2]
            print("data[{}] *= {}".format(opcode[idx + 1],opcode[idx + 2]))
            idx += 3
        elif opcode[idx] == 167:
            data[opcode[idx + 1]] *= data[opcode[idx + 2]]
            print("data[{}] *= data[{}]".format(opcode[idx + 1],opcode[idx + 2]))
            idx += 3
        elif opcode[idx] == 176:
            checktar = data[opcode[idx + 1]] == opcode[idx + 2]
            s.add(data[opcode[idx + 1]] == opcode[idx + 2])
            print("判断:data[{}] == {}".format(opcode[idx + 1],opcode[idx + 2]))
            tar = checktar
            idx += 3
        elif opcode[idx] == 177:
            checktar = data[opcode[idx + 1]] == data[opcode[idx + 2]]
            tar = checktar
            idx += 3
        elif opcode[idx] == 178:
            # if not tar:
            #     return 0
            idx += 1
    if s.check() == sat:
        d = s.model()
        print(d)
        for i in range(8):
            print(d[f[i]].as_long(), end='')

f = [Int(f'f_{i}') for i in range(8)]
s = Solver()
for i in range(8):
    s.add([f[i]>0, f[i]<0xff])

VM(f,s)
print("")
target = [0x0D, 0x08, 0x1A, 0x0A, 0x1D, 0x0F, 0x32, 0x78, 0x2A, 0x7B, 0x2A, 0x7B, 0x7C, 0x7D, 0x71, 0x64, 0x7A, 0x2C, 0x7B, 0x7D, 0x64, 0x28, 0x7D, 0x71, 0x2C, 0x64, 0x78, 0x78, 0x7D, 0x7A, 0x64, 0x28, 0x7A, 0x7D, 0x70, 0x7F, 0x28, 0x7A, 0x2B, 0x7E, 0x7D, 0x79, 0x79, 0x34]
for i in range(len(target)):
    print(chr(target[i]^0x49),end="")
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值