Giter Site home page Giter Site logo

angrop's Introduction

angrop

angrop is a rop gadget finder and chain builder

Overview

angrop is a tool to automatically generate rop chains.

It is built on top of angr's symbolic execution engine, and uses constraint solving for generating chains and understanding the effects of gadgets.

angrop should support all the architectures supported by angr, although more testing needs to be done.

Typically, it can generate rop chains (especially long chains) faster than humans.

It includes functions to generate chains which are commonly used in exploitation and CTF's, such as setting registers, and calling functions.

Architectures

Supported architectures:

  • x86/x64
  • ARM
  • MIPS

It should be relatively easy to support other architectures that are supported by angr. If you'd like to use angrop on other architectures, please create an issue and we will look into it :)

Usage

The ROP analysis finds rop gadgets and can automatically build rop chains.

>>> import angr, angrop
>>> p = angr.Project("/bin/ls")
>>> rop = p.analyses.ROP()
>>> rop.find_gadgets()
>>> chain = rop.set_regs(rax=0x1337, rbx=0x56565656)
>>> chain.payload_str()
b'\xb32@\x00\x00\x00\x00\x007\x13\x00\x00\x00\x00\x00\x00\xa1\x18@\x00\x00\x00\x00\x00VVVV\x00\x00\x00\x00'
>>> chain.print_payload_code()
chain = b""
chain += p64(0x410b23)	# pop rax; ret
chain += p64(0x1337)
chain += p64(0x404dc0)	# pop rbx; ret
chain += p64(0x56565656)

Chains

# angrop includes methods to create certain common chains

# setting registers
chain = rop.set_regs(rax=0x1337, rbx=0x56565656)

# moving registers
chain = rop.move_regs(rax='rdx')

# writing to memory 
# writes "/bin/sh\0" to address 0x61b100
chain = rop.write_to_mem(0x61b100, b"/bin/sh\0")

# calling functions
chain = rop.func_call("read", [0, 0x804f000, 0x100])

# adding values to memory
chain = rop.add_to_mem(0x804f124, 0x41414141)

# shifting stack pointer like add rsp, 0x8; ret (this gadget shifts rsp by 0x10)
chain = rop.shift(0x10)

# generating ret-sled chains like ret*0x10, but works for ARM/MIPS as well
chain = rop.retsled(0x40)

# bad bytes can be specified to generate chains with no bad bytes
rop.set_badbytes([0x0, 0x0a])
chain = rop.set_regs(eax=0)

# chains can be added together to chain operations
chain = rop.write_to_mem(0x61b100, b"/home/ctf/flag\x00") + rop.func_call("open", [0x61b100,os.O_RDONLY]) + ...

# chains can be printed for copy pasting into exploits
>>> chain.print_payload_code()
chain = b""
chain += p64(0x410b23)	# pop rax; ret
chain += p64(0x74632f656d6f682f)
chain += p64(0x404dc0)	# pop rbx; ret
chain += p64(0x61b0f8)
chain += p64(0x40ab63)	# mov qword ptr [rbx + 8], rax; add rsp, 0x10; pop rbx; ret
...

Gadgets

Gadgets contain a lot of information:

For example look at how the following code translates into a gadget

   0x403be4:	and    ebp,edi
   0x403be6:	mov    QWORD PTR [rbx+0x90],rax
   0x403bed:	xor    eax,eax
   0x403bef:	add    rsp,0x10
   0x403bf3:	pop    rbx
   0x403bf4:	ret    
>>> print(rop.rop_gadgets[0])
Gadget 0x403be4
Stack change: 0x20
Changed registers: set(['rbx', 'rax', 'rbp'])
Popped registers: set(['rbx'])
Register dependencies:
    rbp: [rdi, rbp]
Memory write:
    address (64 bits) depends on: ['rbx']
    data (64 bits) depends on: ['rax']

The dependencies describe what registers affect the final value of another register. In the example above, the final value of rbp depends on both rdi and rbp. Dependencies are analyzed for registers and for memory actions. All of the information is stored as properties in the gadgets, so it is easy to iterate over them and find gadgets which fit your needs.

>>> for g in rop.rop_gadgets:
    if "rax" in g.popped_regs and "rbx" not in g.changed_regs:
        print(g)
Gadget 0x4032b3
Stack change: 0x10
Changed registers: set(['rax'])
Popped registers: set(['rax'])
Register dependencies:

TODO's

Allow strings to be passed as arguments to func_call(), which are then written to memory and referenced.

Add a function for open, read, write (for ctf's)

Allow using of angr objects such as BVV, BVS to make using symbolic values easy

The segment analysis for finding executable addresses seems to break on non-elf binaries often, such as PE files, kernel modules.

Allow setting constraints on the generated chain e.g. bytes that are valid.

Common gotchas

Make sure to import angrop before calling proj.analyses.ROP()

Make sure to call find_gadets() before trying to make chains

angrop's People

Contributors

angr-bot avatar antoniobianchi333 avatar astewart-bah avatar bannsec avatar dobin avatar ekilmer avatar kyle-kyle avatar ltfish avatar lukas-dresel avatar mahaloz avatar manouchehri avatar mohitrpatil avatar nebirhos avatar nickstephens avatar ninja3047 avatar nirizr avatar rhelmot avatar salls avatar sweetvishnya avatar symflood avatar twizmwazin avatar zardus avatar zwimer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angrop's Issues

Bad chain produced by write_to_mem

I'm trying to build a ROP chain for this binary, and there seems to be a problem with register usage in the chain built by write_to_mem(). If I run the following snippet, I get the chain below.

import angr, angrop
p = angr.Project("start")
rop = p.analyses.ROP()
rop.find_gadgets()
shellcode = "\x31\xc0\x99\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
shellcode_location = 0x6cc000
chain = rop.write_to_mem(shellcode_location, shellcode)
chain.print_payload_code()
chain = ""
chain += p64(0x443775)	# pop r10; ret 
chain += p64(0x732f2f685099c031)
chain += p64(0x410900)	# pop r15; ret 
chain += p64(0x6cc008)
chain += p64(0x4325fe)	# mov qword ptr [rdi - 8], rdx; ret 
chain += p64(0x443775)	# pop r10; ret 
chain += p64(0xe3896e69622f6868)
chain += p64(0x410900)	# pop r15; ret 
chain += p64(0x6cc010)
chain += p64(0x4325fe)	# mov qword ptr [rdi - 8], rdx; ret 
chain += p64(0x443775)	# pop r10; ret 
chain += p64(0x80cd0bb0e1895350)
chain += p64(0x410900)	# pop r15; ret 
chain += p64(0x6cc018)
chain += p64(0x4325fe)	# mov qword ptr [rdi - 8], rdx; ret 

The pop gadgets are setting r10 and r15, but the mov gadget is using rdi and rdx, thus it fails to write the desired buffer, instead corrupting some other memory.

Fails to craft difficult chain

Current build fails to craft a write_to_mem() chain for a binary with some odd gadgets (specifically the "fluff" challenge at ropemporium.com)
A working chain may be crafted using gadgets found with the 'ropper' tool.

add_to_mem fails in main due to RopValue Type Error

Description

A recent change to the RopValue object seems to have broken the rop.add_to_mem() function.

Steps to reproduce the bug

Included is a zip file. Extract the zip file and run start_new.sh. This will set up a python venv and install requirements. start_new will use the current git main of angrop. It will run a python script that will fetch the Ubuntu i386 libc and Ubuntu armel libc. Then it will prompt the user to produce example add_to_mem chains with both.

The i386 one will error as follows:

"TypeError: bad operand type for unary ~: 'RopValue'" . 

The armel chain will error before it gets that far, as follows:

"angrop.errors.RopException: Couldnt set registers for any memory add gadget". 

The armel error is shown further in #74.

angrop_issue_73.zip

Environment

No response

Additional context

No response

Invalid ropchains: Arguments are all 0x00

angrop seems to correctly identify the rop gadgets, but all arguments for them are 0x0.

x64:

>>> import angr, angrop
>>> p = angr.Project("/bin/ls")
>>> rop = p.analyses.ROP()
>>> rop.find_gadgets()
>>> chain = rop.write_to_mem(0x080d6804, "/bin/sh\0")
>>> chain.print_payload_code()
chain = ""
chain += p64(0x40a418)  # mov eax, edx; pop rbx; pop rbp; ret 
chain += p64(0x0)
chain += p64(0x0)
chain += p64(0x41288a)  # push rax; std ; mov qword ptr [rbx + 0x18], rbp; pop rbx; pop rbp; pop r12; pop r13; pop r14; ret 

x32 (xhttpd binary):

>>> chain.print_payload_code()
chain = ""
chain += p32(0x8063101) # pop edx; pop ecx; pop ebx; ret 
chain += p32(0x0)
chain += p32(0x0)
chain += p32(0x0)
chain += p32(0x8063216) # mov dword ptr [ecx], edx; pop ebp; ret 
chain += p32(0x0)


(gdb) x/5i 0x8063101
   0x8063101 <__lll_unlock_wake_private+33>:    pop    %edx
   0x8063102 <__lll_unlock_wake_private+34>:    pop    %ecx
   0x8063103 <__lll_unlock_wake_private+35>:    pop    %ebx
   0x8063104 <__lll_unlock_wake_private+36>:    ret    
   0x8063105:   nop
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.1 LTS"
$ uname -a
Linux minime 4.4.0-31-generic #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
$ 
$ sudo apt-get install libffi6 libffi6-dbg libffi-dev
$ sudo pip install pyvex claripy simuvex angr
$ sudo python setup.py install

stack pivot using rsp

Description

I have tried the move_regs feature and it works great with other registers ie rax=rbx .

However it gives an error 'unknown registers' when attempting to use rsp=rdi etc. this can be essential when looking for a stack pivot using rsp for example finding a gadget like ‘push rdi; pop rsp ; ret;’ .

If possible also doing computations like rsp = ‘rsp + 0x100’ to find gadget ‘add rsp, 0x100; ret;’ when attempting to pivot to a location where a shellcode is located or rsp = ‘rdi - 0x200’ to find a chain like [’sub rdi, 0x200; ret; ‘ , ’ push rdi; pop rsp; ret;' ]

thanks.

Alternatives

No response

Additional context

No response

gets stuck while generating memory write chain

Description

Running rex hangs in z3 while using angrop. Strangely, the constraints that it hangs on are trivially false, and plugging them into a fresh solver is able to solve them immediately. This is probably either a claripy or z3 bug, but I can't reproduce it elsewhere so I'm putting it here for now.

Steps to reproduce the bug

I don't think I can distribute the files publically. Contact me and ask for dandelion:lunchables/mypipeline/samples/1.tar.gz and dandelion:lunchables/mypipeline/crashes/502392183509221377.bin.

Environment

angr environment report

Date: 2024-03-25 22:21:49.619203
Running in virtual environment at /home/audrey/.virtualenvs/angr-c
/home/audrey/proj/angr/angr/angr/misc/bug_report.py:88: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
import pkg_resources # pylint:disable=import-outside-toplevel
Platform: linux-x86_64
Python version: 3.11.6 (main, Oct 8 2023, 05:06:43) [GCC 13.2.0]
######## angr #########
Python found it in /home/audrey/proj/angr/angr/angr/init.py
Pip version angr 9.2.89.dev0
Git info:
Current commit 45cb17dfd014978248fb7e2900c9707910b5eae1 from branch master
Checked out from remote origin: [email protected]:angr/angr.git
######## ailment #########
Python found it in /home/audrey/proj/angr/ailment/ailment/init.py
Pip version ailment 9.2.89.dev0
Git info:
Current commit c27c069586d147fc21daf664114df8e85df86adb from branch master
Checked out from remote origin: https://github.com/angr/ailment.git
######## cle #########
Python found it in /home/audrey/proj/angr/cle/cle/init.py
Pip version cle 9.2.89.dev0
Git info:
Current commit 2671c1efa743ebe52da8d106ad52336ba4f7485b from branch master
Checked out from remote origin: https://github.com/angr/cle.git
######## pyvex #########
Python found it in /home/audrey/proj/angr/pyvex/pyvex/init.py
Pip version pyvex 9.2.89.dev0
Git info:
Current commit 1b93db3d7a1f95c64f57fc036794d71d1c9b3167 from branch master
Checked out from remote origin: https://github.com/angr/pyvex.git
######## claripy #########
Python found it in /home/audrey/proj/angr/claripy/claripy/init.py
Pip version claripy 9.2.89.dev0
Git info:
Current commit 06a9bd3f7eec4a1ffc77c8676b29ae79b4630796 from branch master
Checked out from remote origin: [email protected]:angr/claripy.git
######## archinfo #########
Python found it in /home/audrey/proj/angr/archinfo/archinfo/init.py
Pip version archinfo 9.2.89.dev0
Git info:
Current commit eebcd9118c02cc7abd24681686d09ab394a937bf from branch master
Checked out from remote origin: https://github.com/angr/archinfo.git
######## z3 #########
Python found it in /home/audrey/.virtualenvs/angr-c/lib/python3.11/site-packages/z3/init.py
Pip version z3-solver 4.10.2.0
Couldn't find git info
######## unicorn #########
Python found it in /home/audrey/.virtualenvs/angr-c/lib/python3.11/site-packages/unicorn/init.py
Pip version unicorn 2.0.1.post1
Couldn't find git info
######### Native Module Info ##########
angr: <CDLL '/home/audrey/proj/angr/angr/angr/state_plugins/../lib/angr_native.so', handle 2c0c430 at 0x7cb326d27190>
unicorn: <CDLL '/home/audrey/.virtualenvs/angr-c/lib/python3.11/site-packages/unicorn/lib/libunicorn.so.2', handle 26116c0 at 0x7cb32a813490>
pyvex: <cffi.api._make_ffi_library..FFILibrary object at 0x7cb32b6f41d0>
z3: <CDLL '/home/audrey/.virtualenvs/angr-c/lib/python3.11/site-packages/z3/lib/libz3.so', handle 22552d0 at 0x7cb32d39ec10>

Additional context

No response

SimUnsatError during gadget chain construction

This raises a SimUnsatError:

import angr
import angrop

p = angr.Project('/lib/x86_64-linux-gnu/libc.so.6')
r = p.analyses.ROP()
r.find_gadgets()
r.execve("/bin/bash")
....
ROP: 100% ||||||||||||||||||||||||||||||||||||||||||| Time: 1:09:08  52.15  B/s

In [5]: r.execve("/bin/bash")
WARNING | 2017-11-14 16:42:07,628 | angrop.chain_builder | writing to 0x7c8fc0
---------------------------------------------------------------------------
SimUnsatError                             Traceback (most recent call last)
<ipython-input-5-8326e2731458> in <module>()
----> 1 r.execve("/bin/bash")

/home/yans/code/angr/angrop/angrop/chain_builder.pyc in execve(self, target, addr_for_str)
    427         # TODO If this fails try using partial controllers
    428         chain2 = self.do_syscall(self._execve_syscall, [addr_for_str, 0, 0],
--> 429                                  use_partial_controllers=use_partial_controllers, needs_return=False)
    430         result = chain + chain2
    431 

/home/yans/code/angr/angrop/angrop/chain_builder.pyc in do_syscall(self, syscall_num, arguments, ignore_registers, modifiable_memory_range, use_partial_controllers, rebase_regs, needs_return)
    127 
    128         # first find gadgets to the set the registers
--> 129         chain = self.set_regs(modifiable_memory_range, use_partial_controllers, rebase_regs, **registers)
    130 
    131         # find small stack change syscall gadget that also fits the stack arguments we want

/home/yans/code/angr/angrop/angrop/chain_builder.pyc in set_regs(self, modifiable_memory_range, use_partial_controllers, rebase_regs, **registers)
     86 
     87         return self._build_reg_setting_chain(gadgets, modifiable_memory_range,
---> 88                                              registers, best_stack_change, rebase_regs)
     89 
     90     # TODO handle mess ups by _find_reg_setting_gadgets and see if we can set a register in a syscall preamble

/home/yans/code/angr/angrop/angrop/chain_builder.pyc in _build_reg_setting_chain(self, gadgets, modifiable_memory_range, register_dict, stack_change, rebase_regs)
    804                                                        endness=self.project.arch.memory_endness)
    805 
--> 806             val = test_symbolic_state.se.eval(sym_word)
    807 
    808             if len(rebase_regs) > 0:

/home/yans/code/angr/angr/angr/state_plugins/solver.pyc in eval(self, e, **kwargs)
    536         """
    537         # eval_upto already throws the UnsatError, no reason for us to worry about it
--> 538         return self.eval_upto(e, 1, **kwargs)[0]
    539 
    540     def eval_one(self, e, **kwargs):

/home/yans/code/angr/angr/angr/state_plugins/solver.pyc in eval_upto(self, e, n, cast_to, **kwargs)
    519             return [self._cast_to(e, concrete_val, cast_to)]
    520 
--> 521         cast_vals = [self._cast_to(e, v, cast_to) for v in self._eval(e, n, **kwargs)]
    522         if len(cast_vals) == 0:
    523             raise SimUnsatError('Not satisfiable: %s, expected up to %d solutions' % (e.shallow_repr(), n))

/home/yans/code/angr/angr/angr/state_plugins/solver.pyc in concrete_shortcut_tuple(self, *args, **kwargs)
    155         v = _concrete_value(args[0])
    156         if v is None:
--> 157             return f(self, *args, **kwargs)
    158         else:
    159             return ( v, )

/home/yans/code/angr/angr/angr/state_plugins/sim_action_object.pyc in ast_stripper(*args, **kwargs)
     51         new_args = _raw_ast(args)
     52         new_kwargs = _raw_ast(kwargs)
---> 53         return f(*new_args, **new_kwargs)
     54     return ast_stripper
     55 

/home/yans/code/angr/angr/angr/state_plugins/solver.pyc in wrapped_f(*args, **kwargs)
     86     def wrapped_f(*args, **kwargs):
     87         try:
---> 88             return f(*args, **kwargs)
     89         except claripy.UnsatError:
     90             e_type, value, traceback = sys.exc_info()

/home/yans/code/angr/angr/angr/state_plugins/solver.pyc in _eval(self, e, n, extra_constraints, exact)
    367         :rtype: tuple
    368         """
--> 369         return self._solver.eval(e, n, extra_constraints=self._adjust_constraint_list(extra_constraints), exact=exact)
    370 
    371     @concrete_path_scalar

/home/yans/code/angr/claripy/claripy/frontend_mixins/concrete_handler_mixin.pyc in eval(self, e, n, **kwargs)
      5             return (c,)
      6         else:
----> 7             return super(ConcreteHandlerMixin, self).eval(e, n, **kwargs)
      8 
      9     def batch_eval(self, exprs, n, **kwargs): #pylint:disable=unused-argument

/home/yans/code/angr/claripy/claripy/frontend_mixins/constraint_filter_mixin.pyc in eval(self, e, n, extra_constraints, **kwargs)
     38     def eval(self, e, n, extra_constraints=(), **kwargs):
     39         ec = self._constraint_filter(extra_constraints)
---> 40         return super(ConstraintFilterMixin, self).eval(e, n, extra_constraints=ec, **kwargs)
     41 
     42     def batch_eval(self, exprs, n, extra_constraints=(), **kwargs):

/home/yans/code/angr/claripy/claripy/frontend_mixins/sat_cache_mixin.pyc in eval(self, e, n, extra_constraints, **kwargs)
     54             r = super(SatCacheMixin, self).eval(
     55                 e, n,
---> 56                 extra_constraints=extra_constraints, **kwargs
     57             )
     58             self._cached_satness = True

/home/yans/code/angr/claripy/claripy/frontend_mixins/simplify_helper_mixin.pyc in eval(self, e, n, *args, **kwargs)
     11         if n > 1:
     12             self.simplify()
---> 13         return super(SimplifyHelperMixin, self).eval(e, n, *args, **kwargs)
     14 
     15     def batch_eval(self, e, n, *args, **kwargs):

/home/yans/code/angr/claripy/claripy/frontend_mixins/constraint_expansion_mixin.pyc in eval(self, e, n, extra_constraints, exact, **kwargs)
     10             extra_constraints=extra_constraints,
     11             exact=exact,
---> 12             **kwargs
     13         )
     14 

/home/yans/code/angr/claripy/claripy/frontends/composite_frontend.pyc in eval(self, e, n, extra_constraints, exact)
    279 
    280     def eval(self, e, n, extra_constraints=(), exact=None):
--> 281         self._ensure_sat(extra_constraints=extra_constraints)
    282 
    283         ms = self._merged_solver_for(e=e, lst=extra_constraints)

/home/yans/code/angr/claripy/claripy/frontends/composite_frontend.pyc in _ensure_sat(self, extra_constraints)
    257     def _ensure_sat(self, extra_constraints):
    258         if self._unsat or (len(extra_constraints) == 0 and not self.satisfiable()):
--> 259             raise UnsatError("CompositeSolver is already unsat")
    260 
    261     def satisfiable(self, extra_constraints=(), exact=None):

SimUnsatError: ('Got an unsat result', <class 'claripy.errors.UnsatError'>, UnsatError('CompositeSolver is already unsat',))

libc.tar.gz

Moving register values

Question

Hello,

I was wondering if there's an example where I can move register values e.g. rop.set_regs(eax="ecx")

Regression: does not find syscall gadget with blob backend

Description

do_syscall does not work with the blob backend anymore.

Steps to reproduce the bug

Consider this minimal example:

import angr, angrop

with open("/tmp/test", "wb") as f:
    f.write(b"\x58\xC3\x0F\x05") # pop rax; ret; syscall

p = angr.Project("/tmp/test", main_opts={'backend': 'blob', 'arch': 'amd64'})
rop = p.analyses.ROP()
rop.find_gadgets()

chain = rop.do_syscall(0x42, [], needs_return=False)
chain.print_payload_code()

This works fine in angrop v9.2.8 but fails with "target does not contain syscall gadget!" in v9.2.9. The first bad commit is 07d2b2e.

Environment

angrop latest commit (e325bb6)

$ /home/me/src/angrop/venv/bin/python -m angr.misc.bug_report
angr environment report
=============================
Date: 2024-04-21 18:45:03.372895
!!! running in global environment.  Are you sure? !!!
/home/me/src/angrop/venv/lib/python3.11/site-packages/angr/misc/bug_report.py:88: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  import pkg_resources  # pylint:disable=import-outside-toplevel
Platform: linux-x86_64
Python version: 3.11.8 (main, Feb 12 2024, 14:50:05) [GCC 13.2.1 20230801]
######## angr #########
Python found it in /home/me/src/angrop/venv/lib/python3.11/site-packages/angr/__init__.py
Pip version angr 9.2.99
Git info:
	Current commit e325bb60a0251bb8c0075205187ed7cff54ec682 from branch master
	Checked out from remote origin: https://github.com/angr/angrop
######## ailment #########
Python found it in /home/me/src/angrop/venv/lib/python3.11/site-packages/ailment/__init__.py
Pip version ailment 9.2.99
Git info:
	Current commit e325bb60a0251bb8c0075205187ed7cff54ec682 from branch master
	Checked out from remote origin: https://github.com/angr/angrop
######## cle #########
Python found it in /home/me/src/angrop/venv/lib/python3.11/site-packages/cle/__init__.py
Pip version cle 9.2.99
Git info:
	Current commit e325bb60a0251bb8c0075205187ed7cff54ec682 from branch master
	Checked out from remote origin: https://github.com/angr/angrop
######## pyvex #########
Python found it in /home/me/src/angrop/venv/lib/python3.11/site-packages/pyvex/__init__.py
Pip version pyvex 9.2.99
Git info:
	Current commit e325bb60a0251bb8c0075205187ed7cff54ec682 from branch master
	Checked out from remote origin: https://github.com/angr/angrop
######## claripy #########
Python found it in /home/me/src/angrop/venv/lib/python3.11/site-packages/claripy/__init__.py
Pip version claripy 9.2.99
Git info:
	Current commit e325bb60a0251bb8c0075205187ed7cff54ec682 from branch master
	Checked out from remote origin: https://github.com/angr/angrop
######## archinfo #########
Python found it in /home/me/src/angrop/venv/lib/python3.11/site-packages/archinfo/__init__.py
Pip version archinfo 9.2.99
Git info:
	Current commit e325bb60a0251bb8c0075205187ed7cff54ec682 from branch master
	Checked out from remote origin: https://github.com/angr/angrop
######## z3 #########
Python found it in /home/me/src/angrop/venv/lib/python3.11/site-packages/z3/__init__.py
Pip version z3-solver 4.10.2.0
Git info:
	Current commit e325bb60a0251bb8c0075205187ed7cff54ec682 from branch master
	Checked out from remote origin: https://github.com/angr/angrop
######## unicorn #########
Python found it in /home/me/src/angrop/venv/lib/python3.11/site-packages/unicorn/__init__.py
Pip version unicorn 2.0.1.post1
Git info:
	Current commit e325bb60a0251bb8c0075205187ed7cff54ec682 from branch master
	Checked out from remote origin: https://github.com/angr/angrop
######### Native Module Info ##########
angr: <CDLL '/home/me/src/angrop/venv/lib/python3.11/site-packages/angr/state_plugins/../lib/angr_native.so', handle 61b245780a50 at 0x7488e5fc9550>
unicorn: <CDLL '/home/me/src/angrop/venv/lib/python3.11/site-packages/unicorn/lib/libunicorn.so.2', handle 61b245187010 at 0x7488e90d2890>
pyvex: <cffi.api._make_ffi_library.<locals>.FFILibrary object at 0x7488e9d646d0>
z3: <CDLL '/home/me/src/angrop/venv/lib/python3.11/site-packages/z3/lib/libz3.so', handle 61b244db4a00 at 0x7488ec3c4210>

Additional context

No response

Reference to missing angr.option

Description

Loading a large binary executes make_initial_state which references angr.options.ADD_AUTO_REFS that does not exist.

    def make_initial_state(project, stack_length):
    """
    :return: an initial state with a symbolic stack and good options for rop
    """
    initial_state = project.factory.blank_state(
        add_options={angr.options.AVOID_MULTIVALUED_READS, angr.options.AVOID_MULTIVALUED_WRITES,
                     angr.options.NO_SYMBOLIC_JUMP_RESOLUTION, angr.options.CGC_NO_SYMBOLIC_RECEIVE_LENGTH,
                     angr.options.NO_SYMBOLIC_SYSCALL_RESOLUTION, angr.options.TRACK_ACTION_HISTORY,
                     angr.options.ADD_AUTO_REFS},
WARNING | 2022-11-09 14:57:50,597 | angrop.rop | Enabling fast mode for large binary
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-41609c3c5113> in <module>()
----> 1 _.find_gadgets()

/usr/local/lib/python3.6/dist-packages/angrop/rop.py in find_gadgets(self, processes, show_progress)
    146         :param processes: number of processes to use
    147         """
--> 148         self._initialize_gadget_analyzer()
    149         self._gadgets = []
    150 

/usr/local/lib/python3.6/dist-packages/angrop/rop.py in _initialize_gadget_analyzer(self)
    137                num_to_check, self.arch.max_block_size)
    138 
--> 139         self._gadget_analyzer = gadget_analyzer.GadgetAnalyzer(self.project, self._fast_mode, arch=self.arch)
    140 
    141     def find_gadgets(self, processes=4, show_progress=True):

/usr/local/lib/python3.6/dist-packages/angrop/gadget_analyzer.py in __init__(self, project, fast_mode, arch, stack_length)
     26         self._stack_length_bytes = self._stack_length * self.project.arch.bytes
     27         self._test_symbolic_state = rop_utils.make_symbolic_state(self.project, self.arch.reg_list,
---> 28                                                                   stack_length=self._stack_length)
     29         self._stack_pointer_value = self._test_symbolic_state.solver.eval(self._test_symbolic_state.regs.sp)
     30 

/usr/local/lib/python3.6/dist-packages/angrop/rop_utils.py in make_symbolic_state(project, reg_list, stack_length)
    180     :return: the symbolic state
    181     """
--> 182     input_state = make_initial_state(project, stack_length)
    183     symbolic_state = input_state.copy()
    184     # overwrite all registers

/usr/local/lib/python3.6/dist-packages/angrop/rop_utils.py in make_initial_state(project, stack_length)
    160                      angr.options.NO_SYMBOLIC_JUMP_RESOLUTION, angr.options.CGC_NO_SYMBOLIC_RECEIVE_LENGTH,
    161                      angr.options.NO_SYMBOLIC_SYSCALL_RESOLUTION, angr.options.TRACK_ACTION_HISTORY,
--> 162                      angr.options.ADD_AUTO_REFS},
    163         remove_options=angr.options.resilience | angr.options.simplification)
    164     initial_state.options.discard(angr.options.CGC_ZERO_FILL_UNCONSTRAINED_MEMORY)

AttributeError: module 'angr.sim_options' has no attribute 'ADD_AUTO_REFS'

REFERENCE:

angr.options.ADD_AUTO_REFS},

Steps to reproduce the bug

  1. Find a large binary
  2. import angr, angrop
  3. p = angr.Project('./binary')
  4. r = p.analyses.ROP()
  5. r.find_gadgets()

Environment

No response

Additional context

No response

add_to_mem causes angrop.errors.RopException: Does not get to a single unconstrained successor

Description

When testing ubuntu i386 libc for add_to_mem, I get the following error:

Traceback (most recent call last):
  File "test.py", line 61, in <module>
    rop.add_to_mem(0xdeadbeef, 0x62a000)
  File "lib/python3.10/site-packages/angrop/chain_builder/__init__.py", line 76, in add_to_mem
    return self._mem_changer.add_to_mem(addr, value, data_size=data_size)
  File "lib/python3.10/site-packages/angrop/chain_builder/mem_changer.py", line 82, in add_to_mem
    state = chain2.exec()
  File "lib/python3.10/site-packages/angrop/rop_chain.py", line 182, in exec
    return rop_utils.step_to_unconstrained_successor(self._p, state, max_steps=max_steps,
  File "lib/python3.10/site-packages/angrop/rop_utils.py", line 224, in step_to_unconstrained_successor
    return step_to_unconstrained_successor(project, succ.flat_successors[0],
  File "lib/python3.10/site-packages/angrop/rop_utils.py", line 224, in step_to_unconstrained_successor
    return step_to_unconstrained_successor(project, succ.flat_successors[0],
  File "lib/python3.10/site-packages/angrop/rop_utils.py", line 219, in step_to_unconstrained_successor
    raise RopException("Does not get to a single successor")
angrop.errors.RopException: Does not get to a single successor

Steps to reproduce the bug

Attached is zip file. Unzip and run start_test.sh.
issue_76.zip

Environment

No response

Additional context

No response

pypi??

Can we get this added to pypi? Would love to be able to pip install it.

angrop fails as `xor` argument get lost in space

Symptoms

I cannot run angrop on garbagetruck plaidctf chall due to an angr bug.

Cause

It seems that Angr (it's vex engine ) cannot handle a Left Shift as 2nd operand of the xor ( or that operation shall be first moved to another reg ).

Versions:

Angrop from sources, commit ce5d98b
angr-7.7.12.16 from pip

Binary:

http://ropshell.com/ropsearch?h=67352acee5f5e8770121b9ea717b1c1a

Script:

import angr, angrop

p = angr.Project("garbagetruck")
rop = p.analyses.ROP()
rop.find_gadgets()

# ... never reached

Debugging info:

https://pastebin.com/TbZBPpu7

angrop.errors.RopException: Couldn't set registers :(

Hi,

I am running angrop, using the following script

import angr, angrop

p = angr.Project('rop')
rop = p.analyses.ROP()
rop.find_gadgets()
chain = rop.set_regs(eax=0x4)
chain.print_payload_code()

and i am getting this error:
angrop.errors.RopException: Couldn't set registers :(

If i try to write to memory,

chain = rop.write_to_mem(0x5655701c, "Hello\0")

i also get this error:
angrop.errors.RopException: No bytes in memory for block starting at 0x41414141.

Am i doing anything wrong?

Thank you very much!

Bad Assumption About Rebasing Data Bytes in Chains against Binaries With PIE

Description

I found a bad assumption here.

It assumes if a binary is built against a binary with PIE enabled, than all concrete values need to be rebased. However, this is only true for gadgets, not data. Take the example where the user wants to build the following chain:

chain = rop.write_to_mem(0xdeadbeef, b"/bin/sh\x00")

This chain should write "/bin/sh" to the static memory location 0xdeadbeef. This location is not in program memory, and as such should not be rebased.

The attached example will produce some chains that hit this bad logic, and some that do not. You will notice that the working chains (that avoid this logic) do not include 0xbeadbeef as a value exactly, but rather something very close to it. This is because, in these cases, angrop as picked a gadget that can not write directly to the address that a register points to, but rather adds or subtracts some small value from the value in the register, and uses the modified value as the write location. In these cases, angrop has not yet set a static concrete value when this logic is checked, and rather has a symbolic BV object in this location. Since it is not an int, this bad logic is bypassed.

Because of this behavior, one possible solution would be to allow the user to specify that a write location is static, and have angrop set it as a symbolic state BV even if it is not necessary for other analysis.

Steps to reproduce the bug

Included is a zip file. Extract the zip file and run start.sh. It will set up a python venv, install requirements, and run the test.py script. This python script will fetch the Ubuntu i386 libc and produce an example of a good chain (one that does not hit this code path) and a bad chain (one that does hit this code path).
angrop_issue_67.zip

Environment

Run on Ubuntu 22.04 in python 3.10

Additional context

No response

keep gadgets with large stack shifts

Description

It looks like angrop discards gadgets that have a stack shift > 0x100 bytes (MAX_PIVOT_BYTES).

In two recent projects, I have found it necessary to jump to a distant portion of the stack. While these gadgets may not be useful for angrop main purpose of automatically building ROP chains, these gadgets are still very valuable for manually selecting stack shifts.

Alternatives

No response

Additional context

No response

Multiple Register Pops Not Working in ARM.

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

Does add_to_mem ever work?

I am testing angrop on a bunch of files, and I noticed that it never successfully produced a chain involving add_to_mem.

Even when I hand-crafted gadgets for it to use, it couldn't find it:

 59d:   58                      pop    %eax
 59e:   5b                      pop    %ebx
 59f:   c3                      ret    
 5a0:   01 c3                   add    %eax,%ebx
 5a2:   c3                      ret    

I'm attaching this hand-made test binary and the script I'm using. I specifically expected the got chain to be produced. Am I doing something wrong?

test.zip

Values passed on stack ignoring badbytes

import angr, angrop
p = angr.Project("bronze_ropchain")
rop = p.analyses.ROP()
rop.set_badbytes([0x0, 0x0a])
rop.find_gadgets()
rop.execve().payload_str()
> b'\xb4d\x05\x08\xc9bin\xbc\xcf\r\x08\x00\x00\x00\x00\xc7a\x06\x08\xb4d\x05\x08\xc9sh\x00\xc0\xcf\r\x08\x00\x00\x00\x00\xc7a\x06\x08\x9c\x89\x04\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\xcf\r\x08\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00`\xf8\x06\x08'

Support for blob loader (`There are 0 addresses within x bytes` bug)

Can't seem to get angrop working with a blob. Haven't been able to figure out the cause yet.

In [1]: import angr, angrop

In [2]: rop = proj.analyses.ROP(only_check_near_rets=False, fast_mode=False, max_block_size=0x10000)
INFO    | 2017-05-03 05:30:08,653 | angrop.rop | There are 0 addresses within 65536 bytes of a ret

Currently loading the blob like this:

proj = angr.Project("./ddr2.raw.dump.bin", load_options={
	'main_opts': {
		'backend': 'blob',
		'custom_arch': 'mips',
		'custom_entry_point': ENTRY_ADDR,
		'segments': {(0x0, RAM_START_ADDR, RAM_SIZE)},
	}
	'auto_load_libs': False, # Probably not needed.
})

`test_rop_i386_cgc` timeout in CI

angr CI, test_rop_i386_cgc will fail about 20% of the time and takes >2 minutes to run.

image


Interestingly nearby gadgets are found, but the target gadget is not.

======================================================================
FAIL: test_rop.test_rop_i386_cgc
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/__w/1/s/build/src/angrop/tests/test_rop.py", line 133, in test_rop_i386_cgc
    compare_gadgets(rop.gadgets, test_gadgets)
  File "/__w/1/s/build/src/angrop/tests/test_rop.py", line 79, in compare_gadgets
    nose.tools.assert_in(g.addr, found_addrs)
AssertionError: 134513864 not found in {134513692, 134513696, 134513697, 134513698, 134513699, 134513700, 134513701, 134513702, 134513704, 134513705, 134513706, 134513707, 134513716, 134513718, 134513720, 134513722, 134513724, 134513725, 134513727, 134513729, 134513731, 134513732, 134513744, 134513746, 134513748, 134513750, 134513751, 134513752, 134513754, 134513756, 134513757, 134513758, 134513759, 134513760, 134513761, 134513762, 134513763, 134513764, 134513776, 134513778, 134513780, 134513782, 134513783, 134513784, 134513786, 134513788, 134513789, 134513790, 134513791, 134513792, 134513793, 134513794, 134513795, 134513796, 134513813, 134513814, 134513815, 134513816, 134513817, 134513819, 134513821, 134513823, 134513825, 134513826, 134513827, 134513828, 134513829, 134513830, 134513831, 134513832, 134513833, 134513834, 134513839, 134513840, 134513841, 134513842, 134513843, 134513845, 134513846, 134513847, 134513849, 134513850, 134513851, 134513852, 134513853, 134513854, 134513855, 134513856, 134513857, 134513858, 134513859, 134513860, 134513861, 134513862, 134513863, 134513865, 134513866, 134513867, 134513868, 134513870, 134513872, 134513874, 134513876, 134513878, 134513879, 134513880, 134513885, 134513886, 134513887, 134513888, 134513889, 134513891, 134513892, 134513893, 134513895, 134513896, 134513897, 134513898, 134513899, 134513900, 134513901, 134513902, 134513903, 134513904, 134513905, 134513906, 134513919, 134513921, 134513922, 134513925, 134513927, 134513928, 134513931, 134513933, 134513962, 134513965, 134513967, 134513471, 134513472, 134513473, 134513476, 134513477, 134513478, 134513479, 134513480, 134513481, 134513482, 134513484, 134513485, 134513486, 134513487, 134513488, 134513489, 134513490, 134513031, 134513032, 134513034, 134513036, 134513038, 134513039, 134513040}

-------------------- >> begin captured stdout << ---------------------
[angrop] Timeout

x86 syscall instructions mis-identified

Description

While using angrop on x86, a syscall gadget containing the x86_64 syscall instruction was identified for use in an example rop chain. This the x86_64 syscall instruction is not valid on x86, execution caused a SIGILL signal.

Steps to reproduce the bug

Attached is a zip file. Unzip and run start.sh. This will init a python env, install requirements, build the test binary, and run the python test file. This file will provide an example of the issue.
angrop_issue_x86_syscall.zip

Environment

No response

Additional context

No response

filter out privileged instructions

Description

angrop is designed for userspace ROP chain generation and should not include privileged instructions in the ROP chain.
We should add a filter in the architecture-specific configurations.

Steps to reproduce the bug

No response

Environment

No response

Additional context

No response

SP not recognized as register on aarch64

----> 1 rop.set_regs(sp = 0x10)

/home/jeff/.virtualenvs/angr/local/lib/python2.7/site-packages/angrop/chain_builder.pyc in set_regs(self, modifiable_memory_range, use_partial_controllers, rebase_regs, **registers)
     81
     82         gadgets, best_stack_change, _ = self._find_reg_setting_gadgets(modifiable_memory_range,
---> 83                                                                        use_partial_controllers, **registers)
     84         if gadgets is None:
     85             raise RopException("Couldn't set registers :(")

/home/jeff/.virtualenvs/angr/local/lib/python2.7/site-packages/angrop/chain_builder.pyc in _find_reg_setting_gadgets(self, modifiable_memory_range, use_partial_controllers, max_stack_change, **registers)
    853             search_regs.add(reg)
    854             if reg not in self._reg_list:
--> 855                 raise RopException("Register %s not in reg list" % reg)
    856
    857         # lets try doing a graph search to set registers, something like dijkstra's for minimum length

RopException: Register sp not in reg list

func_call gadget in mips

Question

I'm looking for a func_call gadget in my mips binary. Using ropper tool I've found this valid gadget:

move    $a1, $s1
jalr    $s3
move    $a2, $s0
lw $ra, 0x48($sp)
lw $s1, 0x48+var_24($sp)
lw $s0, 0x48+var_28($sp)
jr $ra
addiu $sp, 0x48

Using this gadget I can jump to any function (I've control over s3 from previous gadget) with 2 args.

However, when I try to use anrop, it truncates the gadget to the first 3 instructions:

move    $a1, $s1
jalr    $s3
move    $a2, $s0

and therefore fails to find a valid func_call gadget.
I guess that it happens because angr terminates the block after the jalr instruction...
Any ideas on how to fix this?

Thanks!

add ignore_registers support for func_call()

Description

So lets say I want to generate a reverse shell rop chain.

  1. I start with calling "socket(int domain, int type, int protocol)" with domain = 2, type = 1, protocol = 0. The result of this call will be a file descriptor in eax. This could be accomplished with either of the following:
call_number = 359 # syscall number for "socket"
chain += rop.do_syscall(call_number, [2, 1, 0])
#or
chain += rop.func_call("socket", [2, 1, 0])
  1. lets assume a gadget exists that allows for moving the contents of eax to ebx:
eax_to_ebx_gadget.addr = 0xdeadbeef
eax_to_ebx_gadget.popped_regs = ["ecx", "edx"]
eax_to_ebx_chain.add_value(eax_to_ebx_gadget.addr)
for reg in eax_to_ebx_gadget.popped_regs:
    eax_to_ebx_chain.add_value(0)
chain += eax_to_ebx_chain
  1. Now that the file descriptor is in ebx, it can be used to call "dup2(int oldfd, int newfd)" where oldfd is to be the result from the socket call that was moved into ebx and newfd is 0 for stdin and 1 for stdout:
stdin = 0
stdout = 1
call_number = 63 # syscall number for "dup2"
chain += rop.do_syscall(call_number, [0, stdin], ignore_registers=['ebx']) 
chain += rop.do_syscall(call_number, [0, stdout], ignore_registers=['ebx']) 

The "ebx register is ignored, so the "zero" in the arguments list is just a placeholder and could be anything.

This works fine with do_syscall(), but since func_call() does not support ignoring registers, it can not be used here unless you knew ahead of time what the file descriptor would be.

This obviously isnt the end of the chain, but I think this describes the issue.

Alternatives

No response

Additional context

No response

Long Chains Timeout when calling chain.payload_str()

Description

I have run into an issue with long rop chains where calling chain.payload_str() receives a timeout.

[angrop] Timeout

This is due to the hard coded timeout here for _concretize_chain_values
Likely do to the fact that the timeout is independent of the number of ._values that need to be processed.

Steps to reproduce the bug

Attached is a zip file containing an example script. Run setup.sh to build the .venv and run the example.

This will build an example chain and call chain.payload_str() in a loop where the chain size is increased until the timeout is reached.
angrop_issue.zip

Environment

No response

Additional context

No response

write_to_mem Broken for 32 bit Binaries

Description

As of this commit rop.write_to_mem does not work properly for 32 bit binaries. The target write address will never appear in the chain. This problem does not effect 64 bit binaries.

Steps to reproduce the bug

Included is a zip file. Extract the zip file and run start_new.sh and start_old.sh (not at the same time). These will set up a python venv and install requirements. start_new will use the current git main of angrop, while start_old will use 9.2.8. Both will run a respective python script that will fetch the Ubuntu i386 libc and Ubuntu amd64 libc. Then it will produce example chains with both. The examples produced by 9.2.8 will be valid for both 32 and 64 bit version, while the examples produced by git main will only be valid for the 64 bit version.
angrop_issue_68.zip

Environment

Run on Ubuntu 22.04 in python 3.10

Additional context

No response

Import error

Starting with 9.0.7293 there is a ImportError present which blocks the building of the module on NixOS.

  File "<string>", line 1, in <module>
  File "<string>", line 1, in <lambda>
  File "/nix/store/hq6mrm0pc6xn6j8y6lm4qcgg9rwmqd8q-python3-3.8.9/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/nix/store/g021fx75b3jw27clrnx6i1ghg9xfj81r-python3.8-angrop-9.0.7293/lib/python3.8/site-packages/angrop/__init__.py", line 3, in <module>
    from . import rop
  File "/nix/store/g021fx75b3jw27clrnx6i1ghg9xfj81r-python3.8-angrop-9.0.7293/lib/python3.8/site-packages/angrop/rop.py", line 7, in <module>
    from . import chain_builder
ImportError: cannot import name 'chain_builder' from partially initialized module 'angrop' (most likely due to a circular import) (/nix/store/g021fx75b3jw27clrnx6i1ghg9xfj81r-python3.8-angrop-9.0.7293/lib/python3.8/site-packages/angrop/__init__.py)

Can be reproduced on Fedora 24 in a clean venv after an installation from PyPI.

(angrop1) [fabaff@test-python angrop1]$ python
Python 3.9.5 (default, May  4 2021, 00:00:00) 
[GCC 11.1.1 20210428 (Red Hat 11.1.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import angrop
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/fabaff/angrop1/lib64/python3.9/site-packages/angrop/__init__.py", line 3, in <module>
    from . import rop
  File "/home/fabaff/angrop1/lib64/python3.9/site-packages/angrop/rop.py", line 7, in <module>
    from . import chain_builder
ImportError: cannot import name 'chain_builder' from partially initialized module 'angrop' (most likely due to a circular import) (/home/fabaff/angrop1/lib64/python3.9/site-packages/angrop/__init__.py)
>>> 

TODO Features

handle gadgets like

[ins] In [2]: chain.print_payload_code()
chain = b""
chain += p32(0x809d9f7)	# mov eax, dword ptr [esp + 4]; ret 0xc
chain += p32(0x1010101)
chain += p32(0x0)
chain += p32(0xf5f5f5f5)

The issue is that this gadget requires another pop gadget to function correctly. But angrop currently does not support this.
Should be easy enough by adding a special "gadget value" without interfering with the gadget effect

change how angrop works fundamentally to get rid of the assumption of each gadget transition performs similar to a ret

angr-bot dead on this repo

Description

angr-bot seems to have missed this repo since around September. The current version is 9.2.8 in this repo:

__version__ = "9.2.8.dev0"

On PyPi we are on 9.2.7 (last updated in September of 2022):
https://pypi.org/project/angrop/

As you might guess, this causes angrop to fail on import in any pypi install.
@Kyle-Kyle did you intentionally remove it from PyPi? If not, @twizmwazin can this get readded?

Steps to reproduce the bug

No response

Environment

No response

Additional context

No response

x86_64 `ret 0x10` instructions not handled properly

Description

This issue boils down to the order of operations. Angrop currently thinks 0x10 is added to rsp, and then the return address is popped from the stack. The correct order of events is that the return address is popped from the stack, and then 0x10 is added to rsp.

Steps to reproduce the bug

Attached is a zip file. Unzip and run start.sh. This will init a python env, install requirements, build the test binary, and run the python test file. This file will provide an example of the issue.
angrop_issue_retn_0x10.zip

Environment

No response

Additional context

No response

pop ds; ret gadgets are not properly handled.

Description

angrop assumes that "pop ds; ret;" gadgets are acceptable for shifting 8 bytes on the stack. This is a bad assumption, and causes failed chains.

The below is the output of the included example scripts.

Since a "pop ds; ret;" gadget appeared early in the binary, it appears to be the default gadget for shifting 8 bytes on the stack.
This is the result of rop.shift(8):
code_base = 0x0
chain = b""
chain += p32(code_base + 0x11fd)	# pop ds; ret 
chain += p32(0x0)




Now when we try to build a chain for a function call that only takes 1 argument, the stack needs to shift 8 bytes to clean up the argument off of the stack.
This chain calls close(0) followed by exit(0):
code_base = 0x0
chain = b""
chain += p32(code_base + 0x1060)	# close@plt
chain += p32(code_base + 0x11fd)	# pop ds; ret 
chain += p32(0x0)
chain += p32(code_base + 0x1050)	# exit@plt
chain += p32(code_base + 0x11fd)	# pop ds; ret 
chain += p32(0x0)


The chain will fail. There is a cheat to see this failure by uncommenting the call to show_failure_scenario() in test.c.

Steps to reproduce the bug

angrop_issue_pop_ds.zip

Attached is a zip file. Unzip and run ./start.sh.

This will build the included binary, init a python venv, install angr and angrop, and run the example python scrip. This will print out the above description.

Environment

Tested on ubuntu 22.04 with pyhton 3.10.

Additional context

No response

AttributeError: 'unicode' object has no attribute '__slots__'

Version

system OS: Ubuntu 14.04.5 LTS 64bit
angr: 7.8.8.1
angrop:7.8.8.1
angr's requirements(archinfo, cle, claripy, pyvex...): 7.8.8.1

Problem

I recently installed a new version of angr(7.8.8.1) by pip. However, problems occur when using angrop
Please help me find a solution...

Typed Commands in iPython

In [1]: import angr
WARNING | 2018-08-07 15:50:14,757 | angr.analyses.disassembly_utils | Your version of capstone does not support MIPS instruction groups.

In [2]: import angrop

In [3]: p = angr.Project("/bin/ls")

In [4]: rop = p.analyses.ROP()

In [5]: rop.find_gadgets()

Error Message

Exception in thread Thread-3:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 338, in _handle_tasks
    for i, task in enumerate(taskseq):
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 285, in <genexpr>
    self._taskqueue.put((((result._job, i, mapstar, (x,), {})
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 436, in _get_tasks
    x = tuple(itertools.islice(it, size))
  File "/home/lsm/angr-dev/angr/lib/python2.7/site-packages/angrop/rop.py", line 303, in _addresses_to_check_with_caching
    not self._block_has_ip_relative(a, bl):
  File "/home/lsm/angr-dev/angr/lib/python2.7/site-packages/angrop/rop.py", line 264, in _block_has_ip_relative
    diff_constants = differing_constants(bl, bl2)
  File "/home/lsm/angr-dev/angr/lib/python2.7/site-packages/angr/analyses/bindiff.py", line 186, in differing_constants
    differences = compare_statement_dict(statement, statement_2)
  File "/home/lsm/angr-dev/angr/lib/python2.7/site-packages/angr/analyses/bindiff.py", line 237, in compare_statement_dict
    new_diffs = compare_statement_dict(getattr(statement_1, attr), getattr(statement_2, attr))
  File "/home/lsm/angr-dev/angr/lib/python2.7/site-packages/angr/analyses/bindiff.py", line 237, in compare_statement_dict
    new_diffs = compare_statement_dict(getattr(statement_1, attr), getattr(statement_2, attr))
  File "/home/lsm/angr-dev/angr/lib/python2.7/site-packages/angr/analyses/bindiff.py", line 237, in compare_statement_dict
    new_diffs = compare_statement_dict(getattr(statement_1, attr), getattr(statement_2, attr))
  File "/home/lsm/angr-dev/angr/lib/python2.7/site-packages/angr/analyses/bindiff.py", line 228, in compare_statement_dict
    for attr in statement_1.__slots__:
AttributeError: 'unicode' object has no attribute '__slots__'

rop.func_call() bug in ARM

Description

As of this commit, func_call in arm is misbehaving.
Prior to that commit, func_call was working as expected. After the commit, we get a RopException error.
The attached example produces the below output.

This is the GOOD example
WARNING  | 2024-02-21 17:15:00,623 | cle.backends.elf.relocation | Unknown reloc 160 on ARMEL
WARNING  | 2024-02-21 17:15:00,743 | cle.backends.externs | Symbol was allocated without a known size; emulation may fail if it is used non-opaquely: __libc_enable_secure
WARNING  | 2024-02-21 17:15:00,743 | cle.backends.externs | Symbol was allocated without a known size; emulation may fail if it is used non-opaquely: __pointer_chk_guard
WARNING  | 2024-02-21 17:15:00,743 | cle.backends.externs | Symbol was allocated without a known size; emulation may fail if it is used non-opaquely: __stack_chk_guard
WARNING  | 2024-02-21 17:15:00,743 | cle.backends.externs | Symbol was allocated without a known size; emulation may fail if it is used non-opaquely: _dl_argv
WARNING  | 2024-02-21 17:15:00,745 | cle.loader     | For more information about "Symbol was allocated without a known size",see https://docs.angr.io/extending-angr/environment#simdata
WARNING  | 2024-02-21 17:15:00,746 | angr.project   | Address is already hooked, during hook(0x500520, <SimProcedure __tls_get_addr>). Not re-hooking.
ERROR    | 2024-02-21 17:15:00,746 | angr.simos.linux | KeyError while trying to set up rtld_global. Libc emulation may not work.
WARNING  | 2024-02-21 17:15:00,747 | angrop.rop     | rebase is deprecated in angrop!
WARNING  | 2024-02-21 17:15:00,747 | angrop.gadget_finder | Only have syscall strings for i386 and x86_64
ROP: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 237851/237851 [02:33<00:00, 1544.78it/s]
code_base = 0x0
chain = b""
chain += p32(code_base + 0x5edfc)	# pop {r0, r4, pc}
chain += p32(0xcafebabe)
chain += p32(0x0)
chain += p32(code_base + 0x1a5cc)




This is the BAD example
WARNING  | 2024-02-21 17:17:38,999 | cle.backends.elf.relocation | Unknown reloc 160 on ARMEL
WARNING  | 2024-02-21 17:17:39,114 | cle.backends.externs | Symbol was allocated without a known size; emulation may fail if it is used non-opaquely: __libc_enable_secure
WARNING  | 2024-02-21 17:17:39,114 | cle.backends.externs | Symbol was allocated without a known size; emulation may fail if it is used non-opaquely: __pointer_chk_guard
WARNING  | 2024-02-21 17:17:39,114 | cle.backends.externs | Symbol was allocated without a known size; emulation may fail if it is used non-opaquely: __stack_chk_guard
WARNING  | 2024-02-21 17:17:39,114 | cle.backends.externs | Symbol was allocated without a known size; emulation may fail if it is used non-opaquely: _dl_argv
WARNING  | 2024-02-21 17:17:39,116 | cle.loader     | For more information about "Symbol was allocated without a known size",see https://docs.angr.io/extending-angr/environment#simdata
WARNING  | 2024-02-21 17:17:39,117 | angr.project   | Address is already hooked, during hook(0x500520, <SimProcedure __tls_get_addr>). Not re-hooking.
ERROR    | 2024-02-21 17:17:39,117 | angr.simos.linux | KeyError while trying to set up rtld_global. Libc emulation may not work.
WARNING  | 2024-02-21 17:17:39,118 | angrop.rop     | rebase is deprecated in angrop!
WARNING  | 2024-02-21 17:17:39,118 | angrop.gadget_finder | Only have syscall strings for i386 and x86_64
ROP: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 237851/237851 [02:33<00:00, 1545.22it/s]
Traceback (most recent call last):
  File "test.py", line 34, in <module>
    chain1 = rop.func_call("free", [0xcafebabe])
  File ".venv_bad/lib/python3.10/site-packages/angrop/chain_builder/__init__.py", line 110, in func_call
    return self._func_caller.func_call(address, args, **kwargs)
  File ".venv_bad/lib/python3.10/site-packages/angrop/chain_builder/func_caller.py", line 104, in func_call
    return self._func_call(func_gadget, cc, args, **kwargs)
  File ".venv_bad/lib/python3.10/site-packages/angrop/chain_builder/func_caller.py", line 73, in _func_call
    shifter = self.chain_builder._shifter.shift(self.project.arch.bytes)
  File ".venv_bad/lib/python3.10/site-packages/angrop/chain_builder/shifter.py", line 71, in shift
    raise RopException("Encounter a shifting request that requires chaining multiple shifting gadgets" +
angrop.errors.RopException: Encounter a shifting request that requires chaining multiple shifting gadgetstogether which is not support atm. Plz create an issue on GitHub so we can add the support!

Steps to reproduce the bug

Attahced is a zip file. Unzip and run start.sh. This will make two venv. One for the latest angrop commit in main, and one at commit 1a0b0fd. It will analyze libc for arm and try to produce the following chain:

chain1 = rop.func_call("free", [0xcafebabe])

The one at commit 1a0b0fd will succeed, the one at the latest commit will fail.

angrop_arm_func_call_issue.zip

Environment

No response

Additional context

No response

support conditional execution in arm

Description

currently, conditional instructions in arm will be misunderstood by vex/angr, thinking the instruction will always be executed, which is not true.
the fix will be to correctly lift conditional instructions into conditional branches for all conditional instructions

Alternatives

No response

Additional context

No response

Getting "TypeError: reduce() of empty sequence with no initial value"

npFoxitReaderPlugin.zip
I am trying to generate a ROP chain in the attached dll and angrop fails with the following type error, with the code:

import angr, angrop
proj = angr.Project("npFoxitReaderPlugin.dll")
rop = proj.analyses.ROP()
rop.find_gadgets_single_threaded()

The TypeError also happens with find_gadgets() but with multiple threads it continues anyway and the error gets hidden in the info output

TypeError                                 Traceback (most recent call last)
<ipython-input-6-5663c5ee5dc3> in <module>()
----> 1 rop.find_gadgets_single_threaded()

/home/fmagin/gits/angr-dev/angrop/angrop/rop.py in find_gadgets_single_threaded(self)
    158         _set_global_gadget_analyzer(self._gadget_analyzer)
    159         for _, addr in enumerate(self._addresses_to_check_with_caching()):
--> 160             gadget = _global_gadget_analyzer.analyze_gadget(addr)
    161             if gadget is not None:
    162                 if isinstance(gadget, RopGadget):

/home/fmagin/gits/angr-dev/angrop/angrop/gadget_analyzer.py in analyze_gadget(self, addr)
     56             symbolic_state = self._test_symbolic_state.copy()
     57             symbolic_state.ip = addr
---> 58             symbolic_p = rop_utils.step_to_unconstrained_successor(self.project, state=symbolic_state)
     59 
     60             l.debug("... analyzing rop potential of block")

/home/fmagin/gits/angr-dev/angrop/angrop/rop_utils.py in step_to_unconstrained_successor(project, state, max_steps, allow_simprocedures)
    207         state.options.add(angr.options.BYPASS_UNSUPPORTED_SYSCALL)
    208 
--> 209         succ = project.factory.successors(state)
    210         if len(succ.flat_successors) + len(succ.unconstrained_successors) != 1:
    211             raise RopException("Does not get to a single successor")

/home/fmagin/gits/angr-dev/angr/angr/factory.py in successors(self, state, addr, jumpkind, inline, default_engine, engines, **kwargs)
     75         for engine in engines:
     76             if engine.check(state, inline=inline, **kwargs):
---> 77                 r = engine.process(state, inline=inline,**kwargs)
     78                 if r.processed:
     79                     break

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/engine.py in process(self, state, irsb, skip_stmts, last_stmt, whitelist, inline, force_addr, insn_bytes, size, num_inst, traceflags, thumb, opt_level, **kwargs)
     99                 traceflags=traceflags,
    100                 thumb=thumb,
--> 101                 opt_level=opt_level)
    102 
    103     def _check(self, state, *args, **kwargs):

/home/fmagin/gits/angr-dev/angr/angr/engines/engine.py in process(***failed resolving arguments***)
     52         successors = new_state._inspect_getattr('sim_successors', successors)
     53         try:
---> 54             self._process(new_state, successors, *args, **kwargs)
     55         except SimException:
     56             if o.EXCEPTION_HANDLING not in old_state.options:

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/engine.py in _process(self, state, successors, irsb, skip_stmts, last_stmt, whitelist, insn_bytes, size, num_inst, traceflags, thumb, opt_level)
    144 
    145             try:
--> 146                 self._handle_irsb(state, successors, irsb, skip_stmts, last_stmt, whitelist)
    147             except SimReliftException as e:
    148                 state = e.state

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/engine.py in _handle_irsb(self, state, successors, irsb, skip_stmts, last_stmt, whitelist)
    216                 state.scratch.stmt_idx = stmt_idx
    217                 state._inspect('statement', BP_BEFORE, statement=stmt_idx)
--> 218                 self._handle_statement(state, successors, stmt)
    219                 state._inspect('statement', BP_AFTER)
    220             except UnsupportedDirtyError:

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/engine.py in _handle_statement(self, state, successors, stmt)
    323 
    324         # process it!
--> 325         s_stmt = translate_stmt(stmt, state)
    326         if s_stmt is not None:
    327             state.history.extend_actions(s_stmt.actions)

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/statements/__init__.py in translate_stmt(stmt, state)
     27         stmt_class = globals()[stmt_name]
     28         s = stmt_class(stmt, state)
---> 29         s.process()
     30         return s
     31     else:

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/statements/base.py in process(self)
     18         """
     19         # this is where we would choose between different analysis modes
---> 20         self._execute()
     21 
     22     def _execute(self):

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/statements/wrtmp.py in _execute(self)
      4     def _execute(self):
      5         # get data and track data reads
----> 6         data = self._translate_expr(self.stmt.data)
      7         self.state.scratch.store_tmp(self.stmt.tmp, data.expr, data.reg_deps(), data.tmp_deps(),
      8                                      action_holder=self.actions

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/statements/base.py in _translate_expr(self, expr)
     25     def _translate_expr(self, expr):
     26         """Translates an IRExpr into a SimIRExpr."""
---> 27         e = translate_expr(expr, self.state)
     28         self._record_expr(e)
     29         return e

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/expressions/__init__.py in translate_expr(expr, state)
     12     l.debug("Processing expression %s", expr_name)
     13     e = expr_class(expr, state)
---> 14     e.process()
     15     return e
     16 

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/expressions/base.py in process(self)
     34 
     35         # this should change when additional analyses are implemented
---> 36         self._execute()
     37 
     38         self._post_process()

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/expressions/ccall.py in _execute(self)
     21             try:
     22                 func = getattr(ccall, self._expr.callee.name)
---> 23                 self.expr, retval_constraints = func(self.state, *s_args)
     24                 self._constraints.extend(retval_constraints)
     25             except SimCCallError:

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/ccall.py in x86g_calculate_eflags_c(state, cc_op, cc_dep1, cc_dep2, cc_ndep)
    900 
    901 def x86g_calculate_eflags_c(state, cc_op, cc_dep1, cc_dep2, cc_ndep):
--> 902     return pc_calculate_rdata_c(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform='X86')
    903 
    904 def x86g_check_fldcw(state, fpucw):

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/ccall.py in pc_calculate_rdata_c(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform)
    786         return state.se.BVV(0, state.arch.bits), [ ] # TODO: actual constraints
    787 
--> 788     rdata_all = pc_calculate_rdata_all_WRK(state, cc_op,cc_dep1,cc_dep2,cc_ndep, platform=platform)
    789 
    790     if isinstance(rdata_all, tuple):

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/ccall.py in pc_calculate_rdata_all_WRK(state, cc_op, cc_dep1_formal, cc_dep2_formal, cc_ndep_formal, platform)
    453     if cc_str in [ 'G_CC_OP_ADCB', 'G_CC_OP_ADCW', 'G_CC_OP_ADCL', 'G_CC_OP_ADCQ' ]:
    454         l.debug("cc_str: ADC")
--> 455         return pc_actions_ADC(state, nbits, cc_dep1_formal, cc_dep2_formal, cc_ndep_formal, platform=platform)
    456 
    457     if cc_str in [ 'G_CC_OP_SUBB', 'G_CC_OP_SUBW', 'G_CC_OP_SUBL', 'G_CC_OP_SUBQ' ]:

/home/fmagin/gits/angr-dev/angr/angr/engines/vex/ccall.py in pc_actions_ADC(state, nbits, cc_dep1, cc_dep2, cc_ndep, platform)
    324     zf = calc_zerobit(state, res)
    325     sf = res[nbits - 1]
--> 326     of = ((arg_l ^ arg_r ^ -1) & (arg_l ^ res))[nbits-1]
    327 
    328     return pc_make_rdata(data[platform]['size'], cf, pf, af, zf, sf, of, platform=platform)

/home/fmagin/gits/angr-dev/claripy/claripy/operations.py in _op(*args)
     56         #pylint:disable=too-many-nested-blocks
     57         if name in simplifiers:
---> 58             simp = _handle_annotations(simplifiers[name](*fixed_args), args)
     59             if simp is not None:
     60                 return simp

/home/fmagin/gits/angr-dev/claripy/claripy/operations.py in bitwise_xor_simplifier(a, b)
    426         return tuple([ arg for arg in args if arg in unique_args ])
    427 
--> 428     return _flatten_simplifier('__xor__', _flattening_filter, a, b)
    429 
    430 def bitwise_or_simplifier(a, b):

/home/fmagin/gits/angr-dev/claripy/claripy/operations.py in _flatten_simplifier(op_name, filter_func, *args)
    392     ))
    393     if filter_func: new_args = filter_func(new_args)
--> 394     return next(a for a in args if isinstance(a, ast.Base)).make_like(op_name, new_args)
    395 
    396 def bitwise_add_simplifier(a, b):

/home/fmagin/gits/angr-dev/claripy/claripy/ast/bits.py in make_like(self, *args, **kwargs)
     18     def make_like(self, *args, **kwargs):
     19         if 'length' not in kwargs: kwargs['length'] = self.length
---> 20         return Base.make_like(self, *args, **kwargs)
     21 
     22     def size(self):

/home/fmagin/gits/angr-dev/claripy/claripy/ast/base.py in make_like(self, *args, **kwargs)
    304         if 'uninitialized' not in kwargs: kwargs['uninitialized'] = self._uninitialized
    305         if 'symbolic' not in kwargs and self.op in all_operations: kwargs['symbolic'] = self.symbolic
--> 306         return type(self)(*args, **kwargs)
    307 
    308     def _rename(self, new_name):

/home/fmagin/gits/angr-dev/claripy/claripy/ast/base.py in __new__(cls, op, args, **kwargs)
    132             for eb in eager_backends:
    133                 try:
--> 134                     r = operations._handle_annotations(eb._abstract(eb.call(op, args)), args)
    135                     if r is not None:
    136                         return r

/home/fmagin/gits/angr-dev/claripy/claripy/backends/__init__.py in call(self, op, args)
    197         if op in self._op_raw:
    198             # the raw ops don't get the model, cause, for example, Z3 stuff can't take it
--> 199             obj = self._op_raw[op](*converted)
    200         elif not op.startswith("__"):
    201             l.debug("backend has no operation %s", op)

/home/fmagin/gits/angr-dev/claripy/claripy/backends/backend_concrete.py in _op_xor(*args)
     52     @staticmethod
     53     def _op_xor(*args):
---> 54         return reduce(operator.__xor__, args)
     55     @staticmethod
     56     def _op_and(*args):

TypeError: reduce() of empty sequence with no initial value

angrop crashes: AssertionError

I am running angrop in the following code (Python 2.7.13):

import angr
import angrop
project = angr.Project('rop', auto_load_libs=False)
rop = project.analyses.ROP()
rop.find_gadgets()
rop.execve("/bin/sh").print_payload_code()

When the progress bar is at about 20%, I get this error:

Traceback (most recent call last):
  File "./roptest.py", line 5, in <module>
    rop.find_gadgets()
  File "/usr/local/lib/python2.7/dist-packages/angrop/rop.py", line 126, in find_gadgets
    for gadget in it:
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 287, in <genexpr>
    return (item for chunk in result for item in chunk)
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 668, in next
    raise value
AssertionError

LR Register Not Handled Well in Arm

Description

Take the following chain for example:

chain1 = rop.func_call("realloc", [0xcafebabe, 0xa])
print(chain1)

code_base = 0x0
chain = b""
chain += p32(code_base + 0x93be8)       # pop {r0, r1, ip, lr, pc}
chain += p32(0xcafebabe)
chain += p32(0xa)
chain += p32(0x0)
chain += p32(0x0)
chain += p32(code_base + 0x1a540)

This chain calls realloc(0xcafebabe, 0xa)
Note how 0 is popped into LR.
When the program begins executing realloc(), it will push the contents of LR onto the stack.
When the program finishes execututing realloc(), the 0 value from LR is popped into PC and this will SEGFAULT.

Steps to reproduce the bug

Attached is a zip file. Unzip and run start.sh to reproduce the problem chain.
angrop_RL_issue.zip

Environment

No response

Additional context

No response

add_to_mem fails in arm.

Description

add_to_mem does not seem to support arm binaries.

possible_gadgets = {x for x in self._mem_change_gadgets

never finds any possible gadgets in 32 bit arm.

Steps to reproduce the bug

Included is a zip file. Extract the zip file and run start_old.sh. This will set up a python venv and install requirements. start_old will use angrop 9.2.8. It will run a python script that will fetch the Ubuntu i386 libc and Ubuntu armel libc. Then it then attempt to produce example add_to_mem chains with both.

the i386 chain will print as follows:

This is for i386:
Note how calling add_to_mem() succeeds.
code_base = 0x0
chain = b""
chain += p32(code_base + 0x193127)	# neg eax; pop edi; pop ebx; ret 
chain += p32(0xdeadbe92)
chain += p32(0xcafebabe)
chain += p32(code_base + 0x14f2a7)	# add dword ptr [edi + 0x5d], ebx; ret 

The armel chain will fail as follows:

This is the armel chain.
Note how calling add_to_mem() fails.
Traceback (most recent call last):
  File "/test_old.py", line 67, in <module>
    breakpoint()
  File ".venv_old/lib/python3.10/site-packages/angrop/chain_builder/__init__.py", line 367, in add_to_mem
    raise RopException("Couldnt set registers for any memory add gadget")
angrop.errors.RopException: Couldnt set registers for any memory add gadget

angrop_issue_74.zip

Environment

No response

Additional context

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.