钩子编程(hooking),也称作“挂钩”,是计算机程序设计术语,指通过拦截软件模块间的函数调用、消息传递、事件传递来修改或扩展操作系统、应用程序或其他软件组件的行为的各种技术。处理被拦截的函数调用、事件、消息的代码,被称为钩子(hook)。
简单来说就是用我们自己设计的函数去取代被 hook 的函数
一个简单的例子:
其中第一个参数即需要 Hook 的调用函数的地址,第二个参数 length
即指定执行引擎在完成挂钩后应跳过多少字节。具体多少字节由 Hook 处地址的指令长度确定,例如本题:
我们需要 Hook 地址的机器指令长度为 5 个字节,故最后的 hook 函数:
老样子先放最后 EXP,再逐一分析:
运行一下查看结果:
下面来逐步分析:
由于 Angr 可以处理对 scanf 的初始调用,因此我们可以从头开始
如之前分析的而言,首先找到需要 Hook 的函数地址 0x080486B3
,然后设定指令长度
然后我们需要在在 @project.hook
语句之后书写我们的模拟函数。然后如上题一致,我们利用使用 state.memory
的 .load(addr, size)
接口读出 buffer
处的内存数据,与答案进行比较
然后这里的关键是,我们模拟一个函数就是把它视作一个黑盒,能成功模拟输入相对应的输出即可,所以我们需要处理 check 函数的返回值
不难发现这个函数是利用 EAX 寄存器作为返回值,然后成功则返回 1,不成功则返回 0,还需要注意在构建符号位向量的时候 EAX 寄存器是 32 位寄存器
接下来同之前差不多,不再赘述