题目下载:下载
这种简单vm逆向搞了快半辈子了,看别人wp也看的迷迷糊糊的,今天突然就看明白了,可能是受一个python虚拟机题的影响,第一次见vm,简单记录一下~
参考:系统学习vm虚拟机逆向_43v3rY0unG的博客-CSDN博客
基本原理:
是指的意思是一种解释执行系统或者模拟器(Emulator)。逆向中的虚拟机保护是一种基于虚拟机的代码保护技术。它将基于x86汇编系统中的可执行代码转换为字节码指令系统的代码,来达到不被轻易逆向和篡改的目的。简单点说就是将程序的代码转换自定义的操作码(opcode),然后在程序执行时再通过解释这些操作码,选择对应的函数执行,从而实现程序原有的功能。
vm_start:
虚拟机的入口函数,对虚拟机环境进行初始化
vm_dispatcher:
调度器,解释opcode,并选择对应的handle函数执行,当handle执行完后会跳回这里,形成一个循环。
opcode :
程序可执行代码转换成的操作码
在这种情况下,如果要逆向程序,就需要对整个emulator结构进行逆向,理解程序功能,还需要结合opcode进行分析,整个程序逆向工程将会十分繁琐。这是一个一般虚拟机结构:
大概了解vm逆向后,解一下这个题目,载入IDA
有三个函数,进入第一个sub_CD1函数
发现有一个unk_202060,跟进查看发现是一堆数据,根据对vm的简单了解,这些应该是操作码,继续看函数其他的部分,应该是操作码及其对应的操作指令。
进入sub_B5F,看0xF1的指令
是个赋值操作,所以对应mov操作。switch不同,赋值给的对象不同,所以可以看做是不同寄存器,所以0xE1->eax,0xE2->ebx,0xE3->ecx,0xE5->edx。其中还有个qword_2022A8,交叉引用一下,
所以这个应该就是flag。
进入sub_A64函数,看0xF2的指令
是个异或操作,看异或对象可知,xor eax,ebx
进入sub_AC5函数,看0xF5的指令
是获得flag长度,否则wrong
进入sub_956函数,看0xF4的指令
啥都没做,所以nop
进入sub_A08函数,看0xF7的指令
乘的操作,看操作对象是 mul eax,edx
进入sub_8F0函数,看0xF8的操作
是个交换操作,即swap eax,ebx
进入sub_99C函数,看0xF6操作
是一个线性运算,eax=ecx+2*ebx+3*eax
看主函数里的第二个函数sub_E0B函数
读取操作码,如果不是0xF4就进行操作,所以这个应该就是再进行操作码的翻译
看主函数里的第三个函数
这里就是再进行检查,看是否和aFzAmAmFmtSum[i]数组相同。
好了分析了个大概,现在主要操作就是翻译操作码,代码如下
opcode=[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]
#print(opcode[0])
reg={0xE1:'eax',0xE2:'ebx',0xE3:'ecx',0XE5:'edx'}
opcode1={0xF1:'mov',0xF2:'xor',0xF5:'len(flag)',0xF4:'nop',0xF7:'mul',0xF8:'swap'}
i=0
for j in range(len(opcode)):
if opcode[i]==0xF1: #如果是0xf1,就是mov操作,一定会有下面的操作
print('mov',end=' ')
if opcode[i+1]==0xE1:
print('eax '+'flag['+str(opcode[i+2])+']')
elif opcode[i+1]==0xE2:
print('ebx '+'flag['+str(opcode[i+2])+']')
elif opcode[i+1]==0xE3:
print('ecx '+'flag['+str(opcode[i+2])+']')
elif opcode[i+1]==0xE4:
print('flag['+str(opcode[i+2])+'] '+'eax')
elif opcode[i+1]==0xE5:
print('edx '+'flag['+str(opcode[i+2])+']')
elif opcode[i + 1] == 0xE7:
print('flag[' + str(opcode[i + 2]) + '] ' + 'ebx')
i=i+6 #加6是因为1+1+4,操作码+寄存器+dword类型数据(flag下标)
elif opcode[i]==0xF2:
print('xor eax, ebx')
i=i+1
elif opcode[i]==0xF2:
print('xor eax, ebx')
i=i+1
elif opcode[i]==0xF5:
print('len(flag)')
i = i + 1
elif opcode[i]==0xF4:
print('nop')
i = i + 1
elif opcode[i]==0xF7:
print('mul eax, edx')
i = i + 1
elif opcode[i]==0xF8:
print('swap eax, ebx')
i = i + 1
elif opcode[i]==0xF6:
print('eax = ecx + 2 * ebx + 3 * eax')
i = i + 1
else:
i=i+1
得到
len(flag)
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
len(flag)
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]
swap eax, ebx
mov flag[13] eax
mov flag[19] ebx
mov eax flag[14]
mov ebx flag[18]
swap eax, ebx
mov flag[14] eax
mov flag[18] ebx
mov eax flag[15]
mov ebx flag[17]
swap eax, ebx
mov flag[15] eax
mov flag[17] ebx
nop
因为通过上面分析,我们知道如果是0xF4那就不进行操作,所以可以以nop为分界,把上面得到的分为两部分(后面就知道要使用第二部分)
我们先使用第一部分,第一部分就是异或操作,注意这里ebx==0x12,如下图可知
所以代码如下
发现是个假的flag...
通过观察发现还有一个检查函数
所以这次我们使用byte_202020的数据,在进行第二部分操作,第二部分就是对前六个进行异或变化,然后再变化str[6],str[7],str[8],在交换部分数据,所以解密代码如下:
#str1='Fz{aM{aM|}fMt~suM !!'
#str=list(map(ord,str1))
str=[0x69, 0x45, 0x2A, 0x37, 0x09, 0x17, 0xC5, 0x0B, 0x5C, 0x72,
0x33, 0x76, 0x33, 0x21, 0x74, 0x31, 0x5F, 0x33, 0x73, 0x72]
flag=''
str[15],str[17]=str[17],str[15]
str[14],str[18]=str[18],str[14]
str[13],str[19]=str[19],str[13]
for i in range(32,128):
if str[8]==((str[10]+2*str[9]+3*i)*str[12])&0xFF:
str[8]=i
for i in range(32,128):
if str[7]==((str[9]+2*str[8]+3*i)*str[12])&0xFF:
str[7]=i
for i in range(32, 128):
if str[6]==((str[8]+2*str[7]+3*i)*str[12])&0xFF:
str[6]=i
for j in range(5,-1,-1):
str[j]=str[j]^str[j+1]
for i in range(len(str)):
flag+=chr(str[i])
print(flag)
这次成功得到flag:Y0u_hav3_r3v3rs3_1t!