angr stdin 探索中 scanf/fgets 的问题

逆向工程 C 愤怒
2021-06-19 23:52:30

我想使用angr解决这个非常基本的crackme:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    char buffer[64];
    printf("Mot de passe:\n");
    scanf("%64s",buffer);
    if (strcmp(buffer,"super!")==0)
    {
        printf("Bravo!\n");
    }
    else
    {
        printf("Perdu1!\n");
    }
    return 0;
}

它适用于这个 python 脚本:

import angr
from angr.state_plugins import SimSystemPosix

p = angr.Project('./a.out', load_options={'auto_load_libs': False})

sm = p.factory.simulation_manager()
sm.explore(find= 0x400000+0x0000119f, avoid= 0x400000+ 0x000011ad)

print(sm.found[0].posix.dumps(0))

但是,如果我"super!"使用包含空格的密码在我的 Crackme 中更改密码,angr 找不到任何解决方案。

使用fgets而不是scanf得到相同的结果;如果密码包含空格,则 angr 找不到任何密码。

当然,每次我重新编译我的 c 程序时,我都会更新查找和避免地址。

1个回答

那是因为这样做,你不小心使crackme无法解决由于如何scanf%s.

根据 C参考表文档多个来源(严重的是,谷歌充满了描述该内容的 scanf 文档页面):

%s:扫描一个字符串。扫描在空白处终止。空字符存储在字符串的末尾,这意味着提供的缓冲区必须至少比指定的输入长度长一个字符。

%s一旦遇到空白字符(显然包括空格),scanf 将立即停止将字符读入用 表示的字符串中即使您在新创建的可执行文件中手动输入正确的密码,您也会收到错误消息而不是成功。

此外,gets在涉及空格时表现相同。

但是你可以手动解决crackme,它出现

尽管这似乎不是您在程序中遇到的行为,但由于某些未知原因,这仍然是 angr在处理类似库函数时所假定的行为为避免在第一次遇到字符串库函数时出现路径爆炸,angr 不会像任何其他遇到的函数一样“本机”处理这些函数,这可能并不广为人知。为了提高效率和速度,angr“欺骗”了库函数,包括格式化字符串函数。scanfscanf

为此,angr在 python 中有自己的scanf 函数实现,并且该实现遵循标准。您可以看到scanf分隔符已定义用于分隔scanf可能的输出。问题scanf甚至记录在angr 的陷阱页面中

例如,我们的 scanf 实现并不完整,但如果您只需要支持单个已知格式的字符串,您可以编写一个钩子来实现这一点。

避免这种情况的一种方法是将scanf实现修改为不将空格视为分隔符的内容。另一种选择是通过exclude_sim_procedures_list=['scanf']作为参数传递给您的Project. 您也可以,正如陷阱页面所建议的那样,为您的场景实施一些特定的东西。