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="")