Skip to content

Commit

Permalink
improve arm support
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyle-Kyle committed Feb 4, 2024
1 parent 17bd2e1 commit 6bdda85
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 12 deletions.
25 changes: 24 additions & 1 deletion angrop/arch.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ def _get_reg_set(self):
def block_make_sense(self, block):
return True

def get_block(self, addr, num_inst=None):
if num_inst:
return self.project.factory.block(addr, num_inst=num_inst)
else:
return self.project.factory.block(addr)

class X86(ROPArch):
def __init__(self, project, kernel_mode=False):
super().__init__(project, kernel_mode=kernel_mode)
Expand All @@ -56,6 +62,15 @@ class ARM(ROPArch):
def __init__(self, project, kernel_mode=False):
super().__init__(project, kernel_mode=kernel_mode)
self.is_thumb = False # by default, we don't use thumb mode
self.alignment = self.project.arch.bytes

def set_thumb(self):
self.is_thumb = True
self.alignment = 2

def set_arm(self):
self.is_thumb = False
self.alignment = self.project.arch.bytes

def block_make_sense(self, block):
# disable conditional jumps, for now
Expand All @@ -65,8 +80,16 @@ def block_make_sense(self, block):
return False
return True

def get_block(self, addr, num_inst=None):
if num_inst:
return self.project.factory.block(addr, num_inst=num_inst, thumb=self.is_thumb)
else:
return self.project.factory.block(addr, thumb=self.is_thumb)

class MIPS(ROPArch):
pass
def __init__(self, project, kernel_mode=False):
super().__init__(project, kernel_mode=kernel_mode)
self.alignment = self.project.arch.bytes

def get_arch(project, kernel_mode=False):
name = project.arch.name
Expand Down
16 changes: 9 additions & 7 deletions angrop/gadget_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import claripy

from . import rop_utils
from .arch import get_arch
from .rop_gadget import RopGadget, RopMemAccess, RopRegMove, StackPivot
from .errors import RopException, RegNotFoundException

Expand Down Expand Up @@ -97,7 +96,10 @@ def _block_make_sense(self, addr):
"""
try:
l.debug("... checking if block makes sense")
block = self.project.factory.block(addr)
block = self.arch.get_block(addr)

if not block.capstone.insns:
return False

if not self.arch.block_make_sense(block):
return False
Expand Down Expand Up @@ -156,7 +158,7 @@ def _can_reach_unconstrained(self, addr, max_steps=2):
Use static analysis to check whether the address can lead to unconstrained targets
It is much faster than directly doing symbolic execution on the addr
"""
b = self.project.factory.block(addr)
b = self.arch.get_block(addr)
constant_jump_targets = list(b.vex.constant_jump_targets)

if not constant_jump_targets:
Expand Down Expand Up @@ -208,13 +210,13 @@ def _create_gadget(self, addr, init_state, final_state, ctrl_type):
# create the gadget
gadget = RopGadget(addr=addr)
# FIXME this doesnt handle multiple steps
gadget.block_length = self.project.factory.block(addr).size
gadget.block_length = self.arch.get_block(addr).size
gadget.transit_type = transit_type

# for jmp_reg gadget, record the jump target register
if transit_type == "jmp_reg":
state = self._state.copy()
insns = self.project.factory.block(addr).capstone.insns
insns = self.arch.get_block(addr).capstone.insns
if state.project.arch.name.startswith("MIPS"):
idx = -2 # delayed slot
else:
Expand Down Expand Up @@ -659,7 +661,7 @@ def _check_pivot(self, symbolic_p, symbolic_state, addr):
# verify no weird mem accesses
test_p = self.project.factory.simulation_manager(symbolic_state.copy())
# step until we find the pivot action
for _ in range(self.project.factory.block(symbolic_state.addr).instructions):
for _ in range(self.arch.block(symbolic_state.addr).instructions):
test_p.step(num_inst=1)
if len(test_p.active) != 1:
return None
Expand Down Expand Up @@ -692,7 +694,7 @@ def _starts_with_syscall(self, addr):
:param addr: input path to check history of
"""

return self.project.factory.block(addr, num_inst=1).vex.jumpkind.startswith("Ijk_Sys")
return self.arch.get_block(addr, num_inst=1).vex.jumpkind.startswith("Ijk_Sys")

def _windup_to_presyscall_state(self, symbolic_p, symbolic_state):
"""
Expand Down
9 changes: 5 additions & 4 deletions angrop/rop.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def __init__(self, only_check_near_rets=True, max_block_size=None, max_sym_mem_a
if max_sym_mem_access:
self.arch.max_sym_mem_access = max_sym_mem_access
if is_thumb:
self.arch.is_thumb = is_thumb
self.arch.set_thumb()

# get ret locations
self._ret_locations = None
Expand Down Expand Up @@ -338,9 +338,9 @@ def _addresses_to_check(self):
"""
:return: all the addresses to check
"""
# align block size
alignment = self.arch.alignment
if self._only_check_near_rets:
# align block size
alignment = self.arch.alignment
block_size = (self.arch.max_block_size & ((1 << self.project.arch.bits) - alignment)) + alignment
slices = [(addr-block_size, addr) for addr in self._ret_locations]
current_addr = 0
Expand All @@ -356,7 +356,8 @@ def _addresses_to_check(self):
for segment in self.project.loader.main_object.segments:
if segment.is_executable:
l.debug("Analyzing segment with address range: 0x%x, 0x%x", segment.min_addr, segment.max_addr)
for addr in range(segment.min_addr, segment.max_addr):
start = segment.min_addr + (alignment - segment.min_addr % alignment)
for addr in range(start, segment.max_addr, alignment):
yield addr

def _num_addresses_to_check(self):
Expand Down
10 changes: 10 additions & 0 deletions tests/test_find_gadgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ def test_symbolic_memory_access_from_stack():

assert all(gadget_exists(rop, x) for x in [0x000103f4])

def test_arm_thumb_mode():
proj = angr.Project(os.path.join(bin_path, "tests", "armel", "libc-2.31.so"), auto_load_libs=False)
rop = proj.analyses.ROP(fast_mode=False, only_check_near_rets=False, is_thumb=True)
rop._initialize_gadget_analyzer()

gadget = rop._gadget_analyzer.analyze_gadget(0x4bf858)

assert gadget
assert gadget.block_length == 6

def run_all():
functions = globals()
all_functions = {x:y for x, y in functions.items() if x.startswith('test_')}
Expand Down

0 comments on commit 6bdda85

Please sign in to comment.