Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
262 commits
Select commit Hold shift + click to select a range
56a0910
shortcut reg_setter.optimize so we don't normalize every non-self-con…
Kyle-Kyle Feb 28, 2025
89b9681
ignore constant memory accesses that we know for sure are valid
Kyle-Kyle Feb 28, 2025
0335edb
add/sub should be considered moves as well
Kyle-Kyle Feb 28, 2025
eff70bb
respect the preserve_regs argument in gadget normalization
Kyle-Kyle Mar 1, 2025
c21d5c4
normalize jmp_reg gadgets
Kyle-Kyle Mar 1, 2025
da1e266
try to shorten chains when doing reg_setter optimization
Kyle-Kyle Mar 1, 2025
7441c30
capture clobbered_regs side-effect in reg_setter graph building
Kyle-Kyle Mar 1, 2025
d0754b1
support modifable_memory_range for giga_graph_search
Kyle-Kyle Mar 1, 2025
b84d00f
reduce the graph for performance purpose
Kyle-Kyle Mar 1, 2025
b786382
introduce pop_equal_set to avoid some wrong edges in the graph
Kyle-Kyle Mar 1, 2025
08c1984
try to find chains with smallest stack_change using reg_moves as well
Kyle-Kyle Mar 1, 2025
3e2f385
expand simple rop_blocks to allow reuse
Kyle-Kyle Mar 1, 2025
837fb9a
correctly reverse Extract
Kyle-Kyle Mar 5, 2025
df16d4e
oops
Kyle-Kyle Mar 6, 2025
52eb11c
draft of conditional branch support in giga graph search
Kyle-Kyle Mar 6, 2025
d276429
only normalize a gadget at most once
Kyle-Kyle Mar 6, 2025
56fdf16
make conditional branch normalization compatible with transit_type no…
Kyle-Kyle Mar 6, 2025
d39e7a6
don't normalize gadgets that have symbolic accesses
Kyle-Kyle Mar 6, 2025
3b01149
if two gadgets having the same effect, drop the one with conditional_…
Kyle-Kyle Mar 7, 2025
57b2c55
well, jmp_mem gadgets inherently have symbolic access, we monkey-patc…
Kyle-Kyle Mar 7, 2025
c89a025
use a greedy algorithm in reg_setter graph building and a cutoff in o…
Kyle-Kyle Mar 7, 2025
9bc1563
normalize call gadgets correctly
Kyle-Kyle Mar 7, 2025
62b6a76
no need to pass stack_change to _build_reg_setting_chain, it should b…
Kyle-Kyle Mar 7, 2025
ebf9308
try to use the minimal stack shifter
Kyle-Kyle Mar 7, 2025
1f71023
ignore jmp_reg gadgets that do gadget arithmetic for now
Kyle-Kyle Mar 8, 2025
3c3d050
better support jmp_mem gadget normalization
Kyle-Kyle Mar 8, 2025
af281c9
allow pre/post_preserve register list during gadget normalization
Kyle-Kyle Mar 8, 2025
fcf39b9
testcase for rex prefix
Kyle-Kyle Mar 9, 2025
6ae4f5c
don't mess with complicated jmp_reg gadgets yet
Kyle-Kyle Mar 9, 2025
d855059
support resolving stack values when normalizing jmp_mem gadgets
Kyle-Kyle Mar 9, 2025
b4690ed
allow normalizing jmp_mem gadgets in reg_mover
Kyle-Kyle Mar 9, 2025
1f5487a
fix
Kyle-Kyle Mar 9, 2025
bb0282c
don't turn ropblock to gadgets, it will destroy constraints in normal…
Kyle-Kyle Mar 9, 2025
2842bea
speed up in kernel mode
Kyle-Kyle Mar 9, 2025
ac294a9
avoid looping in finding useless paths by providing a cutoff
Kyle-Kyle Mar 9, 2025
2398244
allow pivot to an existing region
Kyle-Kyle Mar 9, 2025
5a4f911
fix pivot
Kyle-Kyle Mar 9, 2025
cbc5709
filter out gadgets with super large stack_change
Kyle-Kyle Mar 24, 2025
df4666a
remove the gadget_timeout test, we shouldn't consider that as a gadge…
Kyle-Kyle Mar 24, 2025
3f1dbbf
analyze stack_change_before_pivot for PivotGadget
Kyle-Kyle Mar 24, 2025
0672483
no more hardcoded stack_gsize
Kyle-Kyle Mar 24, 2025
1886212
bp should be considered a general-purpose register and we always symb…
Kyle-Kyle Mar 24, 2025
f9c888e
restore the default stack_gsize to 80
Kyle-Kyle Mar 24, 2025
b8b2904
warn -> warning
Kyle-Kyle Mar 24, 2025
0e42421
allow dynamically extending the symbolic stack
Kyle-Kyle Mar 24, 2025
183fe40
stack_gsize is no longer an optional to rop_utils.make_symbolic_state
Kyle-Kyle Mar 24, 2025
f726830
remove the new_sim_state function that it simple enough to be inlined
Kyle-Kyle Mar 24, 2025
e5b11bd
allow dynamically extend symbolic stack and compensate for the first …
Kyle-Kyle Mar 24, 2025
aaf0c78
compensate for the init gadget
Kyle-Kyle Mar 25, 2025
32aafb0
correctly handle cases where the jmp_mem target is a variable by itself
Kyle-Kyle Mar 25, 2025
76c43c4
don't add edges to the regsetter graph if we already know it clobbers…
Kyle-Kyle Mar 25, 2025
68a60b0
wrap normalize_gadget in try-except
Kyle-Kyle Mar 26, 2025
b4532ec
support ast_rebalancing where the target is 32bit and we control 64bit
Kyle-Kyle Mar 26, 2025
b44df1a
suppress errors for pivot gadget with conditional jumps, we just don'…
Kyle-Kyle Mar 26, 2025
d01793d
NO_CROSS_INSN_OPT enables instruction-precise sim_action tracking
Kyle-Kyle Mar 26, 2025
079d88e
final_state is always passed
Kyle-Kyle Mar 26, 2025
d471b72
add back step_one_inst
Kyle-Kyle Mar 26, 2025
98724be
we officially don't support rebalancing Concat operation
Kyle-Kyle Mar 26, 2025
c1e3314
support symbolizing GOT table
Kyle-Kyle Mar 26, 2025
e891abd
always try to symbolize GOT table and always disable floating point s…
Kyle-Kyle Mar 27, 2025
da5fcdc
filter out gadgets that contain wrong pops
Kyle-Kyle Mar 27, 2025
c288ee9
avoid taking writable addresses from the GOT table
Kyle-Kyle Mar 27, 2025
85e365d
correctly normalize moves in reg_setter
Kyle-Kyle Mar 27, 2025
229a194
suppress ctypes.ArgumentError in gadget_analyzer
Kyle-Kyle Mar 27, 2025
d38ebd7
do not enforce pre_preserve in reg_setter optimize
Kyle-Kyle Mar 27, 2025
9c5bbef
separate bootstrap and optimize for chain_builder
Kyle-Kyle Mar 27, 2025
7a42b8c
optimize the algorithm of reg_setter.optimize
Kyle-Kyle Mar 27, 2025
0501564
fix testcases due to the optimize change
Kyle-Kyle Mar 27, 2025
684a2c2
handle cases where jmp_mem gadgets have out_of_patch access
Kyle-Kyle Mar 27, 2025
ec25128
although it shouldn't happen, but suppress RecursionError in gadget f…
Kyle-Kyle Mar 27, 2025
cb6d47d
analyze syscall gadgets even if only_check_near_rets is on
Kyle-Kyle Mar 30, 2025
1fb474c
add a test case
Kyle-Kyle Mar 30, 2025
03a0615
fix a key error
Kyle-Kyle Mar 31, 2025
30597b2
separate conditional_branch option
Kyle-Kyle Mar 31, 2025
3bc84f5
fix testcase due to the cond_br change
Kyle-Kyle Mar 31, 2025
8a541e8
add timeout to find_gadgets
Kyle-Kyle Mar 31, 2025
a55e2b4
clearly define symbolic memory access in a gadget
Kyle-Kyle Apr 1, 2025
1b6883a
add arm jmp_mem test case
Kyle-Kyle Apr 1, 2025
749c5e4
support normalizing symbolic memory access
Kyle-Kyle Apr 1, 2025
e21617a
memory access hash will cause issues
Kyle-Kyle Apr 1, 2025
5e53815
fix a mem_change test case
Kyle-Kyle Apr 1, 2025
792a00c
catch unsat
Kyle-Kyle Apr 1, 2025
0cbc59b
support riscv
Kyle-Kyle Apr 2, 2025
cb21767
add test cases for riscv
Kyle-Kyle Apr 2, 2025
c979972
further separate preserve_registers in normalize_jmp_mem
Kyle-Kyle Apr 2, 2025
883e076
correctly set gadgets in _build_reg_setting_chain
Kyle-Kyle Apr 2, 2025
ec84faa
filter out gadgets containing PAC instructions, we can't handle them
Kyle-Kyle Apr 3, 2025
a81e073
rebalance and,or
Kyle-Kyle Apr 3, 2025
7805f57
use simos to infer the target os
Kyle-Kyle Apr 3, 2025
097d3b8
work around an angrop bug where step(num_isnt) doesn't work
Kyle-Kyle Apr 3, 2025
6d3c8a8
add and try-except just for MIPS, huh
Kyle-Kyle Apr 3, 2025
30505a8
analyze gadgets in the order of syscall, rets, all
Kyle-Kyle Apr 4, 2025
bb0e618
allow resolving jump tables and make max basic blocks configurable
Kyle-Kyle Apr 4, 2025
9f78c66
add a test case for the riscv spec
Kyle-Kyle Apr 4, 2025
300a061
even better optimization!
Kyle-Kyle Apr 4, 2025
d618d22
revert jump table resolution
Kyle-Kyle Apr 4, 2025
568729b
add a testcase for nested optimization
Kyle-Kyle Apr 4, 2025
3180324
mem access is not hashable
Kyle-Kyle Apr 5, 2025
6946904
clean up the code for nested optimization
Kyle-Kyle Apr 5, 2025
6e43d9b
update the timeout handler
Kyle-Kyle Apr 5, 2025
cc3038d
even better timeout handling
Kyle-Kyle Apr 5, 2025
53e401f
ooops, fix an infinite loop
Kyle-Kyle Apr 5, 2025
985bc35
fix the gadget filtering logic based on number of symbolic access
Kyle-Kyle Apr 6, 2025
841fde7
only rebase pointers in the main_object
Kyle-Kyle Apr 6, 2025
29c5ecc
correctly stitch chains together
Kyle-Kyle Apr 6, 2025
21a56b3
improve the graph search
Kyle-Kyle Apr 6, 2025
6aba1f3
handle jmp_reg gadgets with oop access
Kyle-Kyle Apr 6, 2025
1d4e352
cleanup execve call
Kyle-Kyle Apr 6, 2025
004a852
speed up tests
Kyle-Kyle Apr 6, 2025
556f6e6
handle double ropblock
Kyle-Kyle Apr 6, 2025
5a02af0
fix a crash when mem_writer happens to have 0x400 stack_change
Kyle-Kyle Apr 6, 2025
e5a16d4
catch the runtime error
Kyle-Kyle Apr 6, 2025
068a053
avoid infinite loop in reg_mover
Kyle-Kyle Apr 6, 2025
77cc213
set preserve_regs correctly in regmover
Kyle-Kyle Apr 8, 2025
2b872c2
reject jmp_gadget early
Kyle-Kyle Apr 15, 2025
1320b3d
for sim_exec, we need to perform on the original state, or it won't c…
Kyle-Kyle Apr 16, 2025
8c912e2
hide a show_progress
Kyle-Kyle Apr 16, 2025
45af8de
if memory address is given by users, reuse those
Kyle-Kyle Apr 16, 2025
592c357
accessing constant memory shouldn't be considered as out_of_patch mem…
Kyle-Kyle Apr 16, 2025
c860643
check whether an ast is contrained only when needed
Kyle-Kyle Apr 16, 2025
f40b534
add a testcase
Kyle-Kyle Apr 16, 2025
e486ad6
we are fine with partial control on 64bit system
Kyle-Kyle Apr 16, 2025
2d35ccd
speed up reg_setter.optimize
Kyle-Kyle Apr 17, 2025
8be4aa1
first step of making the result deterministic: use reg_list
Kyle-Kyle Apr 17, 2025
c1755f6
still use a register as controlled if it is loosely constrained
Kyle-Kyle Apr 17, 2025
04fbd0b
add a test case for reg_controllers
Kyle-Kyle Apr 17, 2025
ecb1f6d
oops
Kyle-Kyle Apr 17, 2025
d394deb
proper multiprocessing
Kyle-Kyle Apr 17, 2025
a87ba53
oops
Kyle-Kyle Apr 17, 2025
0e4c5ec
disable more annoying logs
Kyle-Kyle Apr 17, 2025
d25d7f2
unify the interface for all multiprocessing functions
Kyle-Kyle Apr 17, 2025
72e3655
remove the run_worker function
Kyle-Kyle Apr 17, 2025
6cf909a
support find_gadgets timeout
Kyle-Kyle Apr 17, 2025
d03fa01
support caching in gadget finding
Kyle-Kyle Apr 17, 2025
7afc1d0
print a proper message
Kyle-Kyle Apr 17, 2025
c58f9f0
use concrete values for memory writes
Kyle-Kyle Apr 17, 2025
3e3e580
builders should be aware pointers used by other builders
Kyle-Kyle Apr 17, 2025
b0fdeec
don't even try to be nice
Kyle-Kyle Apr 18, 2025
9d425e3
shrink critical section
Kyle-Kyle Apr 18, 2025
08a3bdc
duh
Kyle-Kyle Apr 18, 2025
ea1fc24
show_progress in cache building as well
Kyle-Kyle Apr 19, 2025
0dd66f6
faster static analysis
Kyle-Kyle Apr 19, 2025
5c22703
make sure there are not too many symbolic accesses
Kyle-Kyle Apr 19, 2025
b9ee692
oops
Kyle-Kyle Apr 19, 2025
24358c2
bug fix
Kyle-Kyle Apr 19, 2025
5d019c9
don't check interrupts
Kyle-Kyle Apr 19, 2025
5257afd
unify the interface between single-threaded and multiprocessing
Kyle-Kyle Apr 20, 2025
c04425d
faster ast controller analysis
salls Apr 20, 2025
5907395
not syscall is Ijk_SYs_syscall
Kyle-Kyle Apr 20, 2025
1669554
no need to step to syscall again since we already have the prologue_s…
Kyle-Kyle Apr 20, 2025
e73f2c9
retire other chain building algorithms
Kyle-Kyle Apr 21, 2025
a3c5e27
reorder functions in reg_setter for better readability
Kyle-Kyle Apr 21, 2025
ba7ceb0
make sure the stack shifter does not clobber our wanted move
Kyle-Kyle Apr 21, 2025
17b9980
we consider 32-bit control valid on 64-bit system
Kyle-Kyle Apr 21, 2025
7126adf
what we want to check is the prologue in syscall gadgets
Kyle-Kyle Apr 21, 2025
0ffeaf9
don't even try to normalize jmp_mem gadgets when we can't write
Kyle-Kyle Apr 22, 2025
e9faf8a
allow normalizing reg_moving gadgets in multiprocessing
Kyle-Kyle Apr 22, 2025
d1b20ad
fix a bug in building normalize_todos
Kyle-Kyle Apr 22, 2025
ae0cbe6
stuff
Kyle-Kyle Apr 22, 2025
c20014b
increase gadget diversity when doing reg_mover normalization to reduc…
Kyle-Kyle Apr 22, 2025
dd4dd33
find_gadgets/optimize integration
Kyle-Kyle Apr 22, 2025
46d88c2
support shifting
Kyle-Kyle Apr 22, 2025
ed77b23
use loader.memory saves us a ton of time and we no longer needs to tr…
Kyle-Kyle Apr 22, 2025
f91d9a4
clean up the get_{}_locations api
Kyle-Kyle Apr 22, 2025
59c7b06
draft of the slice-based static analysis
Kyle-Kyle Apr 23, 2025
55e5752
enhancement
Kyle-Kyle Apr 23, 2025
de42601
deduplicate of slices
Kyle-Kyle Apr 23, 2025
3b97a92
don't decode twice
Kyle-Kyle Apr 23, 2025
5974693
allow 32bit signext and zeroext on 64bit system
Kyle-Kyle Apr 23, 2025
908e3dd
fix fast_unconstrained_check
Kyle-Kyle Apr 23, 2025
c321057
claripy.algorithm.replace returns the target ast
Kyle-Kyle Apr 23, 2025
d7ba1d4
oops
Kyle-Kyle Apr 23, 2025
1aa1fb8
remove the and/or rebalance test case since they are no longer consid…
Kyle-Kyle Apr 23, 2025
6122d59
symbolic memory access specifically means unconstrained access now an…
Kyle-Kyle Apr 23, 2025
6c6e4fd
oops
Kyle-Kyle Apr 24, 2025
f4158a5
cap the length of path
Kyle-Kyle Apr 24, 2025
097ced8
a hack to make sure every used pointer is different
Kyle-Kyle Apr 24, 2025
553918c
cache memory writer gadgets used on the length of data
Kyle-Kyle Apr 24, 2025
edc240e
try to generate the shortest chains
Kyle-Kyle Apr 24, 2025
8e7383d
don't try to normalizing with reg_move if we can't set the source
Kyle-Kyle Apr 25, 2025
6601863
handle jmp_mem with oop access
Kyle-Kyle Apr 25, 2025
0922262
fix stack shifting for jmp_mem
Kyle-Kyle Apr 25, 2025
fa9152b
proper timeout for find_gadgets
Kyle-Kyle Apr 25, 2025
c2c4409
always analyze syscall gadgets first
Kyle-Kyle Apr 25, 2025
5e1522c
support mem_write with addresses from the stack
Kyle-Kyle Apr 25, 2025
80f3c31
rewrite memory scanning logic
Kyle-Kyle Apr 25, 2025
8c4d8bd
only try func_jmp_gadgets when it provides unique capability
Kyle-Kyle Apr 25, 2025
56b1649
oops
Kyle-Kyle Apr 25, 2025
be5a93b
rebalance xor
Kyle-Kyle Apr 25, 2025
8d9c1f4
further limit the amount of chain candidates
Kyle-Kyle Apr 25, 2025
2c40731
Adding support for uv. (#4)
dfraze May 30, 2025
bef5c1e
introduce RopEffect
Kyle-Kyle Apr 26, 2025
3a98a41
deprecate popped_reg_vars
Kyle-Kyle Apr 26, 2025
3a0071a
avoid circular imports
Kyle-Kyle Apr 26, 2025
d93d3cb
introduce reg_pop
Kyle-Kyle Apr 26, 2025
aa56286
make sure we always have the full control chain
Kyle-Kyle Apr 26, 2025
0a3e7cb
in the reg_setter graph, only add an edge if the bits match as well
Kyle-Kyle Apr 26, 2025
1a58f1b
properly handle pop_equal_set
Kyle-Kyle Apr 26, 2025
e509699
don't normalize all unique_chains in reg_setter optimize
Kyle-Kyle Apr 28, 2025
46a471b
better cache mem_writer
Kyle-Kyle Apr 28, 2025
3ab4a4e
make set_regs a route that every builder has access to
Kyle-Kyle Apr 28, 2025
6194cf5
first pass of cleaning up mem_writer
Kyle-Kyle Apr 28, 2025
8f72d57
cached memory writes
Kyle-Kyle Apr 29, 2025
f17922f
don't symbolize GOT during chain building
Kyle-Kyle Apr 29, 2025
a55d477
make gadget filtering faster
Kyle-Kyle Apr 30, 2025
fca4249
fix
Kyle-Kyle Apr 30, 2025
489042d
don't consider a pop a pop if it is what we will jump to
Kyle-Kyle Apr 30, 2025
86b0568
don't cache non-trivial memory write
Kyle-Kyle Apr 30, 2025
e6d2d95
print error message when encountering issues in mem_writer
Kyle-Kyle Apr 30, 2025
08f0a9f
enhance pop_equal_set
Kyle-Kyle Apr 30, 2025
8698383
handle short_write
Kyle-Kyle Apr 30, 2025
b646bf4
correctly identify the target mem_write
Kyle-Kyle Apr 30, 2025
9c10d52
in case of short write, extend the data
Kyle-Kyle Apr 30, 2025
040ef7f
handle ropblock with out of patch accesses
Kyle-Kyle May 1, 2025
42c2add
ignore gadgets with invalid ptr access
Kyle-Kyle May 1, 2025
8442ce2
some stack data has to be constrained for conditional branch guards. …
Kyle-Kyle May 1, 2025
7ec64ac
sanitize check sp
Kyle-Kyle May 1, 2025
2e05478
a hack to reduce the impact of bad memory leak
Kyle-Kyle May 2, 2025
b4557d7
properly handle rop_effect.stack_offset to avoid infinite loop
Kyle-Kyle May 2, 2025
a8a2faa
ropblock needs to have the conditional branch analysis as well
Kyle-Kyle May 2, 2025
6eb22de
don't remove pops that are loosely constrained
Kyle-Kyle May 2, 2025
80474c7
correctly handle conditional jumps and zero register in RISCV
Kyle-Kyle May 3, 2025
3053535
add a testcase for the riscv zero register issue
Kyle-Kyle May 3, 2025
ff025c9
apply constraints when do exec()
Kyle-Kyle May 3, 2025
e1d9731
cannot rebalance ast where both lhs and rhs are symbolic
Kyle-Kyle May 3, 2025
da13a5c
make it faster to obtain writable ptr
Kyle-Kyle May 3, 2025
11a41d0
add a testcase
Kyle-Kyle May 3, 2025
cf94c8d
move branch_dependencies to rop effect
Kyle-Kyle May 3, 2025
9b3ce8a
avoid wasting a lot of time on normalizing jmp_reg gadgets when we kn…
Kyle-Kyle May 3, 2025
a32446f
add testcases
Kyle-Kyle May 3, 2025
e2d134d
raise exception when we have no usable pointers instead of messing up…
Kyle-Kyle May 3, 2025
591fdf9
compensate for the first gadget
Kyle-Kyle May 3, 2025
0787675
do not crash
Kyle-Kyle May 3, 2025
ddd0be4
fix syscall de-duplicattion
Kyle-Kyle May 5, 2025
75ba6cd
do not find gadgets that span across libraries
Kyle-Kyle Jul 21, 2025
50afee3
add angrop-cli
Kyle-Kyle Oct 22, 2025
791512b
update the cli
Kyle-Kyle Oct 22, 2025
64f19d3
add an dockerfile
Kyle-Kyle Oct 22, 2025
00e606d
include angrop-cli
Kyle-Kyle Oct 27, 2025
469d2e5
prettyprinting gadgets
Kyle-Kyle Oct 27, 2025
681165b
duh
Kyle-Kyle Oct 29, 2025
c447194
catch claripy error when normalizing gadgets
Kyle-Kyle Oct 30, 2025
a7d1a9c
update angrop-cli
Kyle-Kyle Oct 30, 2025
4181721
revert CI changes
Kyle-Kyle Dec 29, 2025
c578a32
this is no longer private
Kyle-Kyle Dec 29, 2025
5244b00
revert uv changes
Kyle-Kyle Dec 29, 2025
4a4f100
use normal capstone to disassemble riscv instructions
Kyle-Kyle Dec 30, 2025
f0e6b84
make pyright happy
Kyle-Kyle Jan 4, 2026
13d1398
make pylint happy
Kyle-Kyle Jan 5, 2026
e290ed0
update README
Kyle-Kyle Jan 6, 2026
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
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from python:3.13-bookworm

run apt-get update && apt-get upgrade -y
run pip install --upgrade pip

run apt-get install -y make binutils-riscv64-linux-gnu git

# setup python dependencies
run pip install cffi pwntools unicorn==2.0.1.post1 protobuf==5.28.2
run pip install setuptools==79.0.1

run git clone --depth 1 -b wip/riscv https://github.com/angr/archinfo /archinfo
workdir /archinfo
run pip install -e .
run pip install pyvex==9.2.139 cle==9.2.139 claripy==9.2.139
run git clone --depth 1 -b wip/riscv https://github.com/angr/angr /angr
workdir /angr
run sed -i 's/9.2.153.dev0/9.2.139/' angr/__init__.py
run sed -i 's/9.2.153.dev0/9.2.139/' ./pyproject.toml
run pip install --no-build-isolation -e .

# install angrop
copy . /angrop
workdir /angrop
run pip install -e .
run pip install ailment==9.2.153
copy bin/angrop-cli /usr/bin/angrop-cli
179 changes: 69 additions & 110 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,144 +6,103 @@ 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.
It is built on top of angr's symbolic execution engine.
It uses symbolic execution to understand the effects of gadgets and uses constraint solving and graph search for generating chains.
Its design is architecture-agnostic so it supports multiple architectures.

angrop should support all the architectures supported by angr, although more testing needs to be done.
Typically, it generate rop chains faster than humans.
In some cases, it can generate hard rop chains that may take humans hours to build within a few seconds.
Some examples can be found [here](examples).

Typically, it can generate rop chains (especially long chains) faster than humans.
It comes with a cli and a python api.
The command line `angrop-cli` offers some basic gadget finding/chaining capability such as finding an `system`/`execve` chain or invoking a specific function.
The `angrop` python api offers the full features.
Details can be found in [Usage](README.md#usage).

It includes functions to generate chains which are commonly used in exploitation and CTF's, such as setting registers, and calling functions.
`angrop` does not just only works for userspace binaries, it works for the Linux kernel as well.

## Architectures
Supported architectures:
* x86/x64
* ARM
* MIPS
* AARCH64
* ARM
* AArch64
* RISC-V (64bit)

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.
You can use either the CLI or the Python API.
The CLI only offers some basic functionalities while the Python API provides much more capabilities and is much more powerful.

## CLI
angrop comes with a command line tool for easy day-to-day usage
```bash
# dump command will find gadgets in the target binary, true/false marks whether the gadget is self-contained
$ angrop-cli dump /bin/ls
0x11735: true : adc bl, byte ptr [rbx + 0x4c]; mov eax, esp; pop r12; pop r13; pop r14; pop rbp; ret
0x10eaa: true : adc eax, 0x12469; add rsp, 0x38; pop rbx; pop r12; pop r13; pop r14; pop r15; pop rbp; ret
00xe026: true : adc eax, 0xcec8; pop rbx; cmove rax, rdx; pop r12; pop rbp; ret
00xdfd4: true : adc eax, 0xcf18; pop rbx; cmove rax, rdx; pop r12; pop rbp; ret
00xdfa5: true : adc eax, 0xcf4d; pop rbx; cmove rax, rdx; pop r12; pop rbp; ret
......

# chain command will find some predefined chains in the binary
$ angrop-cli chain -t execve /bin/bash
code_base = 0x0
chain = b""
chain += p64(code_base + 0x36083) # pop rax; pop rbx; pop rbp; ret
chain += p64(code_base + 0x30016) # add rsp, 8; ret
chain += p64(code_base + 0x34873)
chain += p64(code_base + 0x0)
chain += p64(code_base + 0x9616d) # mov edx, ebp; mov rsi, r12; mov rdi, rbx; call rax
chain += p64(code_base + 0xe501e) # pop rsi; ret 0
chain += p64(code_base + 0x0)
chain += p64(code_base + 0x31470) # execve@plt
chain += p64(0x0)
chain += p64(code_base + 0x10d5bf)
```

## Python API
```python
>>> 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 = rop.set_regs(rax=0x41414141, rbx=0x42424242)
>>> chain.print_payload_code()
code_base = 0x0
chain = b""
chain += p64(0x410b23) # pop rax; ret
chain += p64(0x1337)
chain += p64(0x404dc0) # pop rbx; ret
chain += p64(0x56565656)
chain += p64(code_base + 0xf5e2) # pop rbx; pop r12; test eax, eax; pop rbp; cmovs eax, edx; ret
chain += p64(0x42424242)
chain += p64(0x0)
chain += p64(0x0)
chain += p64(code_base + 0x812f) # pop rsi; pop rbp; ret
chain += p64(0x41414141)
chain += p64(0x0)
chain += p64(code_base + 0x169dd) # mov rax, rsi; ret
chain += p64(code_base + 0x10a55)
```
More detailed docs on the Python API can be found [here](docs/pythonapi.md).

## Chains
```python
# 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")
## Demo

# 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

```asm
0x403be4: and ebp,edi
0x403be6: mov QWORD PTR [rbx+0x90],rax
0x403bed: xor eax,eax
0x403bef: add rsp,0x10
0x403bf3: pop rbx
0x403bf4: ret
```

```python
>>> 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.

```python
>>> 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:
```
### gadget finding
![gadget](gifs/find_gadget.gif?raw=true)

## TODO's
Allow strings to be passed as arguments to func_call(), which are then written to memory and referenced.
### find execve chain
![execve](gifs/execve.gif?raw=true)

Add a function for open, read, write (for ctf's)
### container escape chain for the kernel
![kernel](gifs/kernel.gif?raw=true)

The segment analysis for finding executable addresses seems to break on non-elf binaries often, such as PE files, kernel modules.
## Paper
We describe our design and findings in this paper

Allow setting constraints on the generated chain e.g. bytes that are valid.
[__ropbot: Reimaging Code Reuse Attack Synthesis__](https://kylebot.net/papers/ropbot.pdf)

## Common gotchas
Make sure to import angrop before calling proj.analyses.ROP()
Kyle Zeng, Moritz Schloegel, Christopher Salls, Adam Doupé, Ruoyu Wang, Yan Shoshitaishvili, Tiffany Bao

Make sure to call find_gadets() before trying to make chains
*In Proceedings of the Network and Distributed System Security Symposium (NDSS), February 2026*,
55 changes: 45 additions & 10 deletions angrop/arch.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ class ROPArch:
def __init__(self, project, kernel_mode=False):
self.project = project
self.kernel_mode = kernel_mode
self.max_sym_mem_access = 4
self.max_sym_mem_access = 1
self.alignment = project.arch.instruction_alignment
self.reg_set = self._get_reg_set()
self.reg_list = self._get_reg_list()
self.reg_set = set(self.reg_list) # backward compatibility, will be removed
self.max_block_size = None
self.fast_mode_max_block_size = None

Expand All @@ -19,20 +20,24 @@ def __init__(self, project, kernel_mode=False):
self.ret_insts = None
self.execve_num = None

def _get_reg_set(self):
def _get_reg_list(self):
"""
get the set of names of general-purpose registers
get the set of names of general-purpose registers + bp
because bp is usually considered as general-purpose these days
"""
arch = self.project.arch
_sp_reg = arch.register_names[arch.sp_offset]
_ip_reg = arch.register_names[arch.ip_offset]
sp_reg = arch.register_names[arch.sp_offset]
ip_reg = arch.register_names[arch.ip_offset]
bp_reg = arch.register_names[arch.bp_offset]

# get list of general-purpose registers
default_regs = arch.default_symbolic_registers
# prune the register list of the instruction pointer and the stack pointer
return {r for r in default_regs if r not in (_sp_reg, _ip_reg)}
reg_list = [r for r in default_regs if r not in (sp_reg, ip_reg, bp_reg)]
reg_list.append(bp_reg)
return reg_list

def block_make_sense(self, block):
def block_make_sense(self, block) -> bool:
return True

class X86(ROPArch):
Expand All @@ -47,13 +52,25 @@ def __init__(self, project, kernel_mode=False):

def _x86_block_make_sense(self, block):
capstr = str(block.capstone).lower()

for inst in block.capstone.insns:
if inst.mnemonic == 'ret' and inst.op_str:
n = int(inst.op_str, 16)
if n % self.project.arch.bytes != 0 or n >= 0x100:
return False

if inst.mnemonic == 'int' and inst.op_str:
n = int(inst.op_str, 16)
if n != 0x80:
return False

# currently, angrop does not handle "repz ret" correctly, we filter it
if any(x in capstr for x in ('cli', 'rex', 'repz ret')):
if any(x in capstr for x in ('cli', 'rex', 'repz ret', 'retf', 'hlt', 'wait', 'loop', 'lock')):
return False
if not self.kernel_mode:
if "fs:" in capstr or "gs:" in capstr or "iret" in capstr:
return False
if block.size < 1 or block.bytes[0] == 0x4f:
if block.size < 1:
return False
return True

Expand Down Expand Up @@ -115,13 +132,29 @@ def __init__(self, project, kernel_mode=False):
self.fast_mode_max_block_size = self.alignment * 6
self.execve_num = 0xdd

def block_make_sense(self, block):
for x in block.capstone.insns:
# won't be able to ROP with PAC
if x.mnemonic == 'autiasp':
return False
return True

class MIPS(ROPArch):
def __init__(self, project, kernel_mode=False):
super().__init__(project, kernel_mode=kernel_mode)
self.alignment = self.project.arch.bytes
self.max_block_size = self.alignment * 8
self.fast_mode_max_block_size = self.alignment * 6
self.execve_num = 0xfab
self.syscall_insts = {b"\x0c\x00\x00\x00"} # syscall

class RISCV64(ROPArch):
def __init__(self, project, kernel_mode=False):
super().__init__(project, kernel_mode=kernel_mode)
self.ret_insts = {b"\x82\x80"}
self.max_block_size = self.alignment * 10
self.fast_mode_max_block_size = self.alignment * 6
self.execve_num = 0xdd

def get_arch(project, kernel_mode=False):
name = project.arch.name
Expand All @@ -134,6 +167,8 @@ def get_arch(project, kernel_mode=False):
return ARM(project, kernel_mode=mode)
elif name == 'AARCH64':
return AARCH64(project, kernel_mode=mode)
elif name == 'RISCV64':
return RISCV64(project, kernel_mode=mode)
elif name.startswith('MIPS'):
return MIPS(project, kernel_mode=mode)
else:
Expand Down
Loading
Loading