BUUCTF-[GWCTF 2019]babyvm

题目下载:下载

这种简单vm逆向搞了快半辈子了,看别人wp也看的迷迷糊糊的,今天突然就看明白了,可能是受一个python虚拟机题的影响,第一次见vm,简单记录一下~

参考:系统学习vm虚拟机逆向_43v3rY0unG的博客-CSDN博客

基本原理:

是指的意思是一种解释执行系统或者模拟器(Emulator)。逆向中的虚拟机保护是一种基于虚拟机的代码保护技术。它将基于x86汇编系统中的可执行代码转换为字节码指令系统的代码,来达到不被轻易逆向和篡改的目的。简单点说就是将程序的代码转换自定义的操作码(opcode),然后在程序执行时再通过解释这些操作码,选择对应的函数执行,从而实现程序原有的功能。

vm_start:

虚拟机的入口函数,对虚拟机环境进行初始化

vm_dispatcher:

调度器,解释opcode,并选择对应的handle函数执行,当handle执行完后会跳回这里,形成一个循环。

opcode :

程序可执行代码转换成的操作码

在这种情况下,如果要逆向程序,就需要对整个emulator结构进行逆向,理解程序功能,还需要结合opcode进行分析,整个程序逆向工程将会十分繁琐。这是一个一般虚拟机结构:BUUCTF-[GWCTF 2019]babyvm_第1张图片

大概了解vm逆向后,解一下这个题目,载入IDABUUCTF-[GWCTF 2019]babyvm_第2张图片

有三个函数,进入第一个sub_CD1函数BUUCTF-[GWCTF 2019]babyvm_第3张图片

发现有一个unk_202060,跟进查看BUUCTF-[GWCTF 2019]babyvm_第4张图片发现是一堆数据,根据对vm的简单了解,这些应该是操作码,继续看函数其他的部分,应该是操作码及其对应的操作指令。

进入sub_B5F,看0xF1的指令BUUCTF-[GWCTF 2019]babyvm_第5张图片

 是个赋值操作,所以对应mov操作。switch不同,赋值给的对象不同,所以可以看做是不同寄存器,所以0xE1->eax,0xE2->ebx,0xE3->ecx,0xE5->edx。其中还有个qword_2022A8,交叉引用一下,BUUCTF-[GWCTF 2019]babyvm_第6张图片

所以这个应该就是flag。

进入sub_A64函数,看0xF2的指令BUUCTF-[GWCTF 2019]babyvm_第7张图片
是个异或操作,看异或对象可知,xor eax,ebx

进入sub_AC5函数,看0xF5的指令BUUCTF-[GWCTF 2019]babyvm_第8张图片

是获得flag长度,否则wrong

进入sub_956函数,看0xF4的指令BUUCTF-[GWCTF 2019]babyvm_第9张图片
啥都没做,所以nop

进入sub_A08函数,看0xF7的指令BUUCTF-[GWCTF 2019]babyvm_第10张图片
乘的操作,看操作对象是 mul eax,edx

进入sub_8F0函数,看0xF8的操作BUUCTF-[GWCTF 2019]babyvm_第11张图片

是个交换操作,即swap eax,ebx

进入sub_99C函数,看0xF6操作BUUCTF-[GWCTF 2019]babyvm_第12张图片

是一个线性运算,eax=ecx+2*ebx+3*eax

看主函数里的第二个函数sub_E0B函数BUUCTF-[GWCTF 2019]babyvm_第13张图片

读取操作码,如果不是0xF4就进行操作,所以这个应该就是再进行操作码的翻译

看主函数里的第三个函数BUUCTF-[GWCTF 2019]babyvm_第14张图片
这里就是再进行检查,看是否和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,如下图可知BUUCTF-[GWCTF 2019]babyvm_第15张图片

所以代码如下
BUUCTF-[GWCTF 2019]babyvm_第16张图片 发现是个假的flag...

通过观察发现还有一个检查函数BUUCTF-[GWCTF 2019]babyvm_第17张图片

所以这次我们使用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!

你可能感兴趣的:(re简单题,vm,re,ctf)