题目信息

题目信息

解题步骤

DIE分析

main函数

1
2
3
4
5
// attributes: thunk
int __cdecl main(int argc, const char **argv, const char **envp)
{
return main_0(argc, argv, envp);
}

追踪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
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t v3; // eax
const char *v4; // eax
size_t v5; // eax
char v7; // [esp+0h] [ebp-188h]
char v8; // [esp+0h] [ebp-188h]
signed int j; // [esp+DCh] [ebp-ACh]
int i; // [esp+E8h] [ebp-A0h]
signed int v11; // [esp+E8h] [ebp-A0h]
char Destination[108]; // [esp+F4h] [ebp-94h] BYREF
char Str[28]; // [esp+160h] [ebp-28h] BYREF
_BYTE v14[8]; // [esp+17Ch] [ebp-Ch] BYREF

for ( i = 0; i < 100; ++i )
{
if ( (unsigned int)i >= 0x64 )
j____report_rangecheckfailure();
Destination[i] = 0;
}
sub_41132F("please enter the flag:", v7); // 提示输入flag
sub_411375("%20s", (char)Str); // 输入20长度,保存到Str
v3 = j_strlen(Str); // Str的长度
v4 = (const char *)sub_4110BE(Str, v3, v14);
strncpy(Destination, v4, 0x28u);
v11 = j_strlen(Destination);
for ( j = 0; j < v11; ++j )
Destination[j] += j;
v5 = j_strlen(Destination);
if ( !strncmp(Destination, Str2, v5) )
sub_41132F("rigth flag!\n", v8);
else
sub_41132F("wrong flag!\n", v8);
return 0;
}

诶,有一个陌生的函数sub_4110BE,我们跟进一下看下。

看着非常像Base64

Base64编码表

1
Base64编码表:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="

接着分析整体的内容

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
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t v3; // eax
const char *v4; // eax
size_t v5; // eax
char v7; // [esp+0h] [ebp-188h]
char v8; // [esp+0h] [ebp-188h]
signed int j; // [esp+DCh] [ebp-ACh]
int i; // [esp+E8h] [ebp-A0h]
signed int v11; // [esp+E8h] [ebp-A0h]
char Destination[108]; // [esp+F4h] [ebp-94h] BYREF
char Str[28]; // [esp+160h] [ebp-28h] BYREF
_BYTE v14[8]; // [esp+17Ch] [ebp-Ch] BYREF

for ( i = 0; i < 100; ++i )
{
if ( (unsigned int)i >= 0x64 )
j____report_rangecheckfailure();
Destination[i] = 0;
}
sub_41132F("please enter the flag:", v7); // 提示输入flag
sub_411375("%20s", (char)Str); // 输入20长度,保存到Str
v3 = j_strlen(Str); // Str的长度
v4 = (const char *)sub_4110BE(Str, v3, v14); // Base64编码用户输入的内容,返回值 v4 很可能是加密后的字符串
strncpy(Destination, v4, 0x28u); // 将加密后的字符串拷贝到 Destination 中,最多拷贝 0x28 (40) 字节
v11 = j_strlen(Destination); // 获取 Destination 当前内容的长度(即加密后字符串的长度)
for ( j = 0; j < v11; ++j ) // 对 Destination 中的每个字符进行“简单加密”:每个字符加上其索引,例如:Destination[0] += 0; Destination[1] += 1; ...
Destination[j] += j;
v5 = j_strlen(Destination); // 再次获取 Destination 加密后的长度
if ( !strncmp(Destination, Str2, v5) ) // 将处理后的 Destination 与一个名为 Str2 的全局字符串进行比较
sub_41132F("rigth flag!\n", v8);
else
sub_41132F("wrong flag!\n", v8);
return 0;
}

我们接下来看下Str2的内容是什么

加密过程可以总结为:

1
flag → Base64编码 → 每个字符 + 索引值 → 加密结果

graph LR;
id1([flag])-->Base64编码-->markdown[每个字符 + 索引值] --> id2([加密结果]);

因此,解密过程为:

1
加密结果 → 每个字符 - 索引值 → Base64解码 → 原始flag
graph LR;
id1([加密结果])-->markdown[每个字符 - 索引值] -->Base64解码 -->id2([原始FLAG]);
1
2
3
4
5
6
7
8
import base64


encoded_str = 'e3nifIH9b_C@n@dH'
decoded_chars = ''.join(chr(ord(c) - i) for i, c in enumerate(encoded_str))
# Base64 解码
flag = base64.b64decode(decoded_chars).decode('utf-8')
print(flag)

flag{i_l0ve_you}