0%

WEIRD_VM

看到空白出了一道vm题,就做了一下,感觉出的还是很好的,而且拿到了3血。

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned __int16 *v3; // rax
__int64 v4; // rdx
unsigned __int16 *opcode; // rbx
int result; // eax
__int64 v7; // rdx
__int64 v8; // r8
__int64 v9; // rcx
__int64 v10; // rax
__int64 v11; // r9
unsigned __int16 v12; // dx

v3 = (unsigned __int16 *)VirtualAlloc(0i64, 0x20000ui64, 0x1000u, 4u);
qword_140029990 = (__int64)v3;
opcode = v3;
if ( v3 )
{
sub_140002830(v3 + 300, &unk_140024A40, 15790i64);
*opcode = 300;
do
{
if ( opcode[4] == 1 )
{
v7 = opcode[3];
opcode[4] = 0;
printf("%c", v7);
opcode = (unsigned __int16 *)qword_140029990;
}
if ( opcode[6] == 1 )
{
opcode[6] = 0;
scanf("%c", opcode + 5);
opcode = (unsigned __int16 *)qword_140029990;
}
v8 = *opcode;
v9 = opcode[v8 + 1];
v10 = opcode[v8];
v11 = opcode[v8 + 2];
*opcode = v8 + 3;
v12 = ~(opcode[v10] | opcode[v9]);
opcode[v11] = v12;
opcode[1] = __ROL2__(v12, 1);
}
while ( *opcode != 0xFFFF );
VirtualFree(opcode, 0i64, 0x8000u);
result = 0;
qword_140029990 = 0i64;
}
else
{
printf("Init vm failed\n", v4);
return 0;
}
return result;
}

这类的vm感觉设计非常巧妙,我们dump出来opcode,opcode很多,所以只挑一些重点在此分析:

先看明白一些重要的步骤:
如最后一位是7,下一行前两位是7,那么可以认为是传值,即0x1ff2的值传到opcode[3]中

1
2
0x1ff2 0x1ff2 0x7
0x7 0x7 0x3 //a[3] 赋值a[7]P

典型的跳转函数,最后一位是0,就代表要jmp了:

1
2
3
0x7 0x7 0x0 
0x773 0x0
0x0

接下来从头开始看:

这个板块就是printf输出,打印字符串,这个板块统一的模式就是下图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0x1ff2 0x1ff2 0x7
0x7 0x7 0x3 //a[3] 赋值a[7]P
0x138 0x138 0x7
0x7 0x7 0x0 A[0] = 0X13A,jmp a[0]
0x13a 0x1 //跳过
0x139,0x139 0x7
0x7,0x7 0x4 //a[4] =1
0x1fef,0x1fef 0x7
0x7 0x7 0x3 // l
0x14c 0x14c 0x7
0x7 0x7 0x0//jmp
0x14e 0x1 //跳过
0x14d 0x14d 0x7
0x7 0x7 0x4
0x1ff0 0x1ff0 0x7
0x7 0x7 0x3
0x160 0x160 0x7
0x7 0x7 0x0
0x162 0x1
0x161 0x161 0x7
0x7 0x7 0x4

略过printf后,接下来是scanf环节,scanf拥有字符后会传进0x1fc7:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//scanf
0x2fe 0x2fe 0x7
0x7 0x7 0x0//jmp
0x300 0x307 //跳过
0x2ff 0x2ff 0x7
0x7 0x7 0x0 //跳过
0x0
0x30d 0x30d 0x7
0x7 0x7 0x0//跳过
0x30f 0x1
0x30e 0x30e 0x7
0x7 0x7 0x6
0x5 0x5 0x7 //输入传到a[7]
0x7 0x7 0x1fc7 //写入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
0x1f99 0x1f99 0x6c0 //flag运算后存入0x6c0
0x1faa 0x1faa 0x6c1 //这个值存入0x6c1
0x6ce 0x6ce 0x7 //跳转
0x7 0x7 0x0
0x6d1 0x0
0x0
0x1f99 0x1f99 0x6cf //flag运算后存入0x6cf
0x6c1 0x6c1 0x6d0 //固定的这个值要搞两下
0x6cf 0x6d0 0x7 /0x6
0x7 0x7 0x7 //0xfff9
0x7 0x7 0x6c1 //固定值被覆盖0x6
0x6e6 0x6e6 0x7
0x7 0x7 0x0
0x6e9 0x0
0x0
0x1faa 0x1faa 0x6e7 //固定值存在0x6e7
0x6c0 0x6c0 0x6e8 //flag运算后存入0x6c0的值再搞一下
0x6e7 0x6e8 0x7
0x7 0x7 0x7
0x7 0x7 0x6c0 //0x6c0存入0x6e7 0x6e8 0x7 值
0x6c0 0x6c1 0x7
0x7 0x7 0x1f99 //覆盖原flag加密后的值
0x1f99 0x306 0x7 //加密后的跟0搞
0x7 0x7 0x306 //存入306

上面是刚做题时候分析的,其实第一个加密还是很简单的,我们用简单表示一下,也就是经过15次ROL加密,然后对比:

1
2
3
4
5
6
7
8
9
10
for k in range(0,127):
a[5] = k
a[1] = ROL(k,1)
a[5] = a[1]
for i in range(14):
a[1] = ROL(a[5],1)
a[5] = a[1]
#print(hex(a[5]))
if(a[5] == 0x22):
print(chr(k))

第二个加密是很长也是最难分析的:

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
0x1fc9 0x1fc9 0x762 //0X53->0XFFAC
0x1fa2 0x1fa2 0x763 //0X12 ->0XFFED
0x770 0x770 0x7
0x7 0x7 0x0
0x773 0x0
0x0
0x1fc9 0x1fc9 0x771 //0X53 ->0XFFAC//////////////////////////X
0x763 0x763 0x772 //0xFFED->0X12 ///////////////////////0X12
0x771 0x772 0x7 //0X41
0x7 0x7 0x7
0x7 0x7 0x763
0x788 0x788
0x7 0x7 0x7
0x0 0x78b 0x0
0x0
0x1fa2 0x1fa2 0x789 //0X12->>0XFFED
0x762 0x762 0x78a //0XFFAC->0X53
0x789 0x78a 0x7 //0
0x7 0x7 0x7
0x7 0x7 0x762
0x762 0x763 0x7 //0
0x7 0x7 0x1f99
0x7a6 0x7a6 0x7
0x7 0x7
0x0 0x7a9 0x0
0x0
0x1f99 0x1f99
0x7a7 0x1fb8 0x1fb8 /////////////第一等是答案 0x41
0x7a8 0x7b5 0x7b5
0x7 0x7 0x7
0x0 0x7b8 0x0
0x0
0x1f99 0x1f99
0x7b6 0x7a8 0x7a8 //////////////////第二个等式答案0
0x7b7 0x7b6 0x7b7
0x7 0x7 0x7
0x7 0x7 0x7
0x7a8 0x7cd 0x7cd
0x7 0x7 0x7
0x0 0x7d0 0x0
0x0
0x1fb8 0x1fb8 /////////////第一等是答案 0x41
0x7ce 0x7a7 0x7a7
0x7cf 0x7ce 0x7cf
0x7 0x7 0x7ROL(a[5],1)
0x7 0x7 0x7
0x7a7 0x7a7 0x7a8
0x7 0x7 0x7
0x1f99 0x1f99 0x306
0x7 0x7 0x7
0x306

看出来其实也比较简单,就是两组数分别做运算:

1
2
3
4
5
6
7
8
for i in range(27,127):
x = ~(i|i) & 0XFFFF
xx = ~(x|0X33) & 0XFFFF
y = ~(0X33|0X33) & 0XFFFF
yy = ~(y|i) & 0XFFFF
p = ~(xx|yy)&0xffff
if((~(p|p)&0xffff == 0x41)):
print(chr(i))

第三种是最简单的加密:

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
0x1fec 0x1fec
0x7 0x7 0x7
0x1fec 0x1 0x1
0x7 0x7 0x7
0x1f99 0x1d03 0x1d03
0x7 0x7 0x7
0x0 0x1d06 0x0
0x0 0x1f99 0x1f99
0x1d04 0x1fc4 0x1fc4
0x1d05 0x1d12 0x1d12
0x7 0x7 0x7
0x0 0x1d15 0x0
0x0 0x1f99 0x1f99
0x1d13 0x1d05 0x1d05
0x1d14 0x1d13 0x1d14
0x7 0x7 0x7
0x7 0x7 0x7
0x1d05 0x1d2a 0x1d2a
0x7 0x7 0x7
0x0 0x1d2d 0x0
0x0 0x1fc4 0x1fc4
0x1d2b 0x1d04 0x1d04
0x1d2c 0x1d2b 0x1d2c
0x7 0x7 0x7
0x7 0x7 0x7
0x1d04 0x1d04 0x1d05
0x7 0x7 0x7
0x1f99 0x1f99 0x306
0x7 0x7 0x7
0x306
0x1d4e 0x1d4e 0x7
0x7 0x7 0x0
0x1d50 0x0

会发现加密比较明显,就是做了一次ROL:

1
2
3
for i in range(27,127):
if(0X60 == ROL(i,1)):
print(chr(i))

只要把这三种加密搞懂,就可以进行爆破来得出每一位的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
//存在这个地方
0x0 0x1 0x86
0x6 0x7 0x88
0x8 0x8c 0xc
0x12 0x1b 0x1c
0xa0 0x8022 0x23
0x22 0xa6 0x27
0x29 0x2a 0x8029
0xac 0x802f 0x32
0x33 0x37 0x39
0x3c 0x803d 0x3e
0xbe 0x41 0x43
0xca 0x4f 0x53
0x5e 0x5f 0x60
0x62 0xe4 0x6e
0x6f 0xfa 0x7b
0x7e

//写flag进去
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
0x72 0x6f 0x6c
0x65 0x61 0x50
0x73 0x57 0x64
0x74 0x67 0x3a
0x20 0x43 0x66
0x6e 0x52 0x69
0x70 0x75 0x79

他这个rol加密跟平常见的好像还不太一样:

1
2
3
4
5
def ROL(i,index):
tmp = bin(i)[2:].rjust(16, "0")
for _ in range(index):
tmp = tmp[1:] + tmp[0]
return int(tmp, 2) &0xffff

得到flag:NSSCTF{Pr0_ReVEr3Er_F1n1SHeD_We1RD_Vm}

Inflated

这个题是很久以前ACTF的一道题了,但由于最近打ctf经常遇到混淆,所以先从简单的ollvm搞起,顺便仔细学习一下异常类。

Exception

首先是异常,c++异常我们基本上是通过手动patch块来找到catch块,如何分辩可以通过rdx的值。

当前函数抛出异常后,如果在该函数没有找到catch块,那么就继续向上找catch块,出现两种情况

第一:找到catch块

第二:没有找到catch块,调用std::terminal(),即把程序abort掉

当找到catch块后,会执行对应操作。

程序中代码块有个专有名词:landing pad,从抛异常到开始,再到执行landing pad代码,这整个过程叫做Stack unwind

Stack unwind主要作用是:沿着链向上找catch块,且清理调用链上栈中的局部变量

其中 stack unwind库在intel平台上,属于Itanium ABI接口中的一部分,由系统实现,跟语言无关,任何上层语言都能通过接口的基础实现各自异常处理

Itanium ABI定义了数据结构来建立异常处理流程和框架

1
2
3
4
5
6
7
8
9
10
_Unwind_RaiseException,//用于stack unwind
_Unwind_Resume,
_Unwind_DeleteException,
_Unwind_GetGR,
_Unwind_SetGR,
_Unwind_GetIP,
_Unwind_SetIP,
_Unwind_GetRegionStart,
_Unwind_GetLanguageSpecificData,
_Unwind_ForcedUnwind

_Unwind_RaiseException()函数用于进行stack unwind,它在用户执行throw时候被调用,主要功能就是从当前函数开始,对调用链上的每个函数都调用一个personality routine函数

当我们在代码中写下throw xxx,编译器会分配一个数据结构**__cxa_exception**来表示该异常,异常头部:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct __cxa_exception 
{
std::type_info * exceptionType;
void (*exceptionDestructor) (void *);
unexpected_handler unexpectedHandler;
terminate_handler terminateHandler;
__cxa_exception * nextException;

int handlerCount;
int handlerSwitchValue;
const char * actionRecord;
const char * languageSpecificData;
void * catchTemp;
void * adjustedPtr;

_Unwind_Exception unwindHeader;
};

整个头部下面才是exception obj。

所以当我们在程序里执行了抛出异常的操作,编译器为我们做了如下的事情:

  1. 调用 __cxa_allocate_exception 函数,分配一个异常对象(__cxa_exception,数据结构如上)
  2. 调用 __cxa_throw 函数,这个函数会将异常对象做一些初始化
  3. __cxa_throw() 调用 Itanium ABI 里的 _Unwind_RaiseException() 从而开始 unwind
  4. _Unwind_RaiseException() 对调用链上的函数进行 unwind 时,调用 personality routine()
  5. 该异常如能被处理(有相应的 catch),则 personality routine 会依次对调用链上的函数进行清理
  6. _Unwind_RaiseException() 将控制权转到相应的catch代码
  7. unwind 完成,用户代码继续执行

这个题最骚的是把exception源码给改了,我们找到__gxx_personality_v0,点Y修改其函数类型

1
2
3
4
5
6
_Unwind_Reason_Code __fastcall _gxx_personality_v0(
int Version,
_Unwind_Action actions,
__int64 exceptionClass,
_Unwind_Exception *exceptionObject,
_Unwind_Context *context)

然后看scan_eh_tab(),这里面有两个关键值被魔改了,先shift+F1存入参数结构体,然后点Y修改scan_eh_tab

1
2
3
4
5
6
7
8
9
struct scan_results
{
int64_t ttypeIndex;
const uint8_t* actionRecord;
const uint8_t* languageSpecificData;
uintptr_t landingPad;
void* adjustedPtr;
_Unwind_Reason_Code reason;
};
1
void scan_eh_tab(scan_results *results, _Unwind_Action actions, bool native_exception, _Unwind_Exception *unwind_exception, _Unwind_Context *context)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
while ( 1 )
{
if ( v33 <= (unsigned __int64)v22 )
call_terminate(native_exception, unwind_exception);
v35 = readEncodedPointer(&v22, v19);
v36 = readEncodedPointer(&v22, v19);
v10 = readEncodedPointer(&v22, v19);
v37 = (13 * (_BYTE)v22 + 95) & 0x3F ^ 0x33u ^ (unsigned __int64)v10;//landing pad
v38 = readULEB128(&v22);
if ( v35 <= v30 && v30 < v35 + v36 )
break;
if ( v30 < v35 )
call_terminate(native_exception, unwind_exception);
}

此处landing pad被修改,所以catch分发处的地址已经被魔改了

第二处

1
2
3
4
5
6
7
8
9
10
11
12
13
if ( v47 == &`typeinfo for'StdObfException )
{
v48 = thrown_object_ptr;
v27 = 27 * (42 * (char)*thrown_object_ptr + (int)v27) % 0x61u;
}
results->ttypeIndex = v27;
results->actionRecord = v39;
results->adjustedPtr = thrown_object_ptr;
results->reason = _URC_HANDLER_FOUND;
return;
}
}
goto LABEL_54;

v27是ttypeindex,最后的ttypeIndex由 thrown_object_ptr(由我们的第一段输入所决定的thrown_object_ptr) 和 原始固定固定typeIndex 决定

OLLVM

这篇文章写的还是不错的:https://bluesadi.github.io/0x401RevTrain-Tools/angr/10_%E5%88%A9%E7%94%A8angr%E7%AC%A6%E5%8F%B7%E6%89%A7%E8%A1%8C%E5%8E%BB%E9%99%A4%E6%8E%A7%E5%88%B6%E6%B5%81%E5%B9%B3%E5%9D%A6%E5%8C%96/

Bytectf2022

题的质量都很高,而且绝大部分知识点都是我不会的,所以接下来一个月,抽时间就来复现。

OhMySolidity

这个题是一个智能合约题,第一次接触这种类型的题,发现反编译出来的东西很抽象。

给了一个txt文件

我们将第一段input输入https://ethervm.io/这个网站就可以得到反编译后的样子:

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
272
273
274
275
276
277
278
contract Contract {
function main() {
memory[0x40:0x60] = 0x80;
var var0 = msg.value;

if (var0) { revert(memory[0x00:0x00]); }

if (msg.data.length < 0x04) { revert(memory[0x00:0x00]); }

var0 = msg.data[0x00:0x20] >> 0xe0;

if (var0 == 0x14edb54d) {
// Dispatch table entry for k1()
var var1 = 0x006f;
var var2 = k1();
var temp0 = memory[0x40:0x60];
memory[temp0:temp0 + 0x20] = var2 & 0xffffffff;
var temp1 = memory[0x40:0x60];
return memory[temp1:temp1 + (temp0 + 0x20) - temp1];
} else if (var0 == 0x58f5382e) {
// Dispatch table entry for challenge(string)
var1 = 0x014a;
var2 = 0x04;
var var3 = msg.data.length - var2;

if (var3 < 0x20) { revert(memory[0x00:0x00]); }

var1 = challenge(var2, var3);
var temp2 = memory[0x40:0x60];
var2 = temp2;
var3 = var2;
var temp3 = var3 + 0x20;
memory[var3:var3 + 0x20] = temp3 - var3;
var temp4 = var1;
memory[temp3:temp3 + 0x20] = memory[temp4:temp4 + 0x20];
var var4 = temp3 + 0x20;
var var6 = memory[temp4:temp4 + 0x20];
var var5 = temp4 + 0x20;
var var7 = var6;
var var8 = var4;
var var9 = var5;
var var10 = 0x00;

if (var10 >= var7) {
label_018A:
var temp5 = var6;
var4 = temp5 + var4;
var5 = temp5 & 0x1f;

if (!var5) {
var temp6 = memory[0x40:0x60];
return memory[temp6:temp6 + var4 - temp6];
} else {
var temp7 = var5;
var temp8 = var4 - temp7;
memory[temp8:temp8 + 0x20] = ~(0x0100 ** (0x20 - temp7) - 0x01) & memory[temp8:temp8 + 0x20];
var temp9 = memory[0x40:0x60];
return memory[temp9:temp9 + (temp8 + 0x20) - temp9];
}
} else {
label_0178:
var temp10 = var10;
memory[var8 + temp10:var8 + temp10 + 0x20] = memory[var9 + temp10:var9 + temp10 + 0x20];
var10 = temp10 + 0x20;

if (var10 >= var7) { goto label_018A; }
else { goto label_0178; }
}
} else if (var0 == 0x93eed093) {
// Dispatch table entry for 0x93eed093 (unknown)
var1 = 0x01cd;
var2 = func_056F();
var temp11 = memory[0x40:0x60];
memory[temp11:temp11 + 0x20] = var2 & 0xffffffff;
var temp12 = memory[0x40:0x60];
return memory[temp12:temp12 + (temp11 + 0x20) - temp12];
} else if (var0 == 0x9577a145) {
// Dispatch table entry for 0x9577a145 (unknown)
var1 = 0x0251;
var2 = 0x04;
var3 = msg.data.length - var2;

if (var3 < 0x80) { revert(memory[0x00:0x00]); }

func_0205(var2, var3);
stop();
} else if (var0 == 0xa7f81e6a) {
// Dispatch table entry for k2()
var1 = 0x025b;
var2 = k2();
var temp13 = memory[0x40:0x60];
memory[temp13:temp13 + 0x20] = var2 & 0xffffffff;
var temp14 = memory[0x40:0x60];
return memory[temp14:temp14 + (temp13 + 0x20) - temp14];
} else if (var0 == 0xf0407ca7) {
// Dispatch table entry for 0xf0407ca7 (unknown)
var1 = 0x0285;
var2 = func_0623();
var temp15 = memory[0x40:0x60];
memory[temp15:temp15 + 0x20] = var2 & 0xffffffff;
var temp16 = memory[0x40:0x60];
return memory[temp16:temp16 + (temp15 + 0x20) - temp16];
} else { revert(memory[0x00:0x00]); }
}

function challenge(var arg0, var arg1) returns (var r0) {
var temp0 = arg0;
arg0 = temp0 + arg1;
arg1 = temp0;
var var1 = msg.data[arg1:arg1 + 0x20];
var var0 = arg1 + 0x20;

if (var1 > 0x0100000000) { revert(memory[0x00:0x00]); }

var temp1 = arg1 + var1;
var1 = temp1;

if (var1 + 0x20 > arg0) { revert(memory[0x00:0x00]); }

var temp2 = var1;
var temp3 = msg.data[temp2:temp2 + 0x20];
var1 = temp3;
var temp4 = var0;
var0 = temp2 + 0x20;
var var2 = temp4;

if ((var1 > 0x0100000000) | (var0 + var1 > arg0)) { revert(memory[0x00:0x00]); }

var temp5 = var1;
var temp6 = memory[0x40:0x60];
memory[0x40:0x60] = temp6 + (temp5 + 0x1f) / 0x20 * 0x20 + 0x20;
memory[temp6:temp6 + 0x20] = temp5;
var temp7 = temp6 + 0x20;
memory[temp7:temp7 + temp5] = msg.data[var0:var0 + temp5];
memory[temp7 + temp5:temp7 + temp5 + 0x20] = 0x00;
arg0 = temp6;
arg1 = 0x60;
var0 = arg0;
var1 = 0x00;
var2 = 0x08;
var var3 = memory[var0:var0 + 0x20];

if (!var2) { assert(); }

if (var3 % var2 != var1) { revert(memory[0x00:0x00]); }

var1 = 0x60;
var temp8 = memory[var0:var0 + 0x20];
var temp9 = memory[0x40:0x60];
var2 = temp9;
var3 = temp8;
memory[var2:var2 + 0x20] = var3;
memory[0x40:0x60] = var2 + (var3 + 0x1f & ~0x1f) + 0x20;

if (!var3) {
var1 = var2;
var2 = 0xdeadbeef;
var3 = 0x00;

if (var3 >= memory[var0:var0 + 0x20]) {
label_0563:
return var1;
} else {
label_032D:
var var4 = 0x00;
var var5 = 0x00;
var var6 = 0x00;
var var7 = 0x00;

if (var7 & 0xff >= 0x04) {
label_03CD:
var7 = 0x00;

if (var7 & 0xff >= 0x20) {
label_047F:
var7 = 0x00;

if (var7 & 0xff >= 0x04) {
label_0554:
var3 = var3 + 0x08;

if (var3 >= memory[var0:var0 + 0x20]) { goto label_0563; }
else { goto label_032D; }
} else {
label_0493:
var temp10 = var7;
var var8 = (((var5 & 0xffffffff) >> (0x03 - temp10 * 0x08 & 0xff)) & 0xff) << 0xf8;
var var9 = var1;
var var10 = var3 + (temp10 & 0xff);

if (var10 >= memory[var9:var9 + 0x20]) { assert(); }

memory[var10 + 0x20 + var9:var10 + 0x20 + var9 + 0x01] = byte(var8 & ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x00);
var temp11 = var7;
var8 = (((var6 & 0xffffffff) >> (0x03 - temp11 * 0x08 & 0xff)) & 0xff) << 0xf8;
var9 = var1;
var10 = var3 + (temp11 & 0xff) + 0x04;

if (var10 >= memory[var9:var9 + 0x20]) { assert(); }

memory[var10 + 0x20 + var9:var10 + 0x20 + var9 + 0x01] = byte(var8 & ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x00);
var7 = var7 + 0x01;

if (var7 & 0xff >= 0x04) { goto label_0554; }
else { goto label_0493; }
}
} else {
label_03E1:
var temp12 = var4 + var2;
var4 = temp12;
var temp13 = var6;
var temp14 = var5 + (((temp13 & 0xffffffff) << 0x04) + (storage[0x00] & 0xffffffff) ~ temp13 + var4 ~ ((temp13 & 0xffffffff) >> 0x05) + (storage[0x00] / 0x0100 ** 0x04 & 0xffffffff));
var5 = temp14;
var6 = temp13 + (((var5 & 0xffffffff) << 0x04) + (storage[0x00] / 0x0100 ** 0x08 & 0xffffffff) ~ var5 + var4 ~ ((var5 & 0xffffffff) >> 0x05) + (storage[0x00] / 0x0100 ** 0x0c & 0xffffffff));
var7 = var7 + 0x01;

if (var7 & 0xff >= 0x20) { goto label_047F; }
else { goto label_03E1; }
}
} else {
label_034E:
var temp15 = var7;
var8 = 0x03 - temp15 * 0x08 & 0xff;
var9 = var0;
var10 = var3 + (temp15 & 0xff);

if (var10 >= memory[var9:var9 + 0x20]) { assert(); }

var5 = var5 + (((((memory[var10 + 0x20 + var9:var10 + 0x20 + var9 + 0x20] >> 0xf8) << 0xf8) >> 0xf8) & 0xff) << var8);
var temp16 = var7;
var8 = 0x03 - temp16 * 0x08 & 0xff;
var9 = var0;
var10 = var3 + (temp16 & 0xff) + 0x04;

if (var10 >= memory[var9:var9 + 0x20]) { assert(); }

var6 = var6 + (((((memory[var10 + 0x20 + var9:var10 + 0x20 + var9 + 0x20] >> 0xf8) << 0xf8) >> 0xf8) & 0xff) << var8);
var7 = var7 + 0x01;

if (var7 & 0xff >= 0x04) { goto label_03CD; }
else { goto label_034E; }
}
}
} else {
var temp17 = var3;
memory[var2 + 0x20:var2 + 0x20 + temp17] = code[code.length:code.length + temp17];
var1 = var2;
var2 = 0xdeadbeef;
var3 = 0x00;

if (var3 >= memory[var0:var0 + 0x20]) { goto label_0563; }
else { goto label_032D; }
}
}

function func_0205(var arg0, var arg1) {
var temp0 = arg0;
var temp1 = temp0 + 0x20;
arg0 = msg.data[temp0:temp0 + 0x20] & 0xffffffff;
var temp2 = temp1 + 0x20;
arg1 = msg.data[temp1:temp1 + 0x20] & 0xffffffff;
var var0 = msg.data[temp2:temp2 + 0x20] & 0xffffffff;
var var1 = msg.data[temp2 + 0x20:temp2 + 0x20 + 0x20] & 0xffffffff;
storage[0x00] = (arg0 & 0xffffffff) | (storage[0x00] & ~0xffffffff);
storage[0x00] = (arg1 & 0xffffffff) * 0x0100 ** 0x04 | (storage[0x00] & ~(0xffffffff * 0x0100 ** 0x04));
storage[0x00] = (var0 & 0xffffffff) * 0x0100 ** 0x08 | (storage[0x00] & ~(0xffffffff * 0x0100 ** 0x08));
storage[0x00] = (var1 & 0xffffffff) * 0x0100 ** 0x0c | (storage[0x00] & ~(0xffffffff * 0x0100 ** 0x0c));
}

function k1() returns (var r0) { return storage[0x00] / 0x0100 ** 0x04 & 0xffffffff; }

function func_056F() returns (var r0) { return storage[0x00] & 0xffffffff; }

function k2() returns (var r0) { return storage[0x00] / 0x0100 ** 0x08 & 0xffffffff; }

function func_0623() returns (var r0) { return storage[0x00] / 0x0100 ** 0x0c & 0xffffffff; }
}

看这个东西,要看if中的语句,比如下面,当输入0x93eed093时,会调用func_056F函数

image-20221001101445496

我们的第二段输入

0x9577a1450000000000000000000000000000000000000000000000000000000010000000000000000000000000000876543210000000000000002345678000000000000000000000000000000000000000000000000000000000000000000000aabbccdd0000000000000000000000000000000000000000000000000000000044332211

我们直接看func_0205函数

image-20221001101725520

这就要猜了,能看出是赋值了4个值到storage,四个值分别对应0x12345678、0x87654321、0xaabbccdd、0x44332211

第三次输入时challenge方法:输入0x59f5382e,并输出了0xa625e97482f83d2b7fc5125763dcbbffd8115b208c4754eee8711bdfac9e3377622bbf0cbb785e612b82c7f5143d5333

challeng函数是一个魔改的tea

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
#include <stdio.h>
#include <stdint.h>

//加密函数
void encrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */
uint32_t delta=0x9e3779b9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i < 32; i++) { /* basic cycle start */
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
} /* end cycle */
v[0]=v0; v[1]=v1;
}
//解密函数
void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0xdeadbeef*32, i; /* set up */
uint32_t delta=0xdeadbeef; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i<32; i++) { /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
} /* end cycle */
v[0]=v0; v[1]=v1;
}

int main()
{
uint32_t v[12]={0xa625e974,0x82f83d2b,0x7fc51257,0x63dcbbff,0xd8115b20,0x8c4754ee,0xe8711bdf,0xac9e3377,0x622bbf0c,0xbb785e61,0x2b82c7f5,0x143d5333},k[4]={0x12345678,0x87654321,0xaabbccdd,0x44332211};
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
for(int i = 0; i < 6; i+=2)
{
decrypt(v + i, k);
printf("decode:%x %x\n",v[i],v[i + 1]);
}
return 0;
}
1
bytectf{f2d9e0b6-274d-47e0-bc4c-40967015ba79273}

maze6d

这个混淆看了一天,里面涉及到好多不清楚的地方,还有很多之前没搞明白的地方。

第一个点是GOT和PLT表:

GOT表是一个存储外部函数地址的表,PLT表是一个代码片段组成的表,每一个都能跳到GOT表项。众所周知,链接时要进行一个重定位,链接做的事情:对同名section进行合并,对代码段和数据段进行地址分配,进行重定位。

重定位是这样的:如果时在中间文件中定义好的函数,连接时直接可以重定位到函数地址,如果是动态链接库中的函数,只能生成额外的小段代码,就是PLT表,然后重定位到该代码片段。

运行时重定位:运行后加载动态库,把动态库中的相应函数地址填入GOT表

延迟重定位:只有动态库被调用时才会进行地址解析和重定位工作,这时候动态库函数地址被写到GOT表项中。

第一步由函数跳到PLT表中,第二步PLT表跳到GOT表(jmp),第三步GOT跳到PLT(push),并进行压栈,把代表函数的id压栈,第四步跳到公共PLT表项中(jmp),第五步进入GOT表,然后_dl_runtime_resolve对动态函数进行地址解析和重定位,第七步把动态函数真实的地址写入GOT表项,然后执行函数并retn。

image-20221001142814162

柏鹭、MT、DASCTF

这三天打了许多比赛,题目质量我不好说,但自己还是很菜,继续加油吧!

柏鹭杯

他这个比赛的逆向,咋不直接改成密码呢?

walk

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
void __noreturn sub_231280()
{
int v0; // ecx
const struct _s_FuncInfo *v1; // ecx
int v2; // esi
int v3; // edx
char v4; // al
unsigned int *v5; // esi
unsigned int v6; // edi
int v7; // ecx
unsigned __int8 *v8; // eax
unsigned __int8 v9; // bl
int v10; // edx
unsigned int v11; // eax
unsigned __int8 *v12; // edi
unsigned __int8 *v13; // esi
int v14; // edx
int v15; // ecx
int v16; // edx
int v17; // ecx
int v18; // ecx
int v19; // ecx
int v20; // [esp-20h] [ebp-8Ch]
int v21; // [esp-1Ch] [ebp-88h]
int v22; // [esp-18h] [ebp-84h]
int v23; // [esp-14h] [ebp-80h]
int v24; // [esp-10h] [ebp-7Ch] BYREF
const _ThrowInfo *v25; // [esp-Ch] [ebp-78h]
int v26; // [esp-8h] [ebp-74h] BYREF
const _ThrowInfo *v27; // [esp-4h] [ebp-70h]
int v28; // [esp+0h] [ebp-6Ch] BYREF
int v29[4]; // [esp+Ch] [ebp-60h] BYREF
int v30[3]; // [esp+1Ch] [ebp-50h] BYREF
int v31[3]; // [esp+28h] [ebp-44h] BYREF
char v32[8]; // [esp+34h] [ebp-38h] BYREF
unsigned int *v33; // [esp+40h] [ebp-2Ch]
_DWORD *v34; // [esp+44h] [ebp-28h]
int *v35; // [esp+48h] [ebp-24h]
int v36; // [esp+4Ch] [ebp-20h]
unsigned __int8 *v37; // [esp+50h] [ebp-1Ch]
const struct _s_FuncInfo *v38; // [esp+54h] [ebp-18h]
int v39; // [esp+58h] [ebp-14h]
int *v40; // [esp+5Ch] [ebp-10h]
int v41; // [esp+68h] [ebp-4h]

v40 = &v28;
v41 = 0;
sub_2311F0(v31, (int)v25, v26, (int)v27);
v27 = &_TI1_AUTI__;
v26 = v0;
v40 = &v26;
v1 = (const struct _s_FuncInfo *)v35[1];
v2 = v35[2];
v3 = *v35;
v39 = *v35;
v38 = v1;
v36 = v2;
if ( (int)v1 < v2 )
{
v4 = *((_BYTE *)v1 + v3);
if ( v4 == 'c' )
{
LOBYTE(v41) = 2;
__FrameHandler3::TryBlockMap::TryBlockMap((__FrameHandler3::TryBlockMap *)v32, v1, v2);
v25 = &_TI1_AUTC1__;
v24 = v18;
v40 = &v24;
if ( *v34 + 6 <= v34[1] )
{
LOBYTE(v41) = 4;
sub_231230(v29, v20, v21, v22, v23);
v5 = v33;
if ( sub_231150(*v33, v33[1]) )
{
v6 = v5[1];
v7 = 10 * *v5;
v8 = (unsigned __int8 *)(v6 + v7 + v5[3]);
v37 = v8;
v9 = *v8;
v10 = *v8;
if ( *v8 )
{
v11 = v7 + v6;
v12 = (unsigned __int8 *)v38 + v39;
v13 = (unsigned __int8 *)(5 * v11 + v5[2]);
if ( (v10 ^ *v13) != *((unsigned __int8 *)v38 + v39 + 1)
|| (v10 ^ v13[1]) != v12[2]
|| (v10 ^ v13[2]) != v12[3]
|| (v10 ^ v13[3]) != v12[4]
|| (v10 ^ v13[4]) != v12[5] )
{
return;
}
v8 = v37;
}
++dword_2525DC;
dword_2525E4 += 6;
*v8 = v9 & 0xFE;
}
}
}
else if ( v4 == 'w' )
{
if ( sub_2310B0(x - 1, y) )
{
v14 = x;
v15 = 5 * x;
byte_2518B0[10 * x + y] |= 0x80u;
x = v14 - 1;
LABEL_33:
++dword_2525E4;
LOBYTE(v41) = 6;
sub_231260(v30, v15, v2, v15);
}
}
else
{
if ( v4 != 's' )
{
if ( v4 == 'a' )
{
if ( !sub_2310B0(x, y - 1) )
return;
v17 = y;
byte_2518B0[10 * x + y] |= 0x80u;
v15 = v17 - 1;
}
else
{
if ( v4 != 'd' || !sub_2310B0(x, y + 1) )
return;
v19 = y;
byte_2518B0[10 * x + y] |= 0x80u;
v15 = v19 + 1;
}
y = v15;
goto LABEL_33;
}
if ( sub_2310B0(x + 1, y) )
{
v16 = x;
v15 = 5 * x;
byte_2518B0[10 * x + y] |= 0x80u;
x = v16 + 1;
goto LABEL_33;
}
}
}
}

这个题先是很多try_catch块,对应恢复后,是个迷宫。有五个字符,首先c字符,当当前位置在map中是奇数,后面的5个字符将要进行运算与对比,接下来就是wasd,走迷宫,要求是走的时候map中的值小于0x80

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
from os import TMP_MAX


map = [0x61, 0x18, 0x60, 0x54, 0x52, 0x06, 0xD0, 0xA8, 0x9C, 0xCB, 0xDA, 0xF3, 0xE0, 0xA6, 0xE7, 0x60, 0xEC, 0xDD, 0x81, 0xE7, 0xFD, 0xB7, 0x71, 0x56, 0x50, 0x30, 0xE7, 0xD4, 0xA0, 0xAA, 0x88, 0xEC, 0x62, 0xC5, 0xE7, 0xEE, 0xD4, 0xF0, 0xCC, 0xA1, 0x94, 0x86, 0x08, 0x50, 0x74, 0x58, 0xA5, 0x88, 0xE9, 0xA7, 0x81, 0xC0, 0x8A, 0xE0, 0xFC, 0x04, 0xCF, 0xFE, 0xBC, 0x9A, 0xD1, 0x85, 0x80, 0x00, 0x01, 0x6C, 0xC0, 0xE6, 0xD5, 0xCB, 0xF3, 0xF0, 0x8A, 0x2C, 0xE1, 0xF5, 0xF7, 0xF7, 0x97, 0xC6, 0x9D, 0xEA, 0xC7, 0x40, 0x66, 0x0A, 0x44, 0x52, 0xD6, 0xAD, 0xCA, 0xBC, 0xE5, 0xAD, 0x84, 0x9E, 0xF2, 0x2A, 0x2D, 0xDD]
arr = [0x11, 0x0B, 0x15, 0x1B, 0x00, 0x7C, 0x6E, 0x69, 0x7B, 0x77, 0x0B, 0x16, 0x14, 0x0E, 0x01, 0x24, 0x22, 0x25, 0x3A, 0x35, 0x3F, 0x34, 0x22, 0x2B, 0x31, 0x6A, 0x67, 0x72, 0x61, 0x69, 0xB4, 0xA1, 0xBF, 0xA0, 0xA8, 0xDB, 0xDE, 0xC1, 0xC1, 0xD2, 0xFD, 0xFD, 0xEE, 0xE5, 0xF7, 0xAE, 0xA1, 0xA6, 0xBE, 0xAA, 0xAD, 0xA9, 0xB0, 0xA2, 0xB4, 0x84, 0x98, 0x92, 0x80, 0x9A, 0x8E, 0x8F, 0x82, 0x96, 0x84, 0xC9, 0xD5, 0xD3, 0xD5, 0xD5, 0x88, 0x9D, 0x80, 0x81, 0x92, 0x05, 0x07, 0x19, 0x04, 0x1A, 0x8D, 0x98, 0x9D, 0x98, 0x96, 0xB6, 0xB8, 0xAB, 0xB9, 0xB1, 0xE0, 0xF5, 0xF4, 0xE3, 0xF8, 0x8C, 0x8B, 0x9F, 0x9D, 0x96, 0x88, 0x9E, 0x8D, 0x96, 0x98, 0xDB, 0xC7, 0xD8, 0xDD, 0xCE, 0x15, 0x17, 0x08, 0x1E, 0x05, 0x34, 0x2C, 0x24, 0x3B, 0x3D, 0x31, 0x38, 0x21, 0x24, 0x21, 0x5E, 0x56, 0x52, 0x40, 0x58, 0x91, 0x9E, 0x83, 0x9E, 0x8A, 0xA1, 0xAC, 0xA6, 0xAD, 0xA7, 0xD4, 0xC3, 0xD2, 0xD4, 0xD5, 0xDC, 0xDF, 0xC4, 0xC2, 0xCC, 0xEB, 0xEC, 0xE4, 0xEA, 0xFC, 0x88, 0x98, 0x8D, 0x80, 0x9B, 0x12, 0x0C, 0x0D, 0x14, 0x11, 0xA2, 0xA1, 0xAE, 0xB2, 0xA6, 0x97, 0x84, 0x85, 0x86, 0x9F, 0x8A, 0x84, 0x89, 0x8D, 0x9E, 0xBF, 0xBD, 0xB8, 0xA4, 0xB6, 0x87, 0x98, 0x9E, 0x9A, 0x95, 0xB9, 0xAD, 0xA5, 0xB6, 0xBD, 0xC2, 0xC4, 0xD7, 0xD8, 0xC8, 0xED, 0xE2, 0xE3, 0xF2, 0xF8, 0xE5, 0xE1, 0xFF, 0xF7, 0xF6, 0x71, 0x6F, 0x6F, 0x7E, 0x7D, 0x3D, 0x29, 0x26, 0x3C, 0x27, 0x10, 0x07, 0x1E, 0x1D, 0x01, 0x20, 0x29, 0x3F, 0x2E, 0x2D, 0xC4, 0xDF, 0xCC, 0xD0, 0xDD, 0xFE, 0xF8, 0xEA, 0xF2, 0xEE, 0x81, 0x8B, 0x88, 0x84, 0x8E, 0xC3, 0xCA, 0xCE, 0xD6, 0xC5, 0xE2, 0xEB, 0xE3, 0xE9, 0xE6, 0xAC, 0xA7, 0xA9, 0xB1, 0xB0, 0xE5, 0xFB, 0xEB, 0xF2, 0xE9, 0x8C, 0x93, 0x93, 0x88, 0x9A, 0x8A, 0x97, 0x9F, 0x9A, 0x98, 0x73, 0x67, 0x62, 0x6C, 0x72, 0xBF, 0xBA, 0xBA, 0xAD, 0xBB, 0x9B, 0x8E, 0x93, 0x91, 0x96, 0xC4, 0xCB, 0xC6, 0xDD, 0xD3, 0xEE, 0xF6, 0xFB, 0xF2, 0xF1, 0xBD, 0xB8, 0xBB, 0xB4, 0xBA, 0xE6, 0xF5, 0xED, 0xE0, 0xE2, 0xEE, 0xE3, 0xE8, 0xF2, 0xF2, 0x77, 0x79, 0x62, 0x69, 0x67, 0x79, 0x6E, 0x60, 0x69, 0x6A, 0x1E, 0x15, 0x01, 0x02, 0x1B, 0xAA, 0xA9, 0xB0, 0xAB, 0xAD, 0x88, 0x8E, 0x89, 0x8F, 0x94, 0xB1, 0xB3, 0xA2, 0xB7, 0xAC, 0xA1, 0xA0, 0xBC, 0xB8, 0xA5, 0x92, 0x9B, 0x86, 0x87, 0x89, 0x91, 0x8A, 0x95, 0x9E, 0x86, 0xE2, 0xED, 0xF3, 0xEE, 0xFF, 0x46, 0x46, 0x55, 0x44, 0x45, 0x8C, 0x88, 0x82, 0x87, 0x95, 0x93, 0x96, 0x9E, 0x92, 0x82, 0x95, 0x9C, 0x83, 0x98, 0x90, 0x9E, 0x81, 0x87, 0x92, 0x8E, 0xFA, 0xE3, 0xF5, 0xFD, 0xE1, 0xA1, 0xAB, 0xAA, 0xA4, 0xBF, 0xEB, 0xE4, 0xF7, 0xF7, 0xFC, 0x9C, 0x89, 0x80, 0x83, 0x9B, 0xA2, 0xB0, 0xB5, 0xB4, 0xA4, 0x35, 0x32, 0x38, 0x23, 0x35, 0x0E, 0x02, 0x1F, 0x02, 0x05, 0x64, 0x70, 0x64, 0x7F, 0x65, 0x34, 0x20, 0x28, 0x29, 0x2B, 0x3A, 0x27, 0x3E, 0x27, 0x31, 0xA4, 0xB1, 0xBC, 0xB4, 0xAE, 0xCF, 0xCF, 0xCE, 0xDE, 0xDF, 0xA8, 0xB8, 0xBD, 0xB3, 0xB9, 0xC5, 0xCA, 0xD4, 0xD8, 0xDF, 0x87, 0x97, 0x86, 0x80, 0x93, 0xDC, 0xCB, 0xDA, 0xC2, 0xD4, 0xF2, 0xE7, 0xFD, 0xEA, 0xEE, 0xE6, 0xE6, 0xF9, 0xEC, 0xFA, 0x97, 0x9F, 0x95, 0x93, 0x95, 0x4B, 0x45, 0x5B, 0x4F, 0x45, 0x4C, 0x48, 0x55, 0x59, 0x5F, 0xBF, 0xAB, 0xBE, 0xA8, 0xA5]
tmp = []
for i in range(len(map)):
if map[i] < 0x80:
tmp.append(map[i])
else:
map[i] = 0xff
print(tmp)
for i in range(10):
for j in range(10):
print(hex(map[i*10+j])[2:].zfill(2),end=",")
print(" ")
stra = []
for i in range(len(map)):
if(map[i]!=0xff):
tmp=i*5
tmp_str = "c"
for j in range(5):
tmp_str+=chr(map[i]^arr[tmp+j])
stra.append(tmp_str)
print(stra)

生成地图和c开头的字符串,只考虑地图dddddssaaassdddssaassddddsd,c开头的要筛选,当tmp中是奇数,就是要找的,得到路线cpjtzadddddssaaacdfyotssdddssacxoahkassddddsdcaextr,输入得flag。

MTCTF

small

直接审汇编,发现不能反汇编,其实将0xea处改为retn就行,该处本来就是exit,所以没问题

image-20220920155829547

得到返汇编后,发现是一个tea加密

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
_BYTE *__fastcall sub_67(__int64 a1, int a2)
{
unsigned int v2; // eax
int v3; // ebx
int v4; // ebp
int v5; // edi
_BYTE *v6; // rsi
unsigned int v7; // ebp
int v8; // edi
_BYTE *result; // rax
int v10; // esi
int v11; // [rsp+10h] [rbp+10h]

*(_BYTE *)(a1 + 1159922115) += v2;
v7 = ((v3 + v5) ^ ((v2 >> 5) + 35) ^ (16 * a1 + 1)) + v4;
v8 = ((v3 + v7) ^ (16 * v7 + 69) ^ ((v7 >> 5) + 103)) + v5;
if ( a2 + 1 < 35 )
JUMPOUT(0x52i64);
*((_DWORD *)v6 - 2) = v7;
*((_DWORD *)v6 - 1) = v8;
if ( (int)v6 < v11 + 32 )
JUMPOUT(0x1Ci64);
result = v6;
v10 = 32;
while ( *(_BYTE *)(unsigned int)(v10 + 65783) == *result )
{
--v10;
--result;
if ( !v10 )
{
result = (_BYTE *)(&loc_0 + 1);
__asm { syscall; Low latency system call }
return result;
}
}
return result;
}
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
#include <stdio.h>
#include <stdint.h>

//加密函数
void encrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */
uint32_t delta=0x9e3779b9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i < 32; i++) { /* basic cycle start */
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
} /* end cycle */
v[0]=v0; v[1]=v1;
}
//解密函数
void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0x67452301*35, i; /* set up */
uint32_t delta=0x67452301; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i<35; i++) { /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
} /* end cycle */
v[0]=v0; v[1]=v1;
}

int main()
{
uint32_t v[]={0xDE087143, 0xC4F91BD2, 0xDAF6DADC, 0x6D9ED54C, 0x75EB4EE7, 0x5D1DDC04, 0x511B0FD9, 0x51DC88FB},k[4]={0x01,0x23,0x45,0x67};
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
for (int i=0;i<8;i+=2)
{
decrypt(v+i, k);
printf("decode:%x %x\n",v[i],v[1+i]);
}
return 0;
}
//flag{327a6c4304ad5938eaf0efb6cc3e53dc}

delta是0x67452301,很简单。

DASCTF

landing

这题还是很简单的,就是try、catch

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
std::ostream *v3; // rax
std::ostream *v4; // rax
char Str[32]; // [rsp+450h] [rbp+3D0h] BYREF
int i; // [rsp+48Ch] [rbp+40Ch]

_main();
v3 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Input something.");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v3);
std::operator>><char,std::char_traits<char>>(refptr__ZSt3cin, Str);
if ( strlen(Str) == 28 )
{
for ( i = 0; i <= 27; ++i )
{
Str[i] ^= 0x22u;
++Str[i];
}
func1(Str);
}
else
{
v4 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "nono");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v4);
system("pause");
}
return 1;
}

主程序是这样的,func1里是一个base64加密不过是骗人的,发现func1处有一个try块,找到对应catch块,然后patch一下

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
std::ostream *v3; // rax
__int64 v4; // rdx
std::ostream *v5; // rax
size_t v7; // rax
void *v8; // rsp
int v9; // eax
size_t v10; // rax
std::ostream *v11; // rax
std::ostream *v12; // rax
char v13[15]; // [rsp+20h] [rbp-60h] BYREF
char v14[25]; // [rsp+2Fh] [rbp-51h] BYREF
char Str1[1024]; // [rsp+50h] [rbp-30h] BYREF
char Str[32]; // [rsp+450h] [rbp+3D0h] BYREF
char *Str2; // [rsp+470h] [rbp+3F0h]
size_t v18; // [rsp+478h] [rbp+3F8h]
void *v19; // [rsp+480h] [rbp+400h]
int j; // [rsp+488h] [rbp+408h]
int i; // [rsp+48Ch] [rbp+40Ch]

_main();
v3 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Input something.");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v3);
std::operator>><char,std::char_traits<char>>(refptr__ZSt3cin, Str);
if ( strlen(Str) == 28 )
{
for ( i = 0; i <= 27; ++i )
{
Str[i] ^= 0x22u;
v4 = (unsigned int)(unsigned __int8)Str[i]++ + 1;
}
if ( v4 == 1 )
{
v19 = _cxa_begin_catch(Str);
qmemcpy(v13, "GUw\\D~UHG#kYG~", 14);
v13[14] = 127;
qmemcpy(v14, "BA#{QJT(\\A {BG~$BG~$BGz//", sizeof(v14));
v7 = strlen(v13);
v18 = v7 - 1;
v8 = alloca(16 * ((v7 + 15) >> 4));
Str2 = v13;
for ( j = 0; j < strlen(v13); ++j )
Str2[j] = v13[j] ^ 0x12;
v9 = strlen(Str);
nothing(Str1, Str, v9);
v10 = strlen(Str2);
if ( !strncmp(Str1, Str2, v10) )
v11 = (std::ostream *)std::operator<<<std::char_traits<char>>(
refptr__ZSt4cout,
"Goodgood!\n...Please packed the flag with\"DASCTF{}\"");
else
v11 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "nono");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v11);
system("pause");
_cxa_end_catch();
}
else
{
_cxa_begin_catch(Str);
v12 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "nono");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v12);
system("pause");
_cxa_end_catch();
}
}
else
{
v5 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "nono");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v5);
system("pause");
}
return 1;
}

这时主加密其实很清楚就是对一个初始化的对比密文的操作,而对我们输入进行操作的是在nothing里,nothing这个函数点个U就可以看了,发现是个base64,一眼魔改。

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
void __fastcall nothing(char *a1, const char *a2, int a3)
{
char *v3; // rax
char *v4; // rax
char *v5; // rax
char *v6; // rax
unsigned __int64 i; // [rsp+8h] [rbp-18h]
int v8; // [rsp+14h] [rbp-Ch]
int v9; // [rsp+18h] [rbp-8h]
int v10; // [rsp+1Ch] [rbp-4h]

v10 = 0;
v9 = 2;
for ( i = 0i64; a3 > i; ++i )
{
switch ( v9 )
{
case 2:
v8 = (*a2 >> 2) & 0x3F;
break;
case 4:
v8 = (*a2 >> 4) & 0xF;
break;
case 6:
v8 = (*a2 >> 6) & 3;
break;
}
v8 += v10;
v3 = a1++;
*v3 = nothing(char *,char const*,int)::aaa[v8] + 1;
v10 = (*a2 << (6 - v9)) & 0x3F;
v9 += 2;
if ( v9 == 8 )
{
v8 = *a2 & 0x3F;
v4 = a1++;
*v4 = nothing(char *,char const*,int)::aaa[*a2 & 0x3F] + 1;
v10 = 0;
v9 = 2;
}
++a2;
}
if ( v10 )
{
v5 = a1++;
*v5 = nothing(char *,char const*,int)::aaa[v10] + 1;
}
if ( a3 % 3 == 1 )
{
v6 = a1++;
*v6 = 61;
*a1 = 61;
}
if ( a3 % 3 == 2 )
*a1 = 61;
}

很明显在赋值的时候给每个base64后的数加了1,那么我们就很清楚加密流程了。输入->异或->加1->base64->加1

1
2
3
4
5
6
7
8
9
10
11
12
a = 'UGeNVlGZU1yKUlmPS1iCXF:NS2iPUl6PUl6PUh'
flag11 = ""
flag=[0]*28
flag1='LWLRAXOLININGHAXOLGXNNNNNNNN'
for i in range(len(a)):
flag+=chr(ord(a[i]) - 1)
print(flag)
for i in range(28):
flag[i] = ord(flag1[i]) - 1
flag[i] ^=0x22
flag11+=chr(flag[i])
print(flag11)

cbNET

c#逆向

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
private void method_3(object sender, RoutedEventArgs e)
{
string text = this.vmethod_0().Text;
string[] array = new string[24];
int[] array2 = new int[]
{
309,
1981,
2823,
6979,
28339,
39487,
33035,
283711,
623,
4109,
23551,
54761,
67985,
231149,
499603,
1354567,
213,
2651,
22559,
52549,
484663,
290793,
532213,
1746643
};
checked
{
if (text.Length != array2.Length + 7)
{
this.vmethod_2().Content = "wrong";
}
else if (Operators.CompareString(Strings.Mid(text, 1, 6), "CBCTF{", false) != 0 | Operators.CompareString(Strings.Mid(text, array2.Length + 7, 1), "}", false) != 0)
{
this.vmethod_2().Content = "wrong";
}
else
{
this.method_0(ref array, text);
this.method_2(ref array);
int num = array2.Length - 1;
for (int i = 0; i <= num; i++)
{
if (Conversions.ToDouble(array[i]) != (double)array2[i])
{
this.vmethod_2().Content = "wrong";
return;
}
}
this.vmethod_2().Content = "correct";
}
}
}
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
private object method_2(ref string[] string_0)
{
int num = checked(string_0.Length - 1);
int i = 0;
while (i <= num)
{
try
{
string_0[i] = Conversions.ToString((double)(Conversions.ToLong(string_0[i]) ^ Conversions.ToLong(string_0[checked(i - 1)]) / (long)(i % 8)) + Conversions.ToDouble(string_0[checked(i - 1)]) % (double)(i % 8));
goto IL_F3;
}
catch (Exception ex)
{
string_0[i] = Conversions.ToString((double)(Conversions.ToLong(string_0[i]) ^ Conversions.ToLong(string_0[checked(i + 7)]) / 8L) + Conversions.ToDouble(string_0[checked(i + 7)]) % 8.0);
goto IL_F3;
}
goto IL_98;
IL_EA:
double num2;
double num3;
checked
{
i++;
continue;
IL_CE:
if (num2 > num3)
{
goto IL_EA;
}
IL_98:;
}
if (checked(this.method_1((int)Math.Round(num2)) & this.method_1((int)Math.Round(unchecked(Conversions.ToDouble(string_0[i]) - num2)))) == 0)
{
num2 += 1.0;
goto IL_CE;
}
string_0[i] = Conversions.ToString(num2 * (Conversions.ToDouble(string_0[i]) - num2));
goto IL_EA;
IL_F3:
string_0[i] = Conversions.ToString(Conversions.ToDouble(string_0[i]) - 2.0 - Conversions.ToDouble(string_0[i]) % 2.0);
num3 = Conversions.ToDouble(string_0[i]) - 2.0;
num2 = 2.0;
goto IL_CE;
}
return false;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private int method_1(int int_0)
{
checked
{
int result;
if (int_0 < 2)
{
result = 0;
}
else
{
int num = int_0 - 1;
for (int i = 2; i <= num; i++)
{
if (int_0 % i == 0)
{
return 0;
}
}
result = 1;
}
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private object method_0(ref string[] string_0, string string_1)
{
string text = "0rays";
int num = 0;
checked
{
int num2 = string_1.Length - 2;
for (int i = 6; i <= num2; i++)
{
string_0[i - 6] = Conversions.ToString(string_1[i]);
string_0[i - 6] = Conversions.ToString(Strings.Asc(string_0[i - 6]) ^ Strings.Asc(text[num]));
num = (num + 1 ^ 5);
}
return false;
}
}

这个题是真坐牢啊,脚本跑不对,真的难受

学习一下官方wp,如何爆破这种类型题目

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
import hashlib


def isPrime(n):
if n < 2:
return 0
for i in range(2, n - 1):
if n % i == 0:
return 0
return 1


def xordecrypt(key):
str = "0rays"
circle = 0
flag = ""
for i in range(len(key)):
flag = flag + chr(key[i] ^ ord(str[circle]))
circle = (circle + 1) ^ 5
flag = "CBCTF{" + flag + "}"
t = hashlib.sha256()
t.update(flag.encode())
finalflag = t.hexdigest()
if finalflag == "15c4ac7645546a1ef8141441b48e1824954fdbb159bf96400061b17db1af9edf":
print(flag)
exit(0)


def recursion(key2, i):
key = key2.copy()
if (i % 8) != 0:
key[i] = (key[i] - key[i - 1] % (i % 8)) ^ (key[i - 1] // (i % 8))
else:
key[i] = (key[i] - key[i + 7] % 8) ^ (key[i + 7] // 8)
if i != 0:
decrypt(key, i - 1)
else:
xordecrypt(key)


def decrypt(key1, i):
key = key1.copy()
for j in range(2, key[i] - 1):
if key[i] % j == 0 and isPrime(j) and isPrime(key[i] // j): # key[i] % j == 0 因为指数相乘所以是肯定余数为0
key[i] = j + key[i] // j
break
key[i] = key[i] + 2 #+2或者+1都进行测试
recursion(key, i)
key[i] = key[i] + 1
recursion(key, i)


key = [309, 1981, 2823, 6979, 28339, 39487, 33035, 283711, 623, 4109, 23551, 54761, 67985, 231149, 499603, 1354567, 213, 2651, 22559, 52549, 484663, 290793, 532213, 1746643]
decrypt(key, 23)

网鼎杯

这次网鼎杯总共3道re,出了两道,第三道出了一半卡在了写脚本,总之还是不错的。

fakeshell

很简单的一道题,主要是setjmp和longjmp这个知识点,已经做了三次这种题了,经过调试发现是一个加法和一个异或然后进行对比,直接给出脚本

1
2
3
4
5
cmp = [0x0000004B, 0x00000048, 0x00000079, 0x00000013, 0x00000045, 0x00000030, 0x0000005C, 0x00000049, 0x0000005A, 0x00000079, 0x00000013, 0x00000070, 0x0000006D, 0x00000078, 0x00000013, 0x0000006F, 0x00000048, 0x0000005D, 0x00000064, 0x00000064, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000]
flag = ""
for i in range(len(cmp)):
flag += chr(((cmp[i]^0x50)-10)^0x66)
print(flag)

handmake

纯纯动脑子题,一眼看出是个go语言,本来想着慢慢找,但发现他们都做的很快,其实可以直接改几处源码就行,15k行只用改main就行,将要得到的值输出就行。

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
func main() {
var nFAzj, CuSkl string
jjxXf := []byte{
37, 73, 151, 135, 65, 58, 241, 90, 33, 86, 71, 41, 102, 241, 213, 234, 67, 144, 139, 20, 112, 150, 41, 7, 158, 251, 167, 249, 24, 129, 72, 64, 83, 142, 166, 236, 67, 18, 211, 100, 91, 38, 83, 147, 40, 78, 239, 113, 232, 83, 227, 47, 192, 227, 70, 167, 201, 249, 156, 101, 216, 159, 116, 210, 152, 234, 38, 145, 198, 58, 24, 183, 72, 143, 136, 234, 246}
KdlaH := []byte{
191, 140, 114, 245, 142, 55, 190, 30, 161, 18, 200, 7, 21, 59, 17, 44, 34, 181, 109, 116, 146, 145, 189, 68, 142, 113, 0, 33, 46, 184, 21, 33, 66, 99, 124, 167, 201, 88, 133, 20, 211, 67, 133, 250, 62, 28, 138, 229, 105, 102, 125, 124, 208, 180, 50, 146, 67, 39, 55, 240, 239, 203, 230, 142, 20, 90, 205, 27, 128, 136, 151, 140, 222, 92, 152, 1, 222, 138, 254, 246, 223, 224, 236, 33, 60, 170, 189, 77, 124, 72, 135, 46, 235, 17, 32, 28, 245}
fmt.Print(MPyt9GWTRfAFNvb1(jjxXf))
fmt.Scanf("%20s\n", &nFAzj)
fmt.Printf("First scanf: %s\n", nFAzj)
fmt.Print(kZ2BFvOxepd5ALDR(KdlaH))
fmt.Scanf("%20s", &CuSkl)
fmt.Printf("Second Scanf: %s\n", CuSkl)
vNvUO := GwSqNHQ7dPXpIG64(nFAzj)
fmt.Printf("vNvUO %s\n", vNvUO)
YJCya := ""
mvOxK := YI3z8ZxOKhfLmTPC(CuSkl)
fmt.Printf("\n")
fmt.Printf("mvOxK %s\n", mvOxK)
if mvOxK != nil {
YJCya = mvOxK()
}

if YJCya != "" && vNvUO != "" {
fmt.Printf("flag{%s%s}\n", vNvUO, YJCya)
}
}
1
2
3
4
5
6
7
8
9
10
Input the first function, which has 6 parameters and the third named gLIhR: 
ZlXDJkH3OZN4Mayd
First scanf: ZlXDJkH3OZN4Mayd
Input the second function, which has 3 callers and invokes the function named cHZv5op8rOmlAkb6:
YsMgm9rKB7qiuQ1d
Second Scanf: YsMgm9rKB7qiuQ1d
vNvUO 3a4e76449355c414

mvOxK %!s(main.dIWKr=0x877d80)
flag{3a4e76449355c4148ce3da2b46019f75}

whereiscode

qwb2022

这次还是很坐牢,但跟师傅们学习到了很多方法

deeprev

我们会发现,这个题给了个libsecret.so文件和deeprev文件,deeprev里很清楚,只要check函数等于0就行,但在程序中根本找不到check函数。经搜索发现是GoogleCTF改编题,直接跑下面脚本,把关于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
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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
# Author: hgarrereyn
# Desc: Lifter solution for GoogleCTF 2022 eldar

import lief
from collections import namedtuple
from dataclasses import dataclass
from typing import Any
from capstone import *



md = Cs(CS_ARCH_X86, CS_MODE_64)

b = None
try:
b = lief.ELF.parse('./deeprev')
except:
raise Exception('Must have the ./eldar binary in cwd')

rela = [x for x in b.sections if x.name == '.rela.dyn'][0]
print(rela)
dynsym = [x for x in b.sections if x.name == '.dynsym'][0]


@dataclass
class Symbol(object):
idx: int
def __repr__(self):
return f's{self.idx}'

@dataclass
class Reloc(object):
idx: int
def __repr__(self):
return f'r{self.idx}'

@dataclass
class Ref(object):
val: Any
def __repr__(self):
return f'&{self.val}'

@dataclass
class SymAddr(object):
sym: Symbol
field: str
def __repr__(self):
return f'{self.sym}.{self.field}'

@dataclass
class RelocAddr(object):
reloc: Reloc
field: str
def __repr__(self):
return f'{self.reloc}.{self.field}'

def vaddr(self):
off = 0
match self.field:
case 'r_address':off = 0
case 'r_info': off = 8
case 'r_addend': off = 16

return (self.reloc.idx * 24) + off + rela.virtual_address

@dataclass
class FlagAddr(object):
idx: int
def __repr__(self):
return f'flag[{self.idx}]'

@dataclass
class OutAddr(object):
idx: int

def __repr__(self):
return f'out[{self.idx}]'

@dataclass
class ArrAddr(object):
idx: int

def __repr__(self):
return f'arr[{self.idx}]'

BaseAddr = namedtuple('baseaddr', [])
FailAddr = namedtuple('fail', [])

def format_addr(addr: int):
if addr >= rela.virtual_address and addr < rela.virtual_address + rela.size:
offset = addr - rela.virtual_address
r_offset = (offset // 24)
r_rem = offset % 24

if r_offset >= 3 and r_offset <= 88:
arr_idx = (r_offset - 3) * 3 + (r_rem // 8)
return ArrAddr(arr_idx)
elif r_offset == 89:
return OutAddr(r_rem)

match r_rem:
case 0: return RelocAddr(Reloc(r_offset), 'r_address')
case 8: return RelocAddr(Reloc(r_offset), 'r_info')
case 16: return RelocAddr(Reloc(r_offset), 'r_addend')
case _: return RelocAddr(Reloc(r_offset), r_rem)
elif addr > dynsym.virtual_address and addr < dynsym.virtual_address + dynsym.size:
offset = addr - dynsym.virtual_address
r_offset = (offset // 24)
r_rem = offset % 24

match r_rem:
case 0: return SymAddr(Symbol(r_offset), 'st_name')
case 8: return Symbol(r_offset)
case 16: return SymAddr(Symbol(r_offset), 'st_size')
case _: return SymAddr(Symbol(r_offset), r_rem)
elif addr >= 0x404040 and addr < 0x404040+33:
off = addr-0x404040
return FlagAddr(off)
elif addr == 0x804000:
return BaseAddr()
elif addr == 0x404064:
return FailAddr()
else:
return addr

def to_sym(name):
assert len(name) == 1
return Symbol(ord(name[0]))

Rel = namedtuple('REL', ['dst','val','ridx'])
Copy = namedtuple('CPY', ['dst', 'symbol', 'ridx'])
R64 = namedtuple('R64', ['dst','symbol','addend','ridx'])
R32 = namedtuple('R32', ['dst','symbol','addend','ridx'])

def parse(b) -> list:
print('[*] Loading relocations...')
relocs = list(b.relocations)

print('[*] Parsing...')
instructions = []
for i in range(3, len(relocs)):
r = relocs[i]
match r.type:
case 1: # R64
instructions.append(R64(format_addr(r.address), to_sym(r.symbol.name), format_addr(r.addend), i))
case 5: # CPY
instructions.append(Copy(format_addr(r.address), to_sym(r.symbol.name), i))
case 8: # REL
instructions.append(Rel(format_addr(r.address), format_addr(r.addend), i))
case 10: # R32
instructions.append(R32(format_addr(r.address), to_sym(r.symbol.name), format_addr(r.addend), i))

return instructions

Mov = namedtuple('mov', ['dst', 'src', 'sz', 'ridx'])
Add = namedtuple('add', ['dst', 'src', 'addend', 'ridx'])

def lift_mov_add(instructions):
idx = 0

sizes = []
curr = [8] * 8
sizes.append(curr)

for instr in instructions:
c = list(curr)
match instr:
case Rel(SymAddr(Symbol(idx), 'st_size'), val, ridx):
c[idx] = val
sizes.append(c)

while idx < len(instructions):
match instructions[idx]:
case Rel(dst, val, ridx):
instructions[idx] = Mov(dst, Ref(val), 8, ridx)
case Copy(dst, sym, ridx):
instructions[idx] = Mov(dst, sym, sizes[idx][sym.idx], ridx)
case R64(dst, sym, add, ridx):
instructions[idx] = Add(dst, sym, add, ridx)
idx += 1
return instructions

def remove_sizes(instructions):
# Sizes are now nops
idx = 0
while idx < len(instructions):
match instructions[idx]:
case Mov(SymAddr(Symbol(s), 'st_size'), _, _, _) if s != 3:
instructions[idx:idx+1] = []

idx += 1
return instructions

def lift_indirect(instructions):
idx = 0
while idx < len(instructions):
match instructions[idx:idx+3]:
case [
Mov(RelocAddr(Reloc(rel_1), 'r_addend'), Symbol(sidx_1), sz_1, ridx_1),
Add(dst_2, sym_2, _, ridx_2),
Mov(RelocAddr(Reloc(rel_3), 'r_addend'), Ref(0), sz_3, _),
] if (
(rel_1 == ridx_2) and (rel_3 == ridx_2)
):
instructions[idx:idx+3] = [
Add(dst_2, sym_2, Symbol(sidx_1), ridx_1)
]

idx += 1
return instructions

Block = namedtuple('block', ['arr', 'flag', 'ridx'])
Output = namedtuple('output', ['out', 'arr', 'ridx'])

def lift_block(instructions):

idx = 0
while idx < len(instructions):
match instructions[idx:idx+18]:
case [
Mov(_,arr,_,ridx),
Add(_,_,_,_),
Mov(_,flag,_,_),
Mov(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
R32(_,_,_,_),
Mov(_,_,_,_),
Mov(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
Add(_,_,_,_),
Add(_,_,_,_),
Mov(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
]:
instructions[idx:idx+18] = [
Block(arr, flag, ridx)
]
idx += 1
return instructions

Reset = namedtuple('reset', ['ridx'])
ShuffleBlock = namedtuple('shuffleblock', ['f1', 'f2', 'ridx'])

def lift_reset(instructions):
idx = 0
while idx < len(instructions) - 256:
good = True

for i in range(256):
op = instructions[idx+i]
if type(op) == Mov:
dst, src, _, _ = op
if dst != ArrAddr(i) or src != Ref(i):
good = False
break
else:
good = False
break

if good:
instructions[idx:idx+256] = [Reset(instructions[idx].ridx)]

idx += 1
return instructions

def lift_shuffle_block(instructions):
idx = 0
while idx < len(instructions) - 256:
good = True

for i in range(256):
op = instructions[idx+i]
if type(op) == Block:
arr, flag, ridx = op
if arr != Ref(ArrAddr(i)):
good = False
break
else:
good = False
break

if good:
instructions[idx:idx+256] = [ShuffleBlock(instructions[idx].flag, instructions[idx+1].flag, instructions[idx].ridx)]

idx += 1
return instructions

Output = namedtuple('output', ['out', 'arr', 'ridx'])

def lift_output(instructions):
idx = 0
while idx < len(instructions):
match instructions[idx:idx+26]:
case [
Mov(_,arr,_,ridx),
Add(_,_,_,_),
R32(_,_,_,_),
Mov(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
Add(_,_,_,_),
Add(_,_,_,_),
Mov(_,_,_,_),
Mov(_,_,_,_),
Mov(_,_,_,_),
Mov(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
R32(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
Mov(_,_,_,_),
Add(_,_,_,_),
Add(_,_,_,_),
Add(_,_,_,_),
Mov(out,_,_,_),
]:
instructions[idx:idx+26] = [Output(out, arr, ridx)]
idx += 1
return instructions

MultAdd = namedtuple('multadd', ['out', 'val', 'k', 'ridx'])

def lift_multadd(instructions):
idx = 0
while idx < len(instructions):
match instructions[idx:idx+3]:
# block prefix
case [
Mov(Symbol(2), out, _, ridx),
Mov(Symbol(5), Symbol(2), _, _),
Mov(Symbol(6), Ref(0), _, _),
]:
k = 0
double = False

ptr = idx + 3

good = True
while ptr < len(instructions):
match instructions[ptr]:
case Mov(Symbol(2), Ref(Symbol(6)), _, _):
double = True
case Mov(Symbol(2), Ref(Symbol(5)), _, _):
double = False
case Add(Symbol(6), Symbol(6), Symbol(2), _):
k = (k * 2) if double else (k + 1)
case Add(Symbol(7), Symbol(7), Symbol(2), _):
ptr += 1
break
case _:
good = False
break

ptr += 1

if good:
instructions[idx:ptr] = [
MultAdd(Symbol(7), out, k, ridx)
]

idx += 1

return instructions

Trunc = namedtuple('trunc', ['val', 'k', 'ridx'])

def lift_truncate(instructions):
idx = 0
while idx < len(instructions):
match instructions[idx:idx+2]:
case [
Mov(Symbol(2), Ref(SymAddr(Symbol(5), 11)), _, ridx),
Mov(SymAddr(Symbol(7), 11), Symbol(2), 5, _)
]:
instructions[idx:idx+2] = [
Trunc(Symbol(7), 0xffffff, ridx)]
idx += 1
return instructions

ArraySlots = namedtuple('arr', ['values', 'ridx'])

def lift_array_slots(instructions):
idx = 0

while idx < len(instructions):
match instructions[idx]:
case Mov(BaseAddr(), Ref(0), _, ridx):
ptr = idx+1
while ptr < len(instructions):
op = instructions[ptr]
if type(op) != Mov or op.dst != BaseAddr():
break
ptr += 1

start = idx
end = ptr

data = []

# Check for movs into array.
vstart = RelocAddr(Reloc(ridx), 'r_address').vaddr()
offset = 0
while end + offset < len(instructions) and offset < ((end - start) * 3):
op = instructions[end + offset]
if type(op) == Mov and type(op.dst) is RelocAddr and op.dst.vaddr() == vstart + (offset * 8):
data.append(op.src.val)
else:
break
offset += 1

if len(data) > 0:
data += [0] * (((end - start) * 3) - len(data))
instructions[idx:end+offset] = [
ArraySlots(data, ridx)
]

idx += 1
return instructions

Shellcode = namedtuple('shellcode', ['dst', 'code', 'ridx'])

def lift_shellcode(instructions):
idx = 0
while idx < len(instructions):
match instructions[idx:idx+6]:
case [
ArraySlots(values, ridx),
Mov(Symbol(3), Ref(RelocAddr(Reloc(rel2), 'r_address')), _, _),
Mov(SymAddr(Symbol(3), 'st_name'), _, _, _),
Add(dst, Symbol(3), _, _),
Mov(Symbol(2), _, _, _),
Mov(RelocAddr(Reloc(rel6), 'r_address'), Symbol(2), _, _)
] if (rel2 == ridx) and (rel6 == ridx):
instructions[idx:idx+6] = [
Shellcode(dst, b''.join([(x & 0xffffffffffffffff).to_bytes(8, 'little') for x in values]), ridx)
]
idx += 1
return instructions

Aop = namedtuple('aop', ['dst', 'op', 'val', 'k', 'ridx'])

def lift_aop(instructions):
idx = 0
while idx < len(instructions):
match instructions[idx:idx+5]:
case [
Mov(Symbol(2), val, _, ridx),
Mov(Symbol(5), Symbol(2), _, _),
Shellcode(_, data, _),
Mov(Symbol(2), Ref(Symbol(5)), _, _),
Add(dst, dst2, Symbol(2), _)
] if len(data) == 24 and (dst == dst2):
op = next(md.disasm(data, 0))

t = op.mnemonic
k = int(op.op_str.split(', ')[-1], 16)

instructions[idx:idx+5] = [
Aop(dst, t, val, k, ridx)
]

idx += 1
return instructions






def dump(instructions):
for op in instructions:
match op:
case Mov(SymAddr(sym, 'st_name'), Ref(val), 8, ridx) if type(val) is int:
name = val & 0xffffffff
info = (val >> 4) & 0xff
other = (val >> 5) & 0xff
shndx = (val >> 6) & 0xffff
print(f'[{ridx:04d}] :: setinfo {sym}, name=0x{name:x}, info=0x{info:x}, other=0x{other:x}, shndx=0x{shndx:x}')
case Mov(BaseAddr(), Ref(0), _, ridx):
print(f'[{ridx:04d}] :: [ARRAY SLOT]')
case Mov(dst, src, 8, ridx):
print(f'[{ridx:04d}] :: mov {dst}, {src}')
case Mov(dst, src, sz, ridx):
print(f'[{ridx:04d}] :: mov({sz}) {dst}, {src}')
case Add(dst, src, add, ridx):
print(f'[{ridx:04d}] :: add {dst}, {src}, {add}')
case R32(dst, src, add, ridx):
print(f'[{ridx:04d}] :: r32 {dst}, {src}, {add}')
case Block(arr, flag, ridx):
print(f'[{ridx:04d}] :: shuffle {arr}, {flag}')
case Output(out, arr, ridx):
print(f'[{ridx:04d}] :: output {out}, {arr}')
case ShuffleBlock(f1, f2, ridx):
print(f'[{ridx:04d}] :: shuffleblock {f1}, {f2}')
case MultAdd(dst, val, k, ridx):
print(f'[{ridx:04d}] :: madd {dst} += ({val} * {k})')
case Aop(dst, op, val, k, ridx):
print(f'[{ridx:04d}] :: aop {dst} += ({val} {op} {k})')
case Reset(ridx):
print(f'[{ridx:04d}] :: reset')
case Trunc(val, k, ridx):
print(f'[{ridx:04d}] :: trunc {val} &= 0x{k:x}')
case ArraySlots(values, ridx):
print(f'[{ridx:04d}] :: array [{", ".join([hex(x) for x in values])}]')
case Shellcode(dst, code, ridx):
print(f'[{ridx:04d}] :: exec {dst} <- {code.hex()}')
print('-' * 20)
for i in md.disasm(code, 0):
if i.mnemonic == 'ret':
break
print(" 0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str.replace('0x8040e4', 's5').replace('0x8040cc', 's4')))
print('-' * 20)
case _:
print(op)

LIFTS = [
lift_mov_add,
remove_sizes,
lift_indirect,
lift_block,
lift_reset,
lift_shuffle_block,
lift_output,
lift_multadd,
lift_truncate,
lift_array_slots,
lift_shellcode,
lift_aop,
]

def lift(instructions):
for lift_fn in LIFTS:
print(f'[*] {lift_fn.__name__}...')
instructions = lift_fn(instructions)
return instructions

instructions = parse(b)
instructions = lift(instructions)
dump(instructions)

然后得到下面的类似汇编,甚至还有机器码。

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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
[0005] :: mov s2, &flag[0]
[0007] :: mov(1) s4, s2
[0008] :: [ARRAY SLOT]
[0009] :: mov arr[15], &1585408084625667200
[0010] :: mov arr[16], &195
[0011] :: mov s3, &arr[15]
[0012] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0013] :: add arr[15], s3, 0
[0014] :: mov s2, &r101002.r_address
[0016] :: mov(24) arr[15], s2
[0017] :: [ARRAY SLOT]
[0018] :: mov arr[42], &141015791240320
[0019] :: mov arr[43], &195
[0020] :: mov s3, &arr[42]
[0021] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0022] :: add arr[42], s3, 0
[0023] :: mov arr[42], s2
[0024] :: mov s2, &s4
[0026] :: mov(1) arr[0], s2
[0027] :: mov s2, &flag[1]
[0028] :: mov s4, s2
[0029] :: [ARRAY SLOT]
[0030] :: mov arr[78], &1657465678663595136
[0031] :: mov arr[79], &195
[0032] :: mov s3, &arr[78]
[0033] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0034] :: add arr[78], s3, 0
[0035] :: mov s2, &r101002.r_address
[0037] :: mov(24) arr[78], s2
[0038] :: [ARRAY SLOT]
[0039] :: mov arr[105], &72198609829168256
[0040] :: mov arr[106], &195
[0041] :: mov s3, &arr[105]
[0042] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0043] :: add arr[105], s3, 0
[0044] :: mov arr[105], s2
[0045] :: mov s2, &s4
[0047] :: mov(1) arr[0], s2
[0048] :: mov s2, &flag[2]
[0049] :: mov s4, s2
[0050] :: [ARRAY SLOT]
[0051] :: mov arr[141], &1153062520398099584
[0052] :: mov arr[142], &195
[0053] :: mov s3, &arr[141]
[0054] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0055] :: add arr[141], s3, 0
[0056] :: mov s2, &r101002.r_address
[0058] :: mov(24) arr[141], s2
[0059] :: [ARRAY SLOT]
[0060] :: mov arr[168], &144256203867096192
[0061] :: mov arr[169], &195
[0062] :: mov s3, &arr[168]
[0063] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0064] :: add arr[168], s3, 0
[0065] :: mov arr[168], s2
[0066] :: mov s2, &s4
[0068] :: mov(1) arr[0], s2
[0069] :: mov s2, &flag[3]
[0070] :: mov s4, s2
[0071] :: [ARRAY SLOT]
[0072] :: mov arr[204], &1297177708473955456
[0073] :: mov arr[205], &195
[0074] :: mov s3, &arr[204]
[0075] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0076] :: add arr[204], s3, 0
[0077] :: mov s2, &r101002.r_address
[0079] :: mov(24) arr[204], s2
[0080] :: [ARRAY SLOT]
[0081] :: mov arr[231], &216313797905024128
[0082] :: mov arr[232], &195
[0083] :: mov s3, &arr[231]
[0084] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0085] :: add arr[231], s3, 0
[0086] :: mov arr[231], s2
[0087] :: mov s2, &s4
[0089] :: mov(1) arr[0], s2
[0090] :: mov s2, &flag[4]
[0091] :: mov s4, s2
[0092] :: exec r92.r_address <- 803425cc40800010c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x10
--------------------
[0101] :: array [0x4008040cc250480, 0xc3, 0x0]
[0104] :: mov s3, &r101.r_address
[0105] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0106] :: add r101.r_address, s3, 0
[0107] :: mov r101.r_address, s2
[0108] :: mov s2, &s4
[0110] :: mov(1) arr[0], s2
[0111] :: mov s2, &flag[5]
[0112] :: mov s4, s2
[0113] :: exec r113.r_address <- 803425cc40800011c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x11
--------------------
[0122] :: array [0x5008040cc250480, 0xc3, 0x0]
[0125] :: mov s3, &r122.r_address
[0126] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0127] :: add r122.r_address, s3, 0
[0128] :: mov r122.r_address, s2
[0129] :: mov s2, &s4
[0131] :: mov(1) arr[0], s2
[0132] :: mov s2, &flag[6]
[0133] :: mov s4, s2
[0134] :: exec r134.r_address <- 803425cc40800012c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x12
--------------------
[0143] :: array [0x6008040cc250480, 0xc3, 0x0]
[0146] :: mov s3, &r143.r_address
[0147] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0148] :: add r143.r_address, s3, 0
[0149] :: mov r143.r_address, s2
[0150] :: mov s2, &s4
[0152] :: mov(1) arr[0], s2
[0153] :: mov s2, &flag[7]
[0154] :: mov s4, s2
[0155] :: exec r155.r_address <- 803425cc40800013c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x13
--------------------
[0164] :: array [0x7008040cc250480, 0xc3, 0x0]
[0167] :: mov s3, &r164.r_address
[0168] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0169] :: add r164.r_address, s3, 0
[0170] :: mov r164.r_address, s2
[0171] :: mov s2, &s4
[0173] :: mov(1) arr[0], s2
[0174] :: mov s2, &flag[8]
[0175] :: mov s4, s2
[0176] :: exec r176.r_address <- 803425cc40800014c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x14
--------------------
[0185] :: array [0x8008040cc250480, 0xc3, 0x0]
[0188] :: mov s3, &r185.r_address
[0189] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0190] :: add r185.r_address, s3, 0
[0191] :: mov r185.r_address, s2
[0192] :: mov s2, &s4
[0194] :: mov(1) arr[1], s2
[0195] :: mov s2, &flag[9]
[0196] :: mov s4, s2
[0197] :: exec r197.r_address <- 803425cc40800015c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x15
--------------------
[0206] :: array [0x9008040cc250480, 0xc3, 0x0]
[0209] :: mov s3, &r206.r_address
[0210] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0211] :: add r206.r_address, s3, 0
[0212] :: mov r206.r_address, s2
[0213] :: mov s2, &s4
[0215] :: mov(1) arr[1], s2
[0216] :: mov s2, &flag[10]
[0217] :: mov s4, s2
[0218] :: exec r218.r_address <- 803425cc40800016c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x16
--------------------
[0227] :: array [0xa008040cc250480, 0xc3, 0x0]
[0230] :: mov s3, &r227.r_address
[0231] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0232] :: add r227.r_address, s3, 0
[0233] :: mov r227.r_address, s2
[0234] :: mov s2, &s4
[0236] :: mov(1) arr[1], s2
[0237] :: mov s2, &flag[11]
[0238] :: mov s4, s2
[0239] :: exec r239.r_address <- 803425cc40800017c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x17
--------------------
[0248] :: array [0xb008040cc250480, 0xc3, 0x0]
[0251] :: mov s3, &r248.r_address
[0252] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0253] :: add r248.r_address, s3, 0
[0254] :: mov r248.r_address, s2
[0255] :: mov s2, &s4
[0257] :: mov(1) arr[1], s2
[0258] :: mov s2, &flag[12]
[0259] :: mov s4, s2
[0260] :: exec r260.r_address <- 803425cc40800018c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x18
--------------------
[0269] :: array [0xc008040cc250480, 0xc3, 0x0]
[0272] :: mov s3, &r269.r_address
[0273] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0274] :: add r269.r_address, s3, 0
[0275] :: mov r269.r_address, s2
[0276] :: mov s2, &s4
[0278] :: mov(1) arr[1], s2
[0279] :: mov s2, &flag[13]
[0280] :: mov s4, s2
[0281] :: exec r281.r_address <- 803425cc40800019c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x19
--------------------
[0290] :: array [0xd008040cc250480, 0xc3, 0x0]
[0293] :: mov s3, &r290.r_address
[0294] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0295] :: add r290.r_address, s3, 0
[0296] :: mov r290.r_address, s2
[0297] :: mov s2, &s4
[0299] :: mov(1) arr[1], s2
[0300] :: mov s2, &flag[14]
[0301] :: mov s4, s2
[0302] :: exec r302.r_address <- 803425cc40800024c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x24
--------------------
[0311] :: array [0xe008040cc250480, 0xc3, 0x0]
[0314] :: mov s3, &r311.r_address
[0315] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0316] :: add r311.r_address, s3, 0
[0317] :: mov r311.r_address, s2
[0318] :: mov s2, &s4
[0320] :: mov(1) arr[1], s2
[0321] :: mov s2, &flag[15]
[0322] :: mov s4, s2
[0323] :: exec r323.r_address <- 803425cc4080002cc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x2c
--------------------
[0332] :: array [0xf008040cc250480, 0xc3, 0x0]
[0335] :: mov s3, &r332.r_address
[0336] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0337] :: add r332.r_address, s3, 0
[0338] :: mov r332.r_address, s2
[0339] :: mov s2, &s4
[0341] :: mov(1) arr[1], s2
[0342] :: mov s2, &flag[16]
[0343] :: mov s4, s2
[0344] :: exec r344.r_address <- 803425cc40800026c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x26
--------------------
[0353] :: array [0x10008040cc250480, 0xc3, 0x0]
[0356] :: mov s3, &r353.r_address
[0357] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0358] :: add r353.r_address, s3, 0
[0359] :: mov r353.r_address, s2
[0360] :: mov s2, &s4
[0362] :: mov(1) arr[2], s2
[0363] :: mov s2, &flag[17]
[0364] :: mov s4, s2
[0365] :: exec r365.r_address <- 803425cc4080001ec3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x1e
--------------------
[0374] :: array [0x11008040cc250480, 0xc3, 0x0]
[0377] :: mov s3, &r374.r_address
[0378] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0379] :: add r374.r_address, s3, 0
[0380] :: mov r374.r_address, s2
[0381] :: mov s2, &s4
[0383] :: mov(1) arr[2], s2
[0384] :: mov s2, &flag[18]
[0385] :: mov s4, s2
[0386] :: exec r386.r_address <- 803425cc4080001fc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x1f
--------------------
[0395] :: array [0x12008040cc250480, 0xc3, 0x0]
[0398] :: mov s3, &r395.r_address
[0399] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0400] :: add r395.r_address, s3, 0
[0401] :: mov r395.r_address, s2
[0402] :: mov s2, &s4
[0404] :: mov(1) arr[2], s2
[0405] :: mov s2, &flag[19]
[0406] :: mov s4, s2
[0407] :: exec r407.r_address <- 803425cc40800020c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x20
--------------------
[0416] :: array [0x13008040cc250480, 0xc3, 0x0]
[0419] :: mov s3, &r416.r_address
[0420] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0421] :: add r416.r_address, s3, 0
[0422] :: mov r416.r_address, s2
[0423] :: mov s2, &s4
[0425] :: mov(1) arr[2], s2
[0426] :: mov s2, &flag[20]
[0427] :: mov s4, s2
[0428] :: exec r428.r_address <- 803425cc40800020c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x20
--------------------
[0437] :: array [0x14008040cc250480, 0xc3, 0x0]
[0440] :: mov s3, &r437.r_address
[0441] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0442] :: add r437.r_address, s3, 0
[0443] :: mov r437.r_address, s2
[0444] :: mov s2, &s4
[0446] :: mov(1) arr[2], s2
[0447] :: mov s2, &flag[21]
[0448] :: mov s4, s2
[0449] :: exec r449.r_address <- 803425cc40800021c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x21
--------------------
[0458] :: array [0x15008040cc250480, 0xc3, 0x0]
[0461] :: mov s3, &r458.r_address
[0462] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0463] :: add r458.r_address, s3, 0
[0464] :: mov r458.r_address, s2
[0465] :: mov s2, &s4
[0467] :: mov(1) arr[2], s2
[0468] :: mov s2, &flag[22]
[0469] :: mov s4, s2
[0470] :: exec r470.r_address <- 803425cc40800023c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x23
--------------------
[0479] :: array [0x16008040cc250480, 0xc3, 0x0]
[0482] :: mov s3, &r479.r_address
[0483] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0484] :: add r479.r_address, s3, 0
[0485] :: mov r479.r_address, s2
[0486] :: mov s2, &s4
[0488] :: mov(1) arr[2], s2
[0489] :: mov s2, &flag[23]
[0490] :: mov s4, s2
[0491] :: exec r491.r_address <- 803425cc40800027c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x27
--------------------
[0500] :: array [0x17008040cc250480, 0xc3, 0x0]
[0503] :: mov s3, &r500.r_address
[0504] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0505] :: add r500.r_address, s3, 0
[0506] :: mov r500.r_address, s2
[0507] :: mov s2, &s4
[0509] :: mov(1) arr[2], s2
[0510] :: mov s2, &flag[24]
[0511] :: mov s4, s2
[0512] :: exec r512.r_address <- 803425cc40800024c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x24
--------------------
[0521] :: array [0x18008040cc250480, 0xc3, 0x0]
[0524] :: mov s3, &r521.r_address
[0525] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0526] :: add r521.r_address, s3, 0
[0527] :: mov r521.r_address, s2
[0528] :: mov s2, &s4
[0530] :: mov(1) arr[3], s2
[0531] :: mov s2, &flag[25]
[0532] :: mov s4, s2
[0533] :: exec r533.r_address <- 803425cc40800025c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x25
--------------------
[0542] :: array [0x19008040cc250480, 0xc3, 0x0]
[0545] :: mov s3, &r542.r_address
[0546] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0547] :: add r542.r_address, s3, 0
[0548] :: mov r542.r_address, s2
[0549] :: mov s2, &s4
[0551] :: mov(1) arr[3], s2
[0552] :: mov s2, &flag[26]
[0553] :: mov s4, s2
[0554] :: exec r554.r_address <- 803425cc40800026c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x26
--------------------
[0563] :: array [0x1a008040cc250480, 0xc3, 0x0]
[0566] :: mov s3, &r563.r_address
[0567] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0568] :: add r563.r_address, s3, 0
[0569] :: mov r563.r_address, s2
[0570] :: mov s2, &s4
[0572] :: mov(1) arr[3], s2
[0573] :: mov s2, &flag[27]
[0574] :: mov s4, s2
[0575] :: exec r575.r_address <- 803425cc40800027c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [s4], 0x27
--------------------
[0584] :: array [0x1b008040cc250480, 0xc3, 0x0]
[0587] :: mov s3, &r584.r_address
[0588] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0589] :: add r584.r_address, s3, 0
[0590] :: mov r584.r_address, s2
[0591] :: mov s2, &s4
[0593] :: mov(1) arr[3], s2
[0594] :: mov s4, &0
[0595] :: mov fail(), &0
[0596] :: mov s5, &0
[0597] :: mov s2, &arr[0]
[0599] :: mov s6, s2
[0600] :: exec r600.r_address <- 803425fc40800070c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x70
--------------------
[0609] :: mov s2, &s6
[0611] :: add s5, s5, s2
[0614] :: mov s6, &0
[0615] :: mov s2, &arr[0]
[0616] :: mov s6, s2
[0617] :: exec r617.r_address <- 803425fc4080007cc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x7c
--------------------
[0626] :: mov s2, &s6
[0628] :: add s5, s5, s2
[0631] :: mov s6, &0
[0632] :: mov s2, &arr[0]
[0633] :: mov s6, s2
[0634] :: exec r634.r_address <- 803425fc40800073c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x73
--------------------
[0643] :: mov s2, &s6
[0645] :: add s5, s5, s2
[0648] :: mov s6, &0
[0649] :: mov s2, &arr[0]
[0650] :: mov s6, s2
[0651] :: exec r651.r_address <- 803425fc40800078c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x78
--------------------
[0660] :: mov s2, &s6
[0662] :: add s5, s5, s2
[0665] :: mov s6, &0
[0666] :: mov s2, &arr[0]
[0667] :: mov s6, s2
[0668] :: exec r668.r_address <- 803425fc4080006fc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x6f
--------------------
[0677] :: mov s2, &s6
[0679] :: add s5, s5, s2
[0682] :: mov s6, &0
[0683] :: mov s2, &arr[0]
[0684] :: mov s6, s2
[0685] :: exec r685.r_address <- 803425fc40800027c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x27
--------------------
[0694] :: mov s2, &s6
[0696] :: add s5, s5, s2
[0699] :: mov s6, &0
[0700] :: mov s2, &arr[0]
[0701] :: mov s6, s2
[0702] :: exec r702.r_address <- 803425fc4080002ac3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x2a
--------------------
[0711] :: mov s2, &s6
[0713] :: add s5, s5, s2
[0716] :: mov s6, &0
[0717] :: mov s2, &arr[0]
[0718] :: mov s6, s2
[0719] :: exec r719.r_address <- 803425fc4080002cc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x2c
--------------------
[0728] :: mov s2, &s6
[0730] :: add s5, s5, s2
[0733] :: mov s6, &0
[0734] :: mov s2, &arr[1]
[0735] :: mov s6, s2
[0736] :: exec r736.r_address <- 803425fc4080007fc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x7f
--------------------
[0745] :: mov s2, &s6
[0747] :: add s5, s5, s2
[0750] :: mov s6, &0
[0751] :: mov s2, &arr[1]
[0752] :: mov s6, s2
[0753] :: exec r753.r_address <- 803425fc40800035c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x35
--------------------
[0762] :: mov s2, &s6
[0764] :: add s5, s5, s2
[0767] :: mov s6, &0
[0768] :: mov s2, &arr[1]
[0769] :: mov s6, s2
[0770] :: exec r770.r_address <- 803425fc4080002dc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x2d
--------------------
[0779] :: mov s2, &s6
[0781] :: add s5, s5, s2
[0784] :: mov s6, &0
[0785] :: mov s2, &arr[1]
[0786] :: mov s6, s2
[0787] :: exec r787.r_address <- 803425fc40800032c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x32
--------------------
[0796] :: mov s2, &s6
[0798] :: add s5, s5, s2
[0801] :: mov s6, &0
[0802] :: mov s2, &arr[1]
[0803] :: mov s6, s2
[0804] :: exec r804.r_address <- 803425fc40800037c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x37
--------------------
[0813] :: mov s2, &s6
[0815] :: add s5, s5, s2
[0818] :: mov s6, &0
[0819] :: mov s2, &arr[1]
[0820] :: mov s6, s2
[0821] :: exec r821.r_address <- 803425fc4080003bc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x3b
--------------------
[0830] :: mov s2, &s6
[0832] :: add s5, s5, s2
[0835] :: mov s6, &0
[0836] :: mov s2, &arr[1]
[0837] :: mov s6, s2
[0838] :: exec r838.r_address <- 803425fc40800022c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x22
--------------------
[0847] :: mov s2, &s6
[0849] :: add s5, s5, s2
[0852] :: mov s6, &0
[0853] :: mov s2, &arr[1]
[0854] :: mov s6, s2
[0855] :: exec r855.r_address <- 803425fc40800059c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x59
--------------------
[0864] :: mov s2, &s6
[0866] :: add s5, s5, s2
[0869] :: mov s6, &0
[0870] :: mov s2, &arr[2]
[0871] :: mov s6, s2
[0872] :: exec r872.r_address <- 803425fc40800053c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x53
--------------------
[0881] :: mov s2, &s6
[0883] :: add s5, s5, s2
[0886] :: mov s6, &0
[0887] :: mov s2, &arr[2]
[0888] :: mov s6, s2
[0889] :: exec r889.r_address <- 803425fc4080008ec3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x8e
--------------------
[0898] :: mov s2, &s6
[0900] :: add s5, s5, s2
[0903] :: mov s6, &0
[0904] :: mov s2, &arr[2]
[0905] :: mov s6, s2
[0906] :: exec r906.r_address <- 803425fc4080003dc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x3d
--------------------
[0915] :: mov s2, &s6
[0917] :: add s5, s5, s2
[0920] :: mov s6, &0
[0921] :: mov s2, &arr[2]
[0922] :: mov s6, s2
[0923] :: exec r923.r_address <- 803425fc4080002ac3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x2a
--------------------
[0932] :: mov s2, &s6
[0934] :: add s5, s5, s2
[0937] :: mov s6, &0
[0938] :: mov s2, &arr[2]
[0939] :: mov s6, s2
[0940] :: exec r940.r_address <- 803425fc40800059c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x59
--------------------
[0949] :: mov s2, &s6
[0951] :: add s5, s5, s2
[0954] :: mov s6, &0
[0955] :: mov s2, &arr[2]
[0956] :: mov s6, s2
[0957] :: exec r957.r_address <- 803425fc40800027c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x27
--------------------
[0966] :: mov s2, &s6
[0968] :: add s5, s5, s2
[0971] :: mov s6, &0
[0972] :: mov s2, &arr[2]
[0973] :: mov s6, s2
[0974] :: exec r974.r_address <- 803425fc4080002dc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x2d
--------------------
[0983] :: mov s2, &s6
[0985] :: add s5, s5, s2
[0988] :: mov s6, &0
[0989] :: mov s2, &arr[2]
[0990] :: mov s6, s2
[0991] :: exec r991.r_address <- 803425fc40800029c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x29
--------------------
[1000] :: mov s2, &s6
[1002] :: add s5, s5, s2
[1005] :: mov s6, &0
[1006] :: mov s2, &arr[3]
[1007] :: mov s6, s2
[1008] :: exec r1008.r_address <- 803425fc40800034c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x34
--------------------
[1017] :: mov s2, &s6
[1019] :: add s5, s5, s2
[1022] :: mov s6, &0
[1023] :: mov s2, &arr[3]
[1024] :: mov s6, s2
[1025] :: exec r1025.r_address <- 803425fc4080002dc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x2d
--------------------
[1034] :: mov s2, &s6
[1036] :: add s5, s5, s2
[1039] :: mov s6, &0
[1040] :: mov s2, &arr[3]
[1041] :: mov s6, s2
[1042] :: exec r1042.r_address <- 803425fc40800061c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x61
--------------------
[1051] :: mov s2, &s6
[1053] :: add s5, s5, s2
[1056] :: mov s6, &0
[1057] :: mov s2, &arr[3]
[1058] :: mov s6, s2
[1059] :: exec r1059.r_address <- 803425fc40800032c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x8040fc], 0x32
--------------------
[1068] :: mov s2, &s6
[1070] :: add s5, s5, s2
[1073] :: mov s6, &0
[1074] :: mov s2, &flag[28]
[1075] :: mov s6, s2
[1076] :: mov s2, &flag[29]
[1077] :: mov s7, s2
[1078] :: mov s8, &0
[1079] :: mov s2, &s8
[1080] :: add s8, s8, s2
[1083] :: mov s2, &s6
[1084] :: add s8, s8, s2
[1087] :: mov s9, &0
[1088] :: mov s2, &s9
[1089] :: add s9, s9, s2
[1092] :: mov s2, &s7
[1093] :: add s9, s9, s2
[1096] :: mov s2, &s9
[1097] :: add s10, s8, s2
[1100] :: exec r1100.r_address <- 8034255c4180006cc3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x80415c], 0x6c
--------------------
[1109] :: mov s2, &s10
[1111] :: add s5, s5, s2
[1114] :: mov s6, &0
[1115] :: mov s7, &0
[1116] :: mov s8, &0
[1117] :: mov s9, &0
[1118] :: mov s10, &0
[1119] :: mov s2, &flag[28]
[1120] :: mov s6, s2
[1121] :: mov s2, &flag[29]
[1122] :: mov s7, s2
[1123] :: mov s8, &0
[1124] :: mov s2, &s8
[1125] :: add s8, s8, s2
[1128] :: mov s2, &s6
[1129] :: add s8, s8, s2
[1132] :: mov s2, &s8
[1133] :: add s8, s8, s2
[1136] :: mov s9, &0
[1137] :: mov s2, &s9
[1138] :: add s9, s9, s2
[1141] :: mov s2, &s7
[1142] :: add s9, s9, s2
[1145] :: mov s2, &s9
[1146] :: add s10, s8, s2
[1149] :: exec r1149.r_address <- 8034255c418000a1c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x80415c], 0xa1
--------------------
[1158] :: mov s2, &s10
[1160] :: add s5, s5, s2
[1163] :: mov s6, &0
[1164] :: mov s7, &0
[1165] :: mov s8, &0
[1166] :: mov s9, &0
[1167] :: mov s10, &0
[1168] :: mov s2, &flag[30]
[1169] :: mov s6, s2
[1170] :: mov s2, &flag[31]
[1171] :: mov s7, s2
[1172] :: mov s8, &0
[1173] :: mov s2, &s8
[1174] :: add s8, s8, s2
[1177] :: mov s2, &s6
[1178] :: add s8, s8, s2
[1181] :: mov s9, &0
[1182] :: mov s2, &s9
[1183] :: add s9, s9, s2
[1186] :: mov s2, &s7
[1187] :: add s9, s9, s2
[1190] :: mov s2, &s9
[1191] :: add s10, s8, s2
[1194] :: exec r1194.r_address <- 8034255c418000b1c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x80415c], 0xb1
--------------------
[1203] :: mov s2, &s10
[1205] :: add s5, s5, s2
[1208] :: mov s6, &0
[1209] :: mov s7, &0
[1210] :: mov s8, &0
[1211] :: mov s9, &0
[1212] :: mov s10, &0
[1213] :: mov s2, &flag[30]
[1214] :: mov s6, s2
[1215] :: mov s2, &flag[31]
[1216] :: mov s7, s2
[1217] :: mov s8, &0
[1218] :: mov s2, &s8
[1219] :: add s8, s8, s2
[1222] :: mov s2, &s6
[1223] :: add s8, s8, s2
[1226] :: mov s2, &s8
[1227] :: add s8, s8, s2
[1230] :: mov s9, &0
[1231] :: mov s2, &s9
[1232] :: add s9, s9, s2
[1235] :: mov s2, &s7
[1236] :: add s9, s9, s2
[1239] :: mov s2, &s9
[1240] :: add s10, s8, s2
[1243] :: exec r1243.r_address <- 8034255c418000e5c3000000000000000000000000000000
--------------------
0x0: xor byte ptr [0x80415c], 0xe5
--------------------
[1252] :: mov s2, &s10
[1254] :: add s5, s5, s2
[1257] :: mov s6, &0
[1258] :: mov s7, &0
[1259] :: mov s8, &0
[1260] :: mov s9, &0
[1261] :: mov s10, &0
[1262] :: mov s2, &s5
[1264] :: mov(1) fail(),

我们选择一个进行分析

1
2
3
4
5
6
7
8
9
10
11
12
    0x0:	xor	byte ptr [s4], 0x10
--------------------
[0101] :: array [0x4008040cc250480, 0xc3, 0x0]
[0104] :: mov s3, &r101.r_address
[0105] :: setinfo s3, name=0x1a, info=0x1, other=0x0, shndx=0x0
[0106] :: add r101.r_address, s3, 0
[0107] :: mov r101.r_address, s2
[0108] :: mov s2, &s4
[0110] :: mov(1) arr[0], s2
[0111] :: mov s2, &flag[5]
[0112] :: mov s4, s2
[0113] :: exec r113.r_address <- 803425cc40800011c3000000000000000000000000000000

array里的机器码转变顺序放到ida里就是add 0x4,后面的exec其实就是个异或,那么我们能够看出这个题的逻辑是flag先异或在加上自己在数组的位置就等于后面的encflag,根据提示还得爆破后4位才行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import hashlib
xor=[0x16,0x17,0x10,0x12,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x24,0x2c,0x26,0x1e,0x1f,0x20,0x20,0x21,0x23,0x27,0x24,0x25,0x26,0x27]
encflag=[0x70,0x7c,0x73,0x78,0x6f,0x27,0x2a,0x2c,0x7f,0x35,0x2d,0x32,0x37,0x3b,0x22,0x59,0x53,0x8e,0x3d,0x2a,0x59,0x27,0x2d,0x29,0x34,0x2d,0x61,0x32]
a=""
for i in range(len(encflag)):
a+=chr((encflag[i]-i)^xor[i])
l = "1234567890abcdef"
for b in l:
for c in l:
for d in l:
flag = a+b+c+d+"}"
sha = hashlib.sha256(flag.encode("utf-8")).hexdigest()
if sha[0:16] == "f860464d767610bb":
print(flag)
break

gamemaster

是个经典21点游戏

发现dll文件是c#写的,放入dnspy,发现似乎是对文件异或和进行了aes加密,那么源文件已经给了,直接模拟生成一下

image-20220802171638649

发现里面有个MZ签名,dump出来还是一个c#写的

EasyRe

这个题每一行都要分析,能学到很多东西。

先用finger跑一下会发现清晰很多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__int64 __fastcall sub_4021BB(__int64 a1, __int64 a2)
{
int v2; // er8
int v3; // er9
unsigned int v5; // [rsp+1Ch] [rbp-4h]

sub_402150();//将re3的shellcode写到文件中
v5 = fork();//创建子进程,返回子进程id
if ( v5 )
{
sub_401F2F(v5);//主进程进入函数
remove((__int64)"re3");
}
else
{
sys_ptrace(PTRACE_TRACEME, 0LL, 0LL, 0LL, v12, v13, a2);//ptrace函数
sub_44B680((unsigned int)"re3", (unsigned int)"re3", *(_QWORD *)(a2 + 8), 0, v2, v3, a2);
}
return 0LL;
}

ptrace函数最重要的是第一个参数request,它决定了系统调用

image-20220830094057553

我们主要看主进程进入的函数

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
__int64 __fastcall sub_401F2F(unsigned int a1)
{
__int64 v1; // r8
__int64 v2; // r9
unsigned int v3; // ecx
__int64 v4; // rdx
__int64 result; // rax
__int64 v6; // r8
__int64 v7; // r9
__int64 v8; // r8
__int64 v9; // r9
__int64 v10; // r8
__int64 v11; // r9
__int64 v12; // r8
__int64 v13; // r9
__int64 v14; // r8
__int64 v15; // r9
char v16; // [rsp+0h] [rbp-130h]
char v17; // [rsp+0h] [rbp-130h]
char v18; // [rsp+0h] [rbp-130h]
char v19; // [rsp+0h] [rbp-130h]
unsigned int v20; // [rsp+10h] [rbp-120h]
__int64 v21; // [rsp+18h] [rbp-118h]
int v22; // [rsp+2Ch] [rbp-104h] BYREF
char v23[128]; // [rsp+30h] [rbp-100h] BYREF
__int64 v24; // [rsp+B0h] [rbp-80h]
__int64 v25; // [rsp+108h] [rbp-28h]
__int64 v26; // [rsp+110h] [rbp-20h]
__int64 v27; // [rsp+118h] [rbp-18h]
int i; // [rsp+124h] [rbp-Ch]
__int64 v29; // [rsp+128h] [rbp-8h]

sys_wait(a1, 0LL, 0);//等待子进程信号
sys_ptrace(PTRACE_CONT, a1, 0LL, 0LL, v1, v2, v16);//重新运行处于stopped状态程序
v27 = sub_401A30(a1);
v3 = sub_4017E5();//如下表,将下表数据存到result
result = v4;
v20 = v3;
v21 = v4;
for ( i = 0; i <= 2; ++i )
{
v22 = 0;
sys_wait(a1, &v22, 0); //等待子进程信号
result = v22 & 0x7F;
if ( (v22 & 0x7F) == 0 )
break;
sys_ptrace(PTRACE_GETREGS, a1, 0LL, v23, v6, v7, v17);//复制通用寄存器
v26 = v24 - 1;
v25 = sys_ptrace(PTRACE_PEEKTEXT, a1, v24 - 1, 0LL, v8, v9, v18);//子进程给父进程数据
if ( v25 == 0xCAFEB055BFCCLL )
{
v29 = v26;
sub_401BB1(a1, v26, v27, v20, v21);
v24 = v26 + 10;
sys_ptrace(13LL, a1, 0LL, v23, v12, v13, v19);
}
else if ( v25 == 0xCAFE1055BFCCLL )
{
sub_401D78(a1, v29, v26, v27, v20, v21);
v24 = v26 + 10;
sys_ptrace(PTRACE_SETREGS, a1, 0LL, v23, v14, v15, v19);
}
result = sys_ptrace(PTRACE_CONT, a1, 0LL, 0LL, v10, v11, v19);
}
return result;
}

image-20220830102915693

当子进程给父进程数据时,有两个选择,我们需要知道进入了哪个地方。

接下来看re3这个数据

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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
struct __jmp_buf_tag env[1]; // [rsp+10h] [rbp-850h] BYREF
struct __jmp_buf_tag v5[1]; // [rsp+E0h] [rbp-780h] BYREF
struct __jmp_buf_tag v6[1]; // [rsp+1B0h] [rbp-6B0h] BYREF
struct __jmp_buf_tag v7[1]; // [rsp+280h] [rbp-5E0h] BYREF
char v8[640]; // [rsp+350h] [rbp-510h] BYREF
char v9[636]; // [rsp+5D0h] [rbp-290h] BYREF
int v10; // [rsp+84Ch] [rbp-14h]
int v11; // [rsp+850h] [rbp-10h]
int v12; // [rsp+854h] [rbp-Ch]
int v13; // [rsp+858h] [rbp-8h]
int v14; // [rsp+85Ch] [rbp-4h]
__int64 savedregs; // [rsp+860h] [rbp+0h] BYREF

v14 = 1;
if ( a1 != 2 )
return 0LL;
(sub_2490)(a2[1], a2, a3);//主要加密我们现在不关心
(loc_21F9)(&unk_55C0, v9, v8);//这个地方要注意
v13 = _setjmp(env);
if ( v13 <= 24 )
{
v11 = _setjmp(v5);
if ( v11 < byte_50A0[25 * v13] )
{
if ( byte_50A0[25 * v13 + 1 + v11] != *(&savedregs + 25 * v13 + v11 - 655) )
v14 = 0;
longjmp(v5, v11 + 1);
}
longjmp(env, v13 + 1);
}
v12 = _setjmp(v6);
if ( v12 <= 24 )
{
v10 = _setjmp(v7);
if ( v10 < byte_5320[25 * v12] )
{
if ( byte_5320[25 * v12 + 1 + v10] != *(&savedregs + 25 * v12 + v10 - 1295) )
v14 = 0;
longjmp(v7, v10 + 1);
}
longjmp(v6, v12 + 1);
}
if ( v14 == 1 )
puts("GOOD JOB");
return 0LL;
}
1
(loc_21F9)(&unk_55C0, v9, v8);

这个地方的数据非常奇怪,无法反编译,我们需要仔细看一下

image-20220830105602247

发现int 3,并且有一个CAFEB055BF这样一个数据,这个数据是在主进程里进行判断的数据,那么我们可以推测这个题的主要逻辑就是:主进程先等待子进程运行,子进程抛出int 3等待主进程调试,主进程判断异常类型,进行对上面的smc处理。

获取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
__int64 __fastcall sub_401BB1(unsigned int a1, __int64 a2, int a3, char a4, __int64 a5)
{
__int64 v5; // rcx
__int64 v6; // r8
__int64 v7; // r9
int v8; // er8
int v9; // er9
__int64 v10; // rax
int v11; // er8
int v12; // er9
__int64 v13; // r8
__int64 v14; // r9
__int64 result; // rax
char v16; // [rsp+0h] [rbp-C0h]
unsigned int v17; // [rsp+0h] [rbp-C0h]
char v18; // [rsp+0h] [rbp-C0h]
unsigned __int64 v21; // [rsp+20h] [rbp-A0h]
char v22[32]; // [rsp+30h] [rbp-90h] BYREF
char v23[32]; // [rsp+50h] [rbp-70h] BYREF
char v24[24]; // [rsp+70h] [rbp-50h] BYREF
__int64 v25; // [rsp+88h] [rbp-38h]
__int64 v26; // [rsp+90h] [rbp-30h]
int v27; // [rsp+9Ch] [rbp-24h]
__int64 v28; // [rsp+A0h] [rbp-20h]
int v29; // [rsp+ACh] [rbp-14h]
__int64 v30; // [rsp+B0h] [rbp-10h]
int j; // [rsp+B8h] [rbp-8h]
unsigned int i; // [rsp+BCh] [rbp-4h]

v16 = a4;
v30 = sub_401AC2(a1, a2);
v29 = (v30 - a2 - 10) >> 4;
v21 = a2 + 10;
for ( i = 0; ; ++i )
{
result = i;
if ( i >= v29 )
break;
v28 = sys_ptrace(PTRACE_PEEKTEXT, a1, v21, v5, v6, v7, v16);
v27 = sub_40190E((v21 - a3), v17, a5);
sprintf(v23, &unk_490008, v27, &unk_490008, v8, v9, v17);
v10 = j_strnlen(v23);
md5(v23, v10, v24);
for ( j = 15; j > 7; --j )
sprintf(&v22[2 * (15 - j)], "%02x", v24[j], &v22[2 * (15 - j)], v11, v12, v18);
v26 = sub_40B660(v22, 0LL, 16LL);
v25 = v26 ^ v28;
sys_ptrace(PTRACE_POKETEXT, a1, v21, v26 ^ v28, v13, v14, v18);
v21 += 16LL;
}
return result;
}

我们直接看主进程进入的smc函数,最重要的是一个md5一个异或2,经过动态调试

,可以知道v28是在子程序中取int 3后面的qword,v26是将原始值进行md5后再将从第八个字节倒序。如何获取这个值呢,我们需要利用条件断点

image-20220830115323802

拿到值后我们直接去子进程用idapython恢复一下:

1
2
3
4
5
6
7
8
9
10
xorKey = {8723: 2533025110152939745, 8739: 5590097037203163468, 8755: 17414346542877855401, 8771: 17520503086133755340, 8787: 12492599841064285544, 8803: 12384833368350302160, 8819: 11956541642520230699, 8835: 12628929057681570616, 8851: 910654967627959011, 8867: 5684234031469876551, 8883: 6000358478182005051, 8899: 3341586462889168127, 8915: 11094889238442167020, 8931: 17237527861538956365, 8947: 17178915143649401084, 8963: 11176844209899222046, 8979: 18079493192679046363, 8995: 7090159446630928781, 9011: 863094436381699168, 9027: 6906972144372600884, 9043: 16780793948225765908, 9059: 7086655467811962655, 9075: 13977154540038163446, 9091: 7066662532691991888, 9107: 15157921356638311270, 9123: 12585839823593393444, 9139: 1360651393631625694, 9155: 2139328426318955142, 9171: 2478274715212481947, 9187: 12876028885252459748, 9203: 18132176846268847269, 9219: 17242441603067001509, 9235: 8492111998925944081, 9251: 14679986489201789069, 9267: 13188777131396593592, 9283: 5298970373130621883, 9299: 525902164359904478, 9315: 2117701741234018776, 9331: 9158760851580517972}

addr = 0x2213

while True:
data = get_qword(addr)
key = xorKey[addr]
dec = data ^ key
idc.patch_qword(addr, dec)
addr += 16

动态调试:

也就是经常说的patch死循环,但之前一直没操作过,这次学会了。

patch死循环目的是什么呢?我们知道如果不patch我们是没法在主进程中查看子进程的,通过patch死循环可以直接调试子进程。

为什么for循环3次呢?第一次是int3处理smc解密,第二次是int3处理smc加密,就是将解密完的数据再加密回去,第三次是等待子进程结束。

如何操作?先找到子进程末尾,在末尾写个死循环就是jmp到本地址,第二步为了不使smc又把解密完的数据加密回去,异或改为0,第三步patch 401F2F函数的 for 循环为2

patch前

image-20220830155226276

patch后

image-20220830155301280

异或改为0:

image-20220830155531523

for循环改为1:

image-20220830155554253

修改完后运行发现仍然再跑

image-20220830155922080

image-20220830160100683

成功!

用下面脚本找到smc那个函数:

1
2
3
4
5
a = 0x56534AF3F00C
while(a < 0x56534af3f48d):
if(get_wide_byte(a) == 0x55 and get_wide_byte(a+1) == 0x48 and get_wide_byte(a+4) == 0x48):
print(hex(a),end = ", ")
a+=1

image-20220830160553793

这样就可以把这个dump出来了

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
// positive sp value has been detected, the output may be wrong!
void __fastcall sub_21F9(__int64 input, __int64 data1, __int64 data2)
{
int offsett; // [rsp+20h] [rbp-28h]
int statee; // [rsp+24h] [rbp-24h]
char count2; // [rsp+28h] [rbp-20h]
int jj; // [rsp+2Ch] [rbp-1Ch]
int j; // [rsp+30h] [rbp-18h]
int offset; // [rsp+34h] [rbp-14h]
int state; // [rsp+38h] [rbp-10h]
char lineCount; // [rsp+3Ch] [rbp-Ch]
int ii; // [rsp+40h] [rbp-8h]
int i; // [rsp+44h] [rbp-4h]

for ( i = 0; i <= 24; ++i )
{
ii = 0;
lineCount = 0;
state = 0;
offset = 1;
while ( ii <= 24 )
{
if ( *(25 * i + ii + input) )
{
++lineCount;
state = 1;
}
else
{
if ( state )
{
*(data1 + 25LL * i + offset) = lineCount;
lineCount = 0;
++offset;
}
state = 0;
}
if ( ++ii == 25 && state )
{
*(data1 + 25LL * i + offset) = lineCount;
lineCount = 0;
++offset;
}
}
*(25LL * i + data1) = offset - 1;
}


for ( j = 0; j <= 24; ++j )
{
jj = 0;
count2 = 0;
statee = 0;
offsett = 1;
while ( jj <= 24 )
{
if ( *(25 * jj + j + input) )
{
++count2;
statee = 1;
}
else
{
if ( statee )
{
*(data2 + 25LL * j + offsett) = count2;
count2 = 0;
++offsett;
}
statee = 0;
}
if ( ++jj == 25 )
{
if ( statee )
{
*(data2 + 25LL * j + offsett) = count2;
count2 = 0;
++offsett;
}
}
}
*(25LL * j + data2) = offsett - 1;
}
}

其实前面的操作就很难了,后面这个加密更难,其实是个数织游戏

image-20220830161743593

这个地方取出来的数据其实是不对的,因为在程序运行的时候init段进行了初始化,真正的在

image-20220830161940268

找到在线网站解密就行https://handsomeone.github.io/Nonogram/,注意每行第一个数是偏移,不能出现在解密里

image-20220830162146771

DASCTF_7月赛

这次逆向没以前那么坐牢了。

隐秘的角落

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
void __cdecl main_main()
{
__int64 v0; // rdi
__int64 v1; // rsi
__int64 v2; // [rsp+8h] [rbp-88h]
_QWORD *v3; // [rsp+8h] [rbp-88h]
_QWORD *v4; // [rsp+50h] [rbp-40h]
_QWORD v5[4]; // [rsp+58h] [rbp-38h] BYREF
__int64 v6[2]; // [rsp+78h] [rbp-18h] BYREF

sync___ptr_WaitGroup__Add((__int64)&main_wg, 1LL);
runtime_newobject((__int64)&unk_4B0DA0, v2);
v4 = v3;
v6[0] = (__int64)&unk_4B0DA0;
v6[1] = (__int64)&off_4E9BB0;
fmt_Fprintln((__int64)&go_itab__os_File_io_Writer, os_Stdout, (__int64)v6, 1LL, 1LL);
v5[2] = &unk_4AE9C0;
v5[3] = v4;
fmt_Fscanf(v0, v1, (const char *)&go_itab__os_File_io_Reader);
runtime_newproc(16, (char)&off_4D2310, *v4);
v5[0] = &unk_4B0DA0;
v5[1] = &off_4E9BC0;
fmt_Fprintln((__int64)&go_itab__os_File_io_Writer, os_Stdout, (__int64)v5, 1LL, 1LL);
sync___ptr_WaitGroup__Wait((__int64)&main_wg);
}

也是个go,通过动调发现关键函数在off_4D2310,点进去发现有check函数

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
void __golang main_checkflag(__int64 a1, __int64 a2)
{
char v2; // al
__int64 v3; // [rsp+18h] [rbp-70h]
char v4; // [rsp+18h] [rbp-70h]
__int64 v5; // [rsp+20h] [rbp-68h]
char v6[32]; // [rsp+40h] [rbp-48h] BYREF
_QWORD v7[2]; // [rsp+60h] [rbp-28h] BYREF
_QWORD v8[2]; // [rsp+70h] [rbp-18h] BYREF

v3 = runtime_stringtoslicebyte((__int64)v6, a1, a2);
main_Myencode(v3);
if ( v5 == qword_55EA78 )
{
runtime_memequal((__int64)main_enc, v3, qword_55EA78, v3);
v2 = v4;
}
else
{
v2 = 0;
}
if ( v2 )
{
v8[0] = &unk_4B0DA0;
v8[1] = &off_4E9B90;
fmt_Fprintln((__int64)&go_itab__os_File_io_Writer, os_Stdout, (__int64)v8, 1LL, 1LL);
}
else
{
v7[0] = &unk_4B0DA0;
v7[1] = &off_4E9BA0;
fmt_Fprintln((__int64)&go_itab__os_File_io_Writer, os_Stdout, (__int64)v7, 1LL, 1LL);
}
sync___ptr_WaitGroup__Add((__int64)&main_wg, -1LL);
}

直接看encode,发现是rc4,交叉引用密文和密钥,发现密文在init段被异或了,拿脚本直接解了

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
import base64
def rc4_main(key="init_key", message="init_message"):
print("RC4解密主函数调用成功")
print('\n')
s_box = rc4_init_sbox(key)
crypt = rc4_excrypt(message, s_box)
return crypt
def rc4_init_sbox(key):
s_box = list(range(256))
print("原来的 s 盒:%s" % s_box)
print('\n')
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
print("混乱后的 s 盒:%s" % s_box)
print('\n')
return s_box
def rc4_excrypt(plain, box):
print("调用解密程序成功。")
print('\n')
plain = base64.b64decode(plain.encode('utf-8'))
plain = bytes.decode(plain)
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append((ord(s) ^ k))
print("res用于解密字符串,解密后是:%res" % res)
print('\n')
cipher = "".join(res)
print("解密后的字符串是:%s" % cipher)
print('\n')
return cipher
#a=[0xE0,0xB2,0x5F,0x3D,0x8F,0xFA,0x94,0xB6,0xE7,0x9D,0x6C,0x98,0x66,0xD2,0x0F,0xEA,0x6D,0x6F,0xBE,0xC5,0x71,0x40,0x08,0x1B,0xF6,0xF3,0xBD,0xA8,0x8D,0x09,0x7B,0x7C]
a = [251, 198, 166, 157, 196, 219, 123, 86, 182, 70, 166, 192, 133, 100, 122, 154, 55, 76, 16, 150, 233, 167, 40, 196, 177, 45, 241, 222, 71, 59, 181, 243, 44, 125, 103, 29]
s = ""
for i in a:
s += chr(i)
s = str(base64.b64encode(s.encode('utf-8')), 'utf-8')
rc4_main("thisiskkk", s)

EzGo

这个题又是go,确实不难。难的是解方程。

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
void __cdecl main_main()
{
__int64 v0; // rdi
__int64 v1; // rsi
__int128 v2; // xmm0
__int64 v3; // rcx
__int64 v4; // rax
__int64 i; // rdx
__int64 v6; // rdx
__int64 v7; // [rsp+10h] [rbp-120h]
__int64 v8; // [rsp+10h] [rbp-120h]
int v9; // [rsp+18h] [rbp-118h]
__int64 v10; // [rsp+18h] [rbp-118h]
__int64 v11; // [rsp+18h] [rbp-118h]
__int64 v12; // [rsp+18h] [rbp-118h]
__int128 v13; // [rsp+18h] [rbp-118h]
__int64 v14; // [rsp+18h] [rbp-118h]
char v15; // [rsp+18h] [rbp-118h]
_QWORD *v16; // [rsp+20h] [rbp-110h]
__int64 v17; // [rsp+20h] [rbp-110h]
__int64 v18; // [rsp+20h] [rbp-110h]
__int64 v19; // [rsp+28h] [rbp-108h]
__int64 v20; // [rsp+28h] [rbp-108h]
__int64 v21; // [rsp+30h] [rbp-100h]
__int64 v22; // [rsp+30h] [rbp-100h]
__int64 v23; // [rsp+38h] [rbp-F8h]
__int128 v24; // [rsp+40h] [rbp-F0h]
__int64 v25; // [rsp+50h] [rbp-E0h]
__int64 v26; // [rsp+58h] [rbp-D8h]
__int64 v27; // [rsp+60h] [rbp-D0h]
char v28[24]; // [rsp+68h] [rbp-C8h] BYREF
char v29; // [rsp+80h] [rbp-B0h] BYREF
__int64 v30; // [rsp+88h] [rbp-A8h]
__int64 *v31; // [rsp+90h] [rbp-A0h]
_QWORD v32[2]; // [rsp+98h] [rbp-98h] BYREF
_QWORD v33[2]; // [rsp+A8h] [rbp-88h] BYREF
_QWORD v34[2]; // [rsp+B8h] [rbp-78h] BYREF
char v35[8]; // [rsp+C8h] [rbp-68h] BYREF
__int64 v36; // [rsp+D0h] [rbp-60h]
__int128 v37; // [rsp+D8h] [rbp-58h]
char v38[8]; // [rsp+E8h] [rbp-48h] BYREF
__int64 v39; // [rsp+F0h] [rbp-40h]
__int128 v40; // [rsp+F8h] [rbp-38h]
char v41[8]; // [rsp+108h] [rbp-28h] BYREF
__int64 v42; // [rsp+110h] [rbp-20h]
__int128 v43; // [rsp+118h] [rbp-18h]

while ( (unsigned __int64)&v29 <= *(_QWORD *)(*(_QWORD *)NtCurrentTeb()->NtTib.ArbitraryUserPointer + 16LL) )
runtime_morestack_noctxt();
v31 = (__int64 *)runtime_newobject((__int64)&unk_4D3020);
v34[0] = "\b";
v34[1] = v31;
v9 = 2;
v16 = v34;
v19 = 1LL;
v21 = 1LL;
fmt_Fscanf(v0, v1, (const char *)&off_515980);
if ( v31[1] != 40 )
goto LABEL_10;
v41[0] = 0;
v42 = 0LL;
v2 = 0LL;
v43 = 0LL;
v3 = *v31;
v30 = *v31;
v4 = v31[1];
v27 = v4;
for ( i = 0LL; i < v4; i = v26 )
{
if ( *(unsigned __int8 *)(v3 + i) >= 0x80u )
{
runtime_decoderune(v3, v4, i, v9, (__int64)v16);
v6 = v17;
}
else
{
v6 = i + 1;
}
v26 = v6;
v25 = math_big_nat_shl(
v42,
v43,
*((__int64 *)&v43 + 1),
v42,
v43,
*((__int64 *)&v43 + 1),
8LL,
v23,
v24,
*((__int64 *)&v24 + 1));
v43 = v24;
v42 = v23;
v38[0] = 0;
v39 = 0LL;
v40 = 0LL;
v10 = math_big___ptr_Int__SetInt64((__int64)v38, SHIDWORD(v25), v7);
v16 = (_QWORD *)math_big___ptr_Int__Add((__int64)v41, (__int64)v41, v8, v10);
v4 = v27;
v3 = v30;
v2 = 0LL;
}
v35[0] = 0;
v36 = 0LL;
v37 = v2;
v22 = math_big___ptr_Int__SetString(
(__int64)v35,
(__int64)"13145309456454850877228433642468099885703532627357198144609408341691751453534987676043709654743561019"
"0391556347148927592380050533193934285571983556924577144473815598516557161",
174LL,
10LL,
(__int64)v16,
v19);
math_big___ptr_Int__Mul((__int64)v41, (__int64)v41, (__int64)v41, v11);
math_big___ptr_Int__Mod((__int64)v41, (__int64)v41, (__int64)v35, v12);
math_big_nat_itoa(v42, v43, DWORD2(v43), v41[0], 10LL, v19, v22, v23);
v19 = runtime_slicebytetostring((__int64)v28, v20, v21, v13);
if ( v18 != 173 )
goto LABEL_10;
runtime_memequal(
v14,
(__int64)"33529281532734294938614341047870321616766628114182320093600990983456360122704185955921012051918080449587733"
"939007294096845300395098833835443815283246602601870001850089370636",
173LL,
v14);
if ( v15 )
{
v33[0] = &unk_4D3020;
v33[1] = &off_514208;
fmt_Fprintln((__int64)&off_5159A0, qword_59D910, (__int64)v33, 1LL, 1LL, v19, v21, v23);
}
else
{
LABEL_10:
v32[0] = &unk_4D3020;
v32[1] = &off_514218;
fmt_Fprintln((__int64)&off_5159A0, qword_59D910, (__int64)v32, 1LL, 1LL, v19, v21, v23);
}
}

v14是我们通过输入计算出的值,来看程序,首先是输入,然后是一个for循环,for里嵌套一个decode程序,不知道是干什么的,刚开始还以为是解密程序,准备试试能不能解密,发现好像不行,那就慢慢跟程序,else里的是把输入的flag转换成ascii然后拼在一块,接下来是一个Mul函数,是将其乘方,然后是一个Mod函数,也就是mod这个大数,最后是equal函数,与大数对比。我们通过输入和输出就可以判断出自己的想法是否正确。

1
2
3
4
5
输入 '1' * 40
得到 44940666680036190507667229736237320843945547872118244516233712832889597565447002558460113570518306630271439743085954562346590579900861429645286911145287866527699481049284543

猜测:0x31313131313131313131313131313131313131313131313131313131313131313131313131313131 * 0x31313131313131313131313131313131313131313131313131313131313131313131313131313131 % 131453094564548508772284336424680998857035326273571981446094083416917514535349876760437096547435610190391556347148927592380050533193934285571983556924577144473815598516557161 = 44940666680036190507667229736237320843945547872118244516233712832889597565447002558460113570518306630271439743085954562346590579900861429645286911145287866527699481049284543
所以我们可以知道,我们要解一个方程 x^2 % big_num = result

这玩意是个rabin,纯密码学了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import libnum
import gmpy2
#导入公钥
n=131453094564548508772284336424680998857035326273571981446094083416917514535349876760437096547435610190391556347148927592380050533193934285571983556924577144473815598516557161
e = 2
c=33529281532734294938614341047870321616766628114182320093600990983456360122704185955921012051918080449587733939007294096845300395098833835443815283246602601870001850089370636
#n 在线分解
p=17489158711316178659
q=7516261744453902635364442762653073356746063224482072262455102025715350278471780391042196223686233375846890331396948280463168691132631674699134296333350979
inv_p = gmpy2.invert(p, q)
inv_q = gmpy2.invert(q, p)
mp = pow(c, (p + 1) // 4, p)
mq = pow(c, (q + 1) // 4, q)
a = (inv_p * p * mq + inv_q * q * mp) % n
b = n - int(a)
c = (inv_p * p * mq - inv_q * q * mp) % n
d = n - int(c)
#因为rabin 加密有四种结果,全部列出。
aa=[a,b,c,d]
for i in aa:
# print(i)
print(libnum.n2s(int(i)))

#DASCTF{48fa8aa2b489e9adac1750ea16ddc7b5}

fantansic maze

这题刚开始比赛的时候就在看这个,首先是与靶机交互,先爆破四位sha256,然后得到base64加密的ELF文件,创建新文件发现迷宫,就是要走1000次然后到达func1000。

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
.text:0000000000001358                 public function_0
.text:0000000000001358 function_0 proc near ; CODE XREF: function_156+85↓p
.text:0000000000001358 ; function_328+C1↓p ...
.text:0000000000001358
.text:0000000000001358 var_4 = dword ptr -4
.text:0000000000001358
.text:0000000000001358 ; __unwind {
.text:0000000000001358 endbr64
.text:000000000000135C push rbp
.text:000000000000135D mov rbp, rsp
.text:0000000000001360 sub rsp, 10h
.text:0000000000001364 mov eax, cs:tmp
.text:000000000000136A add eax, 1
.text:000000000000136D mov cs:tmp, eax
.text:0000000000001373 lea rdi, s ; "step1:"
.text:000000000000137A call _puts
.text:000000000000137F mov eax, 0
.text:0000000000001384 call read_num
.text:0000000000001389 mov [rbp+var_4], eax
.text:000000000000138C cmp [rbp+var_4], 0Ah
.text:0000000000001390 ja loc_141E
.text:0000000000001396 mov eax, [rbp+var_4]
.text:0000000000001399 lea rdx, ds:0[rax*4]
.text:00000000000013A1 lea rax, unk_3501C
.text:00000000000013A8 mov eax, [rdx+rax]
.text:00000000000013AB cdqe
.text:00000000000013AD lea rdx, unk_3501C
.text:00000000000013B4 add rax, rdx
.text:00000000000013B7 db 3Eh
.text:00000000000013B7 jmp rax
.text:00000000000013BA ; ---------------------------------------------------------------------------
.text:00000000000013BA mov eax, 0
.text:00000000000013BF call function_163
.text:00000000000013C4 mov eax, 0
.text:00000000000013C9 call function_451
.text:00000000000013CE mov eax, 0
.text:00000000000013D3 call function_771
.text:00000000000013D8 mov eax, 0
.text:00000000000013DD call function_602
.text:00000000000013E2 mov eax, 0
.text:00000000000013E7 call function_859
.text:00000000000013EC mov eax, 0
.text:00000000000013F1 call function_998
.text:00000000000013F6 mov eax, 0
.text:00000000000013FB call function_958
.text:0000000000001400 mov eax, 0
.text:0000000000001405 call function_437
.text:000000000000140A mov eax, 0
.text:000000000000140F call function_582
.text:0000000000001414 mov eax, 0
.text:0000000000001419 call function_474
.text:000000000000141E
.text:000000000000141E loc_141E: ; CODE XREF: function_0+38↑j
.text:000000000000141E mov eax, 0
.text:0000000000001423 call main
.text:0000000000001428 nop
.text:0000000000001429 leave
.text:000000000000142A retn
.text:000000000000142A ; } // starts at 1358
.text:000000000000142A function_0 endp

直接看汇编,也就是一个switch,输入1就跳转到function_163这样的。这种switch操作是通过rax寄存器进行跳转,并不是找表来跳转。如果我们每次switch都选择default,其实就可以一直填充计数器,所以只需找一条路直达func1000就行,我们只能从传过来的16进制来分析call指令的地址,call指令占5个字节如00000000000013BF call function_541 在 Hex View 中为\x00\x01\xbd\x7b\xe8(这里为大端序), \xe8可以理解为标志位,\x00\x01\xbd\x7b为地址到跳转函数的00000000000013BF偏移,而这里每一个函数的偏移为0xd3,这里就可以通过偏移来算出call指令所指向的函数,不会写交互脚本,所以只能借鉴出题师傅的脚本来写一遍:

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
from pwn import*
import random
from hashlib import sha256
import sys

p = remote("127.0.0.1",1447)

def pass_proof():
dir = string.ascii_letters + string.digits
p.recvuntil('[+] sha256(XXXX+')
#salt是已知的后面几位
salt = p.recv(16).strip().decode()
p.recvuntil(') == ')
#hash就是要等于的值
hash = p.recv(64).strip().decode()
while True:
rand_str = (''.join([random.choice(dir) for _ in range(4)])) + salt
if sha256(rand_str.encode()).hexdigest() == hash:
print(rand_str[:4])
p.sendlineafter('[+] Plz Tell Me XXXX :', rand_str[:4])
break

def get_elf():
p.recvuntil("map :\n")
data = p.recvuntil('That\'s all\n',drop=True)[:-1]
data = base64.b64decode(data)
fd = open('./1','wb')
fd.write(data)
fd.close()

pass_proof()
get_elf()

fd = open("./1","rb")
#fucn0地址
offset = 0x13c0

def get_map(fd, offset):
Map = []
for i in range(1000):
addr = offset
for j in range(10):
fd.seek(addr)
fc = u64(fd.read(4).ljust(8,b'\x00'))
if fc <= 0x33765:
fc = fc // 0xd3 + i + 1
else:
fc = fc - 0x100000000
if fc > -0xd3:
fc = i
else:
if addr + fc < 0x134a:
fc = 1000
else:
fc = fc // 0xd3
fc = fc + i + 1
Map.append(fc)
addr += 0xa
offset += 0xd3

return Map
Map = get_map(fd, offset)

def do_bfs(Map):
values = []
keys = []
for y in range(1000):
for x in range(10):
if x == 0:
values.append([])
values[y].append(Map[x + y * 10])
for i in range(1000):
keys.append(i)
result = dict(zip(keys, values))
result[1000] = ""
#print(result)
result1 = None
q = [(0, "")]
check_map = {}
while len(q):
f = q[0]
q = q[1:]
if(f[0] == 1000):
result1 = f[1]
break
if f[0] not in check_map:
check_map[f[0]] = f[1]
for i in range(10):
if result[f[0]][i] not in check_map:
q.append((result[f[0]][i],f[1]+str(i)))
return result1

result = do_bfs(Map)
print(result)
result = str(result)
times = 999 - len(result)

#default
for ii in range(times):
p.sendline("11")
for i in range(len(result)):
p.sendline(str(int(result[i])+1))