历年真题刷题小记

是收录在攻防世界真题区的刷题记录,在网上找到的wp大多是各战队比赛时的简单思路,没有很具体的做法,所以想着写个刷题小记当伪wp,顺便也想趁机给自己总结和记录一下。

题目指路:https://adworld.xctf.org.cn/competition

刷题范围:2019年以来的比赛中>=20解的逆向题,循序渐进吧。

P.S. 起步tcl,会有参考其他wp的思路,什么时候没有参考wp了就说明我终于能单刷了(yep!

[2019 *CTF] fanoGo

题目描述

Do you kown go & fano encode?

1
$ nc 34.92.37.22 10001

wp

相关工具/插件:[IDA] IDAGolangHelper

用了插件以后,主函数一般是main_main,所以找到主函数。

然后看到一行fano___Fano__Decode()

于是猜测是让我们输入数据,经过fanoDecode解码后等于该字符串(就是说输入数据=该字符串的fano编码)。

(我摊牌,Go实在看不懂,这里参考wp的思路了。不过如果实在做不出来我可能也会这么猜(?

然后在函数栏搜索能看到,打包的时候把fanoEncode函数也装进来了,所以想到patch call直接复用。

然后patch。

这里整理一下x86的call机器码格式(x64向下兼容:

  • E8 xxxxxxxx

    xxxxxxxx是偏移地址

    偏移地址=目标地址-当前地址-5(取完当前指令之后,pc先自增,程序再跳转;E8 xxxxxxxx有5字节

  • FF 15 [xxxxxxxx]

    xxxxxxxx是绝对地址,FF15会对当前的这个绝对地址解*号,也就是绝对地址[目标地址]

原来的:

先找到fanoEncode的地址:

可以看到fanoEncode的地址为0x45C970。

然后计算偏移地址:

patch(别忘了小端序):

patch完以后愉快地开始动态调试,配置完Debugger以后,为了看加密结果在fanoEncode函数的这里下断点。

然后动态调试

断点处打开Locals窗口(Debugger->Debugger windows->Locals)查看编码结果:

v3这里是结果的地址,我们复制下来并在IDA view里按G跳转

把这个数组dump下来就是要输入的数据。

最后的exp:

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
# ------ Python2 ------
from pwn import *

# context.log_level='debug'
r=process("./fanoGo_ori")

arr=[0x2B, 0x60, 0xC3, 0xBE, 0xC2, 0xB7, 0xC2, 0x82, 0xC2, 0x89, 0xC3, 0x95, 0x5B, 0xC2, 0x87, 0x2A, 0x69, 0x13, 0xC2, 0x96, 0x51, 0xC3, 0xBD, 0x6F, 0x32, 0x28, 0x5A, 0xC3, 0x92, 0x74, 0xC2, 0x94, 0xC2, 0x94, 0xC2, 0x95, 0xC2, 0x96, 0xC2, 0xA4, 0xC3, 0x8A, 0xC2, 0xA3, 0xC3, 0x8E, 0xC2, 0xB3, 0x24, 0x24, 0x24, 0xC2, 0xBA, 0xC2, 0xAE, 0x46, 0x2B, 0xC2, 0xAC, 0x3C, 0xC3, 0xAB, 0x32, 0x23, 0x2A, 0xC3, 0xB0, 0xC3, 0xB3, 0xC2, 0xAC, 0xC3, 0x85, 0xC2, 0x87, 0x2C, 0xC2, 0xA3, 0x6B, 0xC2, 0xAD, 0x0F, 0xC3, 0x87, 0x5C, 0xC2, 0xA8, 0xC3, 0xB3, 0xC2, 0xAF, 0xC3, 0xA1, 0xC3, 0xB9, 0x12, 0xC3, 0x8A, 0x44, 0x72, 0xC2, 0xA6, 0xC2, 0x91, 0x66, 0x6D, 0x31, 0xC3, 0xA7, 0x51, 0x64, 0x67, 0x78, 0x75, 0x6B, 0xC2, 0x96, 0xC2, 0x91, 0x51, 0xC3, 0xA7, 0x3E, 0x13, 0xC3, 0x8E, 0x57, 0x7B, 0x47, 0xC2, 0x9D, 0x45, 0x7F, 0x29, 0x11, 0xC3, 0x95, 0xC3, 0xA1, 0xC3, 0xA7, 0x59, 0xC2, 0x8A, 0x06, 0xC2, 0x8C, 0xC2, 0x91, 0xC2, 0xB5, 0x0F, 0x3A, 0xC2, 0x8E, 0xC2, 0xBA, 0xC3, 0x8B, 0xC3, 0xAA, 0xC3, 0xA8, 0xC3, 0xBC, 0xC2, 0x8E, 0x71, 0xC3, 0xBD, 0x6F, 0x32, 0x36, 0xC3, 0xB9, 0x42, 0xC3, 0xA7, 0x49, 0xC3, 0x92, 0x22, 0x79, 0xC3, 0x89, 0xC3, 0x93, 0x54, 0x79, 0xC3, 0x96, 0x63, 0x6A, 0x1F, 0xC3, 0x96, 0xC3, 0xB3, 0x23, 0x6F, 0xC2, 0x94, 0x37, 0xC2, 0x94, 0xC3, 0xA8, 0x76, 0xC3, 0x83, 0xC3, 0x8E, 0x7C, 0x3F, 0xC2, 0xAD, 0xC3, 0xA0, 0xC2, 0x9F, 0x0C, 0xC2, 0xAA, 0x7B, 0xC3, 0x83, 0x26, 0xC2, 0xAD, 0xC3, 0xB0, 0x7E, 0x3A, 0xC3, 0xA5, 0x47, 0xC2, 0x9D, 0x7F, 0x09, 0xC3, 0xA5, 0x49, 0x44, 0xC2, 0xB0, 0xC2, 0xAF, 0x0F, 0x3A, 0xC3, 0x8C, 0x50, 0x51, 0xC3, 0xBD, 0x6F, 0x32, 0x2C, 0xC3, 0x8C, 0x2D, 0x27, 0x49, 0xC3, 0xA3, 0x2A, 0xC3, 0xB0, 0xC3, 0xB3, 0xC2, 0xAC, 0xC3, 0x88, 0xC2, 0x89, 0xC3, 0xB0, 0xC2, 0x9D, 0x7E, 0x1C, 0xC2, 0x9F, 0x29, 0x11, 0x41, 0x47, 0xC3, 0xB5, 0xC2, 0xBC, 0xC3, 0x88, 0xC2, 0x9A, 0x38, 0xC3, 0xB0, 0xC3, 0xA2, 0xC2, 0xB8, 0xC3, 0xA9, 0x15, 0xC3, 0x92, 0x50, 0x40]
payload=bytearray(arr[:0x136]) #看fano_Str2Bytes可以发现结果的长度为0x136
r.sendafter(':',payload)

r.interactive()

flag

因为要nc没拿到flag(

本地打通就好


[2020 GACTF] EasyRe

  • 2020 GACTF / Reverse / 38 solved
  • Completed:2021.01.02
  • 参考wp:
    • 无(ohhhh!

题目描述

Layers of protection~

Overseas:https://drive.google.com/file/d/1TobAUm_innt7RoQ7ZI4q1CNUWKuH-Tsw/view?usp=sharing

wp

用ida打开发现main看起来没什么特别的,就是输入一个lld。

不过一个一个函数往下翻可以看到sub_8049065()这个,调用了一个mprotect函数(警觉

mprotect的作用一般是改某段内存的读/写/执行权限,并且下面sub_8048EA5()还用了一个函数(就是主函数中即将调用的函数)作为参数,这就要立刻想到smc了,sub_8048EA5()就是加密函数。

这边一看就感觉很复杂的样子,那就懒得逆了,直接动态调试看看过完加密以后sub_8048838()是什么样子。在这个函数下个断点,执行到的时候直接步入。

可以看到这边比较散乱,因为数据全部被处理过了,要看到反汇编和反编译代码就要首先把它们undefined,然后重新分析。

这个函数的起始地址是0x8048838,结束地址是0x8048DE1,算一下长度是0x8048DE1-0x8048838+1=1450。

然后用ida_bytes的del_items函数(7.4的api开始不再兼容6.x的api了,在7.4以前还能用idc.MakeUnkn,见Porting from IDAPython 6.x-7.3, to 7.4)或者选这个区域直接右键->Undefined把这部分undefined掉,再在0x8048838出按p创建函数。

可以看到这其实是个vm题,smc+vm真不愧是Layers of protection呢hhh。vm代码如下:

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
unsigned int __cdecl sub_8048838(_DWORD *a1)
{
_BYTE *v2; // [esp+18h] [ebp-20h]
unsigned int v3; // [esp+2Ch] [ebp-Ch]

v3 = __readgsdword(0x14u);
while ( 1 )
{
if ( *(_BYTE *)a1[8] == 113 )
{
a1[6] -= 4;
*(_DWORD *)a1[6] = *(_DWORD *)(a1[8] + 1);
a1[8] += 5;
}
if ( *(_BYTE *)a1[8] == 65 )
{
a1[1] += a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 66 )
{
a1[1] -= a1[4];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 67 )
{
a1[1] *= a1[3];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 68 )
{
a1[1] /= a1[5];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0x80 )
{
a1[sub_80487EF(a1, 1)] = *(_DWORD *)(a1[8] + 2);
a1[8] += 6;
}
if ( *(_BYTE *)a1[8] == 119 )
{
a1[1] ^= a1[9];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 83 )
{
putchar(*(char *)a1[3]);
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 34 )
{
a1[1] >>= a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 35 )
{
a1[1] <<= a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0x99 )
break;
if ( *(_BYTE *)a1[8] == 118 )
{
a1[3] = *(_DWORD *)a1[6];
*(_DWORD *)a1[6] = 0;
a1[6] += 4;
a1[8] += 5;
}
if ( *(_BYTE *)a1[8] == 84 )
{
v2 = (_BYTE *)a1[3];
*v2 = getchar();
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 48 )
{
a1[1] |= a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 49 )
{
a1[1] &= a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 9 )
{
a1[1] = dword_804B28C;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 16 )
{
a1[9] = a1[1];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 17 )
{
printf("%p\n", (const void *)a1[1]);
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0xA0 )
{
if ( a1[1] != 653840640 )
exit(0);
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0xA1 )
{
printf("flag:");
read(0, byte_804B2E0, 0x28u);
if ( strlen(byte_804B2E0) != 33 )
exit(0);
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0xB1 )
{
a1[9] = dword_804B2A0[0];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0xB2 )
{
a1[9] = dword_804B2A4;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0xA4 )
{
dword_804B2A0[*(unsigned __int8 *)(a1[8] + 1)] = a1[1];
a1[8] += 4;
}
if ( *(_BYTE *)a1[8] == 0xB3 )
{
a1[9] = dword_804B2A8;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0xB4 )
{
a1[9] = dword_804B2AC;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0xC1 )
{
a1[1] = (unsigned __int8)byte_804B2E0[*(unsigned __int8 *)(a1[8] + 1)];
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 0xC2 )
{
if ( a1[1] != *(_DWORD *)(a1[8] + 1) )
exit(0);
a1[8] += 5;
}
}
return __readgsdword(0x14u) ^ v3;
}

仔细研究可以知道,a1这个数组里,a1[1]~a1[4]和a1[9]是一组寄存器,a1[8]指向的地方实际上是opcode(a1[8]其实就是PC),dword_804B28C则是刚刚输入的数据(myInput),byte_804B2E0就是输入的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
//arr->4bytes
0x09 //r1=myInput
0x10 //r9=r1
0x22 //r1>>=r2
0x23 //r1<<=r2
0x30 //r1|=r2
0x31 //r1&=r2
0x41 //r1+=r2
0x42 //r1-=r4
0x43 //r1*=r3
0x44 //r1/=r5
0x71 aa bb cc dd //push ddccbbaa
0x76 ?? ?? ?? ?? //pop r3
0x77 //r1^=r9
0x80 rx aa bb cc dd //rx=ddbbccaa
0x99 //exit
0xA0 //check1(r1==653840640)
0xA1 //check2(input flag;strlen(flag)==33)
0xA4 aa bb cc //arr[ccbbaa]=r1
0xB1 //r9=arr[0]
0xB2 //r9=arr[1]
0xB3 //r9=arr[2]
0xB4 //r9=arr[3]
0xC1 aa //r1=flag[aa]
0xC2 aa bb cc dd //check3(r1==ddbbccaa)

/* 这三个有可能是提供给我们hook用的,但是懒得想了= =总之原opcode全程没用到
if ( *(_BYTE *)a1[8] == 0x53 ){
putchar(*(char *)a1[3]);
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 0x54 ){
v2 = (_BYTE *)a1[3];
*v2 = getchar();
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 0x11 ){
printf("%p\n", (const void *)a1[1]);
++a1[8];
}
*/

然后去a1[8]的地方拿到opcode,反汇编。

把opcode即unk_804B080处的数据dump下来,convert成python样式的byte数组,写反汇编脚本:

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
opcode=[0x09, 0x10, 0x80, 0x02, 0x0D, 0x00, 0x00, 0x00, 0x22, 0x77, 0x10, 0x80, 0x02, 0x09, 0x00, 0x00, 0x00, 0x23, 0x80, 0x02, 0x00, 0x96, 0xF3, 0x78, 0x31, 0x77, 0x10, 0x80, 0x02, 0x11, 0x00, 0x00, 0x00, 0x23, 0x80, 0x02, 0x00, 0x00, 0xD4, 0x85, 0x31, 0x77, 0x10, 0x80, 0x02, 0x13, 0x00, 0x00, 0x00, 0x22, 0x77, 0xA0, 0x09, 0x80, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x31, 0x80, 0x03, 0x02, 0x00, 0x00, 0x00, 0x43, 0x80, 0x02, 0x18, 0x00, 0x00, 0x00, 0x41, 0xA4, 0x00, 0x00, 0x00, 0x09, 0x80, 0x02, 0x08, 0x00, 0x00, 0x00, 0x22, 0x80, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x31, 0x80, 0x05, 0x07, 0x00, 0x00, 0x00, 0x44, 0x80, 0x02, 0x21, 0x00, 0x00, 0x00, 0x41, 0xA4, 0x01, 0x00, 0x00, 0x09, 0x80, 0x02, 0x10, 0x00, 0x00, 0x00, 0x22, 0x80, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x31, 0x80, 0x09, 0xBB, 0x00, 0x00, 0x00, 0x77, 0x80, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x41, 0xA4, 0x02, 0x00, 0x00, 0x09, 0x80, 0x02, 0x18, 0x00, 0x00, 0x00, 0x22, 0x80, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x31, 0x80, 0x04, 0xA0, 0x00, 0x00, 0x00, 0x42, 0x80, 0x02, 0x77, 0x00, 0x00, 0x00, 0x41, 0xA4, 0x03, 0x00, 0x00, 0xA1, 0xC1, 0x00, 0xB1, 0x77, 0xC2, 0x0B, 0x01, 0x00, 0x00, 0xC1, 0x01, 0xB2, 0x77, 0xC2, 0x7A, 0x00, 0x00, 0x00, 0xC1, 0x02, 0xB4, 0x77, 0xC2, 0x95, 0x00, 0x00, 0x00, 0xC1, 0x03, 0xB3, 0x77, 0xC2, 0x06, 0x01, 0x00, 0x00, 0xC1, 0x04, 0xB2, 0x77, 0xC2, 0x7D, 0x00, 0x00, 0x00, 0xC1, 0x05, 0xB4, 0x77, 0xC2, 0xAD, 0x00, 0x00, 0x00, 0xC1, 0x06, 0xB1, 0x77, 0xC2, 0x2F, 0x01, 0x00, 0x00, 0xC1, 0x07, 0xB3, 0x77, 0xC2, 0x65, 0x01, 0x00, 0x00, 0xC1, 0x08, 0xB1, 0x77, 0xC2, 0x2D, 0x01, 0x00, 0x00, 0xC1, 0x09, 0xB1, 0x77, 0xC2, 0x2F, 0x01, 0x00, 0x00, 0xC1, 0x0A, 0xB3, 0x77, 0xC2, 0x39, 0x01, 0x00, 0x00, 0xC1, 0x0B, 0xB3, 0x77, 0xC2, 0x0D, 0x01, 0x00, 0x00, 0xC1, 0x0C, 0xB4, 0x77, 0xC2, 0xBB, 0x00, 0x00, 0x00, 0xC1, 0x0D, 0xB2, 0x77, 0xC2, 0x08, 0x00, 0x00, 0x00, 0xC1, 0x0E, 0xB3, 0x77, 0xC2, 0x0D, 0x01, 0x00, 0x00, 0xC1, 0x0F, 0xB1, 0x77, 0xC2, 0x3F, 0x01, 0x00, 0x00, 0xC1, 0x10, 0xB3, 0x77, 0xC2, 0x3A, 0x01, 0x00, 0x00, 0xC1, 0x11, 0xB3, 0x77, 0xC2, 0x61, 0x01, 0x00, 0x00, 0xC1, 0x12, 0xB2, 0x77, 0xC2, 0x57, 0x00, 0x00, 0x00, 0xC1, 0x13, 0xB1, 0x77, 0xC2, 0x20, 0x01, 0x00, 0x00, 0xC1, 0x14, 0xB3, 0x77, 0xC2, 0x0D, 0x01, 0x00, 0x00, 0xC1, 0x15, 0xB1, 0x77, 0xC2, 0x3F, 0x01, 0x00, 0x00, 0xC1, 0x16, 0xB3, 0x77, 0xC2, 0x3F, 0x01, 0x00, 0x00, 0xC1, 0x17, 0xB4, 0x77, 0xC2, 0xB5, 0x00, 0x00, 0x00, 0xC1, 0x18, 0xB1, 0x77, 0xC2, 0x13, 0x01, 0x00, 0x00, 0xC1, 0x19, 0xB4, 0x77, 0xC2, 0xA0, 0x00, 0x00, 0x00, 0xC1, 0x1A, 0xB1, 0x77, 0xC2, 0x21, 0x01, 0x00, 0x00, 0xC1, 0x1B, 0xB3, 0x77, 0xC2, 0x0D, 0x01, 0x00, 0x00, 0xC1, 0x1C, 0xB2, 0x77, 0xC2, 0x0B, 0x00, 0x00, 0x00, 0xC1, 0x1D, 0xB3, 0x77, 0xC2, 0x39, 0x01, 0x00, 0x00, 0xC1, 0x1E, 0xB1, 0x77, 0xC2, 0x73, 0x01, 0x00, 0x00, 0xC1, 0x1F, 0xB2, 0x77, 0xC2, 0x46, 0x00, 0x00, 0x00, 0x99]
i=0
while True:
if opcode[i]==0x09:
print("r1=myInput")
i+=1
elif opcode[i]==0x10:
print("r9=r1")
i+=1
elif opcode[i]==0x22:
print("r1>>=r2")
i+=1
elif opcode[i]==0x23:
print("r1<<=r2")
i+=1
elif opcode[i]==0x30:
print("r1|=r2")
i+=1
elif opcode[i]==0x31:
print("r1&=r2")
i+=1
elif opcode[i]==0x41:
print("r1+=r2")
i+=1
elif opcode[i]==0x42:
print("r1-=r4")
i+=1
elif opcode[i]==0x43:
print("r1*=r3")
i+=1
elif opcode[i]==0x44:
print("r1/=r5")
i+=1
elif opcode[i]==0x71:
idata=(opcode[i+4]<<24)+(opcode[i+3]<<16)+(opcode[i+2]<<8)+(opcode[i+1])
print("push 0x%x"%idata)
i+=5
elif opcode[i]==0x76:
idata=(opcode[i+4]<<24)+(opcode[i+3]<<16)+(opcode[i+2]<<8)+(opcode[i+1])
print("pop r3 (unknown 0x%x)"%idata)
i+=5
elif opcode[i]==0x77:
print("r1^=r9")
i+=1
elif opcode[i]==0x80:
idata=(opcode[i+5]<<24)+(opcode[i+4]<<16)+(opcode[i+3]<<8)+(opcode[i+2])
print("r%d=0x%x"%(opcode[i+1],idata))
i+=6
elif opcode[i]==0x99:
print("exit")
break
elif opcode[i]==0xA0:
print("check1(r1==653840640)")
i+=1
elif opcode[i]==0xA1:
print("check2(input flag;strlen(flag)==33)")
i+=1
elif opcode[i]==0xA4:
reg=(opcode[i+3]<<16)+(opcode[i+2]<<8)+(opcode[i+1])
print("arr[%d]=r1"%reg)
i+=4
elif opcode[i]==0xB1:
print("r9=arr[0]")
i+=1
elif opcode[i]==0xB2:
print("r9=arr[1]")
i+=1
elif opcode[i]==0xB3:
print("r9=arr[2]")
i+=1
elif opcode[i]==0xB4:
print("r9=arr[3]")
i+=1
elif opcode[i]==0xC1:
print("r1=flag[%d]"%opcode[i+1])
i+=2
elif opcode[i]==0xC2:
idata=(opcode[i+4]<<24)+(opcode[i+3]<<16)+(opcode[i+2]<<8)+(opcode[i+1])
print("check3(r1==0x%x)"%idata)
i+=5
elif opcode[i]==0x53:
print("[Unkn] 0x53: %x"%opcode[i+1])
i+=2
elif opcode[i]==0x54:
print("[Unkn] 0x54: %x"%opcode[i+1])
i+=2
elif opcode[i]==0x11:
print("[Unkn] 0x11")
i+=1
else:
print("[!]unknown opcode %d"%opcode[i])
break

得到:

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
r1=myInput
r9=r1
r2=0xd
r1>>=r2
r1^=r9
r9=r1
r2=0x9
r1<<=r2
r2=0x78f39600
r1&=r2
r1^=r9
r9=r1
r2=0x11
r1<<=r2
r2=0x85d40000
r1&=r2
r1^=r9
r9=r1
r2=0x13
r1>>=r2
r1^=r9
check1(r1==653840640)
# 可以看到check1只调用了一次,并且这里是用来check最开始输入的数字的,因此以这里为界把分析分成了两部分,以下则是check再次输入的flag部分

r1=myInput
r2=0xff
r1&=r2
r3=0x2
r1*=r3
r2=0x18
r1+=r2
arr[0]=r1
r1=myInput
r2=0x8
r1>>=r2
r2=0xff
r1&=r2
r5=0x7
r1/=r5
r2=0x21
r1+=r2
arr[1]=r1
r1=myInput
r2=0x10
r1>>=r2
r2=0xff
r1&=r2
r9=0xbb
r1^=r9
r2=0xff
r1+=r2
arr[2]=r1
r1=myInput
r2=0x18
r1>>=r2
r2=0xff
r1&=r2
r4=0xa0
r1-=r4
r2=0x77
r1+=r2
arr[3]=r1
check2(input flag;strlen(flag)==33)
r1=flag[0]
r9=arr[0]
r1^=r9
check3(r1==0x10b)
r1=flag[1]
r9=arr[1]
r1^=r9
check3(r1==0x7a)
r1=flag[2]
r9=arr[3]
r1^=r9
check3(r1==0x95)
r1=flag[3]
r9=arr[2]
r1^=r9
check3(r1==0x106)
r1=flag[4]
r9=arr[1]
r1^=r9
check3(r1==0x7d)
r1=flag[5]
r9=arr[3]
r1^=r9
check3(r1==0xad)
r1=flag[6]
r9=arr[0]
r1^=r9
check3(r1==0x12f)
r1=flag[7]
r9=arr[2]
r1^=r9
check3(r1==0x165)
r1=flag[8]
r9=arr[0]
r1^=r9
check3(r1==0x12d)
r1=flag[9]
r9=arr[0]
r1^=r9
check3(r1==0x12f)
r1=flag[10]
r9=arr[2]
r1^=r9
check3(r1==0x139)
r1=flag[11]
r9=arr[2]
r1^=r9
check3(r1==0x10d)
r1=flag[12]
r9=arr[3]
r1^=r9
check3(r1==0xbb)
r1=flag[13]
r9=arr[1]
r1^=r9
check3(r1==0x8)
r1=flag[14]
r9=arr[2]
r1^=r9
check3(r1==0x10d)
r1=flag[15]
r9=arr[0]
r1^=r9
check3(r1==0x13f)
r1=flag[16]
r9=arr[2]
r1^=r9
check3(r1==0x13a)
r1=flag[17]
r9=arr[2]
r1^=r9
check3(r1==0x161)
r1=flag[18]
r9=arr[1]
r1^=r9
check3(r1==0x57)
r1=flag[19]
r9=arr[0]
r1^=r9
check3(r1==0x120)
r1=flag[20]
r9=arr[2]
r1^=r9
check3(r1==0x10d)
r1=flag[21]
r9=arr[0]
r1^=r9
check3(r1==0x13f)
r1=flag[22]
r9=arr[2]
r1^=r9
check3(r1==0x13f)
r1=flag[23]
r9=arr[3]
r1^=r9
check3(r1==0xb5)
r1=flag[24]
r9=arr[0]
r1^=r9
check3(r1==0x113)
r1=flag[25]
r9=arr[3]
r1^=r9
check3(r1==0xa0)
r1=flag[26]
r9=arr[0]
r1^=r9
check3(r1==0x121)
r1=flag[27]
r9=arr[2]
r1^=r9
check3(r1==0x10d)
r1=flag[28]
r9=arr[1]
r1^=r9
check3(r1==0xb)
r1=flag[29]
r9=arr[2]
r1^=r9
check3(r1==0x139)
r1=flag[30]
r9=arr[0]
r1^=r9
check3(r1==0x173)
r1=flag[31]
r9=arr[1]
r1^=r9
check3(r1==0x46)
exit

根据上半部分的分析写出爆破脚本把这个数字爆破出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <cmath>
using namespace std;
int main(){
for(unsigned long long i=0;i<pow(2,128);i++){
unsigned long long x=i;
if(((((((((((x>>0xd)^x)<<0x9)&0x78f39600)^(x>>0xd)^x)<<0x11)&0x85d40000)^((((x>>0xd)^x)<<0x9)&0x78f39600)^(x>>0xd)^x)>>0x13)^((((((((x>>0xd)^x)<<0x9)&0x78f39600)^(x>>0xd)^x)<<0x11)&0x85d40000)^((((x>>0xd)^x)<<0x9)&0x78f39600)^(x>>0xd)^x))==653840640){
cout<<i<<endl;
break;
}
}
}
// 其实有很多地方不必加括号的,这里为了保险就全加了
// output:4293442714

可以爆出这个数是4293442714,输入,发现果然出现了输入flag的提示:

接下来是flag的部分,逻辑很清楚啦,就是用这个数字生成一个arr数组,然后用flag[i] xor arr中的某一个等于已知值,基操xor不用多说。

这里为了更快处理就直接把check2下边的部分复制到code.txt中了,直接进行自动化计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# x=4293442714
# arr=[0,0,0,0]
# arr[0]=(x&0xff)*2+0x18
# arr[1]=((x>>0x8)&0xff)//0x7+0x21
# arr[2]=(((x>>0x10)&0xff)^0xbb)+0xff
# arr[3]=(((x>>0x18)&0xff)-0xa0)+0x77
# print(arr)
arr=[332,59,338,214]
with open("code.txt","r") as f:
for i in range(32*4):
line=f.readline().replace("\n","")
if i%4==1:
s=line[3:]+"^"
if i%4==3:
s+=line[11:-1]
print(chr(eval(s)),end='')

flag就出来啦~

flag

GACTF{c7ack_m3_sh3ll_smc_vm_0k?}


TBC…

文章作者: c10udlnk
文章链接: https://c10udlnk.top/2020/12/09/logFor-RealProbs-in-adworld-XCTF/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 c10udlnk_Log