进入题目,先下载附件
将下载好的RE文件拖入ExeinfoPE查看,有无壳
“Diagnose” 一栏的信息 “NOT WIN EXE -o - ELF executable [64bit obj. Exe file - CPU: AMD x86” 可知,这是一个 ELF 格式的可执行文件(通常用于 Linux 系统),并非 Windows 下常见加壳对象格式。图中没有诸如 “Packer” 之类表明加壳工具的相关信息,也没有类似 “Overlay” (附加数据,壳可能存在于此区域) 的详细说明,所以无壳
“[64bit obj.” ,表明这是一个 64 位目标文件
拖入IDA中分析
看到main函数
双击main函数名称,会自动跳转到 main 函数的汇编代码界面,可以看到 main 函数对应的汇编指令
按F5,将汇编代码转换为伪代码
对上述代码进行简单的分析
是一个密码验证程序
读取用户输入的密码(最大长度255字节)
调用验证函数sub_4006FD检查密码合法性
根据验证结果输出提示信息
// __int64 表示返回值类型为 64 位整数,__fastcall 是一种调用约定,规定了参数传递的方式
// main 函数是程序的入口点,a1 通常代表命令行参数的数量,a2 是指向命令行参数字符串数组的指针,a3 是指向环境变量字符串数组的指针
__int64 __fastcall main(int a1, char **a2, char **a3)
{// 定义一个长度为 264 的字符数组 s,用于存储用户输入的密码// [rsp+0h] [rbp-110h] BYREF 是栈上的位置信息,BYREF 表示按引用传递char s[264]; // 定义一个 64 位无符号整数 v5,用于存储栈保护金丝雀值// [rsp+108h] [rbp-8h] 是栈上的位置信息unsigned __int64 v5; // 从 fs 段寄存器偏移 0x28 的位置读取栈保护金丝雀值并存储到 v5 中// 栈保护机制用于检测栈溢出攻击,函数返回时会检查该值是否被修改v5 = __readfsqword(0x28u);// 使用 printf 函数向标准输出打印提示信息,提示用户输入密码printf("Enter the password: ");// 使用 fgets 函数从标准输入(键盘)读取最多 255 个字符到字符数组 s 中// fgets 会读取换行符并将其包含在字符串中,直到达到最大长度或遇到文件结束符// 如果 fgets 返回 NULL,表示读取失败,此时函数返回 0 并结束程序if ( !fgets(s, 255, stdin) )return 0LL;// 调用 sub_4006FD 函数对用户输入的密码进行验证// (unsigned int) 是将 sub_4006FD 函数的返回值强制转换为无符号整数类型// 如果 sub_4006FD 函数返回值不为 0,表示密码验证失败if ( (unsigned int)sub_4006FD(s) ){// 使用 puts 函数向标准输出打印错误信息,表示密码不正确puts("Incorrect password!");// 函数返回 1 表示程序以错误状态结束return 1LL;}else{// 如果 sub_4006FD 函数返回值为 0,表示密码验证成功// 使用 puts 函数向标准输出打印成功信息puts("Nice!");// 函数返回 0 表示程序正常结束return 0LL;}
}
推测flag在约束条件中,双击sub_4006FD函数
进行简单的代码审计
1、初始化了三个加密字符串
v3[0] = "Dufhbmf"; // 长度7
v3[1] = "pG`imos"; // 长度7
v3[2] = "ewUglpt"; // 长度7
2、循环验证,对输入的每个字符进行运算验证(共12个字符)
for (i = 0; i <= 11; ++i) {// 计算规则:v3[i%3][2*(i/3)] - input[i] == 1if (*(char *)(v3[i % 3] + 2 * (i / 3)) - *(char *)(i + a1) != 1)return 1LL; // 验证失败
}
漏洞利用点
加密规则可逆,输入字符可通过数学逆运算得到
每个正确字符满足:
input_char = v3[i%3][2*(i//3)] - 1
方法一:字符位置映射法
按顺序拼接解密字符得到flag
Code_Talkers
方法二:脚本解密
用pycharm运行以下python代码
v3 = ["Dufhbmf", # v3[0]"pG`imos", # v3[1]"ewUglpt" # v3[2]
]flag = []
for i in range(12):# 计算对应的字符串和偏移量str_index = i % 3char_offset = 2 * (i // 3)# 获取加密字符encrypted_char = v3[str_index][char_offset]# 计算原始字符(加密字符ASCII减1)decrypted_char = chr(ord(encrypted_char) - 1)flag.append(decrypted_char)print("Flag:", ''.join(flag))
运行结果如下,最后得到flag
Code_Talkers