[XNUCA2018]Code_Interpreter 题解

一道vm逆向

题目给了两个文件,一个是机器码,用vs打开

f78bbe805c0a4effb21e540c3c2922b3.png

不知道在干嘛,看另一个程序。

64位文件,无壳,直接ida启动

0380f40a06e6477e95e6fff9e950a0af.png

逻辑不复杂。打开code文件后将内容读入ptr,然后读入三个数字做处理。

查看关键函数sub_400806:

十个case,不同的运算,明显的vm特征。

fce1821dd4914f19b819d47ed3c3ec37.png

(这是我改过名后的样子,方便看)

开头将三个数字读入outnum数组,并设置了三个值来操作数据

f91a23a8b36044c59af7eb089dd6f9b4.png

 

来看主体逻辑。case0是v5=0.即退出

case1是将后四个数据从后往前合成一个大数储存起来

case2是简单的下标--

3,4,5,6分别是加减乘和向右的位运算

8badf4c6063646739ef75a6d6abc2d68.png

7是mov,8也是mov,9是xor,10是or,default检查操作码是不是位于0-10,否则退出。

根据code里的opcode编写脚本还原伪代码




opcode=[9,4,4,9,0,0,8,1,0,8,2,1,8,3,2,6,1,4,5,1,0x15,7,0,1,4,0,3,1,0x6b,0xcc,0x7e,0x1d,8,1,3,4,0,1,2,0xa,4,0,9,0,0,8,1,0,8,2,1,8,3,2,6,3,8,5,3,3,7,0,3,3,0,2,1,0x7c,0x79,0x79,0x60,8,1,3,4,0,1,2,10,4,0,9,0,0,8,1,0,8,2,1,8,3,2,6,1,8,7,0,1,3,0,2,1,0xbd,0xbd,0xbc,0x5f,8,1,3,4,0,1,2,10,4,0,0]
aa=[]
cnt1=2
i=0
for a in range(len(opcode)):
  if opcode[i]==0:
    print("over")
    break
  elif opcode[i]== 1:
    temp=(opcode[i+1])|(opcode[i+2]<<8)|(opcode[i+3]<<16)|(opcode[i+4]<<24)
    i+=5
    cnt1 += 1
    print("mov outnum[",cnt1,"] ",hex(temp))
  elif opcode[i] ==2:
    cnt1-=1
    print("sub cnt1 1")
    i+=1
  elif opcode[i] ==3:
    print("add elx[",opcode[i+1],"] elx[",opcode[i+2],"]")
    i += 3
  elif opcode[i] ==4:
    print("sub elx[", opcode[i + 1], "] elx[", opcode[i + 2], "]")
    i += 3
  elif opcode[i] ==5:
    print("mul elx[",opcode[i+1],"] " ,opcode[i + 2])
    i += 3
  elif opcode[i] ==6:
    print("ROR  elx[",opcode[i+1],"] ", opcode[i + 2])
    i += 3
  elif opcode[i] ==7:
    print("mov elx[", opcode[i + 1], "] elx[", opcode[i + 2], "]")
    i+=3
  elif opcode[i] ==8:
    print("mov elx[", opcode[i+1], "] outnum[", opcode[i + 2], "]")
    i += 3
  elif opcode[i] ==9:
    print("xor elx[", opcode[i + 1], "] elx[", opcode[i + 2], "]")
    i += 3
  elif opcode[i] ==10:
    print("or elx[", opcode[i + 1], "] ", opcode[i + 2])
    i += 3


 

结果是

xor elx[ 4 ] elx[ 4 ]
xor elx[ 0 ] elx[ 0 ]
mov elx[ 1 ] outnum[ 0 ]
mov elx[ 2 ] outnum[ 1 ]
mov elx[ 3 ] outnum[ 2 ]
ROR  elx[ 1 ]  4
mul elx[ 1 ]  21
mov elx[ 0 ] elx[ 1 ]
sub elx[ 0 ] elx[ 3 ]
mov outnum[ 3 ]  0x1d7ecc6b
mov elx[ 1 ] outnum[ 3 ]
sub elx[ 0 ] elx[ 1 ]
sub cnt1 1
or elx[ 4 ]  0
xor elx[ 0 ] elx[ 0 ]
mov elx[ 1 ] outnum[ 0 ]
mov elx[ 2 ] outnum[ 1 ]
mov elx[ 3 ] outnum[ 2 ]
ROR  elx[ 3 ]  8
mul elx[ 3 ]  3
mov elx[ 0 ] elx[ 3 ]
add elx[ 0 ] elx[ 2 ]
mov outnum[ 3 ]  0x6079797c
mov elx[ 1 ] outnum[ 3 ]
sub elx[ 0 ] elx[ 1 ]
sub cnt1 1
or elx[ 4 ]  0
xor elx[ 0 ] elx[ 0 ]
mov elx[ 1 ] outnum[ 0 ]
mov elx[ 2 ] outnum[ 1 ]
mov elx[ 3 ] outnum[ 2 ]
ROR  elx[ 1 ]  8
mov elx[ 0 ] elx[ 1 ]
add elx[ 0 ] elx[ 2 ]
mov outnum[ 3 ]  0x5fbcbdbd
mov elx[ 1 ] outnum[ 3 ]
sub elx[ 0 ] elx[ 1 ]
sub cnt1 1
or elx[ 4 ]  0
over

代码逻辑比较简单,化简为这样一个表达式

(((num1>>4)*21-num3-0x1d7ecc6b)|((num3>>8)*3+num2-0x6079797c)|((num1>>8)+num2-0x5fbcbdbd))

f74fe59189b14c90b00385d13c35bf85.png

根据判断函数,式子的结果应该等于0

使用z3求解三个未知数

编写脚本得到flag:


from z3 import*
from libnum import s2n,n2s
s=Solver()
num1=BitVec('num1',32)
num2=BitVec('num2',32)
num3=BitVec('num3',32)
s.add((((num1>>4)*21-num3-0x1d7ecc6b)|((num3>>8)*3+num2-0x6079797c)|((num1>>8)+num2-0x5fbcbdbd))==0)
s.add(num1&0xff==0x5e)
s.add(num3&0xff==0x5e)
s.add((num2 & 0xFF0000) == 0x5E0000)
print(s.check())
answer=s.model()
print(answer)
#[num2 = 1600020063, num3 = 1583243102, num1 = 1583308382]
aa=[1583308382,1600020063,1583243102]
flag="flag{"
for i in range(len(aa)):
    flag += hex(aa[i])[2:]
flag+="}"
print(flag)

flag{5e5f5e5e5f5e5e5f5e5e5f5e}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值