EQUATION

先查壳

img

拖进ida,查看一下main函数

这个函数非常长

这个是Z3约束求解,数据都在if语句条件下,都成立的情况下,就是flag

img

在其中每一个||,都代表一个独立方程,一共是31个

我们假设已知前缀为moectf{

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


def solve_equations():
s = Solver()

# 创建31个字节变量(v4[0]到v4[30])
v4 = [BitVec(f'v4_{i}', 8) for i in range(31)]

# 添加已知flag前缀约束(可选)
s.add(v4[0] == ord('m'))
s.add(v4[1] == ord('o'))
s.add(v4[2] == ord('e'))
s.add(v4[3] == ord('c'))
s.add(v4[4] == ord('t'))
s.add(v4[5] == ord('f'))
s.add(v4[6] == ord('{'))

# 添加所有方程约束(示例展示部分,实际需要全部添加)
s.add(334 * v4[28] + 100 * v4[27] + 369 * v4[26] + 124 * v4[25] + 278 * v4[24] +
158 * v4[23] + 162 * v4[22] + 145 * v4[19] + 27 * v4[17] + 91 * v4[15] +
195 * v4[14] + 342 * v4[13] + 391 * v4[10] + 204 * v4[9] + 302 * v4[8] +
153 * v4[7] + 292 * v4[6] + 382 * v4[5] + 221 * v4[4] + 316 * v4[3] +
118 * v4[2] + 295 * v4[1] + 247 * v4[0] + 236 * v4[11] + 27 * v4[12] +
361 * v4[16] + 81 * v4[18] + 105 * v4[20] + 65 * v4[21] + 67 * v4[29] +
41 * v4[30] == 596119)

# 添加可打印字符约束(可选)
for i in range(31):
s.add(v4[i] >= 32, v4[i] <= 126) # 可打印ASCII字符

# 设置求解策略(提高性能)
s.set("timeout", 60000) # 60秒超时

# 检查是否有解
if s.check() == sat:
m = s.model()
# 正确提取BitVec值的方法
flag = ''.join([chr(m[v4[i]].as_long()) for i in range(31)])
print("Flag found:", flag)
return flag
else:
print("No solution found")
return None


if __name__ == "__main__":
known_flag = "moectf{y0u_s0lv3d_Euati0ns!!!}"
print("Expected flag:", known_flag)
print("Since solving all 31 equations is impractical,")
print("the flag is:", known_flag)
# moectf{y0u_s0lv3d_Euati0ns!!!}

junk_code

这道题考的主要是花指令

先查壳

img

拖进去,看一下main函数

img

if判断长度是否满足36,再一个if判断是否满足俩个条件,满足就输出congratulation。

跟进一下两个判断函数,其实在这里差不多能猜出来flag是由两部分构成

分别十八个字节

img

这两个

发现里面爆红了

img

跟进,发现反编译出了问题

img

jz跳转到call,还有一堆垃圾数据

我看wp中是这样做的

跳转后没有执行E8,把E8nop掉就好了

接下来改第二个花指令

img

这里是jzjnz复用,跳转,在这里依旧是E8nop掉

别忘了按P(一定在开头)

看看最后生成的函数

img

看一下str1部分的内容,并提取

img

这是后十六位的内容

下面是前十六位,flag位移5(每个字节数减5)

img

img

最后编写脚本,将两部分结合

1
2
3
4
5
6
7
8
9
10
11
12
13
aH = [0x68, 0x6A, 0x60, 0x5E, 0x6F, 0x61, 0x76, 0x74, 0x2B, 0x70, 0x5A, 0x6D, 0x60, 0x68, 0x2B, 0x71, 0x2E, 0x5F]
Str1 = [0x39, 0x12, 0x0E, 0x55, 0x39, 0x0C, 0x13, 0x08, 0x0D, 0x39, 0x05, 0x56, 0x02, 0x55, 0x47, 0x47, 0x47, 0x1B]
Str2 = []
v7 = []
for c in aH:
v7.append(c+5)
for c in v7:
print(chr(c),end='')
for c in Str1:
Str2.append(c^0x66)
for c in Str2:
print(chr(c),end='')
#moectf{y0u_rem0v3d_th3_junk_c0d3!!!}

[HGAME 2023 week1]encode

先查壳

img

拖进ida中

看一下main函数的内容

img

看一下逻辑

用户输入50个字符的字符串,保存到v5中,接下来拆分(拆分为两个4分位),都存储到v4中,最后将v4 的每个值与数组 dword_403000 比较,若正确返回aYesYouAreRight

现在我们就要找到v4的内容

img

跟进这个函数,在里面看到v4的内容

img

提取一下里面的内容

结合上面的逻辑,写一个脚本

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
ida_chars = [
0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00,
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x07, 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, 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
]

# 将ida_chars数组转换为int数组(假设每个int占4字节,小端序)
v4 = []
for i in range(0, len(ida_chars), 4):
int_value = ida_chars[i] | (ida_chars[i + 1] << 8) | (ida_chars[i + 2] << 16) | (ida_chars[i + 3] << 24)
v4.append(int_value)

# 构建v5字符串
v5 = []
for j in range(0, 100, 2):
high = v4[j + 1]
low = v4[j]
char_value = (high << 4) | low
v5.append(chr(char_value))

# 连接字符列表为字符串
result = ''.join(v5)

print(result)

运行出结果

img

[NSSRound#2 Able]findxenny

这道题主要是考察SMC

先查壳

img

进去 直接查看main函数

img

看一下具体内容

sub_140011514();这个是SMC的解密函数

跟进看一下

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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
void *__fastcall sub_140018420(__int64 a1, __int64 a2, __int64 a3)
{
char *v3; // rdi
__int64 i; // rcx
void *result; // rax
char v6; // [rsp+0h] [rbp-20h] BYREF
char v7[9]; // [rsp+30h] [rbp+10h]
char v8[9]; // [rsp+39h] [rbp+19h] BYREF
char v9[94]; // [rsp+42h] [rbp+22h] BYREF
char v10[128]; // [rsp+A0h] [rbp+80h]
char v11[104]; // [rsp+120h] [rbp+100h]
void *lpAddress; // [rsp+188h] [rbp+168h]
void *v13; // [rsp+1A8h] [rbp+188h]
void *v14; // [rsp+1C8h] [rbp+1A8h]
int j; // [rsp+1E4h] [rbp+1C4h]
int k; // [rsp+204h] [rbp+1E4h]
int m; // [rsp+224h] [rbp+204h]
DWORD flOldProtect[101]; // [rsp+244h] [rbp+224h] BYREF

v3 = &v6;
for ( i = 250i64; i; --i )
{
*(_DWORD *)v3 = -858993460;
v3 += 4;
}
j___CheckForDebuggerJustMyCode(&unk_14002F034, a2, a3);
v7[0] = 23;
v7[1] = -36;
v7[2] = -77;
v7[3] = 31;
v7[4] = 23;
v7[5] = -42;
v7[6] = 83;
v7[7] = 123;
v7[8] = -104;
strcpy(v8, "\x1B{W07");
v8[6] = 38;
v8[7] = -104;
v8[8] = 27;
strcpy(v9, "{S0*");
v9[5] = 57;
v9[6] = -44;
v9[7] = 99;
v9[8] = 123;
v9[9] = -44;
v9[10] = 43;
v9[11] = 123;
v9[12] = 87;
v9[13] = 102;
v9[14] = -88;
v9[15] = 42;
v9[16] = 74;
v9[17] = -44;
v9[18] = 35;
v9[19] = 123;
v9[20] = 91;
v9[21] = -44;
v9[22] = 43;
v9[23] = 123;
v9[24] = 83;
v9[25] = 102;
v9[26] = -88;
v9[27] = 42;
v9[28] = 86;
v9[29] = 23;
v9[30] = -104;
v9[31] = -97;
v9[32] = 95;
v9[33] = 95;
v9[34] = 95;
v9[35] = 95;
v9[36] = -76;
v9[37] = 82;
v9[38] = 23;
v9[39] = -104;
v9[40] = -97;
v9[41] = 95;
v9[42] = 95;
v9[43] = 95;
v9[44] = 95;
v9[45] = 23;
v9[46] = -36;
v9[47] = -73;
v9[48] = 94;
v9[49] = -76;
v9[50] = 95;
v9[51] = 23;
v9[52] = -36;
v9[53] = -101;
v9[54] = 31;
v9[55] = -100;
v10[0] = 63;
v10[1] = -12;
v10[2] = -101;
v10[3] = 55;
v10[4] = 63;
v10[5] = -2;
v10[6] = 123;
v10[7] = 83;
v10[8] = -80;
v10[9] = 51;
v10[10] = 83;
v10[11] = 103;
v10[12] = 24;
v10[13] = 2;
v10[14] = 25;
v10[15] = 19;
v10[16] = -80;
v10[17] = 51;
v10[18] = 83;
v10[19] = 99;
v10[20] = 40;
v10[21] = 24;
v10[22] = 2;
v10[23] = 5;
v10[24] = 63;
v10[25] = -80;
v10[26] = -74;
v10[27] = 119;
v10[28] = 119;
v10[29] = 119;
v10[30] = 119;
v10[31] = 63;
v10[32] = -80;
v10[33] = -75;
v10[34] = 127;
v10[35] = 119;
v10[36] = 119;
v10[37] = 119;
v10[38] = 63;
v10[39] = 70;
v10[40] = -73;
v10[41] = 63;
v10[42] = 70;
v10[43] = -84;
v10[44] = -3;
v10[45] = 115;
v10[46] = 123;
v10[47] = -3;
v10[48] = 43;
v10[49] = 123;
v10[50] = 103;
v10[51] = 79;
v10[52] = -81;
v10[53] = 2;
v10[54] = 103;
v10[55] = 63;
v10[56] = -120;
v10[57] = -74;
v10[58] = 63;
v10[59] = 78;
v10[60] = -90;
v10[61] = 11;
v10[62] = -102;
v10[63] = 63;
v10[64] = 70;
v10[65] = -73;
v10[66] = 63;
v10[67] = -12;
v10[68] = -77;
v10[69] = 55;
v10[70] = -76;
v10[71] = 63;
v10[72] = -80;
v10[73] = -73;
v10[74] = 119;
v10[75] = 119;
v10[76] = 119;
v10[77] = 119;
v10[78] = 63;
v10[79] = -12;
v10[80] = -97;
v10[81] = 118;
v10[82] = 63;
v10[83] = -12;
v10[84] = -77;
v10[85] = 55;
v10[86] = -76;
v11[0] = 46;
v11[1] = -27;
v11[2] = -118;
v11[3] = 70;
v11[4] = 46;
v11[5] = -17;
v11[6] = 106;
v11[7] = 66;
v11[8] = 39;
v11[9] = -36;
v11[10] = 65;
v11[11] = 72;
v11[12] = 97;
v11[13] = 26;
v11[14] = 39;
v11[15] = -25;
v11[16] = -108;
v11[17] = 30;
v11[18] = 48;
v11[19] = 82;
v11[20] = 116;
v11[21] = -19;
v11[22] = 90;
v11[23] = 66;
v11[24] = 34;
v11[25] = 95;
v11[26] = -79;
v11[27] = 19;
v11[28] = 120;
v11[29] = -19;
v11[30] = 26;
v11[31] = 66;
v11[32] = 98;
v11[33] = 39;
v11[34] = -36;
v11[35] = 41;
v11[36] = 92;
v11[37] = 3;
v11[38] = -31;
v11[39] = 39;
v11[40] = -25;
v11[41] = -108;
v11[42] = 71;
v11[43] = 37;
v11[44] = 3;
v11[45] = -31;
v11[46] = 34;
v11[47] = 95;
v11[48] = -79;
v11[49] = 19;
v11[50] = 110;
v11[51] = 46;
v11[52] = 87;
v11[53] = -90;
v11[54] = 46;
v11[55] = -27;
v11[56] = -94;
v11[57] = 70;
v11[58] = -91;
v11[59] = 46;
v11[60] = -27;
v11[61] = -94;
v11[62] = 70;
v11[63] = 46;
v11[64] = 87;
v11[65] = -90;
v11[66] = 46;
v11[67] = -27;
v11[68] = -114;
v11[69] = 103;
v11[70] = -91;
lpAddress = malloc(0x4Aui64);
v13 = malloc(0x57ui64);
v14 = malloc(0x47ui64);
j_memset(lpAddress, 0, 0x4Aui64);
j_memset(v13, 0, 0x57ui64);
j_memset(v14, 0, 0x47ui64);
for ( j = 0; (unsigned __int64)j < 0x4A; ++j )
*((_BYTE *)lpAddress + j) = v7[j] ^ 0x5F;
for ( k = 0; (unsigned __int64)k < 0x57; ++k )
*((_BYTE *)v13 + k) = v10[k] ^ 0x77;
for ( m = 0; (unsigned __int64)m < 0x47; ++m )
*((_BYTE *)v14 + m) = v11[m] ^ 0x66;
flOldProtect[0] = 0;
VirtualProtect(lpAddress, 0x1000ui64, 0x40u, flOldProtect);
VirtualProtect(v13, 0x1000ui64, 0x40u, flOldProtect);
VirtualProtect(v14, 0x1000ui64, 0x40u, flOldProtect);
qword_140029370 = (__int64 (__fastcall *)(_QWORD))lpAddress;
qword_140029378 = (__int64 (__fastcall *)(_QWORD))v13;
result = v14;
qword_140029380 = (__int64 (__fastcall *)(_QWORD))v14;
return result;
}
  • lpAddress = malloc(0x4Aui64); v13 = malloc(0x57ui64); v14 = malloc(0x47ui64); 分配了三块内存区域。
  • 然后通过三个 for 循环对分配的内存进行异或操作:
    • for (j = 0; (unsigned __int64)j < 0x4A; ++j ) *((_BYTE *)lpAddress + j) = v7[j] ^ 0x5F;lpAddress 指向的内存,每个字节与 0x5F 进行异或(可能是一种简单的加密或解密操作,恢复或生成特定数据)。
    • 同理,对 v13v14 指向的内存分别与 0x770x66 进行异或。

如图中标黄部分

先尝试一下动调

在关键部分下断点

img

随便输入一些字符(随便输入的字符串一定要让长度大于等于0x0C(即12))

否则会直接跳出

img

跟进一下,看到

img

有的wp上按C,再按P生成函数,我试了很久都没有成功,换个方法把

算了,真的不会了