Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Register Pops Not Working in ARM. #62

Closed
astewart-bah opened this issue Jan 1, 2024 · 3 comments
Closed

Multiple Register Pops Not Working in ARM. #62

astewart-bah opened this issue Jan 1, 2024 · 3 comments
Assignees
Labels

Comments

@astewart-bah
Copy link
Contributor

Description

When searching for gadgets, some valid gadgets are skipped due to not passing some of the gadget analyzer tests.

Steps to reproduce the bug

I have following function in a test binary:

void example_function()
{
    __asm__("pop {r0, r3}; \
             ldr r3, [r3]; \
             pop {fp, pc};");
}

built with the following:

arm-linux-gnueabi-gcc example.c  -marm -g -fno-pie -no-pie -z execstack -fno-inline -O0 -fno-stack-protector -o example_binary

Example python script:

import angr
import angrop

known_offset_to_example_function = 0x000105d8

p = angr.Project("example_binary", auto_load_libs=False)
rop = p.analyses.ROP(fast_mode=False, only_check_near_rets=False, is_thumb=False, rebase=False)
rop.find_gadgets()

example_gadget = rop._gadget_analyzer.analyze_gadget(known_offset_to_example_function)

When running the above code, the example gadget is not found by find_gadgets(). Additionally, when we manually search, example_gadget == None.

I found that this is due to this line (https://github.com/angr/angrop/blob/master/angrop/gadget_analyzer.py#L141). None is returned for this example gadget.
If the return here (https://github.com/angr/angrop/blob/master/angrop/gadget_analyzer.py#L143) is commented out, the gadget now returns.
When printed out, it shows as follows:

Gadget 0x105d8
Stack change: 0x10
Changed registers: {'r11', 'r0', 'r3'}
Popped registers: {'r11', 'r0'}
Register dependencies:
Memory read:
    address (32 bits) depends on: []
    data (32 bits) stored in regs:['r3']

And when used in a chain, it works as expected:
chain += p32(0x105d8) # pop {r0, r3}; ldr r3, [r3]; pop {fp, pc}

It looks like the gadget fails both checks on (https://github.com/angr/angrop/blob/master/angrop/gadget_analyzer.py#L141).

Two theories.
One: the symbolic state magic is not properly handling the multi register pop instructions, and that only the first instance is noted.
Two: the symbolic state functions see that r3 is being overwritten with (ldr r3, [r3]) so it assumes it can be ignored.

Both would account for only r0 and r11 (fp) showing up as popped registers, but not r3.

What I have tried already:
removing the "angr.options.AVOID_MULTIVALUED_READS" options here (https://github.com/angr/angrop/blob/master/angrop/rop_utils.py#L161).
added opt_level=0 to the options here (https://github.com/angr/angrop/blob/master/angrop/rop_utils.py#L213)
No observable change

Environment

GCC version: arm-linux-gnueabi-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0

Additional context

No response

@Kyle-Kyle Kyle-Kyle self-assigned this Jan 1, 2024
@Kyle-Kyle
Copy link
Collaborator

This issue should be addressed by #63
The root cause is that currently angrop assumes that the address of symbolic memory access has to come from register control, which is wrong according to the example.
The fix is to track stack control as well. as represented by memaccess.addr_stack_controllers

@Kyle-Kyle
Copy link
Collaborator

And thank you for your issue, I finally made up my mind and cleaned up some extremely ugly code and made it just some ugly code :)

@Kyle-Kyle
Copy link
Collaborator

Now the patch is merged. I'll close this issue. Please reopen it if you think this issue is still not addressed in the latest version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants