Skip to content

Commit

Permalink
fix edge-case of segment issues, specifically, segment.max_addr is th…
Browse files Browse the repository at this point in the history
…e larget addressable address
  • Loading branch information
Kyle-Kyle committed Feb 12, 2024
1 parent 3854cbe commit 5fe3775
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 13 deletions.
7 changes: 2 additions & 5 deletions angrop/chain_builder/sys_caller.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,8 @@ def _try_invoke_execve(self, path_addr):
raise RopException("Fail to invoke execve!")

def execve(self, path=None, path_addr=None):
# look for good syscall gadgets
syscall_locs = self._get_syscall_locations()
syscall_locs = [x for x in syscall_locs if not self._word_contain_badbyte(x)]
if len(syscall_locs) == 0:
raise RopException("No syscall instruction available")
if not self.syscall_gadgets:
raise RopException("target does not contain syscall gadget!")

# determine the execution path
if path is None:
Expand Down
8 changes: 3 additions & 5 deletions angrop/gadget_finder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def _addresses_to_check(self):
if segment.is_executable:
l.debug("Analyzing segment with address range: 0x%x, 0x%x", segment.min_addr, segment.max_addr)
start = segment.min_addr + (alignment - segment.min_addr % alignment)
for addr in range(start, segment.max_addr, alignment):
for addr in range(start, start+segment.memsize, alignment):
yield addr+offset

def _num_addresses_to_check(self):
Expand All @@ -233,8 +233,7 @@ def _num_addresses_to_check(self):
alignment = self.arch.alignment
for segment in self.project.loader.main_object.segments:
if segment.is_executable:
start = segment.min_addr + (alignment - segment.min_addr % alignment)
num += (segment.max_addr - start) // alignment
num += segment.memsize // alignment
return num + len(self._syscall_locations)

def _get_ret_locations(self):
Expand Down Expand Up @@ -305,8 +304,7 @@ def _get_locations_by_strings(self, strings):
for segment in self.project.loader.main_object.segments:
if not segment.is_executable:
continue
num_bytes = segment.max_addr - segment.min_addr
read_bytes = state.solver.eval(state.memory.load(segment.min_addr, num_bytes), cast_to=bytes)
read_bytes = state.solver.eval(state.memory.load(segment.min_addr, segment.memsize), cast_to=bytes)
# find all occurrences of the ret_instructions
addrs += [segment.min_addr + m.start() for m in re.finditer(fmt, read_bytes)]
return sorted(addrs)
Expand Down
8 changes: 7 additions & 1 deletion angrop/gadget_finder/gadget_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,13 @@ def _does_pivot(self, final_state):
:param final_state: the state that finishes the gadget execution
"""
for act in final_state.history.actions:
if act.type != 'reg' or act.action != 'write' or act.storage != self.arch.stack_pointer:
if act.type != 'reg' or act.action != 'write':
continue
try:
storage = act.storage
except KeyError:
continue
if storage != self.arch.stack_pointer:
continue
# this gadget has done symbolic pivoting if there is a symbolic write to the stack pointer
if act.data.symbolic:
Expand Down
7 changes: 7 additions & 0 deletions tests/test_gadgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,13 @@ def test_syscall_gadget():
assert gadget.stack_change == 0x0
assert not gadget.can_return

proj = angr.Project(os.path.join(BIN_DIR, "tests", "x86_64", "roptest"), auto_load_libs=False)
rop = proj.analyses.ROP()
gadget = rop.analyze_gadget(0x4000c1)
assert type(gadget) == SyscallGadget
assert gadget.stack_change == 0
assert not gadget.can_return

def run_all():
functions = globals()
all_functions = {x:y for x, y in functions.items() if x.startswith('test_')}
Expand Down
4 changes: 2 additions & 2 deletions tests/test_rop.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,9 @@ def test_rop_arm():

def test_roptest_x86_64():
p = angr.Project(os.path.join(public_bin_location, "x86_64/roptest"), auto_load_libs=False)
r = p.analyses.ROP()
r = p.analyses.ROP(only_check_near_rets=False)
r.find_gadgets_single_threaded(show_progress=False)
c = r.execve(b"/bin/sh")
c = r.execve(path=b"/bin/sh")

# verifying this is a giant pain, partially because the binary is so tiny, and there's no code beyond the syscall
assert len(c._gadgets) == 8
Expand Down

0 comments on commit 5fe3775

Please sign in to comment.