VNCTF2023

2023VNCTF-RE

👻自从上次试了考前CTF后,越试越上瘾,😭但考系统安全我怎么敢的,不过书确实背不下去啊,中午看到🐟哥也在线,就凑过去玩儿了玩儿,然后就陷进去了,比赛蛮不错的,可惜DLL没时间调了。😭考完试发现背的基本都用不上,看到题目都有点懵,全是分析题,可是🤡的脑子中塞满了5大服务、8大机制、11属性…,烤熟了都🥺🥺🥺。

实践课内容还不错,要是老师能带一下就好了,不然PPT中win server版本太低和一些内容表述不清楚真就是在乱搭。

信息系统安全

基本全是分析题😫,前6道题10分(也会一道题分成两个5分的),后面两道综合题25+15。

题目顺序和具体内容记不太清了,🤐是故意的还是不小心XD

一、“简答题”

  1. 说明消息认证码和加密技术实现消息认证的异同。
  2. 给了个被警告证书问题的URL,要求结合证书的相关知识解释可能出了什么问题。
  3. Kerberos中Client和AS交互AS不会验证对方用户身份就把包发过去是否安全。
  4. 为防止在线/离线的字典攻击给出常用的策略、协议、方法。
  5. 在内核态设计一个针对文件透明加密的系统(就是EFS~)。
  6. 几种数据备份的考察和RAID-5特点。

二、分析题

  1. (1)访问控制(给你案例,让你分析采用什么策略(DAC、MAC等)),使用什么模型(BLP、Biba、BN)。

    (2)实现低粒度访问控制,方便员工外出办公、读取文件,TLS VPN/IPSEC VPN选什么。

  2. 给出原表求匿名表。

2023VNCTF-WP

象棋王子

在play.js中找到主要逻辑,控制台运行那段brainfuck程序即可获取flag。

image-20230221213405239

Snake on web

逻辑在game.wasm,直接用wasm2c转为c文件再无链接编译,查看game_render。

image-20230221213431210

发现可以字符串解密,主要关注0x540和0x5f0偏移的数据。

image-20230221213446889

0x400偏移处的内存在VA 0x2394C处,通过0x2394C-0x400+offset即可提取两处的数据,解密脚本如下。

1
2
3
4
5
6
7
c=[0xFFFFFD84, 0x0000027B, 0x00000275, 0x00000279, 0x0000026B, 0xFFFFFDBB, 0x00000279, 0xFFFFFDB7, 0xFFFFFDA0, 0x00000275, 0xFFFFFDC0, 0xFFFFFDB7, 0xFFFFFDBC, 0xFFFFFDC8, 0xFFFFFDA7, 0xFFFFFDBA, 0xFFFFFDC2, 0xFFFFFDA4, 0xFFFFFDD3, 0xFFFFFDBD, 0xFFFFFD8E, 0xFFFFFD85, 0xFFFFFDC2, 0xFFFFFDD0, 0xFFFFFD96, 0xFFFFFDBD, 0xFFFFFDC1, 0xFFFFFDC2, 0xFFFFFDCC, 0xFFFFFDD1, 0xFFFFFDA7, 0xFFFFFDC3, 0xFFFFFD8D, 0xFFFFFDBE, 0xFFFFFDAB, 0xFFFFFDA3, 0x00000274, 0xFFFFFDD3, 0xFFFFFDC1, 0xFFFFFDBB, 0xFFFFFDBB, 0x0000027D, 0x00000275]
b=[0x73, 0x66, 0x61, 0x63, 0x65, 0x72, 0x61, 0x74, 0x72, 0x65, 0x62, 0x75, 0x6D, 0x76, 0x65, 0x72, 0x6F, 0x64, 0x6F, 0x6C, 0x6F, 0x72, 0x69, 0x6E, 0x64, 0x6F, 0x6C, 0x6F, 0x72, 0x74, 0x61, 0x6B, 0x69, 0x6D, 0x61, 0x74, 0x61, 0x76, 0x65, 0x72, 0x6F, 0x75, 0x00]

for i in range(len(c)):
c[i]=((c[i]^2)-5)^0x72
b[i]=(c[i]+b[i])&0xff
print(bytes(b))

PZGalaxy

逻辑在index.hml的<script>块,爆破日期后半部分解密rc4即可。

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
def Rc4_Encrypt(m,key):
s=[]
t=[]
out=[] #putput
for i in range(256):
s.append(i)
t.append(ord(key[i%len(key)]))

j=0
for i in range(256):
j=(j+s[i]+t[i])%256
s[i],s[j]=s[j],s[i]

i,j=0,0
for p in range(len(m)):
i=(i+1)%256
j=(j+s[i])%256

s[i],s[j]=s[j],s[i]

index=(s[i]+s[j])%256
out.append(s[index]^m[p])
return (bytes(out))
import itertools
c=[166,112,58,220,146,195,151,243,26,223,8,214,65,160,53,144,123,6,212,247,115,95,29,58,73,76,67,88,209,185,79,153,133,51,224,105,124]
for i in itertools.product([str(i) for i in range(10)],repeat=4):
k='2023'+''.join(i)
out=Rc4_Encrypt(bytes(c),k)
try:
print(out.decode())
except:
pass

confuse_re

加了一段花指令,rbp用于存储ip,将push rbp和pop rbp以及中间代码nop掉即可。

1
2
3
4
5
6
7
8
9
10
11
12
.text:0000000000404685                 push    rbp
.text:0000000000404686 call $+5
.text:000000000040468B pop rbp
.text:000000000040468C add rbp, 8
.text:0000000000404690 push rbp
.text:0000000000404691 retn
.text:0000000000404691 sub_40467D endp ; sp-analysis failed
.text:0000000000404691
.text:0000000000404691 ; ---------------------------------------------------------------------------
.text:0000000000404692 db 0E8h
.text:0000000000404693 ; ---------------------------------------------------------------------------
.text:0000000000404693 pop rbp

主逻辑在0x040291F处,第一段密文和第二段密文有个异或操作。

image-20230221213510336

aes加密的轮秘钥加多异或了0x23。

image-20230221213522470

脚本

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include<iostream>
#include<string.h>
#define uint8 unsigned char
#define uint32 unsigned int
uint8_t sbox[256] =
{
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};

uint8_t inv_s[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
};
uint8_t rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 };
uint8_t GFMul(uint8_t a, uint8_t b) {

uint8_t sig = 0, ans = 0;
while (a)
{
if (a & 1) ans ^= b;
a >>= 1;
if (a) {
sig = (b >> 7) & 1;
b <<= 1;
if (sig) b ^= 0x1B;
}
}
return ans;
}
void get_rk(uint8* k, uint8* w) {
uint8 tmp[4];
memcpy(w, k, 16);
for (int i = 4; i < 44; i++) {
tmp[0] = w[4 * (i - 1)];
tmp[1] = w[4 * (i - 1) + 1];
tmp[2] = w[4 * (i - 1) + 2];
tmp[3] = w[4 * (i - 1) + 3];
if (i % 4 == 0) {

tmp[0] = sbox[w[4 * (i - 1) + 1]];
tmp[1] = sbox[w[4 * (i - 1) + 2]];
tmp[2] = sbox[w[4 * (i - 1) + 3]];
tmp[3] = sbox[w[4 * (i - 1)]];

*(uint8*)tmp ^= rcon[i / 4];

}
w[4 * i] = w[4 * (i - 4)] ^ tmp[0];
w[4 * i + 1] = w[4 * (i - 4) + 1] ^ tmp[1];
w[4 * i + 2] = w[4 * (i - 4) + 2] ^ tmp[2];
w[4 * i + 3] = w[4 * (i - 4) + 3] ^ tmp[3];
}
}

void add_key(uint8* m, uint8* k, int len) {
for (int i = 0; i < len; i++)
m[i] ^= k[i]^0x23;
}

void sub_byte(uint8* m, int len) {
for (int i = 0; i < len; i++)
m[i] = sbox[m[i]];
}

void shift_row(uint8* m) {
uint8 sig, tmp, i, j;
for (i = 1; i < 4; i++) {
sig = 0;
while (sig < i)
{
tmp = m[i];
for (j = 0; j < 3; j++)
m[i + 4 * j] = m[i + 4 * (j + 1)];
m[i + 4 * j] = tmp;
sig += 1;
}
}
}
void mix_col(uint8* m) {
uint8 tmp[16];
memcpy(tmp, m, 16);
for (int i = 0; i < 16; i += 4) {
m[i] = GFMul(2, tmp[i]) ^ GFMul(3, tmp[i + 1]) ^ tmp[i + 2] ^ tmp[i + 3];
m[i + 1] = tmp[i] ^ GFMul(2, tmp[i + 1]) ^ GFMul(3, tmp[i + 2]) ^ tmp[i + 3];
m[i + 2] = tmp[i] ^ tmp[i + 1] ^ GFMul(2, tmp[i + 2]) ^ GFMul(3, tmp[i + 3]);
m[i + 3] = GFMul(3, tmp[i]) ^ tmp[i + 1] ^ tmp[i + 2] ^ GFMul(2, tmp[i + 3]);
}
}
void inv_sub_byte(uint8* m, int len) {
for (int i = 0; i < len; i++)
m[i] = inv_s[m[i]];
}
void inv_mix_col(uint8* m) {
uint8 tmp[16];
memcpy(tmp, m, 16);
for (int i = 0; i < 16; i += 4) {
m[i] = GFMul(0xe, tmp[i]) ^ GFMul(0xb, tmp[i + 1]) ^ GFMul(0xd, tmp[i + 2]) ^ GFMul(0x9, tmp[i + 3]);
m[i + 1] = GFMul(0x9, tmp[i]) ^ GFMul(0xe, tmp[i + 1]) ^ GFMul(0xb, tmp[i + 2]) ^ GFMul(0xd, tmp[i + 3]);
m[i + 2] = GFMul(0xd, tmp[i]) ^ GFMul(0x9, tmp[i + 1]) ^ GFMul(0xe, tmp[i + 2]) ^ GFMul(0xb, tmp[i + 3]);
m[i + 3] = GFMul(0xb, tmp[i]) ^ GFMul(0xd, tmp[i + 1]) ^ GFMul(0x9, tmp[i + 2]) ^ GFMul(0xe, tmp[i + 3]);
}
}
void inv_shift_row(uint8* m) {
uint8 sig, tmp, i, j;
for (i = 1; i < 4; i++) {
sig = 0;
while (sig < i)
{
tmp = m[i + 12];
for (j = 3; j > 0; j--)
m[i + 4 * j] = m[i + 4 * (j - 1)];
m[i] = tmp;
sig += 1;
}
}
}
void aes_encry(uint8* m, uint8* rk) {
int i;
add_key(m, rk, 16);
for (i = 1; i < 10; i++) {
sub_byte(m, 16);
shift_row(m);
mix_col(m);
add_key(m, rk + 16 * i, 16);
}
sub_byte(m, 16);
shift_row(m);
add_key(m, rk + 16 * i, 16);
}

void aes_decry(uint8* m, uint8* rk) {
int i;
add_key(m, rk + 160, 16);
for (i = 9; i > 0; i--) {
inv_sub_byte(m, 16);
inv_shift_row(m);
add_key(m, rk + 16 * i, 16);
inv_mix_col(m);
}
inv_sub_byte(m, 16);
inv_shift_row(m);
add_key(m, rk + 16 * i, 16);
}
void hexdump(uint8* m, int len) {
for (int i = 0; i < len; i++)
printf("%02x", m[i]);
printf("\n");
}
int main() {
char k[17] = { 0xCA, 0x9D, 0x7F, 0xF8, 0xA4, 0x09, 0x90, 0x04, 0xFA, 0xD4, 0x06, 0x61, 0xE9, 0x3B, 0x77, 0x5A };
char m[33] = { 0xDC, 0xDC, 0xCC, 0x66, 0x8D, 0xF3, 0x3C, 0x15, 0x50, 0x5E, 0xEF, 0x16, 0x46, 0xD9, 0xD7, 0xDF, 0x50, 0x27, 0x44, 0x77, 0x65, 0xDC, 0xA7, 0x39, 0x68, 0xCB, 0x7F, 0x7B, 0x88, 0xDD, 0x64, 0x0F };
unsigned int w[44];
get_rk((uint8*)k, (uint8*)w);

aes_decry((uint8*)m+16, (uint8*)w);
for (int i = 0; i < 16; i++) {
m[16 + i] = (m[16 + i] - 1) ^ m[i];
}
aes_decry((uint8*)m, (uint8*)w);
printf("%s", m);
return 0;
}

BabyAnti

so库中有反检测,patch为return 0,对于雷电模拟器就x86/x64。

image-20230221213541970

另外有个anticheat插件类,其中a函数会根据一个bool值做处理,这里直接给他用Androidkiller设定为恒真然后重新编译。

image-20230221213615054

之后模拟器运行就可以愉快的CE了,雷电模拟器的进程是Ld9BoxHeadless.exe,直接搜即可。

image-20230221213631137

先精确数值(4字节)搜0,之后在此基础上再次搜你当前score就能找到。

image-20230221213643323

jijiji

释放资源->父进程SMC解密子进程代码->TEA加密。
解法: dump出释放的文件,继续运行父进程到结束,会显示子进程的窗口,直接ida attach上就行了,加密逻辑就魔改tea。

image-20230221213700245

解密脚本

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
#include<iostream>
#define ut32 unsigned int
#define delta 0x88408067
void Tea_Encrypt(ut32* src, ut32* k) {
ut32 sum = 0;
ut32 v0 = src[0];
ut32 v1 = src[1];
for (int i = 0; i < 33; i++)
{
v0 += sum ^ (k[sum & 3] + sum) ^ (v1 + ((v1 >> 5) ^ (16 * v1)));
v1 += (k[(sum >> 11) & 3] + sum) ^ (v0 + ((v0 >> 5) ^ (16 * v0)));
sum += delta;
}
src[0] = v0;
src[1] = v1;
}
void Tea_Decrypt(ut32* enc, ut32* k) {
ut32 sum = delta * 33;
ut32 v0 = enc[0];
ut32 v1 = enc[1];
for (int i = 0; i < 33; i++) {
sum -= delta;
v1 -= (k[(sum >> 11) & 3] + sum) ^ (v0 + ((v0 >> 5) ^ (16 * v0)));
v0 -= sum ^ (k[sum & 3] + sum) ^ (v1 + ((v1 >> 5) ^ (16 * v1)));
}
enc[0] = v0;
enc[1] = v1;
}

void output(ut32* m, ut32 n) {
for (int i = 0; i < n; i++)
printf("0x%08x ", m[i]);
printf("\n");
}

int main() {
ut32 m[8] = { 0xADD4F778, 0xA6D7F132, 0x61813290, 0x2D4A40A6, 0x00B05F11, 0xB6D59424, 0x231BBFC6, 0xCD405B31 };
ut32 k[4] = { 0x62,0x6f,0x6d,0x62 };
for(int i=0;i<8;i+=2)
Tea_Decrypt(m+i, k);
for (int i = 0; i < 32; i++)
printf("%c", *((char*)m + i));
return 0;
}
//2d326e43eb8fea8837737fc0f50f83f2

dll_puzzle

Never gonna give you up

image-20230221213717262

写个程序加载dll,优先选择IDA调试,从TLS Callback函数进行分析,sub_1000B930用于输出明文字符,可以用idapython来帮助提取。

1
2
3
4
5
6
7
8
9
10
11
12
from ida_bytes import *
adr = 0x10023E08
data=0x1003D870+1
i=0
while data+i<0x1003DE48:
d=get_byte(data+i)
i+=1
if d==0xa:
print()
continue
t=get_byte(0x10023E08+d)
print(chr(t),end='')

解密出的一些字符,注册码文件license.ini,附件所给多加了一个下划线。

image-20230221213742478

sub_10001000函数通过比对进程名来进行反调试,断跳转直接把jz的74改成jmp的EB。

image-20230221213754084

也访问了PEB的一些位用来反调试。

image-20230221213805819

写个loaddll程序,设置在加载库时中断,等待目标库载入内存后找到他的tlscallback里面下断,新开一个IDA,并设置基址为库的加载基址,之后对照调试分析即可。

image-20230221213814908

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>
#include<Windows.h>
int main() {
HINSTANCE hDllInst = LoadLibrary("RegisterServer.dll");
if (hDllInst != NULL) printf("load success!\n");
while (true)
{
scanf("%s", 123456);
}
return 0;
}

image-20230221213846408

一步一个反调试,setlasterror之后getlasterror进入if块,sub_79BEB6E0会抛单步异常,不用管他直接跳过,之后是IsDebuggerPresent x) 漏出鸡脚了吧,sub_79BEB6E0是用于获取API的,暂时先不用逆,通过动调拿到计算后的API,这叫以退为进,看是否能调出个逻辑来。

image-20230221213859153

最后以PEB的一些特殊值来进行反调试,直接修改eip调过,之后sub_79BEA670中解密内存中的数据。

image-20230221213912827

对比解密出的数据,搜索特征可为SM4的FK和Sbox

image-20230221213939470

解密的数据终归是要用的,这里直接交叉引用,辅助定位到主要逻辑,发现最终的调用指向DLLMAIN+0x5B1处,而IDA只编译了少部分,仔细观摩发现存在SEH和花指令,在第一个call hint之后对eax的运算值为9,与0x51(81)相比决定跳转,第一次jz不会执行,因为call $+5 压入了mul eax处的地址,所以ret后会再进行mul eax,此时9x9=81即jz条件满足,先patch为jmp使ida反编译。

image-20230221213952590

修复main后部分的花指令。

image-20230222103529035

之后基本图穷匕现了,加密主体和比对密文都已知了,之后就要具体还原如何读入的license和具体的加密细节。

image-20230221214015848

💡: 在调试过程中,既然在TLS成功断下,那么如果后续调试失败而又想动态获取某个函数的返回值,可以直接改ip过去,不过该函数的参数和内部数据要尽量与外界独立,另外也可以使用hook、插桩等技术。

DLLMAIN函数内部仅用到了fdwReason参数,只需在比较时绕过jz即可,故对外依赖并不是很大,但可能还存在未解密的内存数据,调过DLLMAIN函数那获取API函数的地址,基本如下(非顺序对应)。

image-20230221214037587

调试到刚刚那个不可能执行的jz部分,call了一个hint提示,或许这里是作者为了隐藏DLLMAIN的大体代码而为之吧,可是这样毕竟会使得程序丧失原本功能 (或者是有啥修改控制流的逻辑没发现XD。

image-20230221214054129

v76调试知是读入的42转为int,之后进行的运算((((v76 * v76 * v76 * v76 + 21) // 0x15 - 13) >> 2) - 7041) // 0x2710的值为3,做个check验证读入是否正确。

image-20230221214115638

会将ini文件中FLAG的值通过一个函数判定是否为16进制格式。

🆘 : IDA调试时在伪代码窗口双击变量跳转的地址并不对不是预期的正确地址,需要在反汇编窗口调试汇编查看寄存器的值才是正确地址,这是什么原因呢? 😵

image-20230221214142763

下面会逐字节计算flag的和、乘积和或值来进行简单的校检,不要💣,怪怪调。调到try块的部分,进行一个SM4的秘钥扩展阶段。

进入DLLMAIN是在TLSCALLBACK入口直接飞过来的,所以数据没经过解密。并且在调用秘钥扩展时,将扩展秘钥的输出空间的首值设置为了1,所以扩展后的秘钥是 1、exkey[0]…的格式。

image-20230221214346782

💡:跳转到基址设置数据,对sm4_key交叉引用发信其在cxxstd__atoi函数中进行解密,逐字节异或42,也就是文件中的TheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything。

分组调用SM4加密函数,并且exkey是从第二项开始取的,所以那个首DWORD 1 可以忽略。

image-20230221214412147

破碎的程序,总有人在修修补补~ , SM4的加密部分,并且内部L函数并没有魔改。

image-20230221214425881

最后部分便是线性方程,如果不满足要求进入if块便会输出Verfication Error!。

image-20230221214438634

解约束方程即可,不涉及位运算并且数学规律比较明显用INT类型即可,BitVec可能会出错,脚本如下,标准SM4直接找CyberChef了。

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
from z3 import *
sm4k=[0x0A, 0x48, 0x18, 0x19, 0x04, 0x5E, 0x5C, 0x05, 0x53, 0x6C, 0x78, 0x69, 0x1D, 0x42, 0x73, 0x2A]
sm4k=[i^42 for i in sm4k]
buf =[Int("m%d"%i) for i in range(80)]
s=Solver()
s.add(5 * buf[1] + 8 * buf[0] == 2669 )
s.add(6 * buf[1] + 4 * buf[2] == 1402 )
s.add(3 * buf[3] + 6 * buf[2] == 873 )
s.add(7 * buf[4] + 6 * buf[3] == 2627 )
s.add(8 * buf[5] + 4 * buf[4] == 2516 )
s.add(9 * buf[6] + 5 * buf[5] == 2781 )
s.add(3 * buf[6] + 4 * buf[7] == 1228 )
s.add(5 * buf[8] + 9 * buf[7] == 1821 )
s.add(7 * buf[9] + 5 * buf[8] == 554 )
s.add(6 * buf[10] + 9 * buf[9] == 825 )
s.add(5 * buf[11] + 6 * buf[10] == 1857 )
s.add(3 * buf[11] + 4 * buf[12] == 1627 )
s.add(7 * buf[13] + 5 * buf[12] == 2279 )
s.add(3 * buf[14] + 9 * buf[13] == 1974 )
s.add(6 * buf[15] + 6 * buf[14] == 2382 )
s.add(7 * buf[15] + 8 * buf[16] == 1903 )
s.add(8 * buf[17] + 8 * buf[16] == 1336 )
s.add(3 * buf[18] + 6 * buf[17] == 822 )
s.add(5 * buf[19] + 8 * buf[18] == 381 )
s.add(3 * buf[20] + 5 * buf[19] == 823 )
s.add(5 * buf[21] + 5 * buf[20] == 1680 )
s.add(6 * buf[21] + 8 * buf[22] == 2116 )
s.add(9 * buf[23] + 3 * buf[22] == 1059 )
s.add(3 * buf[23] + 8 * buf[24] == 1314 )
s.add(3 * buf[25] + 9 * buf[24] == 1641 )
s.add(5 * buf[25] + 8 * buf[26] == 2148 )
s.add(3 * buf[27] + 3 * buf[26] == 669 )
s.add(5 * buf[28] + 9 * buf[27] == 953 )
s.add(5 * buf[29] + 7 * buf[28] == 1896 )
s.add(3 * buf[30] + 3 * buf[29] == 1275 )
s.add(5 * buf[31] + 7 * buf[30] == 2874 )
s.add(9 * buf[32] + 6 * buf[31] == 1518 )
s.add(7 * buf[33] + 5 * buf[32] == 1312 )
s.add(6 * buf[34] + 5 * buf[33] == 2148 )
s.add(9 * buf[34] + 8 * buf[35] == 2979 )
s.add(3 * buf[35] + 4 * buf[36] == 476 )
s.add(6 * buf[37] + 3 * buf[36] == 1047 )
s.add(7 * buf[38] + 4 * buf[37] == 1488 )
s.add(6 * buf[39] + 6 * buf[38] == 1320 )
s.add(5 * buf[40] + 6 * buf[39] == 1784 )
s.add(3 * buf[41] + 8 * buf[40] == 1994 )
s.add(7 * buf[42] + 3 * buf[41] == 712 )
s.add(3 * buf[43] + 3 * buf[42] == 1002 )
s.add(5 * buf[44] + 7 * buf[43] == 2094 )
s.add(3 * buf[45] + 3 * buf[44] == 465 )
s.add(5 * buf[46] + 6 * buf[45] == 1479 )
s.add(3 * buf[47] + 6 * buf[46] == 1281 )
s.add(7 * buf[48] + 4 * buf[47] == 1064 )
s.add(3 * buf[49] + 4 * buf[48] == 985 )
s.add(3 * buf[50] + 4 * buf[49] == 922 )
s.add(7 * buf[51] + 8 * buf[50] == 1672 )
s.add(9 * buf[51] + 4 * buf[52] == 1740 )
s.add(6 * buf[53] + 7 * buf[52] == 1185 )
s.add(6 * buf[54] + 9 * buf[53] == 711 )
s.add(4 * buf[55] + 4 * buf[54] == 256 )
s.add(7 * buf[56] + 8 * buf[55] == 744 )
s.add(5 * buf[57] + 8 * buf[56] == 1674 )
s.add(6 * buf[58] + 3 * buf[57] == 834 )
s.add(3 * buf[59] + 4 * buf[58] == 348 )
s.add(9 * buf[59] + 4 * buf[60] == 952 )
s.add(3 * buf[60] + 4 * buf[61] == 1117 )
s.add(7 * buf[62] + 9 * buf[61] == 1853 )
s.add(6 * buf[63] + 9 * buf[62] == 399 )
s.add(3 * buf[64] + 6 * buf[63] == 1011 )
s.add(6 * buf[65] + 9 * buf[64] == 3171 )
s.add(8 * buf[66] + 8 * buf[65] == 1760 )
s.add(7 * buf[67] + 7 * buf[66] == 861 )
s.add(6 * buf[68] + 6 * buf[67] == 1710 )
s.add(7 * buf[68] + 8 * buf[69] == 1578 )
s.add(7 * buf[70] + 9 * buf[69] == 1280 )
s.add(3 * buf[71] + 6 * buf[70] == 1134 )
s.add(3 * buf[72] + 8 * buf[71] == 1003 )
s.add(9 * buf[72] + 8 * buf[73] == 1345 )
s.add(5 * buf[74] + 4 * buf[73] == 928 )
s.add(3 * buf[74] + 4 * buf[75] == 824 )
s.add(6 * buf[76] + 8 * buf[75] == 1840 )
s.add(9 * buf[77] + 7 * buf[76] == 1200 )
s.add(3 * buf[77] + 8 * buf[78] == 2032 )
s.add(5 * buf[79] + 5 * buf[78] == 1795 )
s.add(7 * buf[79] + 8 * buf[0] == 2584 )
print(s.check())
m=s.model()
ans=[]
for i in range(80):
ans.append(m[buf[i]].as_long())
for i in sm4k:
print(hex(i)[2:].zfill(2),end='')
print()
for i in ans:
print(hex(i)[2:].zfill(2),end='')

image-20230221214454661


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!