Reverse_2

感觉逆向越来越有意思了

[GWCTF 2019]xxor

链接: https://buuoj.cn/challenges#[GWCTF 2019]xxor

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
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
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
signed int i; // [rsp+8h] [rbp-68h]
signed int j; // [rsp+Ch] [rbp-64h]
__int64 v6; // [rsp+10h] [rbp-60h]
__int64 v7; // [rsp+18h] [rbp-58h]
__int64 v8; // [rsp+20h] [rbp-50h]
__int64 v9; // [rsp+28h] [rbp-48h]
__int64 v10; // [rsp+30h] [rbp-40h]
__int64 v11; // [rsp+40h] [rbp-30h]
__int64 v12; // [rsp+48h] [rbp-28h]
__int64 v13; // [rsp+50h] [rbp-20h]
__int64 v14; // [rsp+58h] [rbp-18h]
__int64 v15; // [rsp+60h] [rbp-10h]
unsigned __int64 v16; // [rsp+68h] [rbp-8h]

v16 = __readfsqword(0x28u);
puts("Let us play a game?");
puts("you have six chances to input");
puts("Come on!");
v6 = 0LL;
v7 = 0LL;
v8 = 0LL;
v9 = 0LL;
v10 = 0LL;
for ( i = 0; i <= 5; ++i )
{
printf("%s", "input: ", (unsigned int)i);
__isoc99_scanf("%d", (char *)&v6 + 4 * i);
}
v11 = 0LL;
v12 = 0LL;
v13 = 0LL;
v14 = 0LL;
v15 = 0LL;
for ( j = 0; j <= 4; j += 2 )
{
dword_601078 = *((_DWORD *)&v6 + j);
dword_60107C = *((_DWORD *)&v6 + j + 1);
sub_400686(&dword_601078, &unk_601060);
*((_DWORD *)&v11 + j) = dword_601078;
*((_DWORD *)&v11 + j + 1) = dword_60107C;
}
if ( (unsigned int)sub_400770(&v11) != 1 )
{
puts("NO NO NO~ ");
exit(0);
}
puts("Congratulation!\n");
puts("You seccess half\n");
puts("Do not forget to change input to hex and combine~\n");
puts("ByeBye");
return 0LL;
}

第一个for循环用于输入
第二个for循环用于加密
函数sub_400770用于校验加密结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
signed __int64 __fastcall sub_400770(_DWORD *a1)
{
signed __int64 result; // rax

if ( a1[2] - a1[3] != 2225223423LL || a1[3] + a1[4] != 4201428739LL || a1[2] - a1[4] != 1121399208LL )
{
puts("Wrong!");
result = 0LL;
}
else if ( *a1 != -548868226 || a1[5] != -2064448480 || a1[1] != 550153460 )
{
puts("Wrong!");
result = 0LL;
}
else
{
puts("good!");
result = 1LL;
}
return result;
}

可以根据已知条件还原出加密的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 __fastcall sub_400686(unsigned int *a1, _DWORD *a2)
{
__int64 result; // rax
unsigned int v3; // [rsp+1Ch] [rbp-24h]
unsigned int v4; // [rsp+20h] [rbp-20h]
int v5; // [rsp+24h] [rbp-1Ch]
unsigned int i; // [rsp+28h] [rbp-18h]

v3 = *a1;
v4 = a1[1];
v5 = 0;
for ( i = 0; i <= 0x3F; ++i )
{
v5 += 1166789954;
v3 += (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
v4 += (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
}
*a1 = v3;
result = v4;
a1[1] = v4;
return result;
}

这里unsigned int a1=&dword_601078
两者都是四字节的数据

1
2
v3 = *a1;
v4 = a1[1];

然而这两句代码就将dword_601078变成了一个数组
一开始有点云里雾里的

但是观察dword_601078text view

1
2
3
4
.bss:0000000000601078 dword_601078    dd ?                    ; DATA XREF: main+E6↑w
.bss:0000000000601078 ; main+103↑o ...
.bss:000000000060107C dword_60107C dd ? ; DATA XREF: main+F8↑w
.bss:000000000060107C ; main+122↑r

便可以理解dword_601078[1]就是dword_60107C

写python脚本时, 为了保证与C语言相同的运行效果, 变量在进行计算时都最好加一个&0xffffffff

网上看到有用ctypes写的, 但是感觉调用起来好麻烦

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
#!/usr/bin/env python3
import binascii
cipher = [
0xdf48ef7e,
0x20caacf4,
0,
0,
0,
0x84f30420,
]
x1 = 0x84A236FF
x2 = 0xFA6CB703
x3 = 0x42D731A8
cipher[2] = (x1+x2+x3)//2
cipher[3] = (cipher[2] - x1)&0xffffffff
cipher[4] = (cipher[2] - x3)&0xffffffff

for i in range(0, 5, 2):
tmp = (0x458BCD42*64)&0xffffffff
for _ in range(64):
cipher[i+1] = (cipher[i+1] - ((cipher[i] + tmp + 20) ^ ((cipher[i] << 6) + 3) ^ ((cipher[i] >> 9) + 4) ^ 0x10))&0xffffffff
cipher[i] = (cipher[i] - ((cipher[i+1] + tmp + 11) ^ ((cipher[i+1] << 6) + 2) ^ ((cipher[i+1] >> 9) + 2) ^ 0x20))&0xffffffff
tmp = (tmp-0x458BCD42)&0xffffffff
flag = ""
for _ in cipher:
flag += hex(_)[2:]
print(binascii.unhexlify(flag.encode()))

flag{re_is_great!}


[HDCTF2019]Maze

链接: https://buuoj.cn/challenges#[HDCTF2019]Maze

EXE 32

UPX脱壳

IDA打开后左侧函数列表中找不到 main 函数

在text view中可以看到_main函数的标识

1
2
jnz     short near ptr loc_40102E+1
call near ptr 0EC85D78Bh

但是这两行明显存在问题, 应该是花指令
第一行patch为nop(右键->Keypatch->Patcher)
第二行转为数据之后把db 0E8hpatch为nop

然后选中 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)
{
signed int i; // [esp+10h] [ebp-14h]
char v5[16]; // [esp+14h] [ebp-10h]

sub_401140((int)aGoThroughTheMa);
scanf(a14s, v5);
for ( i = 0; i <= 13; ++i )
{
switch ( v5[i] )
{
case 'a':
--dword_408078;
break;
case 'd':
++dword_408078;
break;
case 's':
--dword_40807C;
break;
case 'w':
++dword_40807C;
break;
default:
continue;
}
}
if ( dword_408078 != 5 || dword_40807C != -4 )
{
sub_401140((int)aTryAgain);
}
else
{
sub_401140((int)aCongratulation);
sub_401140((int)aHereIsTheFlagF, v5);
}
return 0;
}
  • dword_408078 = 7
  • dword_40807C = 0

接着在数据区浏览可以看到定义迷宫形状的数据

1
*******+********* ******    ****   ******* **F******    **************

因为字符串长度为70, 则可以考虑几种因数组合

1
2
3
4
5
6
7
8
9
10
*******+**->dword_408078+
******* **
**** **
** *****
** **F****
** ****
**********
|
v
dword_40807C+

那么可以得到flag

flag{ssaaasaassdddw}


[FlareOn4]IgniteMe

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

EXE 32

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void __noreturn start()
{
DWORD NumberOfBytesWritten; // [esp+0h] [ebp-4h]

NumberOfBytesWritten = 0;
hFile = GetStdHandle(0xFFFFFFF6);
dword_403074 = GetStdHandle(0xFFFFFFF5);
WriteFile(dword_403074, aG1v3M3T3hFl4g, 0x13u, &NumberOfBytesWritten, 0);
sub_4010F0(NumberOfBytesWritten);
if ( sub_401050() )
WriteFile(dword_403074, aG00dJ0b, 0xAu, &NumberOfBytesWritten, 0);
else
WriteFile(dword_403074, aN0tT00H0tRWe7r, 0x24u, &NumberOfBytesWritten, 0);
ExitProcess(0);
}

函数sub_4010F0功能应该为读取文件并将内容(flag)存放于byte_403078

函数sub_401050则实现了对于flag的加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
signed int sub_401050()
{
int v0; // ST04_4
int i; // [esp+4h] [ebp-8h]
unsigned int j; // [esp+4h] [ebp-8h]
char v4; // [esp+Bh] [ebp-1h]

v0 = sub_401020(byte_403078);
v4 = sub_401000();
for ( i = v0 - 1; i >= 0; --i )
{
byte_403180[i] = v4 ^ byte_403078[i];
v4 = byte_403078[i];
}
for ( j = 0; j < 0x27; ++j )
{
if ( byte_403180[j] != (unsigned __int8)byte_403000[j] )
return 0;
}
return 1;
}

密文结果存放于byte_403000

1
2
3
4
5
6
7
byte_403000 = [
0x0D, 0x26, 0x49, 0x45, 0x2A, 0x17, 0x78, 0x44,
0x2B, 0x6C, 0x5D, 0x5E, 0x45, 0x12, 0x2F, 0x17,
0x2B, 0x44, 0x6F, 0x6E, 0x56, 0x09, 0x5F, 0x45,
0x47, 0x73, 0x26, 0x0A, 0x0D, 0x13, 0x17, 0x48,
0x42, 0x01, 0x40, 0x4D, 0x0C, 0x02, 0x69
]
1
2
3
4
__int16 sub_401000()
{
return (unsigned __int16)__ROL4__(-2147024896, 4) >> 1;
}

v4的值来自于函数sub_401000

__ROL4__用于循环左移四位

手动计算可以得到结果0x00380004

由于返回值的数据类型是unsigned __int16, 则会返回低16位的数据

0x0004

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python3
cipher = [
0x0D, 0x26, 0x49, 0x45, 0x2A, 0x17, 0x78, 0x44,
0x2B, 0x6C, 0x5D, 0x5E, 0x45, 0x12, 0x2F, 0x17,
0x2B, 0x44, 0x6F, 0x6E, 0x56, 0x09, 0x5F, 0x45,
0x47, 0x73, 0x26, 0x0A, 0x0D, 0x13, 0x17, 0x48,
0x42, 0x01, 0x40, 0x4D, 0x0C, 0x02, 0x69
]
tmp = 0x04
_flag = []
for _ in cipher[::-1]:
plain = _^tmp
_flag.append(plain)
tmp = plain
_flag = _flag[::-1]
flag = ""
for _ in _flag:
flag += chr(_)
print(flag)

flag{R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com}


[BJDCTF2020]BJD hamburger competition

链接: https://buuoj.cn/challenges#[BJDCTF2020]BJD hamburger competition

.NET

使用dnSpy打开Assembly-CSharp.dll
在左侧程序集资源管理器中依次打开
Assembly-CSharp->-->ButtonSpawnFruit->Spawn()
可以看到如下代码

1
2
3
4
5
6
7
Init.secret ^= 127;
string str = Init.secret.ToString();
if (ButtonSpawnFruit.Sha1(str) == "DD01903921EA24941C26A48F2CEC24E0BB0E8CC7")
{
this.result = "BJDCTF{" + ButtonSpawnFruit.Md5(str) + "}";
Debug.Log(this.result);
}

其中有一个坑, 函数MD5的代码如下所示

1
2
3
4
5
6
7
8
9
10
11
public static string Md5(string str)
{
byte[] bytes = Encoding.UTF8.GetBytes(str);
byte[] array = MD5.Create().ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder();
foreach (byte b in array)
{
stringBuilder.Append(b.ToString("X2"));
}
return stringBuilder.ToString().Substring(0, 20);
}

返回的结果为MD5前20位

ToString("X2")将字符串转为大写

1
2
3
4
5
6
#!/usr/bin/env python3
import hashlib
for i in range(100000):
if hashlib.sha1(str(i).encode()).hexdigest().upper() == "DD01903921EA24941C26A48F2CEC24E0BB0E8CC7":
print("flag{"+hashlib.md5(str(i).encode()).hexdigest()[:20].upper()+"}")
break

flag{B8C37E33DEFDE51CF91E}


[MRCTF2020]Xor

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

EXE 32

IDA中不能直接找到关于flag加密的函数

根据程序所输出的字符串Give Me Your Flag String:

在IDA中进行搜索(Search->sequence of bytes)

找到对应的数据部分, 然后找到调用该数据的函数

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
int sub_401090()
{
unsigned int v0; // eax

sub_401020((int)"Give Me Your Flag String:\n");
sub_401050((int)"%s", byte_4212C0, 100);
if ( strlen(byte_4212C0) != 27 )
{
LABEL_6:
sub_401020((int)"Wrong!\n");
sub_404B7E("pause");
sub_40355F(0);
__debugbreak();
JUMPOUT(*(_DWORD *)__security_check_cookie);
}
v0 = 0;
do
{
if ( ((unsigned __int8)v0 ^ (unsigned __int8)byte_4212C0[v0]) != byte_41EA08[v0] )
goto LABEL_6;
++v0;
}
while ( v0 < 0x1B );
sub_401020((int)"Right!\n");
sub_404B7E("pause");
return 0;
}
1
2
3
4
5
6
#!/usr/bin/env python3
cipher = "MSAWB~FXZ:J:`tQJ\"N@ bpdd}8g"
flag = ""
for _ in range(len(cipher)):
flag += chr(_^ord(cipher[_]))
print(flag)

flag{@_R3@1ly_E2_R3verse!}


[MRCTF2020]hello_world_go

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

ELF 64

IDA中 main_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
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
__int64 __fastcall main_main(__int64 a1, __int64 a2)
{
__int64 v2; // r8
__int64 v3; // r9
__int64 v4; // r8
__int64 v5; // r9
__int64 v6; // rdx
__int64 v7; // r8
__int64 v8; // rcx
__int64 v9; // rdx
__int64 v10; // r9
signed __int64 v11; // rax
__int64 result; // rax
__int64 v13; // ST58_8
__int64 *v14; // [rsp+8h] [rbp-A8h]
char v15; // [rsp+18h] [rbp-98h]
__int64 *v16; // [rsp+60h] [rbp-50h]
__int128 v17; // [rsp+68h] [rbp-48h]
__int128 v18; // [rsp+78h] [rbp-38h]
__int128 v19; // [rsp+88h] [rbp-28h]
__int128 v20; // [rsp+98h] [rbp-18h]

if ( (unsigned __int64)&v18 + 8 <= *(_QWORD *)(__readfsqword(0xFFFFFFF8) + 16) )
runtime_morestack_noctxt();
runtime_newobject(a1, a2);
v16 = v14;
*(_QWORD *)&v20 = &unk_4AC9C0;
*((_QWORD *)&v20 + 1) = &off_4EA530;
fmt_Fprint(a1, a2, (__int64)&v20, (__int64)&unk_4AC9C0, v2, v3, (__int64)&go_itab__os_File_io_Writer, os_Stdout);
*(_QWORD *)&v19 = &unk_4A96A0;
*((_QWORD *)&v19 + 1) = v16;
fmt_Fscanf(
a1,
a2,
(__int64)&go_itab__os_File_io_Reader,
(__int64)&v19,
v4,
v5,
(__int64)&go_itab__os_File_io_Reader,
os_Stdin,
(__int64)&unk_4D07C9,
2LL);
v8 = v16[1];
if ( v8 != 24 )
goto LABEL_3;
v13 = *v16;
runtime_memequal(a1, a2, v6, (unsigned __int64)&unk_4D3C58);
if ( !v15 )
{
v8 = 24LL;
LABEL_3:
runtime_cmpstring(a1, a2, (__int64)&unk_4D3C58, v8, v7);
if ( (signed __int64)&v19 >= 0 )
v11 = 1LL;
else
v11 = -1LL;
goto LABEL_5;
}
v11 = 0LL;
LABEL_5:
if ( v11 )
{
*(_QWORD *)&v17 = &unk_4AC9C0;
*((_QWORD *)&v17 + 1) = &off_4EA550;
result = fmt_Fprintln(
a1,
a2,
v9,
(__int64)&go_itab__os_File_io_Writer,
v7,
v10,
(__int64)&go_itab__os_File_io_Writer,
os_Stdout);
}
else
{
*(_QWORD *)&v18 = &unk_4AC9C0;
*((_QWORD *)&v18 + 1) = &off_4EA540;
result = fmt_Fprintln(
a1,
a2,
v9,
(__int64)&go_itab__os_File_io_Writer,
v7,
v10,
(__int64)&go_itab__os_File_io_Writer,
os_Stdout);
}
return result;
}

函数runtime_cmpstring看着有些问题

跟进unk_4D3C58得到flag

flag{hello_world_gogogo}


[WUSTCTF2020]level3

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

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // ST0F_1
char *v4; // rax
char v6; // [rsp+10h] [rbp-40h]
unsigned __int64 v7; // [rsp+48h] [rbp-8h]

v7 = __readfsqword(0x28u);
printf("Try my base64 program?.....\n>", argv, envp);
__isoc99_scanf("%20s", &v6);
v3 = time(0LL);
srand(v3);
if ( rand() & 1 )
{
v4 = base64_encode(&v6);
puts(v4);
puts("Is there something wrong?");
}
else
{
puts("Sorry I think it's not prepared yet....");
puts("And I get a strange string from my program which is different from the standard base64:");
puts("d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD==");
puts("What's wrong??");
}
return 0;
}

看到一段Base64编码, 但是不能解码得到flag

跟进函数base64_encode

没有看到明显的加密函数或替换表函数, 逆向Base64编码的具体步骤有些麻烦, 这里采用了曲线救国的方案

1
2
3
4
5
6
7
8
./attachment 
Try my base64 program?.....
>000
HQTw
Is there something wrong?
------
echo -n "000" | base64
MDAw

通过这一步的操作我们可以得到三个字符的替换关系, 那么只要更改输入内容并且重复次数足够多, 就能够fuzz出完整的替换关系

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
#!/usr/bin/env python3
from pwn import *
import base64
import re
import string
dic = string.ascii_lowercase+string.ascii_uppercase+string.digits
length = len(dic)
string1 = ""
string2 = ""
for _ in dic:
test = _*3
test_b64 = base64.b64encode(test.encode()).decode()
lst_res = []
while lst_res == []:
p = process("./attachment")
p.recv()
p.sendline(test)
res = p.recv().decode()
lst_res = re.findall(">(.*?)\nIs there something wrong?", res)
p.close()
res_b64 = lst_res[0]
for _ in range(len(res_b64)):
if res_b64[_] != test_b64[_] and test_b64[_] not in string1 and res_b64[_] not in string2 :
string1 += test_b64[_]
string2 += res_b64[_]
cipher = "d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD=="
flag = ""
for _ in cipher:
if _ in string2:
flag += string1[string2.index(_)]
else:
flag += _
print(base64.b64decode(flag.encode()))

flag{Base64_is_the_start_of_reverse}


[WUSTCTF2020]Cr0ssfun

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

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [rsp+0h] [rbp-30h]

puts(" _ _ _ _ _____ _____ _____ ");
puts("| | | | | | / ___|_ _| / ___| ");
puts("| | | | | | \\ `--. | | \\ `--. ___ ___ ");
puts("| |/\\| | | | |`--. \\ | | `--. \\/ _ \\/ __|");
puts("\\ /\\ / |_| /\\__/ / | | /\\__/ / __/ (__ ");
puts(" \\/ \\/ \\___/\\____/ \\_/ \\____/ \\___|\\___|");
while ( 1 )
{
puts("Input the flag");
__isoc99_scanf("%s", &v4);
if ( (unsigned int)check(&v4) == 1 )
break;
puts("0ops, your flag seems fake.");
puts("==============================");
rewind(_bss_start);
}
puts("Your flag is correct, go and submit it!");
return 0;
}

跟进函数Check以及之后的函数即可得到flag

flag{cpp_@nd_r3verse_@re_fun}


[[FlareOn6]Overlong

链接: https://buuoj.cn/challenges#[FlareOn6]Overlong

EXE 32

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

1
2
3
4
5
6
7
8
9
10
11
12
int __stdcall start(int a1, int a2, int a3, int a4)
{
int v4; // eax
CHAR Text[128]; // [esp+0h] [ebp-84h]
int v7; // [esp+80h] [ebp-4h]

v4 = sub_401160(Text, &unk_402008, 28);
v7 = v4;
Text[v4] = 0;
MessageBoxA(0, Text, Caption, 0);
return 0;
}

unk_402008的长度为175, 即0xAF

但是所限定的长度为28

所以flag应该就在后面的内容之中

静调看代码的话过于复杂, 这题应该用动调

一开始打算把push 1ChPatch成push AFh

但是发现要在IDA中改成AF的话会强制转成dword, 然后多余的三个'\x00'字节会占用掉后面一条汇编代码的空间

用OD调试, 在直接修改汇编代码时同样出现了与IDA中相同的问题

所以可以在数据被PUSH入栈之后再对栈内的数据进行修改

当然你完全可以拿一个十六进制编辑器直接修改字节码

flag{I_a_M_t_h_e_e_n_C_o_D_i_n_g@flare-on.com}


crackMe

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

EXE 32

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

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
int wmain()
{
FILE *v0; // eax
FILE *v1; // eax
char v3; // [esp+3h] [ebp-405h]
char v4; // [esp+4h] [ebp-404h] BYREF
char v5[255]; // [esp+5h] [ebp-403h] BYREF
char Format; // [esp+104h] [ebp-304h] BYREF
char v7[255]; // [esp+105h] [ebp-303h] BYREF
char v8; // [esp+204h] [ebp-204h] BYREF
char v9[255]; // [esp+205h] [ebp-203h] BYREF
char v10; // [esp+304h] [ebp-104h] BYREF
char v11[255]; // [esp+305h] [ebp-103h] BYREF

printf("Come one! Crack Me~~~\n");
v10 = 0;
memset(v11, 0, sizeof(v11));
v8 = 0;
memset(v9, 0, sizeof(v9));
while ( 1 )
{
do
{
do
{
printf("user(6-16 letters or numbers):");
scanf("%s", &v10);
v0 = (FILE *)sub_4024BE();
fflush(v0);
}
while ( !(unsigned __int8)sub_401000(&v10) );
printf("password(6-16 letters or numbers):");
scanf("%s", &v8);
v1 = (FILE *)sub_4024BE();
fflush(v1);
}
while ( !(unsigned __int8)sub_401000(&v8) );
sub_401090(&v10);
Format = 0;
memset(v7, 0, sizeof(v7));
v4 = 0;
memset(v5, 0, sizeof(v5));
v3 = ((int (__cdecl *)(char *, char *))loc_4011A0)(&Format, &v4);
if ( sub_401830((int)&v10, &v8) )
{
if ( v3 )
break;
}
printf(&v4);
}
printf(&Format);
return 0;
}
  • 函数sub_401090用于通过输入的username, 来生成byte_416050
  • 代码块loc_4011A0被插入了花指令
1
2
.text:004011EA                 jbe     near ptr loc_4011EA+2
.text:004011F0 aaa

nop掉这两行就能转为函数了

  • 函数sub_401830用于校验所输入的用户名与密码是否正确
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
bool __cdecl sub_401830(int a1, const char *a2)
{
int v3; // [esp+18h] [ebp-22Ch]
int v4; // [esp+1Ch] [ebp-228h]
int v5; // [esp+28h] [ebp-21Ch]
unsigned int v6; // [esp+30h] [ebp-214h]
char v7; // [esp+36h] [ebp-20Eh]
char v8; // [esp+37h] [ebp-20Dh]
char v9; // [esp+38h] [ebp-20Ch]
unsigned __int8 v10; // [esp+39h] [ebp-20Bh]
unsigned __int8 v11; // [esp+3Ah] [ebp-20Ah]
char v12; // [esp+3Bh] [ebp-209h]
int v13; // [esp+3Ch] [ebp-208h] BYREF
char v14; // [esp+40h] [ebp-204h] BYREF
char v15[255]; // [esp+41h] [ebp-203h] BYREF
char v16; // [esp+140h] [ebp-104h] BYREF
char v17[255]; // [esp+141h] [ebp-103h] BYREF

v4 = 0;
v5 = 0;
v11 = 0;
v10 = 0;
v16 = 0;
memset(v17, 0, sizeof(v17));
v14 = 0;
memset(v15, 0, sizeof(v15));
v9 = 0;
v6 = 0;
v3 = 0;
while ( v6 < strlen(a2) )
{
if ( isdigit(a2[v6]) )
{
v8 = a2[v6] - 48; }
else if ( isxdigit(a2[v6]) )
{
if ( *((_DWORD *)NtCurrentPeb()->SubSystemData + 3) != 2 )
a2[v6] = 34;
v8 = (a2[v6] | 0x20) - 87;
}
else
{
v8 = ((a2[v6] | 0x20) - 97) % 6 + 10;
}
__rdtsc();
__rdtsc();
v9 = v8 + 16 * v9;
if ( !((int)(v6 + 1) % 2) )
{
*(&v14 + v3++) = v9;
v9 = 0;
}
++v6;
}
while ( v5 < 8 )
{
v10 += byte_416050[++v11];
v12 = byte_416050[v11];
v7 = byte_416050[v10];
byte_416050[v10] = v12;
byte_416050[v11] = v7;
if ( ((int)NtCurrentPeb()->UnicodeCaseTableData & 0x70) != 0 )
v12 = v10 + v11;
*(&v16 + v5) = byte_416050[(unsigned __int8)(v7 + v12)] ^ *(&v14 + v4);
if ( (unsigned __int8)*(_DWORD *)&NtCurrentPeb()->BeingDebugged )
{
v10 = 0xAD;
v11 = 43;
}
sub_401710(&v16, a1, v5++);
v4 = v5;
if ( v5 >= (unsigned int)(&v14 + strlen(&v14) + 1 - v15) )
v4 = 0;
}
v13 = 0;
sub_401470(&v16, &v13);
return v13 == 0xAB94;
}

这个函数使用了PEB来进行反调试, 具体情况可以看这个文章

Reverse_PEB

第一部分的while循环用于将密码转为十六进制字符串得到v14

第二部分的while循环用于加密

加密结果v16需要经过函数sub_401470的校验, 要求的v16="dbappsec"

*(&v16 + v5) = byte_416050[(unsigned __int8)(v7 + v12)] ^ *(&v14 + v4);

v16已知, 只需要得到byte_416050, 但是用于加密的byte_416050会在加密之前进行一系列的操作

可以使用动调的方法, 得到真正用于加密的数据

1
.text:00401B3E                  xor     eax, ecx

Debugger中在这条语句下断点, ECX即为所需的数据

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
import hashlib
_416050 = [0x2A, 0xD7, 0x92, 0xE9, 0x53, 0xE2, 0xE4, 0xCD]
v17 = "dbappsec"
passwd = ""
for _ in range(len(v17)):
passwd += hex(ord(v17[_])^_416050[_])[2:]
flag = "flag{" + hashlib.md5(passwd.encode()).hexdigest() + "}"
print(flag)

flag{43097184c2f63f7bcabdadf21b693c8e}


[ACTF新生赛2020]Oruga

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

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
30
31
32
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 result; // rax
int i; // [rsp+0h] [rbp-40h]
char s1[6]; // [rsp+4h] [rbp-3Ch] BYREF
char s2[6]; // [rsp+Ah] [rbp-36h] BYREF
char s[40]; // [rsp+10h] [rbp-30h] BYREF
unsigned __int64 v8; // [rsp+38h] [rbp-8h]

v8 = __readfsqword(40u);
memset(s, 0, 25uLL);
printf("Tell me the flag:");
scanf("%s", s);
strcpy(s2, "actf{");
for ( i = 0; i <= 4; ++i )
s1[i] = s[i];
s1[5] = 0;
if ( !strcmp(s1, s2) )
{
if ( sub_78A((__int64)s) )
printf("That's True Flag!");
else
printf("don't stop trying...");
result = 0LL;
}
else
{
printf("Format false!");
result = 0LL;
}
return result;
}

函数sub_78A用于校验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
_BOOL8 __fastcall sub_78A(__int64 a1)
{
int v2; // [rsp+Ch] [rbp-Ch]
int v3; // [rsp+10h] [rbp-8h]
int v4; // [rsp+14h] [rbp-4h]

v2 = 0;
v3 = 5;
v4 = 0;
while ( byte_201020[v2] != 0x21 )
{
v2 -= v4;
if ( *(_BYTE *)(v3 + a1) != 'W' || v4 == -16 )
{
if ( *(_BYTE *)(v3 + a1) != 'E' || v4 == 1 )
{
if ( *(_BYTE *)(v3 + a1) != 'M' || v4 == 16 )
{
if ( *(_BYTE *)(v3 + a1) != 'J' || v4 == -1 )
return 0LL;
v4 = -1;
}
else
{
v4 = 16;
}
}
else
{
v4 = 1;
}
}
else
{
v4 = -16;
}
++v3;
while ( !byte_201020[v2] )
{
if ( v4 == -1 && (v2 & 0xF) == 0 )
return 0LL;
if ( v4 == 1 && v2 % 16 == 15 )
return 0LL;
if ( v4 == 16 && (unsigned int)(v2 - 240) <= 15 )
return 0LL;
if ( v4 == -16 && (unsigned int)(v2 + 15) <= 30 )
return 0LL;
v2 += v4;
}
}
return *(_BYTE *)(v3 + a1) == '}';
}

byte_201020如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
_416050 = [
0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x23, 0x23, 0x23,
0x00, 0x00, 0x00, 0x23, 0x23, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x4C, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x45,
0x00, 0x00, 0x00, 0x30, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x45,
0x54, 0x54, 0x54, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
0x00, 0x54, 0x00, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
0x00, 0x54, 0x00, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x21, 0x00, 0x00, 0x00, 0x45, 0x45]

结合上面的代码可以知道是个迷宫题

特别之处在于会按照给定方向一直走, 直到遇到非0数据

flag{MEWEMEWJMEWJM}


[FlareOn3]Challenge1

链接: https://buuoj.cn/challenges#[FlareOn3]Challenge1

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Buffer[128]; // [esp+0h] [ebp-94h] BYREF
char *Str1; // [esp+80h] [ebp-14h]
char *Str2; // [esp+84h] [ebp-10h]
HANDLE v7; // [esp+88h] [ebp-Ch]
HANDLE hFile; // [esp+8Ch] [ebp-8h]
DWORD NumberOfBytesWritten; // [esp+90h] [ebp-4h] BYREF

hFile = GetStdHandle(0xFFFFFFF5);
v7 = GetStdHandle(0xFFFFFFF6);
Str2 = "x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q";
WriteFile(hFile, "Enter password:\r\n", 0x12u, &NumberOfBytesWritten, 0);
ReadFile(v7, Buffer, 128u, &NumberOfBytesWritten, 0);
Str1 = (char *)sub_401260(Buffer, NumberOfBytesWritten - 2);
if ( !strcmp(Str1, Str2) )
WriteFile(hFile, "Correct!\r\n", 0xBu, &NumberOfBytesWritten, 0);
else
WriteFile(hFile, "Wrong password\r\n", 0x11u, &NumberOfBytesWritten, 0);
return 0;
}

跟进函数sub_401260可以看到一个Base64表

Base64替换

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
import base64
table1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
table2 = "ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/"
cipher = "x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q"
_flag = ""
for _ in cipher:
_flag += table1[table2.index(_)]
flag = base64.b64decode(_flag)
print(flag)

flag{sh00ting_phish_in_a_barrel@flare-on.com}


firmware

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

Firmware

1
2
3
4
5
6
7
8
9
10
11
binwalk 51475f91-7b90-41dd-81a3-8b82df4f29d0.bin 

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 TP-Link firmware header, firmware version: 1.-20432.3, image version: "", product ID: 0x0, product version: 155254791, kernel load address: 0x0, kernel entry point: 0x80002000, kernel offset: 4063744, kernel length: 512, rootfs offset: 772784, rootfs length: 1048576, bootloader offset: 2883584, bootloader length: 0
69424 0x10F30 Certificate in DER format (x509 v3), header length: 4, sequence length: 64
94080 0x16F80 U-Boot version string, "U-Boot 1.1.4 (Aug 26 2013 - 09:07:51)"
94256 0x17030 CRC32 polynomial table, big endian
131584 0x20200 TP-Link firmware header, firmware version: 0.0.3, image version: "", product ID: 0x0, product version: 155254791, kernel load address: 0x0, kernel entry point: 0x80002000, kernel offset: 3932160, kernel length: 512, rootfs offset: 772784, rootfs length: 1048576, bootloader offset: 2883584, bootloader length: 00
132096 0x20400 LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 2203728 bytes
1180160 0x120200 Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 2774624 bytes, 519 inodes, blocksize: 131072 bytes, created: 2015-04-13 09:35:04

题目中所提到的Backdoor应该就在Squashfs filesystem

binwalk分离文件, 但是unsquashfs命令不能解压缩这个文件系统

需要使用firmware-mod-kit

https://github.com/rampageX/firmware-mod-kit/

用g++10编译源码的时候有点问题, 需要修改下源码

  1. mksquashfs.c中某些函数或变量没有加static造成的重复定义问题
  2. 某部分代码少包含了<sys/sysmacros.h>
1
./unsquashfs_all.sh 120200.squashfs

在tmp中找到backdoor

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

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
bool initConnection()
{
char *v0; // r0
char s[512]; // [sp+4h] [bp-208h] BYREF
int v3; // [sp+204h] [bp-8h]

memset(s, 0, sizeof(s));
if ( mainCommSock )
{
close(mainCommSock);
mainCommSock = 0;
}
if ( currentServer )
++currentServer;
else
currentServer = 0;
strcpy(s, (&commServer)[currentServer]);
v3 = 36667;
if ( strchr(s, ':') )
{
v0 = strchr(s, ':');
v3 = atoi(v0 + 1);
*strchr(s, 58) = 0;
}
mainCommSock = socket(2, 1, 0);
return connectTimeout(mainCommSock, (int)s, v3, 30) == 0;
}

可以得到C2

1
2
echo -n "echo.byethost51.com:36667" | md5sum
33a422c45d551ac6e4756f59812a954b

flag{33a422c45d551ac6e4756f59812a954b}


[Zer0pts2020]easy strcmp

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

ELF 64

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__int64 __fastcall main(int a1, char **a2, char **a3)
{
if ( a1 > 1 )
{
if ( !strcmp(a2[1], byte_8E0) )
puts("Correct!");
else
puts("Wrong!");
}
else
{
printf("Usage: %s <FLAG>\n", *a2);
}
return 0LL;
}

看到一个可疑的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
__int64 __fastcall sub_6EA(__int64 a1, __int64 a2)
{
int i; // [rsp+18h] [rbp-8h]
int v4; // [rsp+18h] [rbp-8h]
int j; // [rsp+1Ch] [rbp-4h]

for ( i = 0; *(_BYTE *)(i + a1); ++i )
;
v4 = (i >> 3) + 1;
for ( j = 0; j < v4; ++j )
*(_QWORD *)(8 * j + a1) -= qword_201060[j];
return qword_201090(a1, a2);
}

虽然main函数中没有调用这个函数, 在IDA中在这个函数下断点, 可以看到输入的内容被进行运算, 大概是hook

1
qword_201060 = [0x0, 0x410A4335494A0942, 0x0B0EF2F50BE619F0, 0x4F0A3A064A35282B,0x0]

IDA中qword_201060所展示出的数据为大端
而字符串"zer0pts{********CENSORED********}"为小端
所以需要在计算之前要先转为大端

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python3
from Crypto.Util.number import *
_201060 = [0x410A4335494A0942, 0x0B0EF2F50BE619F0, 0x4F0A3A064A35282B]
cipher = "********CENSORED********"
flag = "flag{"
for i in range(3):
c = cipher[8*i:8*i+8].encode()[::-1]
plain = bytes_to_long(c)
flag += long_to_bytes(plain + _201060[i]).decode()[::-1]
flag += "}"
print(flag)

flag{l3ts_m4k3_4_DETOUR_t0d4y}


[ACTF新生赛2020]Universe_final_answer

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

ELF 64

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__int64 __fastcall main(int a1, char **a2, char **a3)
{
char v4[32]; // [rsp+0h] [rbp-A8h] BYREF
char v5[104]; // [rsp+20h] [rbp-88h] BYREF
unsigned __int64 v6; // [rsp+88h] [rbp-20h]

v6 = __readfsqword(0x28u);
__printf_chk(1LL, (__int64)"Please give me the key string:", (__int64)a3);
scanf("%s", v5);
if ( sub_860(v5) )
{
sub_C50(v5, v4);
__printf_chk(1LL, (__int64)"Judgement pass! flag is actf{%s_%s}\n", (__int64)v5);
}
else
{
puts("False key!");
}
return 0LL;
}

跟进sub_860

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
bool __fastcall sub_860(char *a1)
{
int b1; // ecx
int b0; // esi
int b2; // edx
int b3; // er9
int b4; // er11
int b6; // ebp
int b5; // ebx
int b7; // er8
int b8; // er10
bool result; // al
int b9; // [rsp+0h] [rbp-38h]

b1 = a1[1];
b0 = *a1;
b2 = a1[2];
b3 = a1[3];
b4 = a1[4];
b6 = a1[6];
b5 = a1[5];
b7 = a1[7];
b8 = a1[8];
result = 0;
if ( -85 * b8 + 58 * b7 + 97 * b6 + b5 + -45 * b4 + 84 * b3 + 95 * b0 - 20 * b1 + 12 * b2 == 12613 )
{
b9 = a1[9];
if ( 30 * b9 + -70 * b8 + -122 * b6 + -81 * b5 + -66 * b4 + -115 * b3 + -41 * b2 + -86 * b1 - 15 * b0 - 30 * b7 == -54400
&& -103 * b9 + 120 * b7 + 108 * b5 + 48 * b3 + -89 * b2 + 78 * b1 - 41 * b0 + 31 * b4 - (b6 << 6) - 120 * b8 == -10283
&& 71 * b6 + (b5 << 7) + 99 * b4 + -111 * b2 + 85 * b1 + 79 * b0 - 30 * b3 - 119 * b7 + 48 * b8 - 16 * b9 == 22855
&& 5 * b9 + 23 * b8 + 122 * b7 + -19 * b6 + 99 * b5 + -117 * b4 + -69 * b2 + 22 * b1 - 98 * b0 + 10 * b3 == -2944
&& -54 * b9 + -23 * b7 + -82 * b2 + -85 * b0 + 124 * b1 - 11 * b3 - 8 * b4 - 60 * b5 + 95 * b6 + 100 * b8 == -2222
&& -83 * b9 + -111 * b5 + -57 * b0 + 41 * b1 + 73 * b2 - 18 * b3 + 26 * b4 + 16 * b6 + 77 * b7 - 63 * b8 == -13258
&& 81 * b9 + -48 * b8 + 66 * b7 + -104 * b6 + -121 * b5 + 95 * b4 + 85 * b3 + 60 * b2 + -85 * b0 + 80 * b1 == -1559
&& 101 * b9 + -85 * b8 + 7 * b6 + 117 * b5 + -83 * b4 + -101 * b3 + 90 * b2 + -28 * b1 + 18 * b0 - b7 == 6308 )
{
result = 99 * b9 + -28 * b8 + 5 * b7 + 93 * b6 + -18 * b5 + -127 * b4 + 6 * b3 + -9 * b2 + -93 * b1 + 58 * b0 == -1697;
}
}
return result;
}

sage解线性方程即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3
b = Matrix([[12613], [-54400], [-10283], [22855], [-2944], [-2222], [-13258], [-1559], [6308], [-1697]])
x = Matrix([
[95, -20, 12, 84, -45, 1, 97, 58, -85, 0],
[-15, -86, -41, -115, -66, -81, -122, -30, -70, 30],
[-41, 78, -89, 48, 31, 108, -64, 120, -120, -103],
[79, 85, -111, -30, 99, 128, 71, -119, 48, -16],
[-98, 22, -69, 10, -117, 99, -19, 122, 23, 5],
[-85, 124, -82, -11, -8, -60, 95, -23, 100, -54],
[-57, 41, 73, -18, 26, -111, 16, 77, -63, -83],
[-85, 80, 60, 85, 95, -121, -104, 66, -48, 81],
[18, -28, 90, -101, -83, 117, 7, -1, -85, 101],
[58, -93, -9, 6, -127, -18, 93, 5, -28, 99,]]).solve_right(b)
key = ""
for _ in x:
key += chr(_[0])
print(key)

得到key="F0uRTy_7w@", 在程序中输入key即可得到flag

flag{F0uRTy_7w@_42}


[UTCTF2020]basic-re

链接: https://buuoj.cn/challenges#[UTCTF2020]basic-re

ELF 64

数据部分即可看到flag

flag{str1ngs_1s_y0ur_fr13nd}

EOF