angr理论笔记(一)loading a binary

angr——loading a binary

主要学习一些api,以及angr的使用。源代码阅读暂时不做考虑

加载器、映射

加载器主要起到将binary加载到固定空间的作用

proj = angr.Project('examples/fauxware/fauxware')

loader有一些api可供调用,可以通过此查看相应libc,加载器等

>>> proj.loader.all_objects
[<ELF Object fauxware, maps [0x400000:0x60105f]>,
 <ELF Object libc-2.23.so, maps [0x1000000:0x13c999f]>,
 <ELF Object ld-2.23.so, maps [0x2000000:0x2227167]>,
 <ELFTLSObject Object cle##tls, maps [0x3000000:0x3015010]>,
 <ExternObject Object cle##externs, maps [0x4000000:0x4008000]>,
 <KernelObject Object cle##kernel, maps [0x5000000:0x5008000]>]
 
 # This is the "main" object, the one that you directly specified when loading the project
>>> proj.loader.main_object
# This is a dictionary mapping from shared object name to object
>>> proj.loader.shared_objects
 # Here's all the objects that were loaded from ELF files
# If this were a windows program we'd use all_pe_objects!
>>> proj.loader.all_elf_objects
[<ELF Object fauxware, maps [0x400000:0x60105f]>,
 <ELF Object libc-2.23.so, maps [0x1000000:0x13c999f]>,
 <ELF Object ld-2.23.so, maps [0x2000000:0x2227167]>]

总之可以看出,它的作用是可以和一些程序加载过程中相关性比较大的内容交互。

以上对象可以被inspect,查看的内容包括被加载内容的起始地址,结束地址,段大小,权限位等。简单来说,就是我们在gdb中也可以看到的一些和被加载程序相关的内容

>>> obj = proj.loader.main_object

>>> obj.entry
0x400580
# 输出地址开始以及末尾
>>> obj.min_addr, obj.max_addr
(0x400000, 0x60105f)

# Retrieve this ELF's segments and sections
# 输出elf的段信息和区间信息
>>> obj.segments
<Regions: [<ELFSegment memsize=0xa74, filesize=0xa74, vaddr=0x400000, flags=0x5, offset=0x0>,
           <ELFSegment memsize=0x238, filesize=0x228, vaddr=0x600e28, flags=0x6, offset=0xe28>]>
>>> obj.sections
<Regions: [<Unnamed | offset 0x0, vaddr 0x0, size 0x0>,
           <.interp | offset 0x238, vaddr 0x400238, size 0x1c>,
           <.note.ABI-tag | offset 0x254, vaddr 0x400254, size 0x20>,
            ...etc

# You can get an individual segment or section by an address it contains:
>>> obj.find_segment_containing(obj.entry)
<ELFSegment memsize=0xa74, filesize=0xa74, vaddr=0x400000, flags=0x5, offset=0x0>
>>> obj.find_section_containing(obj.entry)
<.text | offset 0x580, vaddr 0x400580, size 0x338>

# Get the address of the PLT stub for a symbol
>>> addr = obj.plt['strcmp']
>>> addr
0x400550
>>> obj.reverse_plt[addr]
'strcmp'

# Show the prelinked base of the object and the location it was actually mapped into memory by CLE
# 输出程序加载基地址以及在CLE(一个自定义加载器中)被加载的基地址
>>> obj.linked_base
0x400000
>>> obj.mapped_base
0x400000

符号、重定位

angr还可以用来查找一些符号的地址,包括加载前地址以及运行过程中的地址。

文档中提到,查找一个符号的方法有两种:名称,地址。但是地址往往是含糊的,因为不确定是否是重定位之后的地址。

一下实例说明用名称来查找一个符号

>>> strcmp = proj.loader.find_symbol('strcmp')
>>> strcmp
<Symbol "strcmp" in libc.so.6 at 0x1089cd0>

对于寻找到的符号,有相应的api来快速查询他的名称,重定位基地址,链接地址,归属等信息

>>> strcmp.name
'strcmp'

>>> strcmp.owner
<ELF Object libc-2.23.so, maps [0x1000000:0x13c999f]>

>>> strcmp.rebased_addr
0x1089cd0
>>> strcmp.linked_addr
0x89cd0
>>> strcmp.relative_addr
0x89cd0

除了加载器中的符号,二进制文件本身也会包含符号。下图为寻找二进制文件中包含的strcmp符号。

>>> strcmp.is_export
True
>>> strcmp.is_import
False

# On Loader, the method is find_symbol because it performs a search operation to find the symbol.
# On an individual object, the method is get_symbol because there can only be one symbol with a given name.
>>> main_strcmp = proj.loader.main_object.get_symbol('strcmp')
>>> main_strcmp
<Symbol "strcmp" in fauxware (import)>
>>> main_strcmp.is_export
False
>>> main_strcmp.is_import
True
>>> main_strcmp.resolvedby
<Symbol "strcmp" in libc.so.6 at 0x1089cd0>

两者之间的关系便是:重定位

重定位指的是:当import和export的符号名称相同时,加载器将会把export的地址写到import富豪的某个位置上

CLE加载器

CLE加载器可以自动辨认并加载许多已知文件格式,包括pe,elf等

可以为加载器设置加载起始位置,加载架构

下图为设置加载格式为blob(随机存取块的形式存储任何种类的二进制数据),设置架构为i386,设置库文件为elf格式的命令

>>> angr.Project('examples/fauxware/fauxware', main_opts={'backend': 'blob', 'arch': 'i386'}, lib_opts={'libc.so.6': {'backend': 'elf'}})
<Project examples/fauxware/fauxware>

除此以外,还可以设置加载地址

backend - which backend to use, as either a class or a name

base_addr - a base address to use

entry_point - an entry point to use

arch - the name of an architecture to use

hook 执行

在任意地址处,angr会先检查有没有hook函数,如果有就会先执行hook

以下代码说明如何完成hook

>>> stub_func = angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained'] # 替代函数
>>> proj.hook(0x10000, stub_func())  # hook操作

#接下来验证是否被hook
>>> proj.is_hooked(0x10000)           
True
>>> proj.hooked_by(0x10000)
<ReturnUnconstrained>
>>> proj.unhook(0x10000)

# length指定了当hook执行完毕之后,程序执行流rip需要往后移动多少字节
>>> @proj.hook(0x20000, length=5)
... def my_hook(state):
...     state.regs.rax = 1

>>> proj.is_hooked(0x20000)
True

此外,可以hook具有名称的函数

以下代码将名称为name的函数修改为hook位置的函数指针

proj.hook_symbol(name, hook)

小结

文档中的加载器部分主要想告诉我们:angr可以再加载过程中实现哪些事情。可以看出angr还是可以实现很多的。从加载之前的elf文件分段,信息提取(elf信息,符号信息),到加载过程中架构选择,映射地址选择,再到动态插装中的hook函数。可以看出angr的加载器部分既包含静态分析的功能,也包含动态分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值