June 29, 2022

ACTF2022-dropper

0x00 日常查壳

64位upx壳

image-20220630123736695

0x01 脱壳?

虽然工具可以直接脱,但是哒咩,脱了就不能运行了,直接载入x64debug

upx长度不大直接单步跟即可,当我碰到熟悉的jmp到OEP前的循环就知道这是出口了

image-20220630124402517

但是!直接dump出来依然和脱出来的没什么变化,所以我继续跟入找

0x02 RealProcess

发现每次到这的时候就会停住,然后要输入,输入完直接跑飞,所以搜索一下这个API

image-20220630124703051

可以知道这是在等待其他线程执行,那么也就是说真正的验证函数在另一个线程,于是反复调试可以发现

每次经过这个函数就会多一个线程,可以在任务管理器或者Procexp查看(能查看到不应该叫进程吗,雾,有师傅知道或许可以让我解惑一下

image-20220630125109827

那么我们看这个函数的参数,可以看到R8寄存器指向着MZ开头的东西,直接内存窗口查看dump出来!(要删点多余的数据)

0x03 逆向分析!

dump出来的文件可以正常执行!没错了就是这个

于是在start函数一路寻找找到主函数(下次一定好好命名

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
__int64 sub_7FF6BD84D080()
{
char *v0; // rdi
__int64 i; // rcx
__int64 copy_input; // rax
__int64 base_input; // rax
__int64 bignum; // rax
_DWORD *Wbignum; // rax
__int64 v6; // rax
__int64 v7; // rax
char v9; // [rsp+20h] [rbp+0h] BYREF
char input[72]; // [rsp+28h] [rbp+8h] BYREF
char Winput[2040]; // [rsp+70h] [rbp+50h] BYREF
void (__fastcall ***vbtable1)(_QWORD, __int64); // [rsp+868h] [rbp+848h]
__int64 v13; // [rsp+888h] [rbp+868h]
char v14[3576]; // [rsp+8B0h] [rbp+890h] BYREF
char v15[64]; // [rsp+16A8h] [rbp+1688h] BYREF
char v16[64]; // [rsp+16E8h] [rbp+16C8h] BYREF
char *v17; // [rsp+1728h] [rbp+1708h]
_QWORD *v18; // [rsp+1748h] [rbp+1728h]
void *v19; // [rsp+1768h] [rbp+1748h]
char v20; // [rsp+1788h] [rbp+1768h] BYREF
char *v21; // [rsp+1F78h] [rbp+1F58h]
char v22[64]; // [rsp+1F98h] [rbp+1F78h] BYREF
__int64 v23; // [rsp+1FD8h] [rbp+1FB8h]
void *v24; // [rsp+1FF8h] [rbp+1FD8h]
char v25[64]; // [rsp+2018h] [rbp+1FF8h] BYREF
char v26[64]; // [rsp+2058h] [rbp+2038h] BYREF
void (__fastcall ***v27)(_QWORD, _QWORD); // [rsp+2098h] [rbp+2078h]
unsigned int v28; // [rsp+20B4h] [rbp+2094h]
int v29; // [rsp+20D4h] [rbp+20B4h]
__int64 t; // [rsp+20E8h] [rbp+20C8h]
__int64 v31; // [rsp+20F0h] [rbp+20D0h]
_QWORD *v32; // [rsp+20F8h] [rbp+20D8h]

v0 = &v9;
for ( i = 1726i64; i; --i )
{
*v0 = -858993460;
v0 += 4;
}
v29 = 0;
what(dword_7FF6BD8660F2);
t = Reverse(v15, &flag, 5i64);
v31 = t;
printf(std::cout, t);
clear(v15);
sub_7FF6BD8417DF(input);
get(std::cin, input);
t = strlen_0(input);
copy_input = strcopy(input);
base_input = Base64(copy_input, t);
P1(input, base_input);
v17 = v16;
t = P2(v16, input);
ToW(Winput, t);
v19 = malloc_0(0x7E0ui64);
if ( v19 )
{
v21 = &v20;
t = Reverse(v22, ::bignum, 360i64);
v31 = t;
v29 |= 1u;
bignum = strcopy(t);
Wbignum = W(v21, bignum); // 四位一组 尾巴开始
v32 = vbtable(v19, Wbignum);
}
else
{
v32 = 0i64;
}
v18 = v32;
vbtable1 = v32;
if ( (v29 & 1) != 0 )
{
v29 &= 0xFFFFFFFE;
clear(v22);
}
sub_7FF6BD841226(vbtable1); // 触发异常
v24 = malloc_0(0x7D4ui64);
if ( v24 )
t = sub_7FF6BD84152D(v24, Winput);
else
t = 0i64;
v23 = t;
v13 = t;
(**vbtable1)(vbtable1, t);
SUB(v13, v14, (vbtable1 + 1));
if ( check(v14) )
{
t = Reverse(v25, &unk_7FF6BD85F910, 4i64);
v31 = t;
LODWORD(v6) = printf(std::cout, t);
std::ostream::operator<<(v6, sub_7FF6BD84105A);
clear(v25);
}
else
{
t = Reverse(v26, &unk_7FF6BD85F920, 5i64);
v31 = t;
LODWORD(v7) = printf(std::cout, t);
std::ostream::operator<<(v7, sub_7FF6BD84105A);
clear(v26);
}
v27 = vbtable1;
if ( vbtable1 )
t = sub_7FF6BD841316(v27, 1i64);
else
t = 0i64;
v28 = 0;
clear(input);
return v28;
}

挑真正的执行流来讲,稍加调试即可知

image-20220630130436613

异常处理

在触发异常的函数来,有个F5看不到的地方,就是这,然而触发异常会跑过来(如果有时候知道这个异常是怎么设置的务必教教!

image-20220630130636790

随后跑到这执行虚表函数,而t就是我们的输入

image-20220630130910752

RealEncrypt

可能一开始进去有点bangzhu,但起始都是同一个函数,是以万进制进行加减乘操作(所以要做好函数命名)

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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
_DWORD *__fastcall realVbtable(__int64 bignum, __int64 input)
{
char *v2; // rdi
__int64 i; // rcx
__int64 v4; // rax
__int64 v5; // rax
__int64 v6; // rax
__int64 v7; // rax
__int64 v8; // rax
__int64 v9; // rax
__int64 v10; // rax
__int64 v11; // rax
__int64 v12; // rax
__int64 v13; // rax
__int64 v14; // rax
__int64 v15; // rax
__int64 v16; // rax
__int64 v17; // rax
__int64 v18; // rax
__int64 v19; // rax
__int64 v20; // rax
__int64 v21; // rax
__int64 v22; // rax
__int64 v23; // rax
char v25; // [rsp+20h] [rbp+0h] BYREF
char key1[2048]; // [rsp+30h] [rbp+10h] BYREF
char key2[2048]; // [rsp+830h] [rbp+810h] BYREF
char key3[2048]; // [rsp+1030h] [rbp+1010h] BYREF
char key4[2048]; // [rsp+1830h] [rbp+1810h] BYREF
char v30[2048]; // [rsp+2030h] [rbp+2010h] BYREF
char v31[2048]; // [rsp+2830h] [rbp+2810h] BYREF
char v32[2048]; // [rsp+3030h] [rbp+3010h] BYREF
char v33[2048]; // [rsp+3830h] [rbp+3810h] BYREF
char v34[2048]; // [rsp+4030h] [rbp+4010h] BYREF
char v35[2048]; // [rsp+4830h] [rbp+4810h] BYREF
char copy_input[3576]; // [rsp+5030h] [rbp+5010h] BYREF
char v37[64]; // [rsp+5E28h] [rbp+5E08h] BYREF
char v38[64]; // [rsp+5E68h] [rbp+5E48h] BYREF
char v39[64]; // [rsp+5EA8h] [rbp+5E88h] BYREF
char v40[64]; // [rsp+5EE8h] [rbp+5EC8h] BYREF
char v41[64]; // [rsp+5F28h] [rbp+5F08h] BYREF
char v42[64]; // [rsp+5F68h] [rbp+5F48h] BYREF
char v43[64]; // [rsp+5FA8h] [rbp+5F88h] BYREF
char v44[64]; // [rsp+5FE8h] [rbp+5FC8h] BYREF
char v45[64]; // [rsp+6028h] [rbp+6008h] BYREF
char v46[72]; // [rsp+6068h] [rbp+6048h] BYREF
char v47[2048]; // [rsp+60B0h] [rbp+6090h] BYREF
char v48[2048]; // [rsp+68B0h] [rbp+6890h] BYREF
char v49[2048]; // [rsp+70B0h] [rbp+7090h] BYREF
char v50[2048]; // [rsp+78B0h] [rbp+7890h] BYREF
char v51[2048]; // [rsp+80B0h] [rbp+8090h] BYREF
char v52[2048]; // [rsp+88B0h] [rbp+8890h] BYREF
char v53[2048]; // [rsp+90B0h] [rbp+9090h] BYREF
char v54[2048]; // [rsp+98B0h] [rbp+9890h] BYREF
char v55[2048]; // [rsp+A0B0h] [rbp+A090h] BYREF
char v56[2024]; // [rsp+A8B0h] [rbp+A890h] BYREF
__int64 v57; // [rsp+B098h] [rbp+B078h]
__int64 v58; // [rsp+B0A0h] [rbp+B080h]

v2 = &v25;
for ( i = 10918i64; i; --i )
{
*v2 = 0xCCCCCCCC;
v2 += 4;
}
what(dword_7FF6BD8660F2);
v57 = Reverse(v37, &data1, 80i64);
v58 = v57;
v4 = strcopy(v57);
W(key1, v4);
clear(v37);
v57 = Reverse(v38, &dword_7FF6BD85E7C0, 80i64);
v58 = v57;
v5 = strcopy(v57);
W(key2, v5);
clear(v38);
v57 = Reverse(v39, &unk_7FF6BD85E900, 80i64);
v58 = v57;
v6 = strcopy(v57);
W(key3, v6);
clear(v39);
v57 = Reverse(v40, &unk_7FF6BD85EA40, 80i64);
v58 = v57;
v7 = strcopy(v57);
W(key4, v7);
clear(v40);
v57 = Reverse(v41, &unk_7FF6BD85EB80, 80i64);
v58 = v57;
v8 = strcopy(v57);
W(v30, v8);
clear(v41);
v57 = Reverse(v42, &unk_7FF6BD85ECC0, 80i64);
v58 = v57;
v9 = strcopy(v57);
W(v31, v9);
clear(v42);
v57 = Reverse(v43, &unk_7FF6BD85EE00, 80i64);
v58 = v57;
v10 = strcopy(v57);
W(v32, v10);
clear(v43);
v57 = Reverse(v44, &unk_7FF6BD85EF40, 80i64);
v58 = v57;
v11 = strcopy(v57);
W(v33, v11);
clear(v44);
v57 = Reverse(v45, &unk_7FF6BD85F080, 80i64);
v58 = v57;
v12 = strcopy(v57);
W(v34, v12);
clear(v45);
v57 = Reverse(v46, &unk_7FF6BD85F1C0, 80i64);
v58 = v57;
v13 = strcopy(v57);
W(v35, v13);
clear(v46);
sub_7FF6BD84152D(copy_input, input);
v14 = ADD(copy_input, v47, key1);
a2toa1(copy_input, v14);
v15 = MUL(copy_input, v48, key2);
a2toa1(copy_input, v15);
v16 = SUB(copy_input, v49, key3);
a2toa1(copy_input, v16);
v17 = ADD(copy_input, v50, key4);
a2toa1(copy_input, v17);
v18 = MUL(copy_input, v51, v30);
a2toa1(copy_input, v18);
v19 = SUB(copy_input, v52, v31);
a2toa1(copy_input, v19);
v20 = ADD(copy_input, v53, v32);
a2toa1(copy_input, v20);
v21 = SUB(copy_input, v54, v33);
a2toa1(copy_input, v21);
v22 = ADD(copy_input, v55, v34);
a2toa1(copy_input, v22);
v23 = SUB(copy_input, v56, v35);
a2toa1(copy_input, v23);
return a2toa1(input, copy_input);
}

所以密钥全部拿上,这个虚表出去后还有一轮SUB

再取上最后一轮SUB的密钥,不过在SUB的结尾有个小细节,这个是设置a1[500]的值,

image-20220630131750885

0x04 GetFlag!

在最后的check函数是判断这轮加密后是否为0和a1[500] == 1
没错密文为0!(如何优雅的手撕密文0

image-20220630131613812

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
import base64
key = [0x000020F1, 0x00001DA9, 0x00000156, 0x00000B37, 0x000007C0, 0x0000066A, 0x000024E0, 0x00000D42, 0x00002077, 0x000007EC, 0x00001BA7, 0x00002071, 0x000000F8, 0x00000291, 0x000003DA, 0x0000157C, 0x00001EF4, 0x00002519, 0x00000C25, 0x00002062, 0x00002253, 0x00000640, 0x000008DF, 0x00001E34, 0x00002140, 0x00000F92, 0x0000039B, 0x0000126F, 0x00002403, 0x00000E65, 0x000001F0, 0x00001868, 0x0000016D, 0x000006B6, 0x00002214, 0x00001603, 0x00001925, 0x000016AE, 0x000012D0, 0x00001831, 0x0000018C, 0x00000BF7, 0x00000E97, 0x000000CE, 0x0000061C, 0x00000390, 0x000019E9, 0x000022A5, 0x00001601, 0x00001A1E, 0x000013D1, 0x00000DBC, 0x0000117D, 0x0000225F, 0x00002272, 0x0000007B, 0x000023E6, 0x0000069F, 0x000002D3, 0x00001BEF, 0x000003E6, 0x000017D4, 0x00002284, 0x000003B8, 0x00000251, 0x00001646, 0x00000176, 0x0000081E, 0x000024C3, 0x00001E85, 0x00001097, 0x00001264, 0x00000A34, 0x00001A3B, 0x00000FE7, 0x000026A6, 0x00001F43, 0x00001832, 0x000021AE, 0x0000023C, 0x000004C2, 0x00002585, 0x000017E7, 0x000015DD, 0x00002610, 0x00001B86, 0x00000D2A, 0x00000716, 0x00001C25, 0x00002099]
keys = [[0x000024AC, 0x00000116, 0x000004F4, 0x00000B64, 0x00001DC3, 0x00001B4A, 0x000001B2, 0x00001FCE, 0x00000E81, 0x000025AB, 0x0000015B, 0x0000252D, 0x000002AC, 0x00000F77, 0x000022F5, 0x000019E3, 0x00001C53, 0x00000B66, 0x000011BC, 0x0000193A],
[0x00000DC6, 0x00000854, 0x000015F5, 0x00002567, 0x000008FA, 0x00000E20, 0x00000807, 0x00001007, 0x000018CC, 0x00001E84, 0x00001F11, 0x000013D4, 0x0000076A, 0x00001461, 0x00000B0F, 0x00001F70, 0x00001B3D, 0x00001008, 0x00000D52, 0x0000049A],
[0x00001A89, 0x00000E42, 0x000000FA, 0x0000100D, 0x000014DD, 0x00001BFC, 0x000026DB, 0x00001AC2, 0x00001CA0, 0x000005ED, 0x00000834, 0x000016BF, 0x00000704, 0x00001FAD, 0x000025FD, 0x00001142, 0x00001EEE, 0x00001E60, 0x00000353, 0x000015A8],
[0x00000E17, 0x00000706, 0x00000C1F, 0x00000169, 0x00002248, 0x000007FD, 0x00001768, 0x00001F54, 0x00001574, 0x00002458, 0x00000374, 0x00001D6B, 0x00000918, 0x00000ECF, 0x0000211D, 0x00001D96, 0x00001BEB, 0x00001703, 0x00001B87, 0x000006FA],
[0x00000AE3, 0x0000069F, 0x000001EF, 0x00001C15, 0x00001378, 0x000020D1, 0x0000211D, 0x00002275, 0x000005F4, 0x00002475, 0x00000D13, 0x000008EF, 0x00000E10, 0x000006D4, 0x0000215A, 0x000004D6, 0x0000202F, 0x00001B99, 0x00001C86, 0x000002F1],
[0x00000680, 0x000000D4, 0x00000677, 0x00001E21, 0x0000220D, 0x00000933, 0x00000973, 0x00001947, 0x00000D61, 0x0000247F, 0x00001D21, 0x00001FA2, 0x00001606, 0x000007B0, 0x00001829, 0x000016C0, 0x000026C9, 0x0000248C, 0x00000C9A, 0x00001F8F],
[0x0000257F, 0x00000359, 0x00001831, 0x000021B7, 0x00000BA8, 0x00000FC5, 0x00000BA4, 0x000024E2, 0x00001241, 0x00000D53, 0x00000C82, 0x00001240, 0x00002241, 0x00001156, 0x0000116A, 0x000005F3, 0x000022D5, 0x000008DA, 0x000014A3, 0x0000059E],
[0x00001675, 0x00000AA9, 0x00000D8B, 0x00000D31, 0x00001722, 0x000006C8, 0x0000151B, 0x000017D8, 0x00001FEF, 0x00001624, 0x00002307, 0x00000CB9, 0x0000053C, 0x00000230, 0x00001EAA, 0x00001FD1, 0x00000FAD, 0x00001E30, 0x00002345, 0x00001583],
[0x000001D1, 0x0000056E, 0x00000AA3, 0x0000223C, 0x000009A4, 0x000006C9, 0x00000112, 0x00001977, 0x00002512, 0x00000B60, 0x0000081A, 0x00000F06, 0x00001329, 0x000011AA, 0x00002404, 0x00000E57, 0x0000011E, 0x000011DC, 0x00002474, 0x00001BC7],
[0x000022BE, 0x00001F17, 0x00000588, 0x00001B80, 0x00001479, 0x000016EF, 0x000008CA, 0x00000D6E, 0x0000138F, 0x00001054, 0x000021FA, 0x00000102, 0x000013A6, 0x00000195, 0x000002D1, 0x00002594, 0x00001369, 0x00002534, 0x000015C5, 0x0000168A]]
encInput = 0
for i in key[::-1]:
encInput = encInput * 10000 + i
data= [0] * 10
for i, val in enumerate(keys):
for j in val[::-1]:
data[i] = data[i] * 10000 + j
encInput += data[9]
encInput -= data[8]
encInput += data[7]
encInput -= data[6]
encInput += data[5]
encInput //= data[4]
encInput -= data[3]
encInput += data[2]
encInput //= data[1]
encInput -= data[0]
ans = ''
while encInput:
ans += chr(encInput % 128)
encInput //= 128
print(base64.b64decode(ans))

GetFlag!

image-20220630132306663

文章参考

https://hxz3zo0taq.feishu.cn/docx/doxcnvG34b3f65w5st0bu8Jd7d7

https://mp.weixin.qq.com/s?__biz=MzIzMTQ4NzE2Ng==&mid=2247492349&idx=1&sn=b108b8a122ebe6423dbb90e2deb1b591&chksm=e8a1c12cdfd6483a35b5dcdc91a915df9095f90fb35dc51a248075a1dafa9cb37448ba197664&mpshare=1&scene=23&srcid=0629gArbU9CbyORIgBf1Dpno&sharer_sharetime=1656500672749&sharer_shareid=122e5be9c4961e59957c3603ed41e762#rd

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

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