高校战疫-两道re-wp

这两天攻防世界有个比赛,上面的题目还不错,参与了一下,至于为什么是两道re,因为正好赶上数模美赛,没怎么有时间做(实际上就是因为菜

cyclegraph

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
void FUN_00401080(void)

{
char cVar1;
char *pcVar2;
undefined4 *puVar3;
undefined1 unaff_DI;
int iVar4;
char local_20 [4];
char local_1c;
char acStack27 [16];
char local_b;
uint local_8;

local_8 = DAT_00403004 ^ (uint)&stack0xfffffffc;
DAT_00403370 = 0;
puVar3 = &DAT_00403384;
DAT_00403374 = '0';
DAT_00403378 = &DAT_00403380;
iVar4 = 0;
do {
puVar3[-1] = *(undefined4 *)((int)null_ARRAY_00402178 + iVar4);
*(undefined4 **)puVar3 = &DAT_00403380 + *(int *)((int)null_ARRAY_00402278 + iVar4) * 3;
*(undefined4 **)(puVar3 + 1) = &DAT_00403380 + *(int *)((int)null_ARRAY_004021f8 + iVar4) * 3;
puVar3 = puVar3 + 3;
iVar4 = iVar4 + 4;
} while ((int)puVar3 < 0x403504);
print("You need a flag to get out of this:\n",unaff_DI);
scan(&DAT_0040214c,0xe0);
iVar4 = 5;
do {
cVar1 = local_20[iVar4];
if (*DAT_00403378 + (int)DAT_00403374 == (int)cVar1) {
DAT_00403378 = (int *)DAT_00403378[1];
}
else {
if ((int)DAT_00403374 - *DAT_00403378 != (int)cVar1) {
print("This is not flag~\n",unaff_DI);
system("pause");
/* WARNING: Subroutine does not return */
exit(1);
}
DAT_00403378 = (int *)DAT_00403378[2];
}
DAT_00403374 = local_20[iVar4];
DAT_00403370 = DAT_00403370 + 1;
iVar4 = iVar4 + 1;
} while (iVar4 < 0x15);
if (((((local_20[0] == 'f') && (local_20[1] == 'l')) && (local_20[2] == 'a')) &&
((local_20[3] == 'g' && (local_1c == '{')))) && (local_b == '}')) {
if ((DAT_00403370 < 0x11) && (DAT_00403378 == (int *)&DAT_004034f4)) {
pcVar2 = "Congratulations!!\n";
}
else {
pcVar2 = "This is not flag~\n";
}
}
else {
pcVar2 = "illegal input~\n";
}
print(pcVar2,cVar1);
system("pause");
FUN_004011f4();
return;
}

表面上看起来很复杂,仔细研究就会发现,开始的循环是在构造一个有向图,用到了一个结构体,而后面的部分是一个寻路的过程,正向的过程是根据输入的flag的值进行移动,最终走到最后一个位置,所以逆向的过程就是先寻找路径,然后通过找到的路径来计算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
#include <iostream>

using namespace std;
struct a {
int val;
a *loc1;
a *loc2;
};

bool dfs(a *ss, a *ee, int n, a *s[]) {
if (n == 0) {
return ss == ee;
}
if (dfs(ss->loc1, ee, n - 1, s)) {
for (int i = 0; i < 0x11; i++) {
if (s[i] == nullptr) {
s[i] = ss->loc1;
break;
}
}
return true;
} else {
if (dfs(ss->loc2, ee, n - 1, s)) {
for (int i = 0; i < 0x11; i++) {
if (s[i] == nullptr) {
s[i] = ss->loc2;
break;
}
}
return true;
}
}
}

void fun() {
int dword_402178[] =
{
52, 2, 44, 42, 6, 42, 47, 42, 51, 3, 2, 50, 50, 50, 48, 3, 1, 50, 43, 2, 46, 1, 2, 45, 50, 4, 45,
48, 49, 47, 51, 5
};
int dword_4021F8[] =
{
1, 8, 7, 23, 9, 19, 31, 23, 9, 13, 12, 29, 10, 24, 9, 24, 25, 9, 26, 3, 22, 6, 17, 13, 7, 15, 20, 1,
16, 4, 11, 31
};
int dword_402278[] =
{
2, 2, 1, 18, 7, 2, 26, 13, 4, 10, 4, 21, 14, 1, 0, 14, 5, 7, 28, 12, 28, 15, 15, 2, 16, 23, 30, 23,
19, 9, 22, 31
};

a puVar3[32];
a *DAT_00403378 = puVar3;
a *s[0x12]= {nullptr};
int i = 0;
do {
puVar3[i].val = dword_402178[i];
puVar3[i].loc1 = &puVar3[dword_402278[i]];
puVar3[i].loc2 = &puVar3[dword_4021F8[i]];
i++;
} while (i < 32);

dfs(DAT_00403378, &puVar3[31], 0x10, s);
DAT_00403378 = puVar3;
string flag;
int DAT_00403374 = 48;
char tmp;
for(int j=0; j < 0x10; j++)
{
if(s[0xf-j]==DAT_00403378->loc1)
{
tmp=DAT_00403378->val + DAT_00403374;
DAT_00403378=DAT_00403378->loc1;

} else{
tmp=DAT_00403374 - DAT_00403378->val;
DAT_00403378=DAT_00403378->loc2;
}
flag+=tmp;
DAT_00403374 = tmp;
}
cout<<flag<<endl;
// int input[0x15];
// int iVar4 = 5;
// int DAT_00403374 = 48;
// do {
// int cVar1 = input[iVar4];
// if (DAT_00403378->val + DAT_00403374 == cVar1) {
// DAT_00403378 = DAT_00403378->loc1;
// } else {
// if (DAT_00403374 - DAT_00403378->val == cVar1) {
// DAT_00403378 = DAT_00403378->loc2;
// }
// }
// DAT_00403374 = input[iVar4];
// iVar4 = iVar4 + 1;
// } while (iVar4 < 0x15);


// if (((((input[0] == 'f') && (input[1] == 'l')) && (input[2] == 'a')) &&
// ((input[3] == 'g' && (input[4] == '{')))) && (input[0x14] == '}')) {
// if (DAT_00403378 == &puVar3[31]) {
// string s = "Congratulations!!\n";
// }
// }

}

int main()
{
fun();
return 0;
}

注释部分是对于程序的一个正向还原,寻路用到了dfs算法,不是很难。

最后得到flag

1
flag{d8b0bc97a6c0ba27}

天津垓

题目里所有的内容都是假面骑士……

首先可以关注到一个函数名为f 的函数,这个函数很简单

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
__int64 __fastcall f(__int64 a1, char **a2, char **a3)
{
_main(a1, (__int64)a2, (__int64)a3);
printf("Authorize:");
sub_1004011F6();
sub_100401AA0();
return 0i64;
}

int sub_1004011F6()
{
char v1; // [rsp+20h] [rbp-D0h]
char v2; // [rsp+21h] [rbp-CFh]
char v3; // [rsp+22h] [rbp-CEh]
char v4; // [rsp+23h] [rbp-CDh]
char v5; // [rsp+24h] [rbp-CCh]
char v6; // [rsp+25h] [rbp-CBh]
char v7; // [rsp+26h] [rbp-CAh]
char v8; // [rsp+27h] [rbp-C9h]
char v9; // [rsp+28h] [rbp-C8h]
char v10; // [rsp+29h] [rbp-C7h]
char v11; // [rsp+2Ah] [rbp-C6h]
char v12; // [rsp+2Bh] [rbp-C5h]
char v13; // [rsp+2Ch] [rbp-C4h]
char v14; // [rsp+2Dh] [rbp-C3h]
char v15; // [rsp+2Eh] [rbp-C2h]
char v16; // [rsp+2Fh] [rbp-C1h]
char v17; // [rsp+30h] [rbp-C0h]
char v18; // [rsp+31h] [rbp-BFh]
char Format[4]; // [rsp+38h] [rbp-B8h]
char v20[2]; // [rsp+3Dh] [rbp-B3h]
__int64 v21; // [rsp+40h] [rbp-B0h]
__int64 v22; // [rsp+48h] [rbp-A8h]
__int16 v23; // [rsp+50h] [rbp-A0h]
char v24; // [rsp+52h] [rbp-9Eh]
__int64 v25; // [rsp+60h] [rbp-90h]
__int64 v26; // [rsp+68h] [rbp-88h]
__int64 v27; // [rsp+70h] [rbp-80h]
__int64 v28; // [rsp+78h] [rbp-78h]
__int64 v29; // [rsp+80h] [rbp-70h]
__int16 v30; // [rsp+88h] [rbp-68h]
__int64 v31; // [rsp+90h] [rbp-60h]
__int64 v32; // [rsp+98h] [rbp-58h]
__int64 v33; // [rsp+A0h] [rbp-50h]
__int64 v34; // [rsp+A8h] [rbp-48h]
__int64 v35; // [rsp+B0h] [rbp-40h]
__int64 v36; // [rsp+B8h] [rbp-38h]
__int64 v37; // [rsp+C0h] [rbp-30h]
__int64 v38; // [rsp+C8h] [rbp-28h]
__int64 v39; // [rsp+DCh] [rbp-14h]
int v40; // [rsp+E4h] [rbp-Ch]
__int16 v41; // [rsp+E8h] [rbp-8h]
char v42; // [rsp+EAh] [rbp-6h]
char v43; // [rsp+EBh] [rbp-5h]
int i; // [rsp+ECh] [rbp-4h]

v39 = 'H_gnisiR';
v40 = 'eppo';
v41 = '!r';
v42 = 0;
v31 = 'eht nehW';
v32 = 'oh evif ';
v33 = 'sorc snr';
v34 = 'g eht ,s';
v35 = 'os nedlo';
v36 = 'HT reidl';
v37 = 'si RESUO';
v38 = '\n.nrob ';
v25 = 't pmuj A';
v26 = 'ks eht o';
v27 = ' snrut y';
v28 = 'dir a ot';
v29 = '.kcik re';
v30 = '\n';
v21 = 'etneserP';
v22 = 'IAZ yb d';
v23 = '\nA';
v24 = 0;
strcpy(v20, "%s");
strcpy(Format, "%20s");
v1 = 17;
v2 = 8;
v3 = 6;
v4 = 10;
v5 = 15;
v6 = 20;
v7 = 42;
v8 = 59;
v9 = 47;
v10 = 3;
v11 = 47;
v12 = 4;
v13 = 16;
v14 = 72;
v15 = 62;
v16 = 0;
v17 = 7;
v18 = 16;
scanf(Format, Str);
if ( strlen(Str) != 18 )
{
printf(v20, &v25);
exit(1);
}
for ( i = 0; i <= 17; ++i )
{
v43 = ~(Str[i] & *((_BYTE *)&v39 + i % 14)) & (Str[i] | *((_BYTE *)&v39 + i % 14));
if ( v43 != *(&v1 + i) )
{
printf(v20, &v25);
exit(1);
}
}
printf(v20, &v31);
return printf(v20, &v21);
}

这里进行了简单的验证,中间得处理过程不是很好逆,因为涉及到与或非三种运算符,但是通过列真值表可以发现,这一串运算实际上和一个异或是一样的,所以这一部分就很好处理了

1
2
3
4
5
6
target = 'Rising_Hopper!'
flag = ''
v1 = [17, 8, 6, 10, 15, 20, 42, 59, 47, 3, 47, 4, 16, 72, 62, 0, 7, 16]
for i in range(18):
flag += chr(v1[i] ^ ord(target[i % 14]))
print(flag)

输出Caucasus@s_ability,尝试提交发现不对,这题应该没这么简单,在找找有没有遗漏的地方,然后通过Str的交叉引用结果找到了遗漏的部分

1
2
3
4
5
6
int sub_100401A6C()
{
sub_100401506(sub_10040164D, 1045, (__int64)Str);
sub_10040162B();
return sub_10040164D();
}

这个函数在输入并验证过Str之后又调用了我们的输入,肯定还会有后续的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
BOOL __fastcall sub_100401506(void *a1, int a2, __int64 a3)
{
BOOL result; // eax
DWORD flOldProtect; // [rsp+28h] [rbp-8h]
int i; // [rsp+2Ch] [rbp-4h]
LPVOID lpAddress; // [rsp+40h] [rbp+10h]
int v7; // [rsp+48h] [rbp+18h]
__int64 v8; // [rsp+50h] [rbp+20h]

lpAddress = a1;
v7 = a2;
v8 = a3;
if ( strlen(Str) != 18 )
exit(1);
if ( !VirtualProtect(lpAddress, v7, 0x40u, &flOldProtect) )
exit(1);
for ( i = 0; i < v7; ++i )
*((_BYTE *)lpAddress + i) ^= *(_BYTE *)(i % 18 + v8);
result = VirtualProtect(lpAddress, v7, flOldProtect, &flOldProtect);
if ( !result )
exit(1);
return result;
}

这里是经过处理之后的内容,实际上是对一个地址上的数据进行了处理,显然是一个SMC的过程,这个地址里存储的应该是有用的处理代码,我们输入的内容实际上也只是对数据解密的密钥而已,所以接下来写个IDC脚本来解密一下

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
#include <idc.idc>

static main() {
auto start, end, addr;
auto v1 = 67;
auto v2 = 97;
auto v3 = 117;
auto v4 = 99;
auto v5 = 97;
auto v6 = 115;
auto v7 = 117;
auto v8 = 115;
auto v9 = 64;
auto v10 = 115;
auto v11 = 95;
auto v12 = 97;
auto v13 = 98;
auto v14 = 105;
auto v15 = 108;
auto v16 = 105;
auto v17 = 116;
auto v18 = 121;
start = 0x10040164D;
end = 0x100401A68;
// auto flag = "Caucasus@s_ability";
auto flag;
auto i = 0;
for (addr = start; addr < end; addr++) {
if (i % 18 == 0)
flag = v1;
if (i % 18 == 1)
flag = v2;
if (i % 18 == 2)
flag = v3;
if (i % 18 == 3)
flag = v4;
if (i % 18 == 4)
flag = v5;
if (i % 18 == 5)
flag = v6;
if (i % 18 == 6)
flag = v7;
if (i % 18 == 7)
flag = v8;
if (i % 18 == 8)
flag = v9;
if (i % 18 == 9)
flag = v10;
if (i % 18 == 10)
flag = v11;
if (i % 18 == 11)
flag = v12;
if (i % 18 == 12)
flag = v13;
if (i % 18 == 13)
flag = v14;
if (i % 18 == 14)
flag = v15;
if (i % 18 == 15)
flag = v16;
if (i % 18 == 16)
flag = v17;
if (i % 18 == 17)
flag = v18;
PatchByte(addr, Byte(addr) ^ flag);
i++;
}
AnalyzeArea(start, end);
Message("Down!");
}

不是很会用IDC,而且还没有数组类型,只能这样用很多分支去判断,然后得到了新的汇编代码,如果是汇编很好的话就可以直接做了,我还是习惯了无脑F5,所以干脆patch了一下后面的垃圾数据,写了一个retn,然后创建函数,查看伪代码

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
int sub_10040164D()
{
int result; // eax
char Str[74]; // [rsp+20h] [rbp-60h]
char v2[8]; // [rsp+6Ah] [rbp-16h]
__int16 v3; // [rsp+78h] [rbp-8h]
char v4; // [rsp+7Ah] [rbp-6h]
char v5[4]; // [rsp+7Bh] [rbp-5h]
char v6[8]; // [rsp+80h] [rbp+0h]
char v7[8]; // [rsp+A0h] [rbp+20h]
char Format[8]; // [rsp+D0h] [rbp+50h]
int v9; // [rsp+110h] [rbp+90h]
int v10; // [rsp+114h] [rbp+94h]
int v11; // [rsp+118h] [rbp+98h]
int v12; // [rsp+11Ch] [rbp+9Ch]
int v13; // [rsp+120h] [rbp+A0h]
int v14; // [rsp+124h] [rbp+A4h]
int v15; // [rsp+128h] [rbp+A8h]
int v16; // [rsp+12Ch] [rbp+ACh]
int v17; // [rsp+130h] [rbp+B0h]
int v18; // [rsp+134h] [rbp+B4h]
int v19; // [rsp+138h] [rbp+B8h]
int v20; // [rsp+13Ch] [rbp+BCh]
int v21; // [rsp+140h] [rbp+C0h]
int v22; // [rsp+144h] [rbp+C4h]
int v23; // [rsp+148h] [rbp+C8h]
int v24; // [rsp+14Ch] [rbp+CCh]
int v25; // [rsp+150h] [rbp+D0h]
int v26; // [rsp+154h] [rbp+D4h]
int v27; // [rsp+158h] [rbp+D8h]
int v28; // [rsp+15Ch] [rbp+DCh]
int v29; // [rsp+160h] [rbp+E0h]
int v30; // [rsp+164h] [rbp+E4h]
int v31; // [rsp+168h] [rbp+E8h]
int v32; // [rsp+16Ch] [rbp+ECh]
int v33; // [rsp+170h] [rbp+F0h]
int v34; // [rsp+174h] [rbp+F4h]
int v35; // [rsp+178h] [rbp+F8h]
int v36; // [rsp+17Ch] [rbp+FCh]
int v37; // [rsp+180h] [rbp+100h]
int v38; // [rsp+184h] [rbp+104h]
int v39; // [rsp+188h] [rbp+108h]
int v40; // [rsp+18Ch] [rbp+10Ch]
int v41; // [rsp+190h] [rbp+110h]
int v42; // [rsp+194h] [rbp+114h]
int v43; // [rsp+198h] [rbp+118h]
int v44; // [rsp+19Ch] [rbp+11Ch]
int v45; // [rsp+1A0h] [rbp+120h]
int v46; // [rsp+1A4h] [rbp+124h]
int v47; // [rsp+1A8h] [rbp+128h]
int v48; // [rsp+1ACh] [rbp+12Ch]
int v49; // [rsp+1B0h] [rbp+130h]
int v50; // [rsp+1B4h] [rbp+134h]
int v51; // [rsp+1B8h] [rbp+138h]
int v52; // [rsp+1BCh] [rbp+13Ch]
int v53; // [rsp+1C0h] [rbp+140h]
int v54; // [rsp+1C4h] [rbp+144h]
int v55; // [rsp+1C8h] [rbp+148h]
int v56; // [rsp+1CCh] [rbp+14Ch]
int v57; // [rsp+1D0h] [rbp+150h]
int v58; // [rsp+1D4h] [rbp+154h]
int v59; // [rsp+1D8h] [rbp+158h]
unsigned int v60; // [rsp+1E0h] [rbp+160h]
int v61; // [rsp+1E4h] [rbp+164h]
unsigned int v62; // [rsp+1E8h] [rbp+168h]
unsigned int i; // [rsp+1ECh] [rbp+16Ch]

v9 = 2007666;
v10 = 2125764;
v11 = 1909251;
v12 = 2027349;
v13 = 2421009;
v14 = 1653372;
v15 = 2047032;
v16 = 2184813;
v17 = 2302911;
v18 = 2263545;
v19 = 1909251;
v20 = 2165130;
v21 = 1968300;
v22 = 2243862;
v23 = 2066715;
v24 = 2322594;
v25 = 1987983;
v26 = 2243862;
v27 = 1869885;
v28 = 2066715;
v29 = 2263545;
v30 = 1869885;
v31 = 964467;
v32 = 944784;
v33 = 944784;
v34 = 944784;
v35 = 728271;
v36 = 1869885;
v37 = 2263545;
v38 = 2283228;
v39 = 2243862;
v40 = 2184813;
v41 = 2165130;
v42 = 2027349;
v43 = 1987983;
v44 = 2243862;
v45 = 1869885;
v46 = 2283228;
v47 = 2047032;
v48 = 1909251;
v49 = 2165130;
v50 = 1869885;
v51 = 2401326;
v52 = 1987983;
v53 = 2243862;
v54 = 2184813;
v55 = 885735;
v56 = 2184813;
v57 = 2165130;
v58 = 1987983;
v59 = 2460375;
strcpy(Format, "Input the flag to hijack the ability of Hiden Intelligence:");
strcpy(v7, "Progrise Key confirmed. Ready to break.\n");
strcpy(v6, "Jacking Break! Zaia Enterprise.");
strcpy(v5, "%59s");
v3 = 29477;
v4 = 0;
strcpy(v2, "Not verified!");
v62 = 2147483659;
printf(Format);
scanf(v5, Str);
printf(v7);
if ( strlen(Str) != 51 )
{
printf(v2);
exit(0);
}
v61 = 19683;
for ( i = 0; i <= 0x32; ++i )
{
v60 = v61 * (unsigned int)(unsigned __int8)Str[i] % v62;
if ( v60 != *(&v9 + i) )
{
printf(v2);
exit(0);
}
}
printf(v6);
getchar();
result = getchar();
__asm { icebp }
return result;
}

关键的处理只有一句,但是有个很烦的取余,仔细观察可以发现,v62这个数非常大,最后在计算的时候取不取这个余数都没关系,所以这一部分又变成了一个非常简单的除法,然后问题就很容易解决了

1
2
3
4
5
6
7
8
9
10
11
v9 = [2007666, 2125764, 1909251, 2027349, 2421009, 1653372, 2047032, 2184813, 2302911, 2263545, 1909251, 2165130,
1968300, 2243862, 2066715, 2322594, 1987983, 2243862, 1869885, 2066715, 2263545, 1869885, 964467, 944784, 944784,
944784, 728271, 1869885, 2263545, 2283228, 2243862, 2184813, 2165130, 2027349, 1987983, 2243862, 1869885, 2283228,
2047032, 1909251, 2165130, 1869885, 2401326, 1987983, 2243862, 2184813, 885735, 2184813, 2165130, 1987983,
2460375]
v61 = 19683
v62 = 0x8000000B
flag = ''
for i in range(0x33):
flag += chr(v9[i] // v61)
print(flag)

输出flag

1
flag{Thousandriver_is_1000%_stronger_than_zero-one}

后记

然后这次比赛就没打算再做了,mobile的题,研究了一下,应该不是特别难,但是没太有时间,又是作业又是网课又是美赛,让人很烦,如果后面有wp放出来的话再去研究研究,复现一下,做个补充。

IDA常用宏定义 攻防世界-pwn部分题解(一)

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×