vm正如其名virtual machine也就是虚拟机的意思

如果他要模拟一个机器去执行一个文件的话,必然需要cpu中的寄存器、内存之间的堆栈,然后还要不断的读取指令去执行函数,来模拟执行流。

image-20250716100417738

大概流程就是这样子的

他的伪堆栈和伪寄存器和一些字符串则会放在一个全局变量中,来答到一个模拟机器的效果

我看别人的博客说一般有两种类型的题目

给可执行程序和opcode,逆向emulator,结合opcode文件,推出flag

只给可执行程序,逆向emulator,构造opcode,读取flag

先找了几个简单的练练手

类型一

[GKCTF2020]EzMachine

32位打开,开局有个花指令不难,可以看到main函数

image-20250716150502451

这些和字符串一起放置的猜测是寄存器

image-20250716153024893

0 11B0函数 eip+1

inc后面可能是寄存器加一,或者是内存地址加一,这里5BD8在字符集的地方也出现了,应该是eip,即eip加1

image-20250716155340945

1 1000函数 mov

这里我把字符集名字修改了一下,借字符集实现现在的操作数放到寄存器里面

image-20250716163054735

2 1070函数 push data

可以看出主要特点是读取数据、指针自增(栈顶向上移动)、写入数据、代码指针向前移可能是为读取下一个数据做准备

image-20250716171721905

3 1030函数 push

这个和上面那个函数几乎没差

但是上面那个压入原始数据或字节码,这个则是压入经过查表后的操作码、字符、关键值,可以看到这个其实就是寄存器的地址

image-20250716172827726

4 10A0函数 pop

和上面两个一对比可以明显发现是出栈

5 10E0函数 print

可以按r转化明显看到有打印出的字符串出现,是print函数

image-20250716185913631

6 11D0函数 add

因为它加载了两个寄存器中的值,最后存储在了第一个寄存器中

image-20250716192149057

7 1200函数 sub

看到代码就知道,同理上面的,是相减存在寄存器里面,下面几个基本都是这样的

8 1230函数 mul

9 1270函数 div

10 12B0函数 xor

11 12E0函数 jmp

它取出当前的字节码值 code[dword_F35BD8],乘以3后再减3,把这个结果赋值给程序计数器,相当于跳转到新的字节码地址,所以是跳转的指令

12 1300函数 sub

一个数减去另一个数存在了一个寄存器里面

image-20250716193630226

13 1340函数 je

je的作用:检查ZF标志位

  • 如果 ZF = 1(即前一条比较或算术指令的结果为 0,表示相等),则跳转。
  • 如果 ZF = 0(不相等),则继续执行下一条指令。

image-20250716194442201

14 1370函数 jne

15 13A0函数 jg

大于则跳转

16 13D0函数 jb

17 1400函数 gets

18 1430函数 clean

19 1470函数 mov

从栈中加载数据v0然后给了result所在的寄存器

image-20250716211024939

20 14B0函数 mov

21 11C0函数 end

接下来处理,将字节码换成刚刚分析出的伪汇编

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
code = [0x01, 0x03, 0x03, 0x05, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01,
0x01, 0x11, 0x0C, 0x00, 0x01, 0x0D, 0x0A, 0x00, 0x01, 0x03,
0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x01, 0x02, 0x00,
0x01, 0x00, 0x11, 0x0C, 0x00, 0x02, 0x0D, 0x2B, 0x00, 0x14,
0x00, 0x02, 0x01, 0x01, 0x61, 0x0C, 0x00, 0x01, 0x10, 0x1A,
0x00, 0x01, 0x01, 0x7A, 0x0C, 0x00, 0x01, 0x0F, 0x1A, 0x00,
0x01, 0x01, 0x47, 0x0A, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06,
0x00, 0x01, 0x0B, 0x24, 0x00, 0x01, 0x01, 0x41, 0x0C, 0x00,
0x01, 0x10, 0x24, 0x00, 0x01, 0x01, 0x5A, 0x0C, 0x00, 0x01,
0x0F, 0x24, 0x00, 0x01, 0x01, 0x4B, 0x0A, 0x00, 0x01, 0x01,
0x01, 0x01, 0x07, 0x00, 0x01, 0x01, 0x01, 0x10, 0x09, 0x00,
0x01, 0x03, 0x01, 0x00, 0x03, 0x00, 0x00, 0x01, 0x01, 0x01,
0x06, 0x02, 0x01, 0x0B, 0x0B, 0x00, 0x02, 0x07, 0x00, 0x02,
0x0D, 0x00, 0x02, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x01,
0x00, 0x02, 0x0C, 0x00, 0x02, 0x01, 0x00, 0x02, 0x00, 0x00,
0x02, 0x00, 0x00, 0x02, 0x0D, 0x00, 0x02, 0x05, 0x00, 0x02,
0x0F, 0x00, 0x02, 0x00, 0x00, 0x02, 0x09, 0x00, 0x02, 0x05,
0x00, 0x02, 0x0F, 0x00, 0x02, 0x03, 0x00, 0x02, 0x00, 0x00,
0x02, 0x02, 0x00, 0x02, 0x05, 0x00, 0x02, 0x03, 0x00, 0x02,
0x03, 0x00, 0x02, 0x01, 0x00, 0x02, 0x07, 0x00, 0x02, 0x07,
0x00, 0x02, 0x0B, 0x00, 0x02, 0x02, 0x00, 0x02, 0x01, 0x00,
0x02, 0x02, 0x00, 0x02, 0x07, 0x00, 0x02, 0x02, 0x00, 0x02,
0x0C, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x01, 0x02,
0x01, 0x13, 0x01, 0x02, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x01,
0x0E, 0x5B, 0x00, 0x01, 0x01, 0x22, 0x0C, 0x02, 0x01, 0x0D,
0x59, 0x00, 0x01, 0x01, 0x01, 0x06, 0x02, 0x01, 0x0B, 0x4E,
0x00, 0x01, 0x03, 0x00, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x01, 0x03, 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00
]
opcode = {0: 'eipadd', 1: 'mov', 2: 'pushdata', 3: 'push', 4: 'pop', 5: 'caseprint', 6: 'add', 7: 'sub1', 8: 'mul', 9: 'div',10: 'xor', 11: 'jmp', 12: 'sub', 13: 'je', 14: 'jne', 15: 'jg', 16: 'jb',17: 'gets', 18: 'clean', 19: 'mov', 20: 'mov', 0xFF: 'end'}
n = 0
m = 0
for i in code:
if n == 0:
op = opcode[i]
print(op, end=' ')
else:
print(i, end=" ")
n = n + 1
if n == 3:
n = 0
m = m + 1
print()

打印出来是这样子的

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
mov 3 3 
caseprint 0 0
gets 0 0
mov 1 17
sub 0 1
je 10 0
mov 3 1
caseprint 0 0
end 0 0
#长度不为17就打印并且退出

mov 2 0
mov 0 17
sub 0 2
je 43 0
#如果长度为17,跳到第43行汇编

mov 0 2
mov 1 97
sub 0 1
jb 26 0
mov 1 122
sub 0 1
jg 26 0
mov 1 71
xor 0 1
mov 1 1
add 0 1
jmp 36 0
#在a-z之间的话就【i】^71+1

mov 1 65
sub 0 1
jb 36 0
mov 1 90
sub 0 1
jg 36 0
mov 1 75
xor 0 1
mov 1 1
sub1 0 1
#在A-Z之间的话【i】^75-1

mov 1 16
div 0 1
push 1 0
push 0 0
mov 1 1
add 2 1
jmp 11 0
#将处理后的值除以16并压栈

pushdata 7 0
pushdata 13 0
pushdata 0 0
pushdata 5 0
pushdata 1 0
pushdata 12 0
pushdata 1 0
pushdata 0 0
pushdata 0 0
pushdata 13 0
pushdata 5 0
pushdata 15 0
pushdata 0 0
pushdata 9 0
pushdata 5 0
pushdata 15 0
pushdata 3 0
pushdata 0 0
pushdata 2 0
pushdata 5 0
pushdata 3 0
pushdata 3 0
pushdata 1 0
pushdata 7 0
pushdata 7 0
pushdata 11 0
pushdata 2 0
pushdata 1 0
pushdata 2 0
pushdata 7 0
pushdata 2 0
pushdata 12 0
pushdata 2 0
pushdata 2 0
#数据

mov 2 1
mov 1 2
pop 0 0
sub 0 1
jne 91 0
mov 1 34
sub 2 1
je 89 0
mov 1 1
add 2 1
jmp 78 0 #循环比较
mov 3 0
caseprint 0 0
end 0 0
mov 3 1
caseprint 0 0
end 0 0
eipadd

接下来就是提取数据,写一个脚本,注意这里把数据压入栈中了,所以要先进后出,字节是8位,把数组中两两组合成一个字节

1
2
3
4
5
6
7
8
9
10
11
12
13
array = [0x7, 0xd, 0x0, 0x5, 0x1, 0xc, 0x1, 0x0, 0x0, 0xd, 0x5, 0xf, 0x0, 0x9, 0x5, 0xf, 0x3, 0x0, 0x2, 0x5, 0x3, 0x3, 0x1, 0x7, 0x7, 0xb, 0x2, 0x1, 0x2, 0x7, 0x2, 0xc, 0x2, 0x2, ]
array = array[::-1]
for i in range(0, len(array), 2):
c = array[i] + array[i + 1] * 16
tmp = (c-1) ^ 71
if tmp >= ord('a') and tmp <= ord('z'):
print(chr(tmp), end = "")
continue
tmp = (c+1) ^ 75
if tmp >= ord('A') and tmp <= ord('Z'):
print(chr(tmp), end = "")
continue
print(chr(c), end = "")

天外来题

这道我一开始没看出来是vm┭┮﹏┭┮

后来盯着这个循环才发觉,主程序是这样子的

image-20250718155001697

首先解决vm函数,得到key的计算方法

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
code = [
0xA2, 0x00, 0x84, 0xA3, 0x08, 0x00, 0xA3, 0x08, 0x01, 0xB0, 0x08, 0x013C, 0xB2, 0xA3, 0x09, 0x01, 0xA3, 0x09, 0x02, 0xA3,
0x09, 0x03, 0xB0, 0x09, 0x9E, 0xB2, 0xA6, 0x04, 0x16, 0xA3, 0x00, 0x04, 0xB0, 0x00, 0x0379, 0xB2, 0xA4, 0x05, 0x0B, 0xA1,
0x08, 0x05, 0xA3, 0x08, 0x06, 0xB0, 0x08, 0x26, 0xB2, 0xA3, 0x07, 0x06, 0xB0, 0x07, 0x60, 0xB2, 0xA1, 0x09, 0x01, 0xA3,
0x09, 0x02, 0xA5, 0x09, 0x05, 0xB0, 0x09, 0x6F, 0xB2, 0xA6, 0x05, 0x07, 0xA1, 0x08, 0x00, 0xA5, 0x08, 0x06, 0xA3, 0x08,
0x05, 0xB0, 0x08, 0x035B, 0xB2, 0xA3, 0x03, 0x04, 0xB0, 0x03, 0x02C2, 0xB2, 0xC0
]
opcode = {
160: 'mov', 161: 'mov', 162: 'add', 163: 'add',
164: 'sub', 165: 'sub', 166: 'mul', 167: 'mul',
176: 'cmp', 177: 'cmp', 178: 'jz'}

i = 0
while code[i] != 192:
op = code[i]
if op < 178:
en1 = code[i + 1]
en2 = code[i + 2]
if op == 160:
print("mov " + str(en1) + "," + str(en2))
if op == 161:
print("mov " + str(en1) + "," + str(en2))
if op == 162:
print("add " + str(en1) + "," + str(en2))
if op == 163:
print("add " + str(en1) + "," + str(en2))
if op == 164:
print("sub " + str(en1) + "," + str(en2))
if op == 165:
print("sub " + str(en1) + "," + str(en2))
if op == 166:
print("mul " + str(en1) + "," + str(en2))
if op == 167:
print("mul " + str(en1) + "," + str(en2))
if op == 176:
print("cmp " + str(en1) + "," + str(en2))
if op == 177:
print("cmp " + str(en1) + "," + str(en2))
if op == 178:
print("jz " + str(en1) + "," + str(en2))
print()
i += 1
continue
i += 3

拿到一些表达式,直接用z3解决

1
2
3
4
5
6
7
8
R[0]+132+R[1]=316
R[1]+R[2]+R[3]=158
R[0]+132+R[4]*22=889
R[5]-11+R[6]=38
R[7]+R[6]=96
R[1]+R[2]-R[5]+11=111
(R[5]-11)*7+R[0]+132+R[4]*22-R[6]=859
R[3]+R[4]*22=706
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from z3 import *
solver = Solver()
R = [Int(f'R_{i}') for i in range(8)]

solver.add(R[0] + 132 + R[1] == 316)
solver.add(R[1] + R[2] + R[3] == 158)
solver.add(R[0] + 132 + R[4] * 22 == 889)
solver.add(R[5] - 11 + R[6] == 38)
solver.add(R[7] + R[6] == 96)
solver.add(R[1] + R[2] - R[5] + 11 == 111)
solver.add((R[5] - 11) * 7 + R[0] + 132 + R[4] * 22 - R[6] == 859)
solver.add(R[3] + R[4] * 22 == 706)

if solver.check() == sat:
model = solver.model()
print("解:")
for i in range(8):
print(f"R[{i}] = {model[R[i]]}")
else:
print("无解!")

9787254630123759

然后就能更新dll了,可以看到dll里面的内容是一个异或

1
2
3
4
5
v5 = [13, 8, 26, 10, 29, 15,*b"2x*{*{|}qdz,{}d(}q,dxx}zd(z}p",127,*b"(z+~}yy4"]

a1 = bytes([x ^ 0x49 for x in v5[:44]])

print("Flag:", a1.decode())

【网鼎杯2020】signal

v4是opcode,我们将它取出来

image-20250723175604603

这里有一个switch-case结构构成vm

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
int __cdecl vm_operad(int *opcode, int a2)
{
int result; // eax
char input[200]; // [esp+13h] [ebp-E5h] BYREF
char v4; // [esp+DBh] [ebp-1Dh]
int v5; // [esp+DCh] [ebp-1Ch]
int v6; // [esp+E0h] [ebp-18h]
int v7; // [esp+E4h] [ebp-14h]
int v8; // [esp+E8h] [ebp-10h]
int v9; // [esp+ECh] [ebp-Ch]

v9 = 0; // eip
v8 = 0;
v7 = 0;
v6 = 0;
v5 = 0;
while ( 1 )
{
result = v9;
if ( v9 >= a2 )
return result;
switch ( opcode[v9] )
{
case 1:
input[v6 + 100] = v4;
++v9;
++v6;
++v8;
break;
case 2:
v4 = opcode[v9 + 1] + input[v8];
v9 += 2;
break;
case 3:
v4 = input[v8] - LOBYTE(opcode[v9 + 1]);
v9 += 2;
break;
case 4:
v4 = opcode[v9 + 1] ^ input[v8];
v9 += 2;
break;
case 5:
v4 = opcode[v9 + 1] * input[v8];
v9 += 2;
break;
case 6:
++v9;
break;
case 7:
if ( input[v7 + 100] != opcode[v9 + 1] )
{
printf("what a shame...");
exit(0);
}
++v7;
v9 += 2;
break;
case 8:
input[v5] = v4;
++v9;
++v5;
break;
case 10:
read(input);
++v9;
break;
case 11:
v4 = input[v8] - 1;
++v9;
break;
case 12:
v4 = input[v8] + 1;
++v9;
break;
default:
continue;
}
}
}

这个是取出来的opcode

1
[10, 4, 16, 8, 3, 5, 1, 4, 32, 8, 5, 3, 1, 3, 2, 8, 11, 1, 12, 8, 4, 4, 1, 5, 3, 8, 3, 33, 1, 11, 8, 11, 1, 4, 9, 8, 3, 32, 1, 2, 81, 8, 4, 36, 1, 12, 8, 11, 1, 5, 2, 8, 2, 37, 1, 2, 54, 8, 4, 65, 1, 2, 32, 8, 5, 1, 1, 5, 3, 8, 2, 37, 1, 4, 9, 8, 3, 32, 1, 2, 65, 8, 12, 1, 7, 34, 7, 63, 7, 52, 7, 50, 7, 114, 7, 51, 7, 24, 7, 4294967207, 7, 49, 7, 4294967281, 7, 40, 7, 4294967172, 7, 4294967233, 7, 30, 7, 122]

但是7后面有几个数过大,想一下程序中有LOBYTE取低位的操作重新处理一下,可以得到有效的opcode

1
2
3
4
[10, 4, 16, 8, 3, 5, 1, 4, 32, 8, 5, 3, 1, 3, 2, 8, 11, 1, 12, 8, 4, 4, 1, 5, 3, 8, 3, 33, 1, 11, 8, 11, 1, 4,
9, 8, 3, 32, 1, 2, 81, 8, 4, 36, 1, 12, 8, 11, 1, 5, 2, 8, 2, 37, 1, 2, 54, 8, 4, 65, 1, 2, 32, 8, 5, 1, 1, 5,
3, 8, 2, 37, 1, 4, 9, 8, 3, 32, 1, 2, 65, 8, 12, 1, 7, 34, 7, 63, 7, 52, 7, 50, 7, 114, 7, 51, 7, 24, 7, 167,
7, 49, 7, 241, 7, 40, 7, 132, 7, 193, 7, 30, 7, 122]

好了然后我们可以根据vm函数来打印出整体程序的流程

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
op = 0
v8 = 0
v7 = 0
v6 = 0
v5 = 0
#[10, 4, 16, 8, 3, 5, 1, 4, 32, 8, 5, 3, 1, 3, 2, 8, 11, 1, 12, 8, 4, 4, 1, 5, 3, 8, 3, 33, 1, 11, 8, 11, 1, 4, 9, 8, 3, 32, 1, 2, 81, 8, 4, 36, 1, 12, 8, 11, 1, 5, 2, 8, 2, 37, 1, 2, 54, 8, 4, 65, 1, 2, 32, 8, 5, 1, 1, 5, 3, 8, 2, 37, 1, 4, 9, 8, 3, 32, 1, 2, 65, 8, 12, 1, 7, 34, 7, 63, 7, 52, 7, 50, 7, 114, 7, 51, 7, 24, 7, 4294967207, 7, 49, 7, 4294967281, 7, 40, 7, 4294967172, 7, 4294967233, 7, 30, 7, 122]
opcode = [10, 4, 16, 8, 3, 5, 1, 4, 32, 8, 5, 3, 1, 3, 2, 8, 11, 1, 12, 8, 4, 4, 1, 5, 3, 8, 3, 33, 1, 11, 8, 11, 1, 4,
9, 8, 3, 32, 1, 2, 81, 8, 4, 36, 1, 12, 8, 11, 1, 5, 2, 8, 2, 37, 1, 2, 54, 8, 4, 65, 1, 2, 32, 8, 5, 1, 1, 5,
3, 8, 2, 37, 1, 4, 9, 8, 3, 32, 1, 2, 65, 8, 12, 1, 7, 34, 7, 63, 7, 52, 7, 50, 7, 114, 7, 51, 7, 24, 7, 167,
7, 49, 7, 241, 7, 40, 7, 132, 7, 193, 7, 30, 7, 122]
while op < len(opcode):
if opcode[op] == 1:
print(f"result[{v6 + 100}] = v4")
op += 1
v6 += 1
v8 += 1
elif opcode[op] == 2:
print(f"v4 = {opcode[op + 1]} + result[{v8}]")
op += 2
elif opcode[op] == 3:
print(f"v4 = result[{v8}] - {opcode[op + 1]}")
op += 2
elif opcode[op] == 4:
print(f"v4 = {opcode[op + 1]} ^ result[{v8}]")
op += 2
elif opcode[op] == 5:
print(f"v4 = {opcode[op + 1]} * result[{v8}]")
op += 2
elif opcode[op] == 6:
op += 1
elif opcode[op] == 7:
print(f"cmp result[{v7 + 100}] == {opcode[op + 1]}")
op += 2
v7 += 1
elif opcode[op] == 8:
print(f"result[{v5}] = v4")
op += 1
v5 += 1
elif opcode[op] == 10:
print("start")
op += 1
elif opcode[op] == 11:
print(f"v4 = result[{v8}] - 1")
op += 1
elif opcode[op] == 12:
print(f"v4 = result[{v8}] + 1")
op += 1
else:
continue

打印出来发现对result[100]-[114]进行了操作,然后对比,只需要解出这14位就可以了

这里确实写脚本的话还不如手算来的方便,求出值之后换成ASCII码就行了,最后套个flag

1
2
result[0..14] = [55, 53, 55, 53, 49, 53, 49, 50, 49, 102, 51, 100, 52, 55, 56]
ASCII: 757515121f3d478

符号执行

上面是比较正统的方法,我在网上还看到一种我从没见过的插件

https://github.com/illera88/Ponce

但是如果数据大小那边填15的话,只能输出13个数据

image-20250725160313349

然后我试了一下,大小填17,倒是能输出完整

image-20250725162454416

不断尝试了很多遍任然没有驯服,但是拼拼凑凑也差不多。。。。

image-20250725175210277

类型二

【DDCTF 2018】黑盒破解

这个就是一运行发现是要构造opcode,让程序输出binggo字符串,来读取flag

不正经的法一

看得我头晕

但是既然flag就在程序里面直接修改一下应该也能出来

结果o_o ….

image-20250717114510445

正经的法二

好了,既然是练习还是要认真看一下的

首先先找循环来读取指令,可以发现在main函数中藏着这么个函数,在相等的地方看汇编可以发现要对比的值是固定的

image-20250717172338347

动调提取出值,这里

image-20250717175842017

取出的值,我们需要输入的是这些

1
[0x2a,0x27,0x3e,0x5a,0x3f,0x4e,0x6a,0x2b,0x28]

写个脚本获取输入

1
2
3
4
5
6
data=[0x2,0x0,0x0,0xe,0x16,0x54,0x20,0x18,0x11,0x45,0x50,0x59,0x58,0x53,0x0,0x8,0x44,0x2d,0x46,0x39,0x0,0x54,0x42,0x1,0x3c,0xf,0x0,0x7,0x17,0x0,0x56,0x21,0x0,0x37,0x6d,0x2b,0x2a,0x6e,0x59,0x5d,0x47,0x3a,0x4a,0x34,0x44,0x48,0x43,0x6c,0x3f,0x59,0x25,0x33,0x55,0x2f,0x31,0x68,0x27,0x34,0x7c,0x28,0x67,0x59,0x0,0x52,0x0,0x26,0x0,0x3e,0x56,0x4e,0x33,0x21,0x45,0x6d,0x60,0x39,0x46,0x72,0x6d,0x4d,0x54,0x40,0x0,0x74,0x57,0x73,0x72,0x7a,0x47,0x45,0x0,0x71,0x0,0x4a,0x35,0x70,0x3b,0x36,0x2e,0x26,0x2c,0x6c,0x4a,0x0,0x7c,0x63,0x35,0x57,0x4d,0x41,0x43,0x62,0x0,0x68,0x37,0x0,0x5a,0x6a,0x6b,0x7c,0x29,0x69,0x4c,0x70,0x50,0x71,0x26,0x36,0x3c,0x6,0x1b,0x0,0x3c,0x30,0x0,0x0,0x0,0x4c,0xb,0x4b,0x48,0x8,0x54,0x47,0x12,0x9,0x24,0x0,0x0,0x24,0x40,0xd,0x39,0x6,0x5c,0x2c,0x1a,0x2d,0xa,0x38,0x35,0x37,0x16,0x3b,0x0,0x24,0x48,0x0,0x49,0x0,0x37,0x8,0x1f,0x24,0x45,0x1d,0x11,0x40,0x2f,0x4a,0x8,0x15,0x0,0x11,0x0,0x1a,0x22,0x41,0x52,0x5b,0xb,0x45,0x31,0x19,0x43,0x19,0x1e,0xa,0x21,0x5,0x4d,0x59,0x38,0x34,0x9,0x36,0x2f,0x43,0x2,0x53,0x12,0x2f,0x4c,0x21,0xd,0x3c,0x31,0x2e,0x37,0x8,0x30,0x29,0x32,0x2f,0x0,0x1a,0x14,0x41,0x53,0x15,0x21,0x0,0x8,0x13,0x38,0x5c,0x36,0x3b,0x50,0x0,0x2f,0x1e,0x57,0x0,0x30,0x2e,0xc,0x2e,0x37,0x52,0x1c,0x33,0x34,0x11,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0]
inpt=[0x2a,0x27,0x3e,0x5a,0x3f,0x4e,0x6a,0x2b,0x28]
indx=[]
for ch in inpt:
indx.append(chr(data.index(ch)))
print indx

找到开头的九个字符,正好九个,重开用动调在可以找到对应关系,而且也能到里层部分

1
$8Ct0Eu#;
1
2
3
4
5
6
7
8
9
$->sub_400DC1
8->sub_400E7A
C->sub_400F3A
t->sub_401064
0->sub_4011C9
E->sub_40133D
u->sub_4012F3
#->sub_4014B9
;->sub_400CF1

接下来动调分析函数里面的作用,一定要注意寄存器里面的值

[DDCTF 2018] 黑盒破解 - iPlayForSG - 博客园

得到函数的细节作用

直接构造就行,因为Binggo有6个字符后面要截断操作

总结

刚开始写下来真感觉自己的基础不是很好,寄存器汇编这边也是不断的查找很费时间U_U

练了几道题之后,任然是飞舞一个哈^_^