Reverse_1

虽然闲着但是不想让自己闲着, 先刷完BUUOJ的第一页逆向吧

[BJDCTF2020]JustRE

链接: https://buuoj.cn/challenges#[BJDCTF2020]JustRE

EXE 32

IDA中 DialogFunc 函数反编译结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
BOOL __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
CHAR String; // [esp+0h] [ebp-64h]

if ( a2 != 272 )
{
if ( a2 != 273 )
return 0;
if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
{
sprintf(&String, aD, ++dword_4099F0);
if ( dword_4099F0 == 19999 )
{
sprintf(&String, aBjdDD2069a4579, 19999, 0);
SetWindowTextA(hWnd, &String);
return 0;
}
SetWindowTextA(hWnd, &String);
return 0;
}
EndDialog(hWnd, (unsigned __int16)a3);
}
return 1;
}
  • aD = "您已经点了 %d 次"
  • dword_4099F0 = 0
  • aBjdDD2069a4579 = "BJD{%d%d2069a45792d233ac}"

当计数到达19999之后得到flag, 用199990分别替换两个%d即为flag

flag{1999902069a45792d233ac}


rsa

链接: https://buuoj.cn/challenges#rsa

这题放错分类了吧…

使用openssl从公钥文件中提取e, n

1
2
3
4
5
6
7
8
9
openssl rsa -pubin -modulus -text -in pub.key 
RSA Public-Key: (256 bit)
Modulus:
00:c0:33:2c:5c:64:ae:47:18:2f:6c:1c:87:6d:42:
33:69:10:54:5a:58:f7:ee:fe:fc:0b:ca:af:5a:f3:
41:cc:dd
Exponent: 65537 (0x10001)
Modulus=C0332C5C64AE47182F6C1C876D42336910545A58F7EEFEFC0BCAAF5AF341CCDD
writing RSA key
  • e = 0x10001
  • n = 0xC0332C5C64AE47182F6C1C876D42336910545A58F7EEFEFC0BCAAF5AF341CCDD

http://www.factordb.com/index.php

在这个网站分解n得到两个素数

  • p = 285960468890451637935629440372639283459
  • q = 304008741604601924494328155975272418463
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
from Crypto.Util.number import *
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463
e = 65537
n = p * q
phi = (p - 1)*(q - 1)
d = inverse(e, phi)

import rsa
key = rsa.PrivateKey(n,e,d,p,q)
c = open('flag.enc','rb').read()
print(rsa.decrypt(c,key))

flag{decrypt_256}


CrackRTF

链接: https://buuoj.cn/challenges#CrackRTF

EXE 32

IDA中 _main_0 函数反编译结果如下

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
int __cdecl main_0()
{
DWORD v0; // eax
DWORD v1; // eax
CHAR String; // [esp+4Ch] [ebp-310h]
int v4; // [esp+150h] [ebp-20Ch]
CHAR String1; // [esp+154h] [ebp-208h]
BYTE pbData; // [esp+258h] [ebp-104h]

memset(&pbData, 0, 0x104u);
memset(&String1, 0, 0x104u);
v4 = 0;
printf("pls input the first passwd(1): ");
scanf("%s", &pbData);
if ( strlen((const char *)&pbData) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
v4 = atoi((const char *)&pbData);
if ( v4 < 100000 )
ExitProcess(0);
strcat((char *)&pbData, "@DBApp");
v0 = strlen((const char *)&pbData);
sub_40100A(&pbData, v0, &String1);
if ( !_strcmpi(&String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )
{
printf("continue...\n\n");
printf("pls input the first passwd(2): ");
memset(&String, 0, 0x104u);
scanf("%s", &String);
if ( strlen(&String) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
strcat(&String, (const char *)&pbData);
memset(&String1, 0, 0x104u);
v1 = strlen(&String);
sub_401019((BYTE *)&String, v1, &String1);
if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", &String1) )
{
if ( !(unsigned __int8)sub_40100F(&String) )
{
printf("Error!!\n");
ExitProcess(0);
}
printf("bye ~~\n");
}
}
return 0;
}

输入的第一个密码要求为六位字符
函数atoi则是将字符串转为数字
则第一个密码需要输入六位数字

跟进到函数sub_401230
使用函数CryptCreateHash
第二个参数为所使用的加密算法

https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id

通过这个文档可以得知0x8003为md5, 0x8004为sha1
所以可以爆破第一段hash

1
2
3
4
5
6
7
8
#!/usr/bin/env python3
import hashlib
passwd = b""
for _ in range(100000, 1000000):
test = str(_).encode()+b"@DBApp"
if hashlib.sha1(test).hexdigest() == "6e32d0943418c2c33385bc35a1470250dd8923a9":
print(passwd)
break

123321@DBApp

而对于第二段的md5加密结果, 没有作输入字符集的限定, 比较难以爆破

https://www.somd5.com/

通过这个链接可以得到md5的明文

~!3a@0123321@DBApp

其实完全没必要爆破sha1, 直接在somd5查明文就能解题了

而后续的RTF操作有些复杂, 这里可以通过运行程序输入密码来得到flag

flag{N0_M0re_Free_Bugs}


[ACTF新生赛2020]easyre

链接: https://buuoj.cn/challenges#[ACTF新生赛2020]easyre

EXE 32

存在UPX壳, 脱壳后IDA中 _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
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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [esp+12h] [ebp-2Eh] char c1[12];
char v5; // [esp+13h] [ebp-2Dh]
char v6; // [esp+14h] [ebp-2Ch]
char v7; // [esp+15h] [ebp-2Bh]
char v8; // [esp+16h] [ebp-2Ah]
char v9; // [esp+17h] [ebp-29h]
char v10; // [esp+18h] [ebp-28h]
char v11; // [esp+19h] [ebp-27h]
char v12; // [esp+1Ah] [ebp-26h]
char v13; // [esp+1Bh] [ebp-25h]
char v14; // [esp+1Ch] [ebp-24h]
char v15; // [esp+1Dh] [ebp-23h] c1 end
int v16; // [esp+1Eh] [ebp-22h] int i1[3];
int v17; // [esp+22h] [ebp-1Eh]
int v18; // [esp+26h] [ebp-1Ah] i1 end
__int16 v19; // [esp+2Ah] [ebp-16h] char c2[18];
char v20; // [esp+2Ch] [ebp-14h]
char v21; // [esp+2Dh] [ebp-13h]
char v22; // [esp+2Eh] [ebp-12h]
int v23; // [esp+2Fh] [ebp-11h] int i2[3];
int v24; // [esp+33h] [ebp-Dh]
int v25; // [esp+37h] [ebp-9h] i2 end
char v26; // [esp+3Bh] [ebp-5h] c2 end
int i; // [esp+3Ch] [ebp-4h]

__main();
v4 = '*';
v5 = 'F';
v6 = '\'';
v7 = '"';
v8 = 'N';
v9 = ',';
v10 = '"';
v11 = '(';
v12 = 'I';
v13 = '?';
v14 = '+';
v15 = '@';
printf("Please input:");
scanf("%s", &v19);
if ( (_BYTE)v19 != 'A' || HIBYTE(v19) != 'C' || v20 != 'T' || v21 != 'F' || v22 != '{' || v26 != '}' ) return 0;
v16 = v23;
v17 = v24;
v18 = v25;
for ( i = 0; i <= 11; ++i )
{
if ( *(&v4 + i) != _data_start__[*((char *)&v16 + i) - 1] )
return 0;
}
printf("You are correct!");
return 0;
}

这里值得一提的是, char c2[18]中插入了一个int i2[3],
而int使用4Byte, char使用1Byte, 弄清楚内存大小对应关系即可

v16,v17,v18对应v23,v24,v25, 即flag[5:18]

*((char *)&v16 + i) 意为用char指针去访问v16的内存, 每次读取一个字节, 实际上是读取flag[5:18]

1
_data_start__ == "~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$# !\""
1
2
3
4
5
6
7
8
#!/usr/bin/env python3
data = "~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$# !\""
string1 = "*F'\"N,\"(I?+@"
flag = "flag{"
for _ in string1:
flag += chr(data.index(_)+1)
flag += "}"
print(flag)

flag{U9X_1S_W6@T?}


[2019红帽杯]easyRE

链接: https://buuoj.cn/challenges#[2019红帽杯]easyRE

ELF 64

IDA中函数 sub_4009C6 的反编译结果如下

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
signed __int64 sub_4009C6()
{
signed __int64 result; // rax
__int64 v1; // ST10_8
__int64 v2; // ST18_8
__int64 v3; // ST20_8
__int64 v4; // ST28_8
__int64 v5; // ST30_8
__int64 v6; // ST38_8
__int64 v7; // ST40_8
__int64 v8; // ST48_8
__int64 v9; // ST50_8
__int64 v10; // ST58_8
int i; // [rsp+Ch] [rbp-114h]
char v12; // [rsp+60h] [rbp-C0h] char c1[36];
char v13; // [rsp+61h] [rbp-BFh]
char v14; // [rsp+62h] [rbp-BEh]
char v15; // [rsp+63h] [rbp-BDh]
char v16; // [rsp+64h] [rbp-BCh]
char v17; // [rsp+65h] [rbp-BBh]
char v18; // [rsp+66h] [rbp-BAh]
char v19; // [rsp+67h] [rbp-B9h]
char v20; // [rsp+68h] [rbp-B8h]
char v21; // [rsp+69h] [rbp-B7h]
char v22; // [rsp+6Ah] [rbp-B6h]
char v23; // [rsp+6Bh] [rbp-B5h]
char v24; // [rsp+6Ch] [rbp-B4h]
char v25; // [rsp+6Dh] [rbp-B3h]
char v26; // [rsp+6Eh] [rbp-B2h]
char v27; // [rsp+6Fh] [rbp-B1h]
char v28; // [rsp+70h] [rbp-B0h]
char v29; // [rsp+71h] [rbp-AFh]
char v30; // [rsp+72h] [rbp-AEh]
char v31; // [rsp+73h] [rbp-ADh]
char v32; // [rsp+74h] [rbp-ACh]
char v33; // [rsp+75h] [rbp-ABh]
char v34; // [rsp+76h] [rbp-AAh]
char v35; // [rsp+77h] [rbp-A9h]
char v36; // [rsp+78h] [rbp-A8h]
char v37; // [rsp+79h] [rbp-A7h]
char v38; // [rsp+7Ah] [rbp-A6h]
char v39; // [rsp+7Bh] [rbp-A5h]
char v40; // [rsp+7Ch] [rbp-A4h]
char v41; // [rsp+7Dh] [rbp-A3h]
char v42; // [rsp+7Eh] [rbp-A2h]
char v43; // [rsp+7Fh] [rbp-A1h]
char v44; // [rsp+80h] [rbp-A0h]
char v45; // [rsp+81h] [rbp-9Fh]
char v46; // [rsp+82h] [rbp-9Eh]
char v47; // [rsp+83h] [rbp-9Dh] c1 end
char v48[32]; // [rsp+90h] [rbp-90h]
int v49; // [rsp+B0h] [rbp-70h]
char v50; // [rsp+B4h] [rbp-6Ch]
char v51; // [rsp+C0h] [rbp-60h]
char v52; // [rsp+E7h] [rbp-39h]
char v53; // [rsp+100h] [rbp-20h]
unsigned __int64 v54; // [rsp+108h] [rbp-18h]

v54 = __readfsqword(0x28u);
v12 = 73;
v13 = 111;
v14 = 100;
v15 = 108;
v16 = 62;
v17 = 81;
v18 = 110;
v19 = 98;
v20 = 40;
v21 = 111;
v22 = 99;
v23 = 121;
v24 = 127;
v25 = 121;
v26 = 46;
v27 = 105;
v28 = 127;
v29 = 100;
v30 = 96;
v31 = 51;
v32 = 119;
v33 = 125;
v34 = 119;
v35 = 101;
v36 = 107;
v37 = 57;
v38 = 123;
v39 = 105;
v40 = 121;
v41 = 61;
v42 = 126;
v43 = 121;
v44 = 76;
v45 = 64;
v46 = 69;
v47 = 67;
memset(v48, 0, sizeof(v48));
v49 = 0;
v50 = 0;
sub_4406E0(0LL, (__int64)v48);
v50 = 0;
if ( sub_424BA0(v48) == 36 )
{
for ( i = 0; i < (unsigned __int64)sub_424BA0(v48); ++i )
{
if ( (unsigned __int8)(v48[i] ^ i) != *(&v12 + i) )
{
result = 4294967294LL;
goto LABEL_13;
}
}
sub_410CC0((__int64)"continue!");
memset(&v51, 0, 0x40uLL);
v53 = 0;
sub_4406E0(0LL, (__int64)&v51);
v52 = 0;
if ( sub_424BA0(&v51) == 39 )
{
v1 = sub_400E44((__int64)&v51);
v2 = sub_400E44(v1);
v3 = sub_400E44(v2);
v4 = sub_400E44(v3);
v5 = sub_400E44(v4);
v6 = sub_400E44(v5);
v7 = sub_400E44(v6);
v8 = sub_400E44(v7);
v9 = sub_400E44(v8);
v10 = sub_400E44(v9);
if ( !(unsigned int)sub_400360(v10, (__int64)off_6CC090) )
{
sub_410CC0((__int64)"You found me!!!");
sub_410CC0((__int64)"bye bye~");
}
result = 0LL;
}
else
{
result = 0xFFFFFFFDLL;
}
}
else
{
result = 0xFFFFFFFFLL;
}
LABEL_13:
if ( __readfsqword(0x28u) != v54 )
sub_444020();
return result;
}

可以看到v10off_6CC090进行比较, 相同则输出字符串
而off_6CC090为一段Base64编码

1
Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xVmpKS1NHVkdXbFpOYmtKVVZtcEtTMUl5VGtsaVJtUk9ZV3hhZVZadGVHdFRNVTVYVW01T2FGSnRVbGhhVjNoaFZWWmtWMXBFVWxSTmJFcElWbTAxVDJGV1NuTlhia0pXWWxob1dGUnJXbXRXTVZaeVdrWm9hVlpyV1hwV1IzaGhXVmRHVjFOdVVsWmlhMHBZV1ZSR1lWZEdVbFZTYlhSWFRWWndNRlZ0TVc5VWJGcFZWbXR3VjJKSFVYZFdha1pXWlZaT2NtRkhhRk5pVjJoWVYxZDBhMVV3TlhOalJscFlZbGhTY1ZsclduZGxiR1J5VmxSR1ZXSlZjRWhaTUZKaFZqSktWVkZZYUZkV1JWcFlWV3BHYTFkWFRrZFRiV3hvVFVoQ1dsWXhaRFJpTWtsM1RVaG9hbEpYYUhOVmJUVkRZekZhY1ZKcmRGTk5Wa3A2VjJ0U1ExWlhTbFpqUldoYVRVWndkbFpxUmtwbGJVWklZVVprYUdFeGNHOVhXSEJIWkRGS2RGSnJhR2hTYXpWdlZGVm9RMlJzV25STldHUlZUVlpXTlZadE5VOVdiVXBJVld4c1dtSllUWGhXTUZwell6RmFkRkpzVWxOaVNFSktWa1phVTFFeFduUlRhMlJxVWxad1YxWnRlRXRXTVZaSFVsUnNVVlZVTURrPQ==

结合前面的代码, 大概可以理解为输入的字符串进行10次Base64编码之后与这段Base64编码相比较

得到的内容为https://bbs.pediy.com/thread-254172.htm

显然这不是flag

1
2
3
4
5
6
7
8
for ( i = 0; i < (unsigned __int64)sub_424BA0(v48); ++i )
{
if ( (unsigned __int8)(v48[i] ^ i) != *(&v12 + i) )
{
result = 4294967294LL;
goto LABEL_13;
}
}

这段代码则将输入值与下标异或之后与一个固定值相比较, 则可以逆向得出正确输入值

1
2
3
4
5
6
#!/usr/bin/env python3
string = [73, 111, 100, 108, 62, 81, 110, 98, 40, 111, 99, 121, 127, 121, 46, 105, 127, 100, 96, 51, 119, 125, 119, 101, 107, 57, 123, 105, 121, 61, 126, 121, 76, 64, 69, 67]
flag = ""
for _ in range(len(string)):
flag += chr(string[_]^_)
print(flag)

Info:The first four chars are flag

而在内存分布中off_6CC090的下面存在另外一段字符串qword_6CC0A0

1
2
3
4
5
6
qword_6CC0A0 = [
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
]

IDA中右键->Xrefs graph to..., 得到函数sub_400D35

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
__int64 sub_400D35()
{
__int64 result; // rax
unsigned __int64 v1; // rt1
unsigned int v2; // [rsp+Ch] [rbp-24h]
signed int i; // [rsp+10h] [rbp-20h]
signed int j; // [rsp+14h] [rbp-1Ch]
unsigned int v5; // [rsp+24h] [rbp-Ch]
unsigned __int64 v6; // [rsp+28h] [rbp-8h]

v6 = __readfsqword(0x28u);
v2 = sub_43FD20() - qword_6CEE38;
for ( i = 0; i <= 1233; ++i )
{
sub_40F790(v2);
sub_40FE60(v2);
sub_40FE60(v2);
v2 = (unsigned __int64)sub_40FE60(v2) ^ 0x98765432;
}
v5 = v2;
if ( ((unsigned __int8)v2 ^ qword_6CC0A0[0]) == 'f' && (HIBYTE(v5) ^ qword_6CC0A0[3]) == 'g' )
{
for ( j = 0; j <= 24; ++j )
sub_410E90(qword_6CC0A0[j] ^ *((_BYTE *)&v5 + j % 4));
}
v1 = __readfsqword(0x28u);
result = v1 ^ v6;
if ( v1 != v6 )
sub_444020();
return result;
}

而flag前四字节为"flag", v5长度也为4字节
即可通过已知明文部分来得出v5, 再通过v5得出flag

1
2
3
4
5
6
7
8
9
string1 = [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]
string2 = "flag"
key = []
flag = ""
for _ in range(len(string2)):
key.append(ord(string2[_])^string1[_])
for _ in range(len(string1)):
flag += chr(string1[_]^key[_%4])
print(flag)

flag{Act1ve_Defen5e_Test}


[ACTF新生赛2020]rome

链接: https://buuoj.cn/challenges#[ACTF新生赛2020]rome

EXE 32

IDA中函数 func 的反编译结果如下

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
int func()
{
int result; // eax
int v1; // [esp+14h] [ebp-44h]
int v2; // [esp+18h] [ebp-40h]
int v3; // [esp+1Ch] [ebp-3Ch]
int v4; // [esp+20h] [ebp-38h]
unsigned __int8 v5; // [esp+24h] [ebp-34h] char c1[22];
unsigned __int8 v6; // [esp+25h] [ebp-33h]
unsigned __int8 v7; // [esp+26h] [ebp-32h]
unsigned __int8 v8; // [esp+27h] [ebp-31h]
unsigned __int8 v9; // [esp+28h] [ebp-30h]
int v10; // [esp+29h] [ebp-2Fh]
int v11; // [esp+2Dh] [ebp-2Bh]
int v12; // [esp+31h] [ebp-27h]
int v13; // [esp+35h] [ebp-23h]
unsigned __int8 v14; // [esp+39h] [ebp-1Fh] c1 end
char v15; // [esp+3Bh] [ebp-1Dh]
char v16; // [esp+3Ch] [ebp-1Ch]
char v17; // [esp+3Dh] [ebp-1Bh]
char v18; // [esp+3Eh] [ebp-1Ah]
char v19; // [esp+3Fh] [ebp-19h]
char v20; // [esp+40h] [ebp-18h]
char v21; // [esp+41h] [ebp-17h]
char v22; // [esp+42h] [ebp-16h]
char v23; // [esp+43h] [ebp-15h]
char v24; // [esp+44h] [ebp-14h]
char v25; // [esp+45h] [ebp-13h]
char v26; // [esp+46h] [ebp-12h]
char v27; // [esp+47h] [ebp-11h]
char v28; // [esp+48h] [ebp-10h]
char v29; // [esp+49h] [ebp-Fh]
char v30; // [esp+4Ah] [ebp-Eh]
char v31; // [esp+4Bh] [ebp-Dh]
int i; // [esp+4Ch] [ebp-Ch]

v15 = 81;
v16 = 115;
v17 = 119;
v18 = 51;
v19 = 115;
v20 = 106;
v21 = 95;
v22 = 108;
v23 = 122;
v24 = 52;
v25 = 95;
v26 = 85;
v27 = 106;
v28 = 119;
v29 = 64;
v30 = 108;
v31 = 0;
printf("Please input:");
scanf("%s", &v5);
result = v5;
if ( v5 == 'A' )
{
result = v6;
if ( v6 == 'C' )
{
result = v7;
if ( v7 == 'T' )
{
result = v8;
if ( v8 == 'F' )
{
result = v9;
if ( v9 == '{' )
{
result = v14;
if ( v14 == '}' )
{
v1 = v10;
v2 = v11;
v3 = v12;
v4 = v13;
for ( i = 0; i <= 15; ++i )
{
if ( *((_BYTE *)&v1 + i) > 64 && *((_BYTE *)&v1 + i) <= 90 )
*((_BYTE *)&v1 + i) = (*((char *)&v1 + i) - 51) % 26 + 65;
if ( *((_BYTE *)&v1 + i) > 96 && *((_BYTE *)&v1 + i) <= 122 )
*((_BYTE *)&v1 + i) = (*((char *)&v1 + i) - 79) % 26 + 97;
}
for ( i = 0; i <= 15; ++i )
{
result = (unsigned __int8)*(&v15 + i);
if ( *((_BYTE *)&v1 + i) != (_BYTE)result )
return result;
}
result = printf("You are correct!");
}
}
}
}
}
}
return result;
}
1
2
3
4
5
6
7
8
for ( i = 0; i <= 15; ++i )
{
if ( *((_BYTE *)&v1 + i) > 64 && *((_BYTE *)&v1 + i) <= 90 )
*((_BYTE *)&v1 + i) = (*((char *)&v1 + i) - 51) % 26 + 65;
if ( *((_BYTE *)&v1 + i) > 96 && *((_BYTE *)&v1 + i) <= 122 )
*((_BYTE *)&v1 + i) = (*((char *)&v1 + i) - 79) % 26 + 97;
}

重点看这段代码
*((_BYTE *)&v1 + i) = (*((char *)&v1 + i) - 51) % 26 + 65;

与下面的写法等效
*((_BYTE *)&v1 + i) = (*((char *)&v1 + i) - 65 + 14) % 26 + 65;

那么显而易见得就是凯撒密码了

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python3
cipher = [81, 115, 119, 51, 115, 106, 95, 108, 122, 52, 95, 85, 106, 119, 64, 108]
flag = "flag{"
for _ in cipher:
if _ in range(65, 91):
flag += chr(((_-65-14)%26)+65)
elif _ in range(97, 123):
flag += chr(((_-97-18)%26)+97)
else:
flag += chr(_)
flag += "}"
print(flag)

flag{Cae3ar_th4_Gre@t}


Youngter-drive

链接: https://buuoj.cn/challenges#Youngter-drive

EXE 32

存在UPX壳, 脱壳后IDA中 _main_0 函数反编译结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main_0()
{
HANDLE v2; // [esp+D0h] [ebp-14h]
HANDLE hObject; // [esp+DCh] [ebp-8h]

sub_4110FF();
::hObject = CreateMutexW(0, 0, 0);
j_strcpy(Dest, Source);
hObject = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)StartAddress, 0, 0, 0);
v2 = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sub_41119F, 0, 0, 0);
CloseHandle(hObject);
CloseHandle(v2);
while ( dword_418008 != -1 )
;
sub_411190();
CloseHandle(::hObject);
return 0;
}

这里可以看到程序使用了多线程

分别跟进两个线程中所运行的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void __stdcall StartAddress_0(int a1)
{
while ( 1 )
{
WaitForSingleObject(hObject, 0xFFFFFFFF);
if ( dword_418008 > -1 )
{
sub_41112C((int)Source, dword_418008);
--dword_418008;
Sleep(0x64u);
}
ReleaseMutex(hObject);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
void __stdcall sub_411B10(int a1)
{
while ( 1 )
{
WaitForSingleObject(hObject, 0xFFFFFFFF);
if ( dword_418008 > -1 )
{
Sleep(0x64u);
--dword_418008;
}
ReleaseMutex(hObject);
}
}

hObject可以理解为一个标识, 先运行StartAddress_0, 此时hObject空闲状态

WaitForSingleObjecthObject空闲状态时可以运行后续的代码, 并将hObject设置为繁忙状态, 直到后续代码运行结束之后再运行函数ReleaseMutex, 将hObject空闲状态设置为空闲状态

而当hObject空闲状态之前, 函数sub_411B10都在运行WaitForSingleObject, 即等待hObject变为空闲状态

那么函数StartAddress_0, sub_411B10将交替运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
char *__cdecl sub_411940(int a1, int a2)
{
char *result; // eax
char v3; // [esp+D3h] [ebp-5h]

v3 = *(_BYTE *)(a2 + a1);
if ( (v3 < 97 || v3 > 122) && (v3 < 65 || v3 > 90) )
exit(0);
if ( v3 < 97 || v3 > 122 )
{
result = off_418000[0];
*(_BYTE *)(a2 + a1) = off_418000[0][*(char *)(a2 + a1) - 38];
}
else
{
result = off_418000[0];
*(_BYTE *)(a2 + a1) = off_418000[0][*(char *)(a2 + a1) - 96];
}
return result;
}

函数sub_411940用于替换所输入的Source字符串

off_418000[0][*(char *)(a2 + a1) - 38]表面上是个二维数组, 但是第一维只有一个值, 所以当一维数组处理即可

  • dword_418008 = 29
  • off_418000 = “QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm”

最后运行函数sub_411880(), 用于校验被替换之后的flag是否正确

1
2
3
4
5
6
7
8
9
10
11
int sub_411880()
{
int i; // [esp+D0h] [ebp-8h]

for ( i = 0; i < 29; ++i )
{
if ( Source[i] != off_418004[i] )
exit(0);
}
return printf("\nflag{%s}\n\n", Dest);
}
  • off_418004 = “TOiZiZtOrYaToUwPnToBsOaOapsyS”
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
source = "TOiZiZtOrYaToUwPnToBsOaOapsyS"
off = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
flag = "flag{"
for _ in range(len(source)):
if _%2 == 0:
flag += source[_]
elif ord(source[_]) < 97:
flag += chr(off.index(source[_])+96)
else:
flag += chr(off.index(source[_])+38)
flag += "}"
print(flag)

由于未知原因, 需要加上一个'E'才能正确提交flag

另外一点, dword_418008 = 29, 而字符串长度也为29
在访问off_418004[29]时理论上是访问到\x00
那么替换时, 会被off_418000[0][-38]所替换

flag{ThisisthreadofwindowshahaIsESE}


[FlareOn4]login

链接: https://buuoj.cn/challenges#[FlareOn4]login

Javascript

1
2
3
4
5
6
7
8
9
document.getElementById("prompt").onclick = function () {
var flag = document.getElementById("flag").value;
var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
alert("Correct flag!");
} else {
alert("Incorrect flag, rot again");
}
}

由于不熟悉JS, 只能通过在浏览器Console中运行JS来判断加密方法

1
2
3
4
5
flag = "abcdefghjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()_+-="
"abcdefghjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()_+-="
------
flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
"nopqrstuwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM`~!@#$%^&*()_+-="

rot13

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python3
cipher = "PyvragFvqrYbtvafNerRnfl@syner-ba.pbz"
flag = ""
for _ in cipher:
if 65<=ord(_)<=90:
flag += chr((ord(_)-65+13)%26+65)
elif 97<=ord(_)<=122:
flag += chr((ord(_)-97+13)%26+97)
else:
flag += _
print(flag)

flag{ClientSideLoginsAreEasy@flare-on.com}


[GUET-CTF2019]re

链接: https://buuoj.cn/challenges#[GUET-CTF2019]re

ELF 64

UPX脱壳

字符串aInputYourFlag -> sub_400E28 -> sub_4009AE

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
_BOOL8 __fastcall sub_4009AE(char *a1)
{
if ( 1629056 * *a1 != 166163712 )
return 0LL;
if ( 6771600 * a1[1] != 731332800 )
return 0LL;
if ( 3682944 * a1[2] != 357245568 )
return 0LL;
if ( 10431000 * a1[3] != 1074393000 )
return 0LL;
if ( 3977328 * a1[4] != 489211344 )
return 0LL;
if ( 5138336 * a1[5] != 518971936 )
return 0LL;
if ( 7532250 * a1[7] != 406741500 )
return 0LL;
if ( 5551632 * a1[8] != 294236496 )
return 0LL;
if ( 3409728 * a1[9] != 177305856 )
return 0LL;
if ( 13013670 * a1[10] != 650683500 )
return 0LL;
if ( 6088797 * a1[11] != 298351053 )
return 0LL;
if ( 7884663 * a1[12] != 386348487 )
return 0LL;
if ( 8944053 * a1[13] != 438258597 )
return 0LL;
if ( 5198490 * a1[14] != 249527520 )
return 0LL;
if ( 4544518 * a1[15] != 445362764 )
return 0LL;
if ( 3645600 * a1[17] != 174988800 )
return 0LL;
if ( 10115280 * a1[16] != 981182160 )
return 0LL;
if ( 9667504 * a1[18] != 493042704 )
return 0LL;
if ( 5364450 * a1[19] != 257493600 )
return 0LL;
if ( 13464540 * a1[20] != 767478780 )
return 0LL;
if ( 5488432 * a1[21] != 312840624 )
return 0LL;
if ( 14479500 * a1[22] != 1404511500 )
return 0LL;
if ( 6451830 * a1[23] != 316139670 )
return 0LL;
if ( 6252576 * a1[24] != 619005024 )
return 0LL;
if ( 7763364 * a1[25] != 372641472 )
return 0LL;
if ( 7327320 * a1[26] != 373693320 )
return 0LL;
if ( 8741520 * a1[27] != 498266640 )
return 0LL;
if ( 8871876 * a1[28] != 452465676 )
return 0LL;
if ( 4086720 * a1[29] != 208422720 )
return 0LL;
if ( 9374400 * a1[30] == 515592000 )
return 5759124 * a1[31] == 719890500;
return 0LL;
}

两个坑

  • 没有给出a1[6]
  • a[17]和a[16]调换顺序
1
2
3
4
5
6
7
#!/usr/bin/env python3
num1 = [1629056, 6771600, 3682944, 10431000, 3977328, 5138336, 7532250, 5551632, 3409728, 13013670, 6088797, 7884663, 8944053, 5198490, 4544518, 10115280, 3645600, 9667504, 5364450, 13464540, 5488432, 14479500, 6451830, 6252576, 7763364, 7327320, 8741520, 8871876, 4086720, 9374400, 5759124]
num2 = [166163712, 731332800, 357245568, 1074393000, 489211344, 518971936, 406741500, 294236496, 177305856, 650683500, 298351053, 386348487, 438258597, 249527520, 445362764, 981182160, 174988800, 493042704, 257493600, 767478780, 312840624, 1404511500, 316139670, 619005024, 372641472, 373693320, 498266640, 452465676, 208422720, 515592000, 719890500]
flag = ""
for _ in range(len(num1)):
flag += chr(num2[_] // num1[_])
print(flag)

最后需要爆破flag[6]

flag{e165421110ba03099a1c039337}


[SUCTF2019]SignIn

链接: https://buuoj.cn/challenges#[SUCTF2019]SignIn

ELF 64

IDA中 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
27
28
29
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char v4; // [rsp+0h] [rbp-4A0h]
char v5; // [rsp+10h] [rbp-490h]
char v6; // [rsp+20h] [rbp-480h]
char v7; // [rsp+30h] [rbp-470h]
char v8; // [rsp+40h] [rbp-460h]
char v9; // [rsp+B0h] [rbp-3F0h]
unsigned __int64 v10; // [rsp+498h] [rbp-8h]

v10 = __readfsqword(0x28u);
puts("[sign in]");
printf("[input your flag]: ", a2);
__isoc99_scanf("%99s", &v8);
sub_96A(&v8, (__int64)&v9);
__gmpz_init_set_str((__int64)&v7, (__int64)"ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35", 16LL);// c
__gmpz_init_set_str((__int64)&v6, (__int64)&v9, 16LL);// m
__gmpz_init_set_str(
(__int64)&v4,
(__int64)"103461035900816914121390101299049044413950405173712170434161686539878160984549",// n
10LL);
__gmpz_init_set_str((__int64)&v5, (__int64)"65537", 10LL);// e
__gmpz_powm((__int64)&v6, (__int64)&v6, (__int64)&v5, (__int64)&v4);// v6=v6**v5%v4
if ( (unsigned int)__gmpz_cmp(&v6, &v7) )
puts("GG!");
else
puts("TTTTTTTTTTql!");
return 0LL;
}

函数__gmpz_powm((__int64)&v6, (__int64)&v6, (__int64)&v5, (__int64)&v4)意为

v6 = (v6**v5)%v4

最后比较v6与v7

所以很明显就是RSA

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python3
from Crypto.Util.number import *
p = 282164587459512124844245113950593348271
q = 366669102002966856876605669837014229419
e = 65537
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
n = p * q
phi = (p - 1)*(q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)
print(flag)

flag{Pwn_@_hundred_years}


相册

链接: https://buuoj.cn/challenges#相册

Android

下载得到一个APk包, 提取class.dex文件转jar之后也没看到什么有价值的信息

提取libcore.so到IDA中看看

看到一段Base64字符串MTgyMTg0NjUxMjVAMTYzLmNvbQ==

解码之后为18218465125@163.com

即为flag

flag{18218465125@163.com}


[BJDCTF2020]easy

链接: https://buuoj.cn/challenges#[BJDCTF2020]easy

EXE 32

IDA中 _main 函数反编译结果如下

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl main(int argc, const char **argv, const char **envp)
{
time_t v4; // [esp+10h] [ebp-3F0h]
struct tm *v5; // [esp+3FCh] [ebp-4h]

__main();
time(&v4);
v5 = localtime(&v4);
puts("Can you find me?\n");
system("pause");
return 0;
}

没有得到关于flag的信息

继续查看其他函数

函数 _ques 有数据以及输出

修改一下反编译之后的代码

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
#define SHIDWORD(x)   (*((__int32*)&(x)+1))
#define LODWORD(x) (*((__int32*)&(x)))
#define HIDWORD(x) (*((__int32*)&(x)+1))
#include <stdio.h>

int main(void)
{
int v0;
int result;
int v2[50];
int v3[10] = {2147122737, 140540, 2286567993, 141956, 139457077, 262023, 2286043699, 143749, 2118271985, 143868};
int j;
__int64 v14;
int v15;
int v16;
int i;

for ( i = 0; i <= 4; ++i )
{
memset(v2, 0, sizeof(v2));
v16 = 0;
v15 = 0;
v0 = *(&v3[1] + 2 * i);
LODWORD(v14) = *(&v3[0] + 2 * i);
HIDWORD(v14) = v0;
while ( SHIDWORD(v14) > 0 || v14 >= 0 && (__int32)v14 )
{
v2[v16++] = ((SHIDWORD(v14) >> 31) ^ (((unsigned __int8)(SHIDWORD(v14) >> 31) ^ (unsigned __int8)v14) - (unsigned __int8)(SHIDWORD(v14) >> 31)) & 1) - (SHIDWORD(v14) >> 31);
v14 /= 2LL;
}
for ( j = 50; j >= 0; --j )
{
if ( v2[j] )
{
if ( v2[j] == 1 )
{
putchar(42);
++v15;
}
}
else
{
putchar(32);
++v15;
}
if ( !(v15 % 5) )
putchar(32);
}
result = putchar(10);
}
return 0;
}

运行即可得到flag

IDA Pro反编译代码类型转换参考

flag{HACKIT4FUN}


[ACTF新生赛2020]usualCrypt

链接: https://buuoj.cn/challenges#[ACTF新生赛2020]usualCrypt

EXE 32

IDA中 _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
27
28
29
30
31
32
33
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // esi
int result; // eax
int v5; // [esp+8h] [ebp-74h]
int v6; // [esp+Ch] [ebp-70h]
int v7; // [esp+10h] [ebp-6Ch]
__int16 v8; // [esp+14h] [ebp-68h]
char v9; // [esp+16h] [ebp-66h]
char v10; // [esp+18h] [ebp-64h]

sub_403CF8(&unk_40E140);
scanf(aS, &v10);
v5 = 0;
v6 = 0;
v7 = 0;
v8 = 0;
v9 = 0;
sub_401080((int)&v10, strlen(&v10), (int)&v5);
v3 = 0;
while ( *((_BYTE *)&v5 + v3) == byte_40E0E4[v3] )
{
if ( ++v3 > strlen((const char *)&v5) )
goto LABEL_6;
}
sub_403CF8(aError);
LABEL_6:
if ( v3 - 1 == strlen(byte_40E0E4) )
result = sub_403CF8(aAreYouHappyYes);
else
result = sub_403CF8(aAreYouHappyNo);
return result;
}

函数 sub_401080 对输入的内容进行变换

继续浏览信息可以看到两个字符串

1
2
char byte_40E0A0[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *byte_40E0AA = &byte_40E0A0[10];

两个字符串的关系大概是这样

很明显是在进行Base64编码的操作

但是在编码前有函数 sub_401000, 编码后有函数 sub_401030

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
signed int sub_401000()
{
signed int result; // eax
char v1; // cl

result = 6;
do
{
v1 = byte_40E0AA[result];
byte_40E0AA[result] = byte_40E0A0[result];
byte_40E0A0[result++] = v1;
}
while ( result < 15 );
return result;
}

这个函数的话大概就是在调换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
int __cdecl sub_401030(const char *a1)
{
__int64 v1; // rax
char v2; // al

v1 = 0i64;
if ( strlen(a1) != 0 )
{
do
{
v2 = a1[HIDWORD(v1)];
if ( v2 < 97 || v2 > 122 )
{
if ( v2 < 65 || v2 > 90 )
goto LABEL_9;
LOBYTE(v1) = v2 + 32;
}
else
{
LOBYTE(v1) = v2 - 32;
}
a1[HIDWORD(v1)] = v1;
LABEL_9:
LODWORD(v1) = 0;
++HIDWORD(v1);
}
while ( HIDWORD(v1) < strlen(a1) );
}
return v1;
}

大小写转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python3
import base64
cipher1 = "zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9"
cipher2 = cipher1.swapcase() # re_sub_401030
cipher3 = ""
table1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
table_lst = []
for _ in table1:
table_lst.append(_)
offset = 10
for i in range(6, 15): # re_sub_401000
tmp = table_lst[i+offset]
table_lst[i+offset] = table_lst[i]
table_lst[i] = tmp
table2 = "".join(table_lst)
for _ in cipher2:
cipher3 += table1[table2.index(_)]
flag = base64.b64decode(cipher3)
print(flag)

flag{bAse64_h2s_a_Surprise}


[MRCTF2020]Transform

链接: https://buuoj.cn/challenges#[MRCTF2020]Transform

EXE 64

IDA中 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
27
28
29
30
31
32
33
34
35
36
37
38
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rdx
__int64 v4; // rdx
char v6[104]; // [rsp+20h] [rbp-70h]
int j; // [rsp+88h] [rbp-8h]
int i; // [rsp+8Ch] [rbp-4h]

sub_402230(argc, argv, envp);
sub_40E640(argc, (__int64)argv, v3, (__int64)"Give me your code:\n");
sub_40E5F0(argc, (__int64)argv, (__int64)v6, (unsigned __int64)"%s");
if ( strlen(*(const char **)&argc) != 33 )
{
sub_40E640(argc, (__int64)argv, v4, (__int64)"Wrong!\n");
system(*(const char **)&argc);
exit(argc);
}
for ( i = 0; i <= 32; ++i )
{
byte_414040[i] = v6[dword_40F040[i]];
v4 = i;
byte_414040[i] ^= LOBYTE(dword_40F040[i]);
}
for ( j = 0; j <= 32; ++j )
{
v4 = j;
if ( byte_40F0E0[j] != byte_414040[j] )
{
sub_40E640(argc, (__int64)argv, j, (__int64)"Wrong!\n");
system(*(const char **)&argc);
exit(argc);
}
}
sub_40E640(argc, (__int64)argv, v4, (__int64)"Right!Good Job!\n");
sub_40E640(argc, (__int64)argv, (__int64)v6, (__int64)"Here is your flag: %s\n");
system(*(const char **)&argc);
return 0;
}

v6为输入的值, 即flag

先将flag字符串打乱顺序, 再进行异或处理

这里值得注意的一点为

  • dword_40F040[32] = 0x00000000

由于后续还有三个连续的0x00000000, 可能会误以为dword_40F040的长度只有31

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python3
_40F040 = [
0x09, 0x0A, 0x0F, 0x17, 0x07, 0x18, 0x0C, 0x06,
0x01, 0x10, 0x03, 0x11, 0x20, 0x1D, 0x0B, 0x1E,
0x1B, 0x16, 0x04, 0x0D, 0x13, 0x14, 0x15, 0x02,
0x19, 0x05, 0x1F, 0x08, 0x12, 0x1A, 0x1C, 0x0E,
0x00]
cipher = [
0x67, 0x79, 0x7B, 0x7F, 0x75, 0x2B, 0x3C, 0x52,
0x53, 0x79, 0x57, 0x5E, 0x5D, 0x42, 0x7B, 0x2D,
0x2A, 0x66, 0x42, 0x7E, 0x4C, 0x57, 0x79, 0x41,
0x6B, 0x7E, 0x65, 0x3C, 0x5C, 0x45, 0x6F, 0x62,
0x4D]
for _ in range(len(cipher)):
cipher[_] = cipher[_]^_40F040[_]
plain = [0 for _ in range(33)]
for _ in range(len(plain)):
plain[_40F040[_]] = chr(cipher[_])
flag = ''.join(plain)
print(flag)

flag{Tr4nsp0sltiON_Clph3r_1s_3z}


[WUSTCTF2020]level1

链接: https://buuoj.cn/challenges#[WUSTCTF2020]level1

ELF 64

IDA中 main 函数反编译结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl main(int argc, const char **argv, const char **envp)
{
FILE *stream; // ST08_8
signed int i; // [rsp+4h] [rbp-2Ch]
char ptr[24]; // [rsp+10h] [rbp-20h]
unsigned __int64 v7; // [rsp+28h] [rbp-8h]

v7 = __readfsqword(0x28u);
stream = fopen("flag", "r");
fread(ptr, 1uLL, 20uLL, stream);
fclose(stream);
for ( i = 1; i <= 19; ++i )
{
if ( i & 1 )
printf("%ld\n", (unsigned int)(ptr[i] << i));
else
printf("%ld\n", (unsigned int)(i * ptr[i]));
}
return 0;
}

没有给出flag[0]

所以解密时也需要填充一个flag[0], 以保证下标对齐

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
cipher = [" ", 198, 232, 816, 200, 1536, 300, 6144, 984, 51200, 570, 92160, 1200, 565248, 756, 1474560, 800, 6291456, 1782, 65536000]
for _ in range(1, 20):
if _ & 1:
cipher[_] = chr(cipher[_]>>_)
else:
cipher[_] = chr(cipher[_]//_)
flag = "".join(cipher)
print(flag)

flag{d9-dE6-20c}


[WUSTCTF2020]level2

链接: https://buuoj.cn/challenges#[WUSTCTF2020]level2

ELF 32

UPX脱壳即可用IDA在main函数中看到flag

flag{Just_upx_-d}

EOF