ezvm

vm类型的题目,第一次做

先简单学习一下该类型的题目结构

(6条消息) 站在巨人的肩膀上学习ctf vm_0xDQ的博客-CSDN博客

[原创]虎符第三题 -vm 虚拟机逆向-CTF对抗-看雪论坛-安全社区|安全招聘|bbs.pediy.com

先来翻译一下每一个case的含义

动调跑一下

把这些dword看作是虚拟机的寄存器

这种类似的操作就相当于

push r0[0xD1+r4++]

栈位于r0的9*4 的位置

而这里的0xD1则是存放异或数据的位置

对比数据也存放在其下面

然后

pop r5

剩下的都大差不差

输入用getchar的方式存放在r3

然后r3入栈

通过从ida提取出来的步骤数据

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
code = [
0x12, 8, 0x12, 9, 0x10, 4, 1, 0x0F,
0x0D, 2, 0x12, 8, 0x12, 9, 0, 4, 0x0F, 0x0D,
0x12, 9, 0x12, 0x0A, 0x13, 0x12, 0x0B, 0x15,
3, 0x14, 1, 0, 0x0F, 0x0D, 0x12, 0x0A,
0x12, 0x12, 0x12, 8, 0x13, 0x0F, 7, 4, 9,
0x0D, 9, 8, 5, 6, 4, 1, 0, 0x0F,
0x0D, 0x12, 9, 0x12, 8, 0x12, 0x0A,
0x12, 7, 0x0F, 0x0C, 0x11, 0x0E
]

for i in range(len(code)):
c=code[i]
if c == 0:
print ("_%02X:\t" % i + "mov r3 r2")
elif c == 1:
print ("_%02X:\t" % i + "add r2 1")
elif c == 2:
print ("_%02X:\t" % i + "dec r2 1")
elif c == 3:
print ("_%02X:\t" % i + "xor r3 r7")
elif c == 4:
print ("_%02X:\t" % i + "push r3")
elif c == 5:
print ("_%02X:\t" % i + "push r5")
elif c == 6:
print ("_%02X:\t" % i + "push r6")
elif c == 7:
print ("_%02X:\t" % i + "pop r3")
elif c == 8:
print ("_%02X:\t" % i + "pop r5")
elif c == 9:
print ("_%02X:\t" % i + "pop r6")
elif c == 10:
print ("_%02X:\t" % i + "pop r2")
elif c == 11:
print ("_%02X:\t" % i + "popr7")
elif c == 12:
print ("_%02X:\t" % i + "jz r0+r6")
elif c == 13:
print ("_%02X:\t" % i + "jnz r0+r6")
elif c == 14:
print ("_%02X:\t" % i + "jmp r0+r2")
elif c == 15:
print ("_%02X:\t" % i + "cmp r3 r5")
elif c == 16:
print ("_%02X:\t" % i + "getchar r3")
elif c == 17:
print ("_%02X:\t" % i + "putchar r3")
elif c == 18:
print ("_%02X:\t" % i + "push r0[0xD1+r4++]")
elif c == 19:
print ("_%02X:\t" % i + "mov r3 stack ")
elif c == 20:
print ("_%02X:\t" % i + "mov stack r3")
elif c == 21:
print ("_%02X:\t" % i + "shl r3 1")

输出

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
65
_00:    push r0[0xD1+r4++]
_01: pop r5
_02: push r0[0xD1+r4++]
_03: pop r6
_04: getchar r3
_05: push r3
_06: add r2 1
_07: cmp r3 r5
_08: jnz r0+r6
_09: dec r2 1
_0A: push r0[0xD1+r4++]
_0B: pop r5
_0C: push r0[0xD1+r4++]
_0D: pop r6
_0E: mov r3 r2
_0F: push r3
_10: cmp r3 r5
_11: jnz r0+r6 ;loop
_12: push r0[0xD1+r4++]
_13: pop r6
_14: push r0[0xD1+r4++]
_15: pop r2
_16: mov r3 stack
_17: push r0[0xD1+r4++]
_18: popr7
_19: shl r3 1
_1A: xor r3 r7
_1B: mov stack r3
_1C: add r2 1
_1D: mov r3 r2
_1E: cmp r3 r5 ;字符比较是否为0xa
_1F: jnz r0+r6
_20: push r0[0xD1+r4++]
_21: pop r2
_22: push r0[0xD1+r4++]
_23: push r0[0xD1+r4++]
_24: push r0[0xD1+r4++]
_25: pop r5
_26: mov r3 stack
_27: cmp r3 r5
_28: pop r3
_29: push r3
_2A: pop r6
_2B: jnz r0+r6
_2C: pop r6
_2D: pop r5
_2E: push r5
_2F: push r6
_30: push r3
_31: add r2 1
_32: mov r3 r2
_33: cmp r3 r5
_34: jnz r0+r6
_35: push r0[0xD1+r4++]
_36: pop r6
_37: push r0[0xD1+r4++]
_38: pop r5
_39: push r0[0xD1+r4++]
_3A: pop r2
_3B: push r0[0xD1+r4++]
_3C: pop r3
_3D: cmp r3 r5
_3E: jz r0+r6
_3F: putchar r3
_40: jmp r0+r2

看的出来这里是对数据进行一次左移,然后再异或

通过动调可以得出加密数据长度为0x20

简单逻辑

1
2
3
4
5
6
data1=[142, 136, 163, 153, 196, 165, 195, 221, 25, 236, 108, 155, 243, 27, 139, 91, 62, 155, 241, 134, 243, 244, 164, 248, 248, 152, 171, 134, 137, 97, 34, 193]
data2= [94, 70, 97, 67, 14, 83, 73, 31, 81, 94, 54, 55, 41, 65, 99, 59, 100, 59, 21, 24, 91, 62, 34, 80, 70, 94, 53, 78, 67, 35, 96, 59]
flag=[]
for i in range(32):
flag.append(chr(((data1[i]^data2[i]))//2))
print(''.join(flag))