0x00判断文件类型 我们得到的问题通常是二进制可执行文件,其中大多数不是Windows平台下的PE文件或Linux平台下的ELF文件。无论问题中给出的文件的扩展名如何,我们都应该亲自检查文件头并使用任何文本编辑工具打开二进制文件。如果你在开始时看到MZ,你基本上可以确认这是一个Win系统。可执行文件,如果你看到ELF类型,你基本上可以得出结论,这是一个在Linux系统下运行的可执行文件,扩展名是exe,本质上是一个ELF文件。这种情况是过去的CTF游戏。它也出现了。 0x01检查和解除清除 由于近年来CTF竞争中反向壳体问题的频率略有增加,因此在静态分析之前检查壳体是非常必要的。常用的工具是PEID等。检查shell后,如果它是一个简单而常见的shell如UPX,那么你可以使用该工具来完成shelling。如果您暂时找不到可用的工具,您也可以尝试解压缩shell。例如,ASPP可以使用ESP法来删除。如果你专注于炮击问题,一般程序本身就相对简单了。可以说,如果这样的问题能够被成功地炮轰,那么基本上就可以了。当然,炮击并不能解决所有问题。过去,CTF竞赛中甚至存在VMP问题。对于这种情况,建议使用调试器进行动态调试。毕竟,在逆向工程中依赖IDA的F5功能是不可接受的。或者你应该锻炼自己的汇编指导阅读能力。如果是较新版本的VMP,您可能还需要使用Sharp OD等插件来隐藏调试行为。 0x02静态分析 通常,二进制文件直接拖入IDA进行分析。在此过程中,您可以注意是否存在符号库路径的提示。如果是这种情况,程序在编译阶段不会清除相应的符号信息。可以从符号库路径的命名中学习有关该问题的一些重要信息。大多数时候,静态分析完成后,我们将直接进入程序启动,直接F5,往下看主函数,直接查看Decompiled C伪代码,但有时IDA无法识别该函数。例如,如果分析某段代码,则视图将从C伪代码更改为汇编指令视图。此时,您可以尝试手动在汇编指令中识别该函数,并使用IDA创建函数函数,以便可以连续查看C伪代码以提高我们的工作效率。 如何从汇编代码中找出函数? 首先你必须找到函数头,许多函数的头部将如下所示: 按 ebp Mov ebp,尤其是 首先弹出调用者堆栈的基地址(ebp)以保存先前任务的信息。 然后将调用者的堆栈顶部指针(esp)的值分配给ebp作为新的基地址(即被调用者堆栈的底部)。 然后我们继续寻找函数的尾部 流行ebp 惩戒 应该注意的是,如果函数不仅具有路径返回值,我们必须确保函数末尾下方的跳转都面朝下,并且上面的跳转都面朝上。 如果我在IDA中遇到Sp分析失败怎么办? 在这种情况下,有时由于某些指令的干扰,IDA分析的堆栈余额被破坏,这可能导致IDA生成C伪代码。
我们需要手动调整堆栈余额,单击IDA中的Options-General,然后检查堆栈 指针。 函数开头的指令如下图所示:
函数结束前的说明如下:
您可以看到每条指令前面都添加了一个数字。此数字表示堆栈顶部指针(SP)。在使用参数调用Call后,推送和弹出或堆叠和清除将更改堆栈顶部指针。上图中的mov esp,ebp后的SP值显然不合理,应使用Alt + K快捷键进行调整,如下图所示:
然后使用F5,IDA已经能够生成正确的C伪代码。 0x03一些常见问题 1. 方程式(HCTF2017反向第一个问题) XOR输入
这个问题中三个方程的关键代码
爆破解决方案: Def解决(idx1,idx2,idx3,idx4): for x in range(0,255): if(((x ^ idx1)& idx2)>> idx3)| (((x ^ idx1)<< idx3)& idx2)==idx4: print(chr(x ^0x76),end='') Key1=[0x6f,0xdd,0xdd,0x48,0x64,0x63,0xd7] 对于key1:中的ele 求解(0xAD,0xAA,0x1,ele) Key2=[0x2e,0x2c,0xfe,0x6a,0x6d,0x2a,0xf2] 对于key2:中的ele 求解(0xbe,0xcc,0x2,ele) KEY3=[0x6f,0x9A执行,送出0x4d,0x8b,0x4b,0xFA回应,0X1A] 对于key3:中的ele 解决(0xef,0xf0,0x4,ELE) Z3约束解决方案: 来自z3进口* 定义z3_solve(idx1,idx2,idx3,idx4): 求解器=求解器() x=BitVec('x',32) solver.add((((x ^ idx1)& idx2)>> idx3)|(((x ^ idx1)<< idx3)& idx2)==idx4) 如果solver.check()==sat: print(chr(solver.model()[x] .as_long()^0x76),end='') Key1=[0x6f,0xdd,0xdd,0x48,0x64,0x63,0xd7] 对于key1:中的ele z3_solve(0xAD,0xAA,0x1,ele) Key2=[0x2e,0x2c,0xfe,0x6a,0x6d,0x2a,0xf2] 对于key2:中的ele z3_solve(0xbe,0xcc,0x2,ele) KEY3=[0x6f,0x9A执行,送出0x4d,0x8b,0x4b,0xFA回应,0X1A] 对于key3:中的ele Z3_solve(0xef,0xf0,0x4,ELE) Z3是Microsoft开发的约束求解器,其代码目前托管在https://github.com/Z3Prover/z3 如果标题方程相对简单,爆破的使用当然简单粗暴,方便快捷;但是当主题涉及多个方程式或方程式时,强烈建议使用Z3解决方案更有效。