学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

116

积分

0

好友

25

主题
发表于 2020-6-15 00:45:16 | 查看: 2473| 回复: 0

相关题目:


前言  在逆向中,使用Hook来解决问题非常的常见,在之前对angr的学习中,我并未关注到hook方法,现在有时间学习整理一遍,我倍感快乐,其实Hook也十分的简单,而且可以将复杂的问题简单化
初识  一个比较简单的例子defcamp_r100/r100
  解题代码只有以下短短的几行:
import angr

project = angr.Project("angr-doc/examples/defcamp_r100/r100", auto_load_libs=False)

@project.hook(0x400844)
def print_flag(state):
print("FLAG SHOULD BE:", state.posix.dumps(0))
project.terminate_execution()

project.execute()
  官方文档的介绍如下:

深入浅出angr(四)

深入浅出angr(四)
  我们可以通过@proj.hook(proj.entry)的方式来Hook任意一个地址。
  例子中使用了project.execute()方法,此方法并不常用,它往往和project.terminate_execution()结合起来使用,并且通常用在hook时

深入浅出angr(四)

深入浅出angr(四)
  因此代码大概的执行流程如下:
  • 初始化proj
  • hook指定地址的函数
  • 调用project.execute()
  • 当遇到project.terminate_execution()符号执行结束
  此时angr会执行到0x400844并打印出flag的结果。
hook符号表  这里以tumctf2016_zwiebel作为例子进行说明。首先看官方文档的说明。

深入浅出angr(四)

深入浅出angr(四)
  hook_symbol函数可以根据所给出的符号名,在二进制文件中找寻对应的地址,并且hook该地址。
  IDA载入题目

深入浅出angr(四)

深入浅出angr(四)
  这是一个smc的题目,对于angr来说为了能在符号执行时进行自解密,需要添加support_selfmodifying_code=True参数

深入浅出angr(四)

深入浅出angr(四)
  很明显,我们无法使用sm.explore(find=xxx,avoid=xxx)的方式来使用angr,同时注意到程序中出现了ptrace想必一定有反调试,让我们通过hook的方法来绕过反调试。
p.hook_symbol('ptrace', angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained'](return_value=0))
  因为angr实现了大量的符号化函数,以此来替代程序中对库函数的外部调用,其中angr.SIM_PROCEDURES是angr对符号化函数的字典调用,我们可以采用angr.SIM_PROCEDURES['模块名']['库函数名']()进行hook
  而后便可以通过simulation_manager进行执行了。
state = p.factory.full_init_state(cadd_options=angr.options.unicorn)
sm = p.factory.simulation_manager(state)
  这里只能采用类似step的方法进行解决,效率很低,例子中提供的代码是这样的。
while sm.active:
# in order to save memory, we only keep the recent 20 deadended or
# errored states
#print(len(sm.active))
sm.run(n=20)
if 'deadended' in sm.stashes and sm.deadended:
sm.stashes['deadended'] = sm.deadended[-20:]
if sm.errored:
sm.errored = sm.errored[-20:]

assert sm.deadended
flag = sm.deadended[-1].posix.dumps(0).split(b"\n")[0]
import ipdb; ipdb.set_trace()
return flag
  我觉得有点多此一举了,他这段代码的目的就是执行完sm.run()此时正确的输入应该保存在最后一个deadended节点的posix.dumps(0)当中,最后跑了两个小时,我也是醉了。不过至少知道了angr是如何hook,并绕过反调试的。
典型例题defcon2016quals_baby-re  这道题作为例子可能会更好一点。
  这题其实不用hook也能顺利的解出,只是我们需要对结果进行处理一下,才能得到我们想要的flag。

深入浅出angr(四)

深入浅出angr(四)
  IDA载入

深入浅出angr(四)

深入浅出angr(四)
  其实之前我们遇到过类似的题目,不过那时我们采取的方法是:跳过输入部分,直接对内存进行存储,从而进行输入,这里当然也能这么做,只需对[rbp+var_60]内存进行操作即可
  ps:本来只想简单尝试一下,没想到花了几分钟随便写的代码居然跑出结果了,因此这里顺便贴一下代码。

深入浅出angr(四)

深入浅出angr(四)
import angr
import claripy

# 最简单的方法,不过需要对结果进行变化
def main():
proj = angr.Project('./baby-re', auto_load_libs=False)
state = proj.factory.entry_state(add_options={angr.options.LAZY_SOLVES})
sm = proj.factory.simulation_manager(state)
sm.explore(find=0x4028E9, avoid=0x402941)

# 跳过程序自身的输入,通过内存控制输入
def main2():
proj = angr.Project('./baby-re', auto_load_libs=False)
flag_chars = [claripy.BVS('flag_%d' % i, 32) for i in range(13)]

state = proj.factory.blank_state(addr=0x4028E0,add_options={angr.options.LAZY_SOLVES})
for i in range:
state.memory.store(state.regs.rbp-0x60+i*4,flag_chars[i])
state.regs.rdi = state.regs.rbp-0x60
sm = proj.factory.simulation_manager(state)
sm.explore(find=0x4028E9, avoid=0x402941)
if __name__ == '__main__':
main2()
  当然说了这么多,这里最主要还是想说一下如何使用Hook技术,来控制输入,从而方便我们的输出。
  我们可以通过这样的方式进行Hook
  proj.hook_symbol('__isoc99_scanf', my_scanf(), replace=True)
  我们用自己的my_scanf()来代替__isoc99_scanf,我们在保持scanf功能不变的情况下,将我们的符号变量存储进去。
class my_scanf(angr.SimProcedure):
def run(self, fmt, ptr): # pylint: disable=arguments-differ,unused-argument
self.state.mem[ptr].dword = flag_chars[self.state.globals['scanf_count']]
self.state.globals['scanf_count'] += 1
  这样程序每次调用scanf时,其实就是在执行my_scanf就会将flag_chars存储到self.state.mem[ptr]当中,这其中ptr参数,其实就是本身scanf函数传递进来的rdi也就是[rbp+var_60]+i*4,为了控制下标,我们设置了一个全局符号变量scanf_count,相信聪明的你一定不难理解。
  如此一来,只要angr执行到我们想要到达的分支,那么我们就可以通过solver.eval()的方式将其打印出来
  代码如下:
import angr
import claripy

def main():
proj = angr.Project('./baby-re', auto_load_libs=False)

# let's provide the exact variables received through the scanf so we don't have to worry about parsing stdin into a bunch of ints.
flag_chars = [claripy.BVS('flag_%d' % i, 32) for i in range(13)]
class my_scanf(angr.SimProcedure):
def run(self, fmt, ptr): # pylint: disable=arguments-differ,unused-argument
self.state.mem[ptr].dword = flag_chars[self.state.globals['scanf_count']]
self.state.globals['scanf_count'] += 1

proj.hook_symbol('__isoc99_scanf', my_scanf(), replace=True)

sm = proj.factory.simulation_manager()
sm.one_active.options.add(angr.options.LAZY_SOLVES)
sm.one_active.globals['scanf_count'] = 0

# search for just before the printf("%c%c...")
# If we get to 0x402941, "Wrong" is going to be printed out, so definitely avoid that.
sm.explore(find=0x4028E9, avoid=0x402941)

# evaluate each of the flag chars against the constraints on the found state to construct the flag
flag = ''.join(chr(sm.one_found.solver.eval(c)) for c in flag_chars)
return flag

def test():
assert main() == 'Math is hard!'

if __name__ == '__main__':
print(main())
总结  我感觉Hook的代码还是比较难写的,不过如果学会了,确实可以省下我们写脚本分析的时间,又是一个提高效率的方法。


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。

小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

GMT+8, 2024-4-25 21:14 , Processed in 0.097514 second(s), 42 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表