前言
这是笔者做的第一道vm题,虽然相较于同类题题面很简单,但是在过程中收获了很多。
wp
64位无壳,拖入IDA看看先
长这个样,三个函数挨个点进去看看
如果比较有经验的话,可以直接认出来这是比较明显的vm。先不细看,点开下一个。
认真分析一下,可以发现是一个循环执行段,执行(*(16 * (i + 1LL) + a1 + 16))(a1)这一地址的函数,直到**(a1 + 16) == 0xF4为止。。。。
第三个函数是一个判断。现在再看第一个函数
这样看其实比较麻烦对不对,但是没关系,可以通过结构体来简化这一段代码
对vm有了解的话,可以看出这里代码的前四行相当于设置了寄存器,unk_202060相当于是操作码(指令流),而下面一个数字一个函数的相当于汇编指令。明白了这些,为了看到更明白,我们打开结构体窗口操作一下:
在下面空白右键,新建结构体
这里我命名为cpu,随便怎么都可以,你开心就好
创建好后按d新建成员,由于上面是4位,所以创建好后多点几次d,把类型改成对应的dd
一共有四个寄存器,按照顺序命名
是这个效果,不要直接命名为eax等真实的,记的加个_啥的,不然会报错。
给操作码也起个名方便看,它占8位所以要设置成dq,不要忘记按顺序设置结构体的元素。
下面就到函数部分了。每一个函数对应一个编码,为此我们可以设置一个另外的结构体来存放函数。注意大小是8不要搞错。
做好后,再到刚刚大的结构体里添加一个新的元素,按y键设置类型为我们刚刚设置好的结构体
上面一共有七个函数,我们点击刚设置好的结构体成员,按*将其设置为大小为8的数组,再把名字改改方便看。
好的,设置完成。我们回到第一个函数。点击类型,按y将其改为我们结构体的名字
点第一个
美观!如法炮制把每个函数都设置一遍,这样就方便看了很多
然后点进函数分析
第一个很明显是mov,对寄存器移来移去的
第二个明显xor
第三个判断flag长度
第四个啥事不干 明显是nop
第五个mul,没啥说的
第六个是明显的交换XCHG
第七个是eax = ecx+2*ebx+3*eax
函数都比较简单,下面只需要编写代码还原一下代码就行了
code=[0xF5, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4,
0x20, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x01, 0x00, 0x00, 0x00,
0xF2, 0xF1, 0xE4, 0x21, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x02,
0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x22, 0x00, 0x00, 0x00,
0xF1, 0xE1, 0x03, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x23,
0x00, 0x00, 0x00, 0xF1, 0xE1, 0x04, 0x00, 0x00, 0x00, 0xF2,
0xF1, 0xE4, 0x24, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x05, 0x00,
0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x25, 0x00, 0x00, 0x00, 0xF1,
0xE1, 0x06, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x26, 0x00,
0x00, 0x00, 0xF1, 0xE1, 0x07, 0x00, 0x00, 0x00, 0xF2, 0xF1,
0xE4, 0x27, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x08, 0x00, 0x00,
0x00, 0xF2, 0xF1, 0xE4, 0x28, 0x00, 0x00, 0x00, 0xF1, 0xE1,
0x09, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x29, 0x00, 0x00,
0x00, 0xF1, 0xE1, 0x0A, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4,
0x2A, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0B, 0x00, 0x00, 0x00,
0xF2, 0xF1, 0xE4, 0x2B, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0C,
0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x2C, 0x00, 0x00, 0x00,
0xF1, 0xE1, 0x0D, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x2D,
0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0E, 0x00, 0x00, 0x00, 0xF2,
0xF1, 0xE4, 0x2E, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0F, 0x00,
0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x2F, 0x00, 0x00, 0x00, 0xF1,
0xE1, 0x10, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x30, 0x00,
0x00, 0x00, 0xF1, 0xE1, 0x11, 0x00, 0x00, 0x00, 0xF2, 0xF1,
0xE4, 0x31, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x12, 0x00, 0x00,
0x00, 0xF2, 0xF1, 0xE4, 0x32, 0x00, 0x00, 0x00, 0xF1, 0xE1,
0x13, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x33, 0x00, 0x00,
0x00, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xF1,
0xE1, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x01, 0x00, 0x00,
0x00, 0xF2, 0xF1, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE1,
0x01, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x02, 0x00, 0x00, 0x00,
0xF2, 0xF1, 0xE4, 0x01, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x02,
0x00, 0x00, 0x00, 0xF1, 0xE2, 0x03, 0x00, 0x00, 0x00, 0xF2,
0xF1, 0xE4, 0x02, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x03, 0x00,
0x00, 0x00, 0xF1, 0xE2, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xF1,
0xE4, 0x03, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x04, 0x00, 0x00,
0x00, 0xF1, 0xE2, 0x05, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4,
0x04, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x05, 0x00, 0x00, 0x00,
0xF1, 0xE2, 0x06, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x05,
0x00, 0x00, 0x00, 0xF1, 0xE1, 0x06, 0x00, 0x00, 0x00, 0xF1,
0xE2, 0x07, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0x08, 0x00, 0x00,
0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 0x00, 0xF6, 0xF7, 0xF1,
0xE4, 0x06, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x07, 0x00, 0x00,
0x00, 0xF1, 0xE2, 0x08, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0x09,
0x00, 0x00, 0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 0x00, 0xF6,
0xF7, 0xF1, 0xE4, 0x07, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x08,
0x00, 0x00, 0x00, 0xF1, 0xE2, 0x09, 0x00, 0x00, 0x00, 0xF1,
0xE3, 0x0A, 0x00, 0x00, 0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00,
0x00, 0xF6, 0xF7, 0xF1, 0xE4, 0x08, 0x00, 0x00, 0x00, 0xF1,
0xE1, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x13, 0x00, 0x00,
0x00, 0xF8, 0xF1, 0xE4, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xE7,
0x13, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0E, 0x00, 0x00, 0x00,
0xF1, 0xE2, 0x12, 0x00, 0x00, 0x00, 0xF8, 0xF1, 0xE4, 0x0E,
0x00, 0x00, 0x00, 0xF1, 0xE7, 0x12, 0x00, 0x00, 0x00, 0xF1,
0xE1, 0x0F, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x11, 0x00, 0x00,
0x00, 0xF8, 0xF1, 0xE4, 0x0F, 0x00, 0x00, 0x00, 0xF1, 0xE7,
0x11, 0x00, 0x00, 0x00, 0xF4,-1,-1,0,0,0,0,0,0,]
i=0
jd=0
while 1:
if code[i]==241:
if code[i+1]==225:
print("mov eax,flag[",code[i+2],"]")
elif code[i+1]==226:
print("mov ebx,flag[",code[i+2],"]")
elif code[i+1]==227:
print("mov ecx,flag[",code[i+2],"]")
elif code[i+1]==228:
print("mov flag[",code[i + 2],"]" ,"eax" )
elif code[i+1]==229:
print("mov edx,flag[",code[i+2],"]")
elif code[i+1]==231:
print("mov flag[",code[i + 2],"]" ,"ebx" )
i+=6
elif code[i]==242:
print("xor eax,ebx")
i+=1
elif code[i]==245:
print("judge len")
i+=1
elif code[i]==244:
print("nop")
i+=1
elif code[i]==247:
print("mul eax,edx")
i+=1
elif code[i]==248:
print("XCHG eax,ebx")
i+=1
elif code[i]==246:
print("eax = ecx+2*ebx+3*eax")
i+=1
elif code[i]==0:
i+=1
elif code[i]==-1:
break
这是结果
judge len
mov eax,flag[ 0 ]
xor eax,ebx
mov flag[ 32 ] eax
mov eax,flag[ 1 ]
xor eax,ebx
mov flag[ 33 ] eax
mov eax,flag[ 2 ]
xor eax,ebx
mov flag[ 34 ] eax
mov eax,flag[ 3 ]
xor eax,ebx
mov flag[ 35 ] eax
mov eax,flag[ 4 ]
xor eax,ebx
mov flag[ 36 ] eax
mov eax,flag[ 5 ]
xor eax,ebx
mov flag[ 37 ] eax
mov eax,flag[ 6 ]
xor eax,ebx
mov flag[ 38 ] eax
mov eax,flag[ 7 ]
xor eax,ebx
mov flag[ 39 ] eax
mov eax,flag[ 8 ]
xor eax,ebx
mov flag[ 40 ] eax
mov eax,flag[ 9 ]
xor eax,ebx
mov flag[ 41 ] eax
mov eax,flag[ 10 ]
xor eax,ebx
mov flag[ 42 ] eax
mov eax,flag[ 11 ]
xor eax,ebx
mov flag[ 43 ] eax
mov eax,flag[ 12 ]
xor eax,ebx
mov flag[ 44 ] eax
mov eax,flag[ 13 ]
xor eax,ebx
mov flag[ 45 ] eax
mov eax,flag[ 14 ]
xor eax,ebx
mov flag[ 46 ] eax
mov eax,flag[ 15 ]
xor eax,ebx
mov flag[ 47 ] eax
mov eax,flag[ 16 ]
xor eax,ebx
mov flag[ 48 ] eax
mov eax,flag[ 17 ]
xor eax,ebx
mov flag[ 49 ] eax
mov eax,flag[ 18 ]
xor eax,ebx
mov flag[ 50 ] eax
mov eax,flag[ 19 ]
xor eax,ebx
mov flag[ 51 ] eax
nop
judge len
mov eax,flag[ 0 ]
mov ebx,flag[ 1 ]
xor eax,ebx
mov flag[ 0 ] eax
mov eax,flag[ 1 ]
mov ebx,flag[ 2 ]
xor eax,ebx
mov flag[ 1 ] eax
mov eax,flag[ 2 ]
mov ebx,flag[ 3 ]
xor eax,ebx
mov flag[ 2 ] eax
mov eax,flag[ 3 ]
mov ebx,flag[ 4 ]
xor eax,ebx
mov flag[ 3 ] eax
mov eax,flag[ 4 ]
mov ebx,flag[ 5 ]
xor eax,ebx
mov flag[ 4 ] eax
mov eax,flag[ 5 ]
mov ebx,flag[ 6 ]
xor eax,ebx
mov flag[ 5 ] eax
mov eax,flag[ 6 ]
mov ebx,flag[ 7 ]
mov ecx,flag[ 8 ]
mov edx,flag[ 12 ]
eax = ecx+2*ebx+3*eax
mul eax,edx
mov flag[ 6 ] eax
mov eax,flag[ 7 ]
mov ebx,flag[ 8 ]
mov ecx,flag[ 9 ]
mov edx,flag[ 12 ]
eax = ecx+2*ebx+3*eax
mul eax,edx
mov flag[ 7 ] eax
mov eax,flag[ 8 ]
mov ebx,flag[ 9 ]
mov ecx,flag[ 10 ]
mov edx,flag[ 12 ]
eax = ecx+2*ebx+3*eax
mul eax,edx
mov flag[ 8 ] eax
mov eax,flag[ 13 ]
mov ebx,flag[ 19 ]
XCHG eax,ebx
mov flag[ 13 ] eax
mov flag[ 19 ] ebx
mov eax,flag[ 14 ]
mov ebx,flag[ 18 ]
XCHG eax,ebx
mov flag[ 14 ] eax
mov flag[ 18 ] ebx
mov eax,flag[ 15 ]
mov ebx,flag[ 17 ]
XCHG eax,ebx
mov flag[ 15 ] eax
mov flag[ 17 ] ebx
nop
前面一段是假的代码,只看后面即可,逻辑比较简单。
还有一处坑
第三个函数是假的judge函数,真正的数据需要交叉引用看到
真正的检查函数
编写脚本得到flag
from z3 import*
def swap(a, b):
a,b=b,a
return a, b
bb=[105, 69, 42, 55, 9, 23, 197, 11, 92, 114,
51, 118, 51, 33, 116, 49, 95, 51, 115, 114]
bb[15],bb[17]=swap(bb[15],bb[17])
bb[14],bb[18]=swap(bb[14],bb[18])
bb[19],bb[13]=swap(bb[19],bb[13])
s = Solver()
f = [BitVec(f"f{[i]}", 8) for i in range(11)]
s.add((f[6]*3+f[7]*2+f[8])*bb[12]==bb[6])
s.add(bb[12]*(f[7]*3+f[8]*2+f[9])==bb[7])
s.add(bb[12]*(f[8]*3+f[9]*2+f[10])==bb[8])
s.add(bb[0] == f[0] ^ f[1])
s.add(bb[1] == f[1] ^ f[2])
s.add(bb[2] == f[2] ^ f[3])
s.add(bb[3] == f[3] ^ f[4])
s.add(bb[4] == f[4] ^ f[5])
s.add(bb[5] == f[5] ^ f[6])
s.add(f[9]==bb[9])
s.add(f[10]==bb[10])
if s.check() == sat:
t = s.model()
for i in f:
print(chr(t[i].as_long()), end='')
for i in range(0,9):
print(chr(bb[11+i]),end="")
flag{Y0u_hav3_r3v3rs3_1t!}