UNCTF - 2019 EasyVm

整体而言是一个比较好分析的一个VM题目,对得起其easy的名字?

拖入IDA进行反编译,可以清楚的发现对应的结构特点

1.png

我们跟进到创建栈空间的函数可发现其对应的操作函数集合

2.png

我们可以发现里面的运算,可以进行简单的标注一下。

我们在这个函数的集合中可以发现第一个run_vm中存在有switch - case结构,因此可以推断出来这个函数就是在执行对应的操作指令判断,来进行执行后面的函数

进行简单的一下调试我们可以观察到其栈空间的分配规律:

4.png

同时我们可以注意到operate函数下方的opcode并没有按顺序进行执行,而是先跳到了opcede+9处的指令

3.png

简单的调试,我们可以获取到其对应的执行流程以及对应的指令操作的代表功能

对应指令翻译:

操作码 对应指令集合
*(a1+16) 寄存器r1(占1字节)
*(a1+17) 寄存器r2(占1字节)
*(a1+18) 寄存器r3(占1字节)
*(a1+19) 寄存器r4(占1字节)
*(a1+20) 寄存器r5(占4字节)
0xA0 r1++
0xA1 r2++
0xA2 r3++
0xA3 r1 -= r3
0xA4 r1 ^= r2
0xA5 r2 ^= r1
0xA6 r1 = 0xCD
0xA7 r2 = r1
0xA8 r3 = 0xCD
0xA9 r1 = input[r3]
0xAA r2 = input[r3]
0xAB func1()
0xAC func2()
0xAD func3()
0xAE 判断r5的值
0xAF 判断r5的值

可以得到程序对每个输入的字符进行的执行流程为:

1
0xa9, 0xa3, 0xa5, 0xa6, 0xa4, 0xab, 0xa7, 0xae, 0xa2, 0xad, 0xaf

因此我们可以写出对应的翻译脚本与解密脚本进行解密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# 翻译脚本
# opcode = [0xa9, 0xa3, 0xa5, 0xa6, 0xa4, 0xab, 0xa7, 0xae, 0xa2, 0xad, 0xaf]

# for i in opcode:
# if i == 0xa0:
# print("r1++")
# if i == 0xa1:
# print("r2++")
# if i == 0xa2:
# print("r3++")
# if i == 0xa3:
# print("r1 -= r3")
# if i == 0xa4:
# print("r1 ^= r2")
# if i == 0xa5:
# print("r2 ^= r1")
# if i == 0xa6:
# print("r1 = 0xcd")
# if i == 0xa7:
# print("r2 = r1")
# if i == 0xa8:
# print("r3 = 0xcd")
# if i == 0xa9:
# print("r1 = input[r3]")
# if i == 0xaa:
# print("r2 = input[r3]")
# if i == 0xab:
# print("fun1()")
# if i == 0xac:
# print("func2()")
# if i == 0xad:
# print("func3()")
# if i == 0xae:
# print("if(r5==0)")
# if i == 0xaf:
# print("if(r5!=1)")

# 翻译结果
"""
r1 = input[r3]
r1 -= r3
r2 ^= r1
r1 = 0xcd
r1 ^= r2
fun1()
r2 = r1
if(r5!=0)
r3++
func3()
if(r5!=1)
"""

# 解密脚本
res = [0xF4, 0x0A, 0xF7, 0x64, 0x99, 0x78, 0x9E, 0x7D, 0xEA, 0x7B, 0x9E, 0x7B, 0x9F, 0x7E, 0xEB, 0x71, 0xE8, 0x00, 0xE8, 0x07, 0x98, 0x19, 0xF4, 0x25, 0xF3, 0x21, 0xA4, 0x2F, 0xF4, 0x2F, 0xA6, 0x7C]
flag = [0]*32
temp = 0
for i in range(0,32):
flag[i] = (temp ^ res[i] ^ 0xcd) + i
temp = res[i]

print("UNCTF{",end='')
for i in range(32):
print(chr(flag[i]),end='')
print("}")

因此我们可以得到flag为:UNCTF{942a4115be2359ffd675fa6338ba23b6}


UNCTF - 2019 EasyVm
https://equinox-shame.github.io/2022/07/22/UNCTF - 2019 EasyVm/
作者
梓曰
发布于
2022年7月22日
许可协议