我有一个正在处理的 ELF 可执行文件(从之前的 CTF 比赛中获得)。可执行文件只要求输入密码,然后打印出“congrats”。
代码片段和我的注释很长,所以我将它们包含在单独的 HTML 链接中。
//让你大致了解这个程序在 C 中做了什么。
int main(int argc, char ** argv)
{
int32_t 结果;// 成功值
如果(argc > 1)
{
设置(); //分配一个整型数组(g1)
int32_t v1 = 0; //柜台
而(真)
{
char v2 = *(char *) (*(int32_t *) ((int32_t)argv + 4) + v1);
int32_t v3 = *(int32_t *) (4 * v1 + (int32_t) & g1);
int32_t v4 = v1 + 1; //在g1数组中的索引
如果(检查((int32_t *)v3,(int32_t)v2)!= 0)
{
puts("不");
返回-1;
}
if (v4 >= 31) //当我们到达数组中的最后一个索引时
{
休息;
}
v1 = v4;
}
puts("恭喜!");
结果 = 0;
}
别的
{
puts("用法./smoothie");
结果 = -1;
}
返回结果;
}
我尝试使用 GDB 调试程序和 IDA 来理解控制流。我的推论最终有 3 件事:
- setup() 生成某种整数数组
- check(int32_t * array, int * array) 被调用 31 次以确认我们的“密码”,如可能的 while 循环所示
- 在 check(...) 内部,它遍历每个 malloc 的数组[5] 并确认我们密码的每个“字符”。
这是 IDA 的 check() 控制流程图(简单 - 3 部分):

这是 check() 的控制流程图,点击放大:
大多数 check() 比较 * (array) 的上半部分和 * (array + 8) 的下半部分加上 passwordIndex 比较。
在这个程序的main(int argc, char ** argv)中,有一个while循环需要执行31次(密码可能是31个字符)。如果 check() 返回 1,while 循环将退出。
我认为中间部分进行了一些计算(add、sub、cdq 和 idiv、imul 和 xor),这可能有助于了解作为密码传递的内容。
请指导我朝着正确的方向前进(如果可以,请提供提示)。自己调试程序可能会使我的问题更清楚。
假铅
- 在 check() 中,我假设第一组检查“计算”了我的输入 ascii 应该匹配的正确数字(例如计算 90,因此 index[i] 应该等于 'Z' ~ 90)。
- 在检查的后半部分,它使用 * (array + 8),这意味着它使用数组的第三个数字进行 101, 142, ... , 数字比较。我们可以将 * (array + 8) 的解引用值更改为计算出的数字 (90) 以进行最终比较。
- 一旦我们到达最后的比较,它会将我们的输入与第一组检查中计算出的数字进行比较,因此 90 == 90。由于它们相等,函数返回 0 表示成功。
尽管 check(int32_t * array, (int32_t) input) 有任何字符输入,但由于数组中的预设值,结果将是相同的。我能做些什么来纠正这个问题?
