BUUCTF

刮开有奖

首先使用Exeinfo PE检查是否有壳并确定是32位还是64位

有壳脱壳/无壳查看文件类型-使用32/64位ida打开

shift+F12进入字符串窗口 发现base64加密方式(确定flag部分用到base64解码)

 

返回main函数 F5查看

 

跟进查看DialogFunc参数

String设定长度为8位且下面if语句使用到String

找到可疑点 v4”ak1w“ 和 v5”V1Ax” (先用base64解码得到 v4”jMp” 和 v5”WP1”)

所以此时猜测flag为长为8的字符串

此时还有两个需注意函数 sub_4010F0 和 sub_401000

 

此时想解决if语句中String[0]的值,那就要先解决v7值为多少

于是跟进前面与v7有关的函数sub_4010F0(v7,0,10)

 

此函数传入v7-v16十个数 直接c语言实现一下sub_4010F0查看此函数的作用(算法分析)

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


int __cdecl sub_4010F0(char *a1, int a2, int a3)
{
int result; // eax
int i; // esi
int v5; // ecx
int v6; // edx


result = a3;
for ( i = a2; i <= a3; a2 = i )
{
v5 = i;
v6 = i[a1];
if ( a2 < result && i < result )
{
do
{
if ( v6 > a1[result] )
{
if ( i >= result )
break;
++i;
a1[v5] = a1[result];
if ( i >= result )
break;
while ( a1[i] <= v6 )
{
if ( ++i >= result )
goto LABEL_13;
}
if ( i >= result )
break;
v5 = i;
a1[result] = a1[i];
}
--result;
}
while ( i < result );
}
LABEL_13:
a1[result] = v6;
sub_4010F0(a1, a2, i - 1);
result = a3;
++i;
}
return result;
}


int main()
{
char str[20]={90,74,83,69,67,97,78,72,51,110,103};
sub_4010F0(str,0,10);
printf("%s ",str);
return 0;
}

 

运行得出

 

有理由得出sub_4010F0函数是一个排序函数 且由小到大 所以v7-v16十个数重新由小到大赋值

解得

 

String[0]=51+34=85//ascii=U

String[1]=//ascii=J

String[2]=3*69+141/4=87//ascii=W

String[3]=同String[2]=ascii=P

v4”jMp” 和 v5”WP1”

所有字符都已得出

还要再考虑字符的排序 最后得出flag

后面v4 v5 可以看到第三第四字符已经是WP了 说明 WP1在前 jMp在后

将他们拼接在一起得到 UJWP1jMp


flag{UJWP1jMp}


[GWCTF 2019]pyre

pyc文件需用pyc反编译器反编译

寻找在线反编译器即可

将编译出来的py文件分析 然后进行逆向 写出对应脚本 得到flag

 

根据逻辑分析

num = ((input1[i] + i) % 128 + 128) % 128 #input1[i]中对应的值加上下标的值 模128(后面+128 %128无用)

code[i] = code[i] ^ code[i + 1] #code[i]与后一项进行 异或(同一位置上的数字相等则得0 同一位置上的数字相异则得1)

分析结束后用py编写脚本实现逆向操作

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
code = [
'\x1f',
'\x12',
'\x1d',
'(',
'0',
'4',
'\x01',
'\x06',
'\x14',
'4',
',',
'\x1b',
'U',
'?',
'o',
'6',
'*',
':',
'\x01',
'D',
';',
'%',
'\x13']


n = len(code)


for i in range(n-2,-1,-1): #从倒数第二个数开始异或
code[i] = chr(ord(code[i]) ^ ord(code[i+1]))


for i in range(n):
print(chr((ord(code[i])-i) % 128), end = "") #end = ""作用为减去每次循环的换行 改用空

运行得到flag


flag{Just_Re_1s_Ha66y!}


迷宫/数独

迷宫思想:给出几个键位 一般是四个 来控制上下左右 并给出迷宫

 

 

^ 1 1 1 1

0 1 0 0 0

0 1 0 1 0

1 1 1 1 #

数独思想:给出数独表 并且函数里面可以分析得出行和列不能有同样值

 

flag长为10,输入范围为0-4(已知)

1 4 _ 2 3

3 0 _ 1 _

0 _ 2 3 _

_ 3 _ _ 0

4 2 _ _ 1


[网鼎杯 2020 青龙组]jocker

题目为jocker 后面做题要小心点

无壳 32位 ida32打开

 

shift+f12查看字符串

 

双击到please input you flag:(其实哪个都可以)

f5进入查看伪代码

 

main函数得出flag长度为24

进入wrong(Str)和omg(Str)函数:

 

 

先不着急分析代码 因为题目是jocker

继续查看main函数里面的encrypt()和finally()函数 发现encrypt打不开 finally没东西

encrypt显示40151D指令转换不成代码 可疑

 

找完main函数里面所有的函数 发现最开始的几个字符串还有两个没有找到 并且字符串所在的函数进不去 猜测很有可能真正的flag藏在encrypt函数里面

 

回到main函数 现在我们主要目标就是进入encrypt函数和finally函数

发现其与0x41进行了异或操作

 

从IDA View窗口找到相应位置(可以找到wrong和omg字符串的位置 此位置下面就是我们要找的for循环和异或操作的汇编指令)

记录标志位 转战od进行动态分析 dump出函数

(也可以利用ida进行动态分析 或者shift+f2 使用idc修复指令 可惜我不会)

 

可以看到 40181B异或了41h jle跳转到了401807 说明此范围是for循环

紧接着到了call指令 所以可以确定call指令进入的就是encrypt函数

记录标志位 1833

od32打开找到标志位1833 在此处设置断点

 

f8执行到此处

发现od在执行到此处时会停止

 

其实是运行到了scanf 需要我们输入字符串

这里一定要输入与flag等长的字符串 不然程序会自动停止退出

前面得到flag长为24 我们输入123456789012345678901234

f7步入jocker.4021D0中

 

这就是encrypt函数内部 而且我们从右下角发现剩余没找到的字符串 也更加证明了我们之前的猜想

使用插件->ollydumpex->dump process进行dump脱壳并保存成新的exe文件

(关于为什么到这一步进行dump 说实话我也不是很懂)

 

选择Get EIP as OEP并进行dump 获得新的exe文件 再用ida32打开

 

找到start函数并进入(因为没有找到main函数)

发现以前未发现的字符串 come here 说明我们的方向是对的

 

for循环的if语句解释为:将我们输入的a1与aHahahahaDoYouF[i]进行异或并判断等不等于v2

但是需要注意一点:for循环了19次 而我们的flag是24位长 再根据wp开始时寻找的字符串 出现过“i hide the last part” 说明flag还缺少一部分

先求解flag的第一部分:aHa[i]已知 v2[i](v2的值是unk_403040赋予的)也已知

 

 

接下来写脚本求解

1
2
3
4
5
6
aHa = "hahahaha_do_you_find_me?"
v2 = [0x0e,0x0d,0x09,0x06,0x13,0x05,0x58,0x56,0x3e,
0x06,0x0c,0x3c,0x1f,0x57,0x14,0x6b,0x57,0x59,0x0d]

for i in range(19):
print(chr(ord(aHa[i]) ^ v2[i]),end='')

运行得到:

flag{d07abccf8a410c

接着我们去找剩下的flag

在start函数中我们X键对start使用交叉引用 进入第一个函数里面

 

发现这正是我们之前的main函数

 

接着我们进入finally函数 dump后变成了sub_40159A函数

 

v3=%tp&: 然后并没有其他可用信息了

接下来进行猜测:

flag的标准形式最后一位是 ‘} ’ 也就是说 v3的最后一位 ‘:’ 与一个数异或得到了 ‘}’

: ^ } = 71

1
print(ord(':') ^ ord('}'))

输出

71

我们可以假设 v3的所有位都与71进行了异或 编写脚本

1
2
3
4
v3 = "%tp&:"

for i in range(5):
print(chr(ord(v3[i]) ^ 71),end='')

运行得到:

b37a}

将flag的两个部分拼接


flag{d07abccf8a410cb37a}


[2019红帽杯]childRE

无壳 64位 ida64打开

 

shift+f12寻找字符串

 

根据字符串的内容推测 得出的flag要经过md5加密才可以提交

进入main函数 找到输出flag字符串位置 从下往上分析

 

第一部分 对outputString取余数和商的结果已知 并且和其进行对比的字符串也已知

编写脚本:

1
2
3
4
5
6
7
8
9
10
11
str1 = '(_@4620!08!6_0*0442!@186%%0@3=66!!974*3234=&0^3&1@=&0908!6_0*&'
str2 = '55565653255552225565565555243466334653663544426565555525555222'
str3 = '1234567890-=!@#$%^&*()_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;,ASDFGHJKL:"ZXCVBNM<>?zxcvbnm,./'

name = ''

for i in range(62):
name += chr(str3.index(str1[i]) + str3.index(str2[i])*23) #.index可以找出后缀在前缀中的匹配位置
#余数+商*除数
#.index返回的值是一个是余数和一个是商
print("outputString = " + name)

输出结果

outputString = private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)

继续向上分析:

 

以下资料摘自:https://blog.csdn.net/liweigao01/article/details/78351464

C++ 编译器的函数名修饰规则

无论 __cdecl,__fastcall还是__stdcall调用方式,函数修饰都是以一个“?”開始,后面紧跟函数的名字。再后面是參数表的開始标识和 依照參数类型代号拼出的參数表。

知:outputString = ?My_Aut0_PWN

对于C++的类成员函数(其调用方式是__thiscall)。函数的名字修饰与非成员的C++函数稍有不同,首先就是在函数名字和參数表之间插入以“@”字 符引导的类名。

知:outputString = ?My_Aut0_PWN@R0Pxx

其次是參数表的開始标识不同,公有(public)成员函数的标识是“@@QAE”,保护(protected)成员函数的标识是 “@@IAE”,私有(private)成员函数的标识是“@@AAE”。

知:outputString = ?My_Aut0_PWN@R0Pxx@****@AAE

之后是添加參数,先填返回值类型參数,再添加函数形參

X–void

D–char

E–unsigned char

F–short

H–int

I–unsigned int

J–long

K–unsigned long(DWORD)

M–float

N–double

_N–bool

U–struct

….

指针的方式有些特别。用PA表示指针,用PB表示const类型的指针。

返回值类型为char 对应PAD

形参类型为unsigned char 对应PAE

知:outputString = ?My_Aut0_PWN@R0Pxx@@AAEPADPAE

參数表后以“@Z”标识整个名字的结束。假设该函数无參数,则 以“Z”标识结束。

知:outputString = ?My_Aut0_PWN@R0Pxx@****@AAEPADPAE@Z

继续向上分析:

 

if( v4 )里面我们无法得知进行了怎么的顺序重排 所以这时候需要进行动态调试:

此处设下断点

 

选择 Local Windows debugger

 

运行 输入一串长为31且互不相同的字符串

这里我使用的:qwertyuiopasdfghjklzxcvbnm12345

之后f7单步步入进去 找到与值对应的赋值命令 al里面的值便是我们所需要的(动调前可以根据字符串等来进行定位)

 

之后f8单步运行并记录下RAX中的31个字符(字符根据自己输入内容而改变 并不是完全不变)

 

得到打乱后顺序:

0x68,0x6a,0x69,0x6b,0x6c,0x6f,0x72,0x7a,0x78,0x70,0x63,0x76,0x61,0x74,0x77,0x62,0x6e,

0x73,0x6d,0x31,0x64,0x79,0x32,0x33,0x66,0x34,0x35,0x67,0x75,0x65,0x71

接下来编写脚本进行求解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
flag = '?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z'    

a = 'qwertyuiopasdfghjklzxcvbnm12345' #自己输入字符串 动调获得打乱的顺序 逆向求解
b = [0x68,0x6a,0x69,0x6b,0x6c,0x6f,0x72,0x7a,0x78,0x70,0x63,
0x76,0x61,0x74,0x77,0x62,0x6e,0x73,0x6d,0x31,0x64,0x79,
0x32,0x33,0x66,0x34,0x35,0x67,0x75,0x65,0x71]
B = ''
c = [0]*31
d = [0]*31

for i in range(31): #将动调获得的结果转换为字符串
B += chr(b[i]) #B = 'hjiklorzxpcvatwbnsm1dy23f45gueq'

for i in range(31):
c[i] = a.index(B[i]) #获得顺序
d[c[i]] = flag[i] #重新排列顺序并打印

for i in range(31):
print(d[i], end='')

输出结果:

Z0@tRAEyuP@xAAA?M_A0_WNPx@@EPDP

最后进行MD5加密


flag{63b148e750fed3a33419168ac58083f5}


[2019红帽杯]easyRE

无壳 64位 ida64打开 elf文件

 

shift+f12进入字符串查找 找到与flag相关 进入函数

并且发现base64加密表 后面可能会进行解密

 

进入main函数分析:

 

查看其他wp时候 发现v15异或之后等于

the first four chars are ‘flag’

不过对我好像没有什么太大的影响

接着向下分析:

 

off_6CC090的值:

Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xVmpKS1NHVkdXbFpOYmtKVVZtcEtTMUl5VGtsaVJtUk9ZV3hhZVZadGVHdFRNVTVYVW01T2FGSnRVbGhhVjNoaFZWWmtWMXBFVWxSTmJFcElWbTAxVDJGV1NuTlhia0pXWWxob1dGUnJXbXRXTVZaeVdrWm9hVlpyV1hwV1IzaGhXVmRHVjFOdVVsWmlhMHBZV1ZSR1lWZEdVbFZTYlhSWFRWWndNRlZ0TVc5VWJGcFZWbXR3VjJKSFVYZFdha1pXWlZaT2NtRkhhRk5pVjJoWVYxZDBhMVV3TlhOalJscFlZbGhTY1ZsclduZGxiR1J5VmxSR1ZXSlZjRWhaTUZKaFZqSktWVkZZYUZkV1JWcFlWV3BHYTFkWFRrZFRiV3hvVFVoQ1dsWXhaRFJpTWtsM1RVaG9hbEpYYUhOVmJUVkRZekZhY1ZKcmRGTk5Wa3A2VjJ0U1ExWlhTbFpqUldoYVRVWndkbFpxUmtwbGJVWklZVVprYUdFeGNHOVhXSEJIWkRGS2RGSnJhR2hTYXpWdlZGVm9RMlJzV25STldHUlZUVlpXTlZadE5VOVdiVXBJVld4c1dtSllUWGhXTUZwell6RmFkRkpzVWxOaVNFSktWa1phVTFFeFduUlRhMlJxVWxad1YxWnRlRXRXTVZaSFVsUnNVVlZVTURrPQ==

对它进行十次base64解密

 

https://bbs.pediy.com/thread-254172.html

网站内容不错。。 就是没有flag

我在找off_6CC090字符串的时候 它下面有两个值我注意了一下 不过也没有放在心上

这时候回头来看 交叉引用找到所在函数

 

然后对函数名进行交叉引用发现来自.fini段

 

其解示为

此节区包含了可执行的指令,是进程终止代码的一部分。程序正常退出时,系统将安排执行这里的代码。

所以我们应该是找对了地方

开始着手分析:

 

补充两点:

1.byte_6CC0A0的长度为24

2.&v4+j = v4[j]

这里就是我前面说的 v15的值对我做这道题没有什么影响

编写脚本求解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
byte_ = [0x40,0x35,0x20,0x56,0x5D,0x18,0x22,0x45,0x17,0x2F, 
0x24,0x6E,0x62,0x3C,0x27,0x54,0x48,0x6C,0x24,0x6E,
0x72,0x3C,0x32,0x45,0x5B]
STR = 'flag'
v4 = ''
flag = ''

for i in range(4):
v4 += chr(byte_[i] ^ ord(STR[i])) #求出v4

for i in range(len(byte_)):
flag += chr(byte_[i] ^ ord(v4[i%4]))

print(flag)

运行得到结果


flag{Act1ve_Defen5e_Test}


Youngter-drive

查壳 发现upx壳 32位

用upx脱壳工具 upx -d Youngter-drive.exe 脱完放进ida32打开

shift+f12打开字符串寻找main函数 留意

 

分析:

 

进入线程StartAddress进行查看

找到关键函数sub_41112C

 

进入 分析:

 

再进入另一个线程sub_41119F分析查看

 

也就是说 线程对字符串加密时只对奇数位加密 偶数位直接赋值

另外 我们现在还没有找到输出flag的字符

继续向下分析main函数:

 

 

接下来编写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
off_418004 = 'TOiZiZtOrYaToUwPnToBsOaOapsyS'
off_418000 = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
flag = ''

for i in range(29):
if(i % 2 == 0):
flag += off_418004[i] #线程sub_41119F命令
continue
else:
if(off_418004[i].isupper()): #线程StartAddress命令
flag += chr(off_418000.index(off_418004[i]) + 96)
else:
flag += chr(off_418000.index(off_418004[i]) + 38)

print(flag)

运行得出

ThisisthreadofwindowshahaIsES

少了一位

网上的wp都没有很好的告诉最后一位怎么求 只是穷举

但有人说最后一位是什么都可以 BUU平台只认可E

不明白


flag{ThisisthreadofwindowshahaIsESE}


[2019红帽杯]Snake

第一次遇到 unity 和 .dll 文件处理

第一次使用pyhton的ctypes库

 

用dnSpy打开位于 \Snake_Data\Managed 的 Assembly-CSharp.dll 文件

unity在打包后,会将所有的代码打进一个Assembly-CSharp.dll的文件里面,通过这个文件的反编译,就是详细看见里面的代码内容。

找到这个(具体怎么找还在学ing)

 

其中对于GameObject解释:

 

 

ida64打开 Interface.dll

所在位置 \Snake_Data\Plugins

发现flag相关字符串 证明找对入口

 

接下来使用python的ctypes库进行爆破

 

脚本:

1
2
3
4
5
6
7
8
import ctypes

for i in range(100):
dll = ctypes.cdll.LoadLibrary("\\Interface.dll")
print(i)
dll.GameObject(i) #调用GameObject()函数

#要跑很久很久

flag{Ch4rp_W1th_R$@}


[羊城杯 2020]Bytecode

python的bytecode 也就是字节码

反汇编指令功能可以从下面网站查找

dis — Python 字节码反汇编器 — Python 3.7.12 文档

原题目给的txt文档:

我尽量写的详细一点

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
 4           0 LOAD_CONST               0 (3)
3 LOAD_CONST 1 (37)
6 LOAD_CONST 2 (72)
9 LOAD_CONST 3 (9)
12 LOAD_CONST 4 (6)
15 LOAD_CONST 5 (132)
18 BUILD_LIST 6
21 STORE_NAME 0 (en)
#STORE_NAME:声明变量
#BUILD_LIST:创建一个列表
#第4行代码:en = [3,37,72,9,6,132]
5 24 LOAD_CONST 6 (101)
27 LOAD_CONST 7 (96)
30 LOAD_CONST 8 (23)
33 LOAD_CONST 9 (68)
36 LOAD_CONST 10 (112)
39 LOAD_CONST 11 (42)
42 LOAD_CONST 12 (107)
45 LOAD_CONST 13 (62)
48 LOAD_CONST 7 (96)
51 LOAD_CONST 14 (53)
54 LOAD_CONST 15 (176)
57 LOAD_CONST 16 (179)
60 LOAD_CONST 17 (98)
63 LOAD_CONST 14 (53)
66 LOAD_CONST 18 (67)
69 LOAD_CONST 19 (29)
72 LOAD_CONST 20 (41)
75 LOAD_CONST 21 (120)
78 LOAD_CONST 22 (60)
81 LOAD_CONST 23 (106)
84 LOAD_CONST 24 (51)
87 LOAD_CONST 6 (101)
90 LOAD_CONST 25 (178)
93 LOAD_CONST 26 (189)
96 LOAD_CONST 6 (101)
99 LOAD_CONST 27 (48)
102 BUILD_LIST 26
105 STORE_NAME 1 (output)
#第5行代码转换同第4行
7 108 LOAD_CONST 28 ('welcome to GWHT2020')
111 PRINT_ITEM
112 PRINT_NEWLINE
#PRINT:打印
9 113 LOAD_NAME 2 (raw_input)
116 LOAD_CONST 29 ('please input your flag:')
119 CALL_FUNCTION 1
122 STORE_NAME 3 (flag)
#CALL_FUNCTION:可以理解为调用函数或者指令
#第9行代码:flag = raw_input('please input your flag:')
10 125 LOAD_NAME 3 (flag)
128 STORE_NAME 4 (str)
#赋值
#第10行代码:str = flag
12 131 LOAD_NAME 5 (len)
134 LOAD_NAME 4 (str)
137 CALL_FUNCTION 1
140 STORE_NAME 6 (a)
#CALL_FUNCTION调用了len函数
#第12行代码:a = len(str)
13 143 LOAD_NAME 6 (a)
146 LOAD_CONST 30 (38)
149 COMPARE_OP 0 (<)
152 POP_JUMP_IF_FALSE 173
#POP_JUMP_IF_FALSE:可以看成使用if语句判断 失败则跳到173位置
#第13行代码:if(a < 38):
14 155 LOAD_CONST 31 ('lenth wrong!')
158 PRINT_ITEM
159 PRINT_NEWLINE

15 160 LOAD_NAME 7 (exit)
163 LOAD_CONST 32 (0)
166 CALL_FUNCTION 1
169 POP_TOP
170 JUMP_FORWARD 0 (to 173)
#第15行代码:exit(0)
17 >> 173 LOAD_NAME 8 (ord)
176 LOAD_NAME 4 (str)
179 LOAD_CONST 32 (0)
182 BINARY_SUBSCR
#BINARY_SUBSCR:作用为使之变成str[0]
183 CALL_FUNCTION 1
186 LOAD_CONST 33 (2020)
189 BINARY_MULTIPLY
#到这里 第17行的代码为 ord(str[0])*2020
190 LOAD_NAME 8 (ord)
193 LOAD_NAME 4 (str)
196 LOAD_CONST 34 (1)
199 BINARY_SUBSCR
200 CALL_FUNCTION 1
203 BINARY_ADD
#这里是相加 在前面基础上加上 ord(str[1])
204 LOAD_CONST 33 (2020)
207 BINARY_MULTIPLY
#关键逻辑点在这里 这里的相乘是2020乘上前面的所有
#即到这里 第17行代码为 (ord(str[0]) * 2020 + ord(str[1])) * 2020
#后面逻辑与此相同
208 LOAD_NAME 8 (ord)
211 LOAD_NAME 4 (str)
214 LOAD_CONST 35 (2)
217 BINARY_SUBSCR
218 CALL_FUNCTION 1
221 BINARY_ADD
222 LOAD_CONST 33 (2020)
225 BINARY_MULTIPLY
226 LOAD_NAME 8 (ord)
229 LOAD_NAME 4 (str)
232 LOAD_CONST 0 (3)
235 BINARY_SUBSCR
236 CALL_FUNCTION 1
239 BINARY_ADD
240 LOAD_CONST 33 (2020)
243 BINARY_MULTIPLY
244 LOAD_NAME 8 (ord)
247 LOAD_NAME 4 (str)
250 LOAD_CONST 36 (4)
253 BINARY_SUBSCR
254 CALL_FUNCTION 1
257 BINARY_ADD
258 LOAD_CONST 37 (1182843538814603)
261 COMPARE_OP 2 (==)
264 POP_JUMP_IF_FALSE 275
#第17行代码:if((((ord(str[0]) * 2020 + ord(str[1])) * 2020 + ord(str[2])) * 2020 + ord(str[3])) * 2020 + ord(str[4]) == 1182843538814603):
18 267 LOAD_CONST 38 ('good!continue\xe2\x80\xa6\xe2\x80\xa6')
270 PRINT_ITEM
271 PRINT_NEWLINE
272 JUMP_FORWARD 15 (to 290)

20 >> 275 LOAD_CONST 39 ('bye~')
278 PRINT_ITEM
279 PRINT_NEWLINE

21 280 LOAD_NAME 7 (exit)
283 LOAD_CONST 32 (0)
286 CALL_FUNCTION 1
289 POP_TOP

23 >> 290 BUILD_LIST 0
293 STORE_NAME 9 (x)
#第23行代码:x = []
24 296 LOAD_CONST 40 (5)
299 STORE_NAME 10 (k)

25 302 SETUP_LOOP 128 (to 433)
305 LOAD_NAME 11 (range)
308 LOAD_CONST 41 (13)
311 CALL_FUNCTION 1
314 GET_ITER
>> 315 FOR_ITER 114 (to 432)
318 STORE_NAME 12 (i)
#从这里到433位置是for循环里面的内容
#第25行代码:for i in range(13):
26 321 LOAD_NAME 8 (ord)
324 LOAD_NAME 4 (str)
327 LOAD_NAME 10 (k)
330 BINARY_SUBSCR
331 CALL_FUNCTION 1
334 STORE_NAME 13 (b)

27 337 LOAD_NAME 8 (ord)
340 LOAD_NAME 4 (str)
343 LOAD_NAME 10 (k)
346 LOAD_CONST 34 (1)
349 BINARY_ADD
350 BINARY_SUBSCR
351 CALL_FUNCTION 1
354 STORE_NAME 14 (c)

28 357 LOAD_NAME 14 (c)
360 LOAD_NAME 0 (en)
363 LOAD_NAME 12 (i)
366 LOAD_CONST 4 (6)
369 BINARY_MODULO
370 BINARY_SUBSCR
371 BINARY_XOR
372 STORE_NAME 15 (a11)
#BINARY_MODULO:进行 % 操作
#BINARY_XOR:进行 ^ 操作
#第28行代码:a11 = c ^ en[i%6]
29 375 LOAD_NAME 13 (b)
378 LOAD_NAME 0 (en)
381 LOAD_NAME 12 (i)
384 LOAD_CONST 4 (6)
387 BINARY_MODULO
388 BINARY_SUBSCR
389 BINARY_XOR
390 STORE_NAME 16 (a22)

30 393 LOAD_NAME 9 (x)
396 LOAD_ATTR 17 (append)
399 LOAD_NAME 15 (a11)
402 CALL_FUNCTION 1
405 POP_TOP
#第30行代码:x.append(a11)
31 406 LOAD_NAME 9 (x)
409 LOAD_ATTR 17 (append)
412 LOAD_NAME 16 (a22)
415 CALL_FUNCTION 1
418 POP_TOP

32 419 LOAD_NAME 10 (k)
422 LOAD_CONST 35 (2)
425 INPLACE_ADD
426 STORE_NAME 10 (k)
429 JUMP_ABSOLUTE 315
>> 432 POP_BLOCK
#INPLACE_ADD:就地实现加法
#第32行代码:k += 2
33 >> 433 LOAD_NAME 9 (x)
436 LOAD_NAME 1 (output)
439 COMPARE_OP 2 (==)
442 POP_JUMP_IF_FALSE 453

34 445 LOAD_CONST 38 ('good!continue\xe2\x80\xa6\xe2\x80\xa6')
448 PRINT_ITEM
449 PRINT_NEWLINE
450 JUMP_FORWARD 15 (to 468)

36 >> 453 LOAD_CONST 42 ('oh,you are wrong!')
456 PRINT_ITEM
457 PRINT_NEWLINE

37 458 LOAD_NAME 7 (exit)
461 LOAD_CONST 32 (0)
464 CALL_FUNCTION 1
467 POP_TOP

39 >> 468 LOAD_NAME 5 (len)
471 LOAD_NAME 4 (str)
474 CALL_FUNCTION 1
477 STORE_NAME 18 (l)

40 480 LOAD_NAME 8 (ord)
483 LOAD_NAME 4 (str)
486 LOAD_NAME 18 (l)
489 LOAD_CONST 43 (7)
492 BINARY_SUBTRACT
493 BINARY_SUBSCR
494 CALL_FUNCTION 1
497 STORE_NAME 19 (a1)
#BINARY_SUBTRACT:进行 - 操作
#这里先进行了BINARY_SUBTRACT再进行BINARY_SUBSCR
#第40行代码:a1 = ord(str[l-7])
41 500 LOAD_NAME 8 (ord)
503 LOAD_NAME 4 (str)
506 LOAD_NAME 18 (l)
509 LOAD_CONST 4 (6)
512 BINARY_SUBTRACT
513 BINARY_SUBSCR
514 CALL_FUNCTION 1
517 STORE_NAME 20 (a2)

42 520 LOAD_NAME 8 (ord)
523 LOAD_NAME 4 (str)
526 LOAD_NAME 18 (l)
529 LOAD_CONST 40 (5)
532 BINARY_SUBTRACT
533 BINARY_SUBSCR
534 CALL_FUNCTION 1
537 STORE_NAME 21 (a3)

43 540 LOAD_NAME 8 (ord)
543 LOAD_NAME 4 (str)
546 LOAD_NAME 18 (l)
549 LOAD_CONST 36 (4)
552 BINARY_SUBTRACT
553 BINARY_SUBSCR
554 CALL_FUNCTION 1
557 STORE_NAME 22 (a4)

44 560 LOAD_NAME 8 (ord)
563 LOAD_NAME 4 (str)
566 LOAD_NAME 18 (l)
569 LOAD_CONST 0 (3)
572 BINARY_SUBTRACT
573 BINARY_SUBSCR
574 CALL_FUNCTION 1
577 STORE_NAME 23 (a5)

45 580 LOAD_NAME 8 (ord)
583 LOAD_NAME 4 (str)
586 LOAD_NAME 18 (l)
589 LOAD_CONST 35 (2)
592 BINARY_SUBTRACT
593 BINARY_SUBSCR
594 CALL_FUNCTION 1
597 STORE_NAME 24 (a6)

46 600 LOAD_NAME 19 (a1)
603 LOAD_CONST 0 (3)
606 BINARY_MULTIPLY
607 LOAD_NAME 20 (a2)
610 LOAD_CONST 35 (2)
613 BINARY_MULTIPLY
614 BINARY_ADD
615 LOAD_NAME 21 (a3)
618 LOAD_CONST 40 (5)
621 BINARY_MULTIPLY
622 BINARY_ADD
623 LOAD_CONST 44 (1003)
626 COMPARE_OP 2 (==)
629 POP_JUMP_IF_FALSE 807
#if语句 里面算法逻辑写出来如下
#第46行代码:if(a1 * 3 + a2 * 2 + a3 * 5) == 1003:
47 632 LOAD_NAME 19 (a1)
635 LOAD_CONST 36 (4)
638 BINARY_MULTIPLY
639 LOAD_NAME 20 (a2)
642 LOAD_CONST 43 (7)
645 BINARY_MULTIPLY
646 BINARY_ADD
647 LOAD_NAME 21 (a3)
650 LOAD_CONST 3 (9)
653 BINARY_MULTIPLY
654 BINARY_ADD
655 LOAD_CONST 45 (2013)
658 COMPARE_OP 2 (==)
661 POP_JUMP_IF_FALSE 807

48 664 LOAD_NAME 19 (a1)
667 LOAD_NAME 20 (a2)
670 LOAD_CONST 46 (8)
673 BINARY_MULTIPLY
674 BINARY_ADD
675 LOAD_NAME 21 (a3)
678 LOAD_CONST 35 (2)
681 BINARY_MULTIPLY
682 BINARY_ADD
683 LOAD_CONST 47 (1109)
686 COMPARE_OP 2 (==)
689 POP_JUMP_IF_FALSE 804

49 692 LOAD_NAME 22 (a4)
695 LOAD_CONST 0 (3)
698 BINARY_MULTIPLY
699 LOAD_NAME 23 (a5)
702 LOAD_CONST 35 (2)
705 BINARY_MULTIPLY
706 BINARY_ADD
707 LOAD_NAME 24 (a6)
710 LOAD_CONST 40 (5)
713 BINARY_MULTIPLY
714 BINARY_ADD
715 LOAD_CONST 48 (671)
718 COMPARE_OP 2 (==)
721 POP_JUMP_IF_FALSE 801

50 724 LOAD_NAME 22 (a4)
727 LOAD_CONST 36 (4)
730 BINARY_MULTIPLY
731 LOAD_NAME 23 (a5)
734 LOAD_CONST 43 (7)
737 BINARY_MULTIPLY
738 BINARY_ADD
739 LOAD_NAME 24 (a6)
742 LOAD_CONST 3 (9)
745 BINARY_MULTIPLY
746 BINARY_ADD
747 LOAD_CONST 49 (1252)
750 COMPARE_OP 2 (==)
753 POP_JUMP_IF_FALSE 798

51 756 LOAD_NAME 22 (a4)
759 LOAD_NAME 23 (a5)
762 LOAD_CONST 46 (8)
765 BINARY_MULTIPLY
766 BINARY_ADD
767 LOAD_NAME 24 (a6)
770 LOAD_CONST 35 (2)
773 BINARY_MULTIPLY
774 BINARY_ADD
775 LOAD_CONST 50 (644)
778 COMPARE_OP 2 (==)
781 POP_JUMP_IF_FALSE 795

52 784 LOAD_CONST 51 ('congraduation!you get the right flag!')
787 PRINT_ITEM
788 PRINT_NEWLINE
789 JUMP_ABSOLUTE 795
792 JUMP_ABSOLUTE 798
>> 795 JUMP_ABSOLUTE 801
>> 798 JUMP_ABSOLUTE 804
>> 801 JUMP_ABSOLUTE 807
>> 804 JUMP_FORWARD 0 (to 807)
>> 807 LOAD_CONST 52 (None)
810 RETURN_VALUE

之后自己把python源码写出:

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
en = [3,37,72,9,6,132]
output = [101,96,23,68,112,42,107,62,96,53,176,179,98,53,67,29,41,120,60,106,51,101,178,189,101,48]

print('welcome to GWHT2020')

flag = raw_input('please input your flag:')
str = flag

a = len(str)
if(a < 38):
print('lenth wrong!')
exit(0)

if((((ord(str[0]) * 2020 + ord(str[1])) * 2020 + ord(str[2])) * 2020 + ord(str[3])) * 2020 + ord(str[4]) == 1182843538814603):
print('good!continue\xe2\x80\xa6\xe2\x80\xa6')

else:
print('bye~')
exit(0)
x = []
k = 5
for i in range(13):
b = ord(str[k])
c = ord(str[k+1])
a11 = c ^ en[i%6]
a22 = b ^ en[i%6]
x.append(a11)
x.append(a22)
k += 2
if(output == x):
print('good!continue\xe2\x80\xa6\xe2\x80\xa6')
else:
print('oh,you are wrong!')
exit(0)

l = len(str)
a1 = ord(str[l-7])
a2 = ord(str[l-6])
a3 = ord(str[l-5])
a4 = ord(str[l-4])
a5 = ord(str[l-3])
a6 = ord(str[l-2])
if(a1 * 3 + a2 * 2 + a3 * 5) == 1003:
if(a1 * 4 + a2 * 7 + a3 * 9) == 2013:
if(a1 + a2 *8 + a3 *2) == 1109:
if(a4 * 3 + a5 * 2 + a6 * 5) == 671:
if(a4 * 4 + a5 * 7 + a6 * 9) == 1252:
if(a4 + a5 * 8 + a6 * 2) == 644:
print('congraduation!you get the right flag!')

如何边写边检验:

python的dis库

使用方法:

python3 -m dis xxxxxxx.py

 

 

这个题还没完 只是把源码解出 还没有解出flag

看到有多项式 直接z3一把梭

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

s = Solver()

a1 = Int('a1')
a2 = Int('a2')
a3 = Int('a3')
a4 = Int('a4')
a5 = Int('a5')
a6 = Int('a6')

s.add(a1 * 3 + a2 * 2 + a3 * 5 == 1003)
s.add(a1 * 4 + a2 * 7 + a3 * 9 == 2013)
s.add(a1 + a2 *8 + a3 *2 == 1109)
s.add(a4 * 3 + a5 * 2 + a6 * 5 == 671)
s.add(a4 * 4 + a5 * 7 + a6 * 9 == 1252)
s.add(a4 + a5 * 8 + a6 * 2 == 644)

if s.check() == sat: #z3标配语句 若有结果则赋值给result
result = s.model()

#print(result)
#[a5 = 55, a2 = 101, a6 = 51, a3 = 102, a4 = 102, a1 = 97]

en = [3,37,72,9,6,132]
output = [101,96,23,68,112,42,107,62,96,53,176,179,98,53,67,29,41,120,60,106,51,101,178,189,101,48]
k = 0
flag = ''
for i in range(13):
flag += chr(output[k+1] ^ en[i%6])
flag += chr(output[k] ^ en[i%6])
k += 2

print(flag + chr(97) + chr(101) + chr(102) + chr(102) + chr(55) + chr(51))

flag{cfa2b87b3f746a8f0ac5c5963faeff73}


[NPUCTF2020]BasicASM

安利

[【逆向漫谈】关于汇编 | NPUCTF2020]BasicASM_哔哩哔哩_bilibili

这个题给了两个文件

 

一个是.s文件 内容如下 x86的汇编语言

另一个是运行后的输出结果

0x66,0x2e,0x61,0x25,0x7b,0x26,0x30,0x1d,0x79,0x72,0x75,0x1d,0x6b,0x2c,0x6f,0x35,0x5f,0x3a,0x38,0x74,0x2d,0x74,0x34,0x1d,0x61,0x77,0x6d,0x7d,0x7d

我尽量多写(抄)几行注释

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
00007FF7A8AC5A50  push        rbp  
00007FF7A8AC5A52 push rdi
00007FF7A8AC5A53 sub rsp,238h
00007FF7A8AC5A5A lea rbp,[rsp+20h]
00007FF7A8AC5A5F mov rdi,rsp
00007FF7A8AC5A62 mov ecx,8Eh
00007FF7A8AC5A67 mov eax,0CCCCCCCCh
00007FF7A8AC5A6C rep stos dword ptr [rdi]
00007FF7A8AC5A6E mov rax,qword ptr [__security_cookie (07FF7A8AD3018h)]
00007FF7A8AC5A75 xor rax,rbp
00007FF7A8AC5A78 mov qword ptr [rbp+208h],rax
00007FF7A8AC5A7F lea rcx,[__06A15900_ConsoleApplication@cpp (07FF7A8AD902Ah)]
00007FF7A8AC5A86 call __CheckForDebuggerJustMyCode (07FF7A8AC1122h)
#反调试
00007FF7A8AC5A8B lea rdx,[string "flag{this_is_a_fake_flag}" (07FF7A8ACF450h)]
#取假flag地址
00007FF7A8AC5A92 lea rcx,[flag]
#flag地址
00007FF7A8AC5A96 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF7A8AC15E1h)
00007FF7A8AC5A9B nop
00007FF7A8AC5A9C mov dword ptr [p],0
00007FF7A8AC5AA3 mov dword ptr [rbp+64h],0
00007FF7A8AC5AAA jmp main+64h (07FF7A8AC5AB4h)
#main函数开始位置 跳转
00007FF7A8AC5AAC mov eax,dword ptr [rbp+64h]
00007FF7A8AC5AAF inc eax
00007FF7A8AC5AB1 mov dword ptr [rbp+64h],eax
00007FF7A8AC5AB4 movsxd rax,dword ptr [rbp+64h]
#main函数跳转到这里 取dword
00007FF7A8AC5AB8 mov qword ptr [rbp+1F8h],rax
00007FF7A8AC5ABF lea rcx,[flag]
#取flag地址
00007FF7A8AC5AC3 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::length (07FF7A8AC122Bh)
#求flag长度
00007FF7A8AC5AC8 mov rcx,qword ptr [rbp+1F8h]
#rcx = qword[rbp+1F8h]
00007FF7A8AC5ACF cmp rcx,rax
#比较长度
00007FF7A8AC5AD2 jae main+1B2h (07FF7A8AC5C02h)
#可以看作不等于跳转到false
00007FF7A8AC5AD8 mov eax,dword ptr [rbp+64h]
00007FF7A8AC5ADB and eax,1
00007FF7A8AC5ADE cmp eax,1
#cmp判断是奇数位还是偶数位
#取奇数位
00007FF7A8AC5AE1 jne main+126h (07FF7A8AC5B76h)
#非奇数位跳转
00007FF7A8AC5AE7 movsxd rax,dword ptr [rbp+64h]
00007FF7A8AC5AEB mov rdx,rax
00007FF7A8AC5AEE lea rcx,[flag]
00007FF7A8AC5AF2 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator[] (07FF7A8AC1442h)
#构建一个以rcx为起始 以rax为偏移的数组
00007FF7A8AC5AF7 movsx eax,byte ptr [rax]
00007FF7A8AC5AFA xor eax,42h
#全篇看下来只有这里一处运算
00007FF7A8AC5AFD mov dword ptr [p],eax
#异或后的字符放进p
00007FF7A8AC5B00 mov dl,30h
00007FF7A8AC5B02 lea rcx,[rbp+144h]
00007FF7A8AC5B09 call std::setfill<char> (07FF7A8AC1046h)
#输出
00007FF7A8AC5B0E mov qword ptr [rbp+1F8h],rax
00007FF7A8AC5B15 mov edx,2
00007FF7A8AC5B1A lea rcx,[rbp+168h]
00007FF7A8AC5B21 call std::setw (07FF7A8AC10D2h)
00007FF7A8AC5B26 mov qword ptr [rbp+200h],rax
00007FF7A8AC5B2D lea rdx,[std::hex (07FF7A8AC1488h)]
#输出16进制
00007FF7A8AC5B34 mov rcx,qword ptr [__imp_std::cout (07FF7A8AD71C0h)]
00007FF7A8AC5B3B call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF7A8AD7160h)]
00007FF7A8AC5B41 mov rcx,qword ptr [rbp+200h]
00007FF7A8AC5B48 mov rdx,rcx
00007FF7A8AC5B4B mov rcx,rax
00007FF7A8AC5B4E call std::operator<<<char,std::char_traits<char>,__int64> (07FF7A8AC12F8h)
#输出
00007FF7A8AC5B53 mov rcx,qword ptr [rbp+1F8h]
00007FF7A8AC5B5A mov rdx,rcx
00007FF7A8AC5B5D mov rcx,rax
00007FF7A8AC5B60 call std::operator<<<char,std::char_traits<char>,char> (07FF7A8AC11A4h)
00007FF7A8AC5B65 mov edx,dword ptr [p]
00007FF7A8AC5B68 mov rcx,rax
00007FF7A8AC5B6B call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF7A8AD7158h)]
00007FF7A8AC5B71 jmp main+1ADh (07FF7A8AC5BFDh)
00007FF7A8AC5B76 movsxd rax,dword ptr [rbp+64h]
#偶数位没有变化
00007FF7A8AC5B7A mov rdx,rax
00007FF7A8AC5B7D lea rcx,[flag]
00007FF7A8AC5B81 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator[] (07FF7A8AC1442h)
00007FF7A8AC5B86 movsx eax,byte ptr [rax]
00007FF7A8AC5B89 mov dword ptr [p],eax
00007FF7A8AC5B8C mov dl,30h
00007FF7A8AC5B8E lea rcx,[rbp+194h]
00007FF7A8AC5B95 call std::setfill<char> (07FF7A8AC1046h)
00007FF7A8AC5B9A mov qword ptr [rbp+1F8h],rax
00007FF7A8AC5BA1 mov edx,2
00007FF7A8AC5BA6 lea rcx,[rbp+1B8h]
00007FF7A8AC5BAD call std::setw (07FF7A8AC10D2h)
00007FF7A8AC5BB2 mov qword ptr [rbp+200h],rax
00007FF7A8AC5BB9 lea rdx,[std::hex (07FF7A8AC1488h)]
00007FF7A8AC5BC0 mov rcx,qword ptr [__imp_std::cout (07FF7A8AD71C0h)]
00007FF7A8AC5BC7 call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF7A8AD7160h)]
00007FF7A8AC5BCD mov rcx,qword ptr [rbp+200h]
00007FF7A8AC5BD4 mov rdx,rcx
00007FF7A8AC5BD7 mov rcx,rax
00007FF7A8AC5BDA call std::operator<<<char,std::char_traits<char>,__int64> (07FF7A8AC12F8h)
00007FF7A8AC5BDF mov rcx,qword ptr [rbp+1F8h]
00007FF7A8AC5BE6 mov rdx,rcx
00007FF7A8AC5BE9 mov rcx,rax
00007FF7A8AC5BEC call std::operator<<<char,std::char_traits<char>,char> (07FF7A8AC11A4h)
00007FF7A8AC5BF1 mov edx,dword ptr [p]
00007FF7A8AC5BF4 mov rcx,rax
00007FF7A8AC5BF7 call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF7A8AD7158h)]
00007FF7A8AC5BFD jmp main+5Ch (07FF7A8AC5AACh)
00007FF7A8AC5C02 mov dword ptr [rbp+1E4h],0
00007FF7A8AC5C0C lea rcx,[flag]
00007FF7A8AC5C10 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF7A8AC1302h)
00007FF7A8AC5C15 mov eax,dword ptr [rbp+1E4h]
00007FF7A8AC5C1B mov edi,eax
00007FF7A8AC5C1D lea rcx,[rbp-20h]
00007FF7A8AC5C21 lea rdx,[__xt_z+540h (07FF7A8ACEFE0h)]
00007FF7A8AC5C28 call _RTC_CheckStackVars (07FF7A8AC1596h)
00007FF7A8AC5C2D mov eax,edi
00007FF7A8AC5C2F mov rcx,qword ptr [rbp+208h]
00007FF7A8AC5C36 xor rcx,rbp
00007FF7A8AC5C39 call __security_check_cookie (07FF7A8AC1190h)
00007FF7A8AC5C3E lea rsp,[rbp+218h]
00007FF7A8AC5C45 pop rdi
00007FF7A8AC5C46 pop rbp
00007FF7A8AC5C47 ret

所以加密方法很简单

奇数位异或0x42 偶数位直接输出

另一种:

根据上面看到只有一处进行异或的运算

所以exp可以这么来写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
res = [0x66,0x2e,0x61,0x25,0x7b,0x26,0x30,0x1d,0x79,0x72,0x75,0x1d,0x6b,0x2c,
0x6f,0x35,0x5f,0x3a,0x38,0x74,0x2d,0x74,0x34,0x1d,0x61,0x77,0x6d,0x7d,0x7d]

#for i in range(len(res)):
#print(chr(res[i]), end='')

#输出结果 f.a%{&0yruk,o5_:8t-t4awm}}
#从前5位来看 一般答案为flag{ result.txt中给出的结果为f.a%{
#所以有可能只有奇数位发生了异或

for i in range(1,len(res),2):
res[i] ^= 0x42

for i in range(len(res)):
print(chr(res[i]), end='')

flag{d0_y0u_know_x86-64_a5m?}


[De1CTF2019]Re_Sign

脱壳:

查壳发现有upx壳

试了一下upx -d re_sign.exe 发现报错

 

正好自己也没有手动脱过upx壳 试一下

upx壳一般适用ESP脱壳大法

ESP 定律法 - CTF Wiki (ctf-wiki.org)

od32打开 发现程序没有自动断在pushad上下

(关于 pushad 和 popad 的详细解释可以点上面的wiki链接)

 

F9运行一下 找到了pushad

 

F8步过 留意ESP的值 发现变红

 

 

在ESP上设置硬件断点

 

F9跳到硬件断点位置 发现popad

 

断点下面有两个跳转 一个短的跳转和一个长的跳转

而我们所需要找的程序入口一般为 长跳转所指地址

 

 

所以程序的真正入口点在0x405012处

将程序dump出来 修改入口点

 

如果:

之后程序打不开 这时候要再修复程序的输入表

工具 ImportREC

打开进程 修改OEP

此时修改OEP所填是偏移地址

 

之后点击IAT自动搜索 获取导入表 然后查找无效dll

 

找到无效dll 右键剪切

 

之后修正转储 选择之前dump出来的文件

生成新的dump_.exe 文件 这就是我们所需要的了

 

分析:

下面开始分析脱壳后的程序:

ida打开 查找字符串 交叉引用找到加密部分:

图中部分代码依据个人习惯改了函数名

 

无奈只好动调 一步一步来 对比着ida反编译代码和汇编地址 用od一步步动调

od打开原exe文件 因为dump出来的和修复完之后的不能进行动调

od之前已经找到了esp

所以这里f9运行到 popad 后面的 cmp 指令

 

然后跳转到esp 也就是0x405012地址处

ida中起始地址为0x401000 所以在od中找到相同位置 f4运行到此处

 

 

首先来看第一个函数 od f8单步步过

 

 

运行到此处程序暂停 也就是说 sub_402BA0 也就是改名后 inputt 函数是一个检测输入的函数

我们随意输入一串字符 这里我输入

123456789abcedfg

接着我们运行到那个换表base64函数 即 sub_401233

(字符串查找时发现了base64原表 ctrl+x 交叉引用找到了改名后为 nonbase64 的函数)

 

运行过此函数之后发现我们的输入变成了

EP8hR3AlRhVcGD9MHDIeHd==

如果是正常的base64加密 那我们输入的字符串会变成

MTIzNDU2Nzg5YWJjZWRmZw==

所以可以确定里面是换表的base64加密

接下来就还有两大步

1.找base64换表之后的表

2.找check时候的判断是否相等的字符串

所以我们od重新载入 按照之前的方法来到 sub_401233函数 f7 步进

运行到大概这个位置前后 找到 ptr ss:[ebp-44]

(我也不会找位置)

 

找到变换后的表

 

0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm+/

之后进行第二步

老方法 在ida中找到改名后为 check 的函数 找到起始地址和终止地址

od重新载入

 

 

找到 0x401F0A 位置 f7步入函数

(猜测:check大多会在函数结束时候发生 也就是在终止地址前面不是很远)

其中这里面需要注意

我们运行到这里的时候 0x401FFC 是一个大跳转 如果直接运行下去 程序会自动退出

 

所以我们在它下面的位置设置新的运行点

一路f8 并且注意 cmp 指令 查看它的上一条 pop eax/ebx 或者是 push eax/ebx

 

 

 

上面就是我们需要进行对比的数据

0x08,0x3b,0x01,0x20,0x07,0x34,0x09,0x1f,0x18,0x24,0x13,0x03,0x10,0x38,0x09,0x1b,0x08,0x34,0x13,0x02,0x08,0x22,0x12,0x03,0x05,0x06,0x12,0x03,0x0f,0x22,0x12,0x17,0x08,0x01,0x29,0x22,0x06,0x24,0x32,0x24,0x0f,0x1f,0x2b,0x24,0x03,0x15,0x41,0x41

上面的数据最大是0x41 也就是65 最小是1

所以这里可以猜一下 动调出来的数据可能是对base64的原始表的排序

排序完的字符串再进行换表base64解密

先写exp试一下 (两个exp可以融合成一个的)

1
2
3
4
5
6
7
8
9
10
11
12
unk = [0x08,0x3b,0x01,0x20,0x07,0x34,0x09,0x1f,0x18,0x24,0x13,0x03,
0x10,0x38,0x09,0x1b,0x08,0x34,0x13,0x02,0x08,0x22,0x12,0x03,
0x05,0x06,0x12,0x03,0x0f,0x22,0x12,0x17,0x08,0x01,0x29,0x22,
0x06,0x24,0x32,0x24,0x0f,0x1f,0x2b,0x24,0x03,0x15,0x41,0x41] #这个是顺序表

flag = ''
base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='

for i in unk:
flag += base[i-1]

print(flag)

输出:H6AfGzIeXjSCP3IaHzSBHhRCEFRCOhRWHAohFjxjOeqjCU==

1
2
3
4
5
6
7
8
9
10
import base64
import string

table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" #base64初始加密表

model = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm+/" #魔改之后的表

flag = "H6AfGzIeXjSCP3IaHzSBHhRCEFRCOhRWHAohFjxjOeqjCU==" #密文 要解密的字符串

print(base64.b64decode(flag.translate(str.maketrans(model,table)))) #maketrans作用 将model中要替换的字符转换为table对应的字符(同一位置)

输出结果正是flag

猜想成立


flag{E_L4nguag3_1s_K3KeK3_N4Ji4}