angr / tracer

Utilities for generating dynamic traces
BSD 2-Clause "Simplified" License
88 stars 28 forks source link

Adding PIE load_addr support #5

Closed bannsec closed 7 years ago

bannsec commented 7 years ago

When playing with tracer, i noticed it would not successfully trace a PIE compiled binary. Turns out, there's a mismatch between the base address that angr will by default load at and the base address that QEMU loads at.

Luckily, that base address is displayed in the default QEMU output that is created when you run the dynamic trace. Basically, what I'm adding is to pull that value out, then use it when you create your initial path group. In the case of normal non-PIE binaries the functionality should be the same as currently. However, in PIE, it seems best to find the value QEMU displays and use that, since the chosen base address may vary from QEMU installs or versions. It also warns the user if this is the case.

An example PIE (vulnerable) binary is attached. The actually binary doesn't matter that much, just an example.

a.zip

An example of what doesn't work currently but should in the patch is:

import  tracer
t = tracer.Tracer("./a.out","A")
t.next_branch()
bannsec commented 7 years ago

Bleh. Looks like there is strangeness now when tracing a non-PIE exe. Specifically, it doesn't map correctly? Here's a logging example:


In [2]: logging.basicConfig(level=logging.INFO)

In [3]: import tracer
WARNING:claripy:Claripy is setting the recursion limit to 15000. If Python segfaults, I am sorry.
INFO:simuvex.plugins.unicorn:native plugin is enabled

In [4]: t = tracer.Tracer("./login","test\ntest2\n")
INFO:angr.project:Loading binary ./login
INFO:cle.loader:[Rebasing /home/user/fgets_bug/login @0x0]
INFO:cle.loader:[Rebasing /lib/i386-linux-gnu/libc-2.24.so @0x9000000]
INFO:cle.loader:[Rebasing /lib/i386-linux-gnu/ld-2.24.so @0xa000000]
INFO:cle.loader:[Rebasing ##cle_tls## @0xb000000]
INFO:cle.loader:[Rebasing ##angr_externs## @0xc000000]
INFO:cle.loader:[Rebasing ##angr_externs## @0xd000000]
INFO:angr.project:Providing strcmp from libc.so.6 with SimProcedure
INFO:angr.project:Providing printf from libc.so.6 with SimProcedure
INFO:angr.project:Providing fgets from libc.so.6 with SimProcedure
INFO:angr.project:Providing __stack_chk_fail from libc.so.6 with SimProcedure
INFO:angr.project:Providing puts from libc.so.6 with SimProcedure
INFO:angr.project:Providing __libc_start_main from libc.so.6 with SimProcedure
INFO:angr.path_history:Callstack on the path is unbalanced.
INFO:angr.simos:A factory.call_state-created path returned!
INFO:angr.path_history:Callstack on the path is unbalanced.
INFO:angr.simos:A factory.call_state-created path returned!
INFO:angr.path_history:Callstack on the path is unbalanced.
INFO:angr.simos:A factory.call_state-created path returned!
INFO:tracer.Tracer:tracing as raw input
INFO:tracer.Tracer:trace consists of 61 basic blocks
Requesting 0x8048000
INFO:angr.project:Loading binary ./login
INFO:cle.loader:[Rebasing /home/user/fgets_bug/login @0x8048000]
INFO:cle.loader:[Rebasing /lib/i386-linux-gnu/libc-2.24.so @0x11000000]
INFO:cle.loader:[Rebasing /lib/i386-linux-gnu/ld-2.24.so @0x12000000]
INFO:cle.loader:[Rebasing ##cle_tls## @0x13000000]
INFO:cle.loader:[Rebasing ##angr_externs## @0x14000000]
INFO:cle.loader:[Rebasing ##angr_externs## @0x15000000]
INFO:angr.project:Providing strcmp from libc.so.6 with SimProcedure
INFO:angr.project:Providing printf from libc.so.6 with SimProcedure
INFO:angr.project:Providing fgets from libc.so.6 with SimProcedure
INFO:angr.project:Providing __stack_chk_fail from libc.so.6 with SimProcedure
INFO:angr.project:Providing puts from libc.so.6 with SimProcedure
INFO:angr.project:Providing __libc_start_main from libc.so.6 with SimProcedure
INFO:angr.path_history:Callstack on the path is unbalanced.
INFO:angr.simos:A factory.call_state-created path returned!
INFO:angr.path_history:Callstack on the path is unbalanced.
INFO:angr.simos:A factory.call_state-created path returned!
INFO:angr.path_history:Callstack on the path is unbalanced.
INFO:angr.simos:A factory.call_state-created path returned!
Got 0x10090000

In [5]: t._p.loader.all_objects()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-1c72fc263365> in <module>()
----> 1 t._p.loader.all_objects()

TypeError: 'list' object is not callable

In [6]: t._p.loader.all_objects
Out[6]: 
[<ELF Object login, maps [0x10090000:0x10092047]>,
 <ELF Object libc-2.24.so, maps [0x11000000:0x111b9a1b]>,
 <ELF Object ld-2.24.so, maps [0x12000000:0x12024917]>,
 <ELFTLSObj Object ##cle_tls##, maps [0x13000000:0x13030000]>,
 <AngrExternObject Object ##angr_externs##, maps [0x14000000:0x14004000]>,
 <AngrExternObject Object ##angr_externs##, maps [0x15000000:0x15004000]>]

The logging inside the loader function claims to give the main_bin the requested base_addr, but then afterwards it appears that is not the case. Any ideas on this?

bannsec commented 7 years ago

In the meantime, I added a little logic that will only request the custom base address if it's a PIE binary. It appears to work as normal for both PIE and non-PIE now. Still curious on the loader though.