Skip to content

Commit

Permalink
Merge pull request #126 from chanijindal1/master
Browse files Browse the repository at this point in the history
Added addr_offset field for memory read and write gadgets
  • Loading branch information
salls authored Jan 31, 2025
2 parents 4f86ccf + 72b6d4a commit 62a08ab
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 0 deletions.
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

0 comments on commit 62a08ab

Please sign in to comment.