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

Added addr_offset field for memory read and write gadgets #126

Merged
merged 1 commit into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions angrop/gadget_finder/gadget_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,8 @@ def _build_mem_access(self, a, gadget, init_state, final_state):
mem_access.addr_dependencies = rop_utils.get_ast_dependency(a.addr.ast)
mem_access.addr_controllers = rop_utils.get_ast_controllers(init_state, a.addr.ast,
mem_access.addr_dependencies)
mem_access.addr_offset = rop_utils.get_ast_const_offset(init_state, a.addr.ast,
mem_access.addr_dependencies)
# case 3: the symbolic address comes from controlled stack
elif all(x.startswith("symbolic_stack") for x in a.addr.ast.variables):
mem_access.addr_stack_controllers = set(a.addr.ast.variables)
Expand Down
2 changes: 2 additions & 0 deletions angrop/rop_gadget.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class RopMemAccess:
Attributes:
addr_dependencies (set): All the registers that affect the memory address.
addr_controller (set): All the registers that can determine the symbolic memory access address by itself
addr_offset (int): Constant offset in the memory address relative to register(s)
addr_stack_controller (set): all the controlled gadgets on the stack that can determine the address by itself
data_dependencies (set): All the registers that affect the data written.
data_controller (set): All the registers that can determine the symbolic data by itself
Expand All @@ -17,6 +18,7 @@ class RopMemAccess:
def __init__(self):
self.addr_dependencies = set()
self.addr_controllers = set()
self.addr_offset: int | None = None
self.addr_stack_controllers = set()
self.data_dependencies = set()
self.data_controllers = set()
Expand Down
22 changes: 22 additions & 0 deletions angrop/rop_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,28 @@ def get_ast_controllers(state, ast, reg_deps) -> set:
return controllers


def get_ast_const_offset(state, ast, reg_deps) -> int:
"""
Gets the constant offset for a memory access
:param state: the input state
:param ast: the ast of which we are trying to analyze controllers
:param reg_deps: All registers which it depends on
:return: Constant value
"""
size = ast.size()
zero_val = claripy.BVV(0, size)

# Replace symbolic values with zero to get the constant value
# This is faster than eval with extra contraints
for reg in reg_deps:
reg_val = state.registers.load(reg)
ast = claripy.algorithm.replace(
expr=ast, old=reg_val, new=zero_val)

assert not ast.symbolic
return state.solver.eval(ast)


def unconstrained_check(state, ast, extra_constraints=None):
"""
Attempts to check if an ast is completely unconstrained
Expand Down
8 changes: 8 additions & 0 deletions tests/test_gadgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,14 @@ def test_syscall_gadget():
assert not gadget.can_return
assert len(gadget.concrete_regs) == 1 and gadget.concrete_regs.pop('rax') == 0x3b

gadget = rop.analyze_gadget(0x521cef)
assert type(gadget) == RopGadget
assert len(gadget.mem_writes) == 1
mem_write = gadget.mem_writes[0]
assert mem_write.addr_offset == 0x68
assert len(mem_write.addr_controllers) == 1 and 'rdx' in mem_write.addr_controllers
assert len(mem_write.data_controllers) == 1 and 'rcx' in mem_write.data_controllers

gadget = rop.analyze_gadget(0x4c1437)
assert type(gadget) == SyscallGadget
assert gadget.stack_change == 0
Expand Down