Angr CTF Part 1
有这么串代码,需要找到执行至Success的路径。
user_input = ?
if user_input = "yes":print 'Success'
else:print 'Try again'
可以把条件,user_input想象成为一个未知变量,而获取路径的过程就是一个解方程的过程。于是,我们设user_input为未知变量,然后进行到if判断的时候,就会进入两条路径,一条是输出Success,一条是输出Try again,当我们找到我们想要的结果时,就能轻易根据约束条件推出一开始的user_input。
这时候我们换一个复杂一点的例子
#define SECRET 100
int check_code(int input) {if (input >= SECRET+88) return 0;if (input > SECRET+100) return 0;if (input == SECRET+68) return 0;if (input < SECRET) return 0;if (input <= SECRET+78) return 0;if (input & 0x1) return 0;if (input & 0x2) return 0;if (input & 0x4) return 0;return 1;
}
当这一串代码中想要获取return 1的路径,首先获取代码的所有路径,并整理为树形结构。这种情况就要运用深度优先算法来得到return 1的路径。
获取到了路径之后,我们就可以构建一个可以用SMT求解器求解的方程,就能快速的得到input的值。
input >= SECRET+88
∧ input > SECRET+100
∧ input == SECRET68
∧ input < SECRET
∧ input <= SECRET+78
∧ input & 0x1
∧ input & 0x2
∧ input & 0x4
当然,随着复杂度的增加就需要运用到这次的妙妙工具了Angr。Angr是一个符号执行引擎。 它可以遍历二进制文件并搜索符合给定条件的程序状态然后在给定路径约束的情况下求解符号变量。
执行路径表示程序从某个地方开始到另一个地方结束的可能执行流程。 Angr中执行路径的节点由“SimState”对象表示。顾名思义,它存储程序的状态以及以前状态的历史。 Angr在“simulation manager”对象中存储和处理给定程序的一组可能路径。Simulation manage提供逐步执行程序以生成可能的路径/状态的功能。
1.Angr在指示程序启动的任何地方启动程序
2.在每个活动(未终止)状态下执行指令,直到到达分支点或状态终止
3.在每个分支点,将状态拆分为多个状态,并将它们添加到活动状态集中
4.重复步骤2…4,直到找到所需内容或所有状态终止
但是用这个方法每次IF命令都会使存储的路径翻倍,所以每次应当尽早地排除掉错误地路径。这个过程在Angr中也能表示出来simulation.explore(find=你想要去的地址,avoid=你想要避免的地址)。比如simulation.explore(find=0x801000,avoid=0x802000),意思就是找到去801000地址的路径,并避免到达802000。