前言 就我感觉angr比较适合用来解决混淆的题目,面对混淆题去混淆感觉自己能力不够,直接动态调试,又觉得非常浪费时间,那么这时angr可以成为非常好的帮手。
如何快速的寻找find和avoid 在解题时我们时常会遇到带有强混淆的程序,这类程序要找出所有的find和avoid是一件耗时耗力的事情,那么我们可以采取何种高效的办法进行寻找呢?
这里以hackcon2016_angry-reverser为例。
IDA载入
深入浅出angr(六)
很明显的混淆,如果自己分析一遍,然后去除混淆也是需要费点时间的,不过如果你掌握了angr,那么只需要几分钟就可以解决此题,根本不要关心其使用了何种加密方式。
此题中,正确的路径只有一条find=0x405a6e,需要避免的路径则有很多,我们可以通过如下代码,得到所有需要avoid的地址。
e = open('./yolomolo', 'rb').read()
avoids = []
index = 0
while True:
index = e.find(b'\xB9\x00\x00\x00\x00',index+1)
if index == -1:
break
addr = 0x400000 + index
avoids.append()
print (len(avoids))
print (avoids)
其中\xB9\x00\x00\x00\x00是mov ecx 0的机器码,因此完整代码可以如下组织:
import angr
import claripy
def main():
flag = claripy.BVS('flag', 20*8, explicit_name=True)
buf = 0x606000
crazy = 0x400646
find = 0x405a6e
e = open('./yolomolo', 'rb').read()
avoids = []
index = 0
while True:
index = e.find(b'\xB9\x00\x00\x00\x00',index+1)
if index == -1:
break
addr = 0x400000 + index
avoids.append(addr)
proj = angr.Project('./yolomolo')
state = proj.factory.blank_state(addr=crazy, add_options={angr.options.LAZY_SOLVES})
state.memory.store(buf, flag, endness='Iend_BE')
state.regs.rdi = buf
for i in range(19):
state.solver.add(flag.get_byte(i) >= 0x30)
state.solver.add(flag.get_byte(i) <= 0x7f)
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=find, avoid=avoids)
found = simgr.found[0]
return found.solver.eval(flag, cast_to=bytes)
if __name__ in '__main__':
import logging
logging.getLogger('angr.sim_manager').setLevel(logging.DEBUG)
print(main())
例题 其实angr最适合拿来解决线性的程序。
就比如说这题ekopartyctf2016_rev250
深入浅出angr(六)
如果去混淆,不一定能去除成功,如果动态调试,必定会耗费相当多的时间。如果你会使用angr,那么使用angr是在容易不过的事情了。
由于需要调用当前的动态库,我们可以这样运行LD_LIBRARY_PATH=./ ./FUck_binary
深入浅出angr(六)
OK,并不是命令行参数输入。
通过IDA,获取更多的信息。
深入浅出angr(六)
最终的find应该在这里。
深入浅出angr(六)
需要避免的分支0x403ABA,403A7E等
我们可以通过之前提到过的方法提取出所有的avoid分支。
avoids = []
def get_avoids():
file_bytes = open('./FUck_binary','rb').read()
index = 0
while True:
index = file_bytes.find(b'\x66\x90',index+1)
if index == -1:
break
if index < 0x3a7e:
continue
addr = 0x400000+index
avoids.append(addr)
在对输入进行条件约束时我们可以这么组织,这是常用的限制可打印字符的方式。
state.solver.And(c <= '~', c >= ' ')
跑了一下结果还以为代码写错了,这答案也太让人摸不着头脑了。
深入浅出angr(六)
代码如下:
import angr
import claripy
BUF_LEN = 100
avoids = []
def get_avoids():
file_bytes = open('./FUck_binary','rb').read()
index = 0
while True:
index = file_bytes.find(b'\x66\x90',index+1)
if index == -1:
break
if index < 0x3a7e:
continue
addr = 0x400000+index
avoids.append(addr)
def main():
p = angr.Project('FUck_binary')
flag = claripy.BVS('flag', BUF_LEN*8)
state = p.factory.entry_state(stdin=flag)
for c in flag.chop(8):
state.solver.add(state.solver.And(c <= '~', c >= ' '))
ex = p.factory.simulation_manager(state)
ex.explore(find=0x403a40,avoid=avoids)
found = ex.found[0]
print(found.posix.dumps(0))
if __name__ == '__main__':
#main()
get_avoids()
main()
总结 既然选择了angr,便只顾风雨兼程
|