xuenixiang 发表于 2020-6-15 00:47:55

深入浅出angr(六)


前言  就我感觉angr比较适合用来解决混淆的题目,面对混淆题去混淆感觉自己能力不够,直接动态调试,又觉得非常浪费时间,那么这时angr可以成为非常好的帮手。
如何快速的寻找find和avoid  在解题时我们时常会遇到带有强混淆的程序,这类程序要找出所有的find和avoid是一件耗时耗力的事情,那么我们可以采取何种高效的办法进行寻找呢?
  这里以hackcon2016_angry-reverser为例。
  IDA载入
  很明显的混淆,如果自己分析一遍,然后去除混淆也是需要费点时间的,不过如果你掌握了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
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是在容易不过的事情了。
  由于需要调用当前的动态库,我们可以这样运行LD_LIBRARY_PATH=./ ./FUck_binary
  OK,并不是命令行参数输入。
  通过IDA,获取更多的信息。
  最终的find应该在这里。
  需要避免的分支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 >= ' ')
  跑了一下结果还以为代码写错了,这答案也太让人摸不着头脑了。
  代码如下:
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
print(found.posix.dumps(0))

if __name__ == '__main__':
#main()
get_avoids()
main()总结  既然选择了angr,便只顾风雨兼程


页: [1]
查看完整版本: 深入浅出angr(六)