January 11, 2022

GWCTF 2019-babyvm

0x00 日常查壳

无壳64位

image-20220111164319409

0x01 分析主函数

vm的题,关键是找到操作码和操作数,太久没做vm的题,一直动调在跟(虽然也有必要但真的把我弄乱了)

image-20220111170444003

init函数

初始化四个数其实就是四个临时的数的区域 方便理解可以理解成rax rbx rcx rdx四个寄存器即可

其他分别的0xF1 0xF2其实都是一个操作

image-20220111170604897

借用别的师傅的整理好的一用(文末有链接)

image-20220111170755876

所以初始化完是个什么样子?画了个草图

大概内存长这样(具体动调看一下即可),首先开始的四个位置是内存区域的数(其实不算eax也不算rax,只是用了四个字节存放了一个数),然后0x0010放着指向操作码的地址,随后就是0xF1然后指向0xF1的地址

image-20220111171430496

0xF1

特别讲下0xF1的函数,0xE1 0xE2都是指向内存区域的四个位置,这里暂且称为rax rbx

动调可以发现qword_2022A8是指向flag的位置(虽然从头到尾都没发现哪里让我们输入了),不过通过0xF5函数(判断长度的flag的长度的函数)可以发现所判断的字符串的和这串是同一串,于是可以确定指向的地址是我们输入flag的地址

话说回来,E1 E2 E3 E5分别是rax rbx rcx rdx,v2是操作码里的给下标,于是可以直接翻译为mov rax, flag[0]

那么E4 E7 就可以翻译成mov flag[0], rax(下标0只是个例子)

(那么其他的0xFX翻译起来都没有问题了,只需要注意是a1 + x的问题)

image-20220111171839780

Excute

这边就是执行操作码的地方了(可以动调跟几条操作码)

image-20220111172444629

0x02 反汇编

分析到现在(如果你已经动调跟了一段认真看了各个函数),于是差不多可以是看着操作码还原了

但操作码太长了,于是直接获取操作码机译即可

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
107
108
109
110
#include <stdio.h>
#include <string.h>

int main(void)
{
unsigned char 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
};
int i, j;

for ( i = 0; i < sizeof(opcode) / sizeof(unsigned char); i++ )
{
if ( opcode[i] == 0xF1 )
{
switch (opcode[i + 1])
{
case 0xE1:
printf("mov rax, flag[%d]\n", opcode[i + 2]);
break;
case 0xE2:
printf("mov rbx, flag[%d]\n", opcode[i + 2]);
break;
case 0xE3:
printf("mov rcx, flag[%d]\n", opcode[i + 2]);
break;
case 0xE4:
printf("mov flag[%d], rax\n", opcode[i + 2]);
break;
case 0xE5:
printf("mov rdx, flag[%d]\n", opcode[i + 2]);
break;
case 0xE7:
printf("mov flag[%d], rbx\n", opcode[i + 2]);
break;
}
}
else if ( opcode[i] == 0xF2 )
printf("xor rax, rbx\n");
else if ( opcode[i] == 0xF5 )
printf("\n!!!Judgment length\n");
else if ( opcode[i] == 0xF4 )
printf("nop\n");
else if ( opcode[i] == 0xF7 )
printf("mul rax, rdx\n");
else if ( opcode[i] == 0xF8 )
printf("swap rax, rbx\n");
else if ( opcode[i] == 0xF6 )
printf("rax = rcx + rbx * 2 + rax * 3\n");
}

return 0;
}

直接复制过来 会发现前一段是假的的!!!(一开始跟的我头大) 从第二个Judgment length才是真的flag加密

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
!!!Judgment length		//错误的
mov rax, flag[0]
xor rax, rbx
mov flag[32], rax
mov rax, flag[1]
xor rax, rbx
mov flag[33], rax
mov rax, flag[2]
xor rax, rbx
mov flag[34], rax
mov rax, flag[3]
xor rax, rbx
mov flag[35], rax
mov rax, flag[4]
xor rax, rbx
mov flag[36], rax
mov rax, flag[5]
xor rax, rbx
mov flag[37], rax
mov rax, flag[6]
xor rax, rbx
mov flag[38], rax
mov rax, flag[7]
xor rax, rbx
mov flag[39], rax
mov rax, flag[8]
xor rax, rbx
mov flag[40], rax
mov rax, flag[9]
xor rax, rbx
mov flag[41], rax
mov rax, flag[10]
xor rax, rbx
mov flag[42], rax
mov rax, flag[11]
xor rax, rbx
mov flag[43], rax
mov rax, flag[12]
xor rax, rbx
mov flag[44], rax
mov rax, flag[13]
xor rax, rbx
mov flag[45], rax
mov rax, flag[14]
xor rax, rbx
mov flag[46], rax
mov rax, flag[15]
xor rax, rbx
mov flag[47], rax
mov rax, flag[16]
xor rax, rbx
mov flag[48], rax
mov rax, flag[17]
xor rax, rbx
mov flag[49], rax
mov rax, flag[18]
xor rax, rbx
mov flag[50], rax
mov rax, flag[19]
xor rax, rbx
mov flag[51], rax
nop

!!!Judgment length //正确的
mov rax, flag[0]
mov rbx, flag[1]
xor rax, rbx
mov flag[0], rax
mov rax, flag[1]
mov rbx, flag[2]
xor rax, rbx
mov flag[1], rax
mov rax, flag[2]
mov rbx, flag[3]
xor rax, rbx
mov flag[2], rax
mov rax, flag[3]
mov rbx, flag[4]
xor rax, rbx
mov flag[3], rax
mov rax, flag[4]
mov rbx, flag[5]
xor rax, rbx
mov flag[4], rax
mov rax, flag[5]
mov rbx, flag[6]
xor rax, rbx
mov flag[5], rax
mov rax, flag[6]
mov rbx, flag[7]
mov rcx, flag[8]
mov rdx, flag[12]
rax = rcx + rbx * 2 + rax * 3
mul rax, rdx
mov flag[6], rax
mov rax, flag[7]
mov rbx, flag[8]
mov rcx, flag[9]
mov rdx, flag[12]
rax = rcx + rbx * 2 + rax * 3
mul rax, rdx
mov flag[7], rax
mov rax, flag[8]
mov rbx, flag[9]
mov rcx, flag[10]
mov rdx, flag[12]
rax = rcx + rbx * 2 + rax * 3
mul rax, rdx
mov flag[8], rax
mov rax, flag[13]
mov rbx, flag[19]
swap rax, rbx
mov flag[13], rax
mov flag[19], rbx
mov rax, flag[14]
mov rbx, flag[18]
swap rax, rbx
mov flag[14], rax
mov flag[18], rbx
mov rax, flag[15]
mov rbx, flag[17]
swap rax, rbx
mov flag[15], rax
mov flag[17], rbx
nop

于是打个草稿

  1. 前五位异或

  2. 678位Z3解

  3. 三位三位置换

image-20220111173208893

0x03 GetFlag

check

还有个坑就是check函数 噢突然发现这边也提示了flag的区域就在这

image-20220111173628246

坑在哪?就是这串flag并不能逆回去 我们点进2022A8 查找引用会发现这第五个还有个判断 会发现还有一串

image-20220111173754073

或者点进aFzAmAm…就是假的那串enflag

会发现还有串数据 一般是不会留无用的数据 直接ctrl + x上面那串数据 就能确定这才是真正的enflag

image-20220111173930379

逻辑比较简单 写个逆回去的脚本

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
from z3 import *

ef = [0x69, 0x45, 0x2A, 0x37, 0x09, 0x17, 0xC5, 0x0B, 0x5C, 0x72, 0x33, 0x76, 0x33, 0x21, 0x74, 0x31, 0x5F, 0x33, 0x73, 0x72]
f = [0 for i in range(len(ef))]

(ef[13], ef[19]) = (ef[19], ef[13])
(ef[14], ef[18]) = (ef[18], ef[14])
(ef[15], ef[17]) = (ef[17], ef[15])

# S = Solver()

# x, y, z = BitVecs('x y z', 7)
# S.add( (x * 3 + y * 2 + z) * ef[12] == ef[6] )
# S.add( (y * 3 + z * 2 + ef[9]) * ef[12] == ef[7] )
# S.add( (z * 3 + ef[9] * 2 + ef[10]) * ef[12] == ef[8] )

# if S.check() == sat:
# print(S.model())
# [z = 95, y = 51, x = 118]

ef[6] = 118
ef[7] = 51
ef[8] = 95

for i in range(5, -1, -1):
ef[i] = ef[i] ^ ef[i + 1]

print("flag{", end="")
for i in range(len(ef)):
print(chr(ef[i]), end="")
print("}")

GetFlag!

image-20220111174103524

文献参考

http://91wxk.cn/index.php/archives/932/

https://blog.csdn.net/m0_46296905/article/details/116374983

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

This post is written by P.Z, licensed under CC BY-NC 4.0.