* AIL: Merge likes/matches into a single mode-parameterized walk
* AIL: Make __eq__ idx-aware at every node, not just the root
* AIL: Stop hashing fields that equality does not compare
* AIL: Regression-test the hash/eq contract
* AIL: Compare bits in StringLiteral and Struct
* AIL: Replace the CMP_* constants with a CmpMode enum
* AIL: cargo fmt
* AIL: Compare and hash rounding_mode on Convert and BinaryOp
* Update comments.
- Make SPropagator, SRDA, and BlockSimplifier normal classes instead of Analysis classes.
- Share peephole optimizer instances across BlockSimplifiers.
- BlockSimplifier: Skip unnecessary peephole passes; avoid block-level comparisons for fixpoint determination.
- Add a runtime-only peephole_optimized flag to AIL statements so we skip running peephole optimizations on already optimized statements.
Also,
- Refactored variable_kb into kb.dec_variables.
- Spill decompilation cache into RuntimeDb.
- Save decompilation cache into angrDb. Decompilation results can be preserved across runs.
- No longer check in _pb2.py files; they are generated during build.
* port the VEX->AIL converter and Manager to Rust
* allow a non-constant rounding mode on Convert/BinaryOp
* construct AilExpression/AilStatement natively in the converter
* resolve libpyvex symbols on Windows
* classify name-only VEX ops; guarantee ins_addr on every stmt
* take the Manager as a typed pyclass handle in the converter
* Lint code.
* ailment.pyi: add Manager and VEXIRSBConverter stubs
The clarirs workspace lints enable clippy::cargo, and CI runs clippy with
-D warnings, so the angr crate's missing description/license/readme/
keywords/categories/repository metadata failed the Rust Check job.
Inherit the shared fields from workspace.package.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This PR migrates AIL classes (Block, Statement, Expression, etc.) to Rust. Key changes include:
- Block, Statement, and Expression are native Rust objects. Every access to their properties will create a new Python class object. Therefore, `expr.dst is expr.dst` will always evaluate to False. You'll want to do `expr.dst == expr.dst` instead.
- However, keep in mind that `expr_0 == expr_1` can be expensive because equality checks may potentially go over two expression trees and compare every single node. In this case, you may want to resort to `expr_0.idx == expr_1.idx`. There are still a few places where `idx` is reused; we plan to remove all such cases and guarantee the uniqueness of `idx` for all Statements and Expressions during a single decompilation run.
- `type(expr) is Const` no longer works. You must use `isinstance(expr, Const)` instead. `isinstance(..., ExpressionCls/StatementCls)` is also more expensive than before due to the use of custom meta classes.
- New changes to AIL requires rebuilding the Rust component to land. You can do `python setup.py build_rust --inplace --release` to rebuild the angr Rust component in-place in an editable install.
---------
Co-authored-by: Kevin Phoenix <kevin@kphoenix.us>
* Icicle: auto-invalidate code cache on memory mutations.
Before this change, calling mem_write/mem_unmap/mem_protect from Python
on an address whose page had been executed would raise SelfModifyingCode
(from the VM's SMC detection) or silently leave a stale lifted/JIT
block in place, so subsequent runs executed the old code.
mem_write/mem_unmap/mem_protect now call an internal invalidate_code_range
that drops any BlockGroup, JIT compilation, and cached disassembly
overlapping the written range. SMC detection is disabled at construction
since explicit invalidation replaces it for our sync writes. restore_snapshot
additionally calls Vm::reset before Vm::restore so lifted code, JIT cache,
and prev_isa_mode — none of which the snapshot covers — are discarded.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* IcicleEngine: re-sync simproc breakpoints on every run.
SimProcedure.call() creates new extern hooks on demand (for instance, the
continuation targets of __libc_start_main), so the simproc set grows
during execution. IcicleEngine's full-init path seeded the emu's
breakpoint table once, but neither the continuation nor the snapshot-
restore paths re-synced new entries.
Before this, a main() return landing on a dynamically-created
after_main extern silently fell through to zero bytes in the extern
region (SIGSEGV in fauxware fully- or partly-snapshot-mode runs).
add_breakpoint is idempotent so iterating over project._sim_procedures
before each run is cheap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* IcicleEngine: fix continuation sync for BV addresses and stale path tracer.
Two related fixes uncovered while chasing fauxware failures when snapshot
mode is forced on:
1. The SimInspect mem_write hook only recorded dirty pages when
`mem_write_address` and `mem_write_length` were Python ints. In
practice both are typically claripy BitVectors (concrete addresses
wrapped), and `state.memory.store(addr, bvv)` is commonly called
without an explicit size, so `length` arrives as None. Normalise BV
args to int via `.concrete_value`, and fall back to
`mem_write_expr.size() // 8` when length is absent. Without this,
data written by SimProcedures between icicle runs (e.g. `read`
writing into the stack password buffer) never made it into
dirty_pages, so the next continuation-sync run left the emu holding
pre-read zeros and comparisons downstream took the wrong branch.
2. The path tracer isn't cleared on continuation, so
`emu.recent_blocks` accumulates blocks across every reused run.
`__convert_icicle_state_to_angr` then re-appends the whole list each
time, duplicating prior blocks in `state.history.bbl_addrs`. Call
`emu.clear_path_tracer()` at the start of a continuation run so
recent_blocks reflects only this run's blocks.
With these two fixes plus the earlier simproc-breakpoint re-sync, all
61 icicle/emulator/fuzzer tests pass with `_snapshot_mode` forced True,
matching the snapshot-off baseline.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* IcicleEngine: make snapshot mode the default; remove the opt-in.
The first call always saves a snapshot of the fresh VM; subsequent calls
either continue with the cached emu or restore the snapshot and
delta-sync. Dropped `enable_snapshot_mode()` and the `_snapshot_mode`
flag — with the earlier sync fixes on this branch, the restore-based
path passes the same tests as the prior full-init-each-call behaviour
and runs roughly 3x faster on the fauxware suite.
- Removes the `enable_snapshot_mode()` method and its callers in three
tests (now redundant) and in the Rust fuzzer executor.
- Updates the class docstring.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
* faster
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---------
Co-authored-by: rileyseefeldt <riley@evilcomputer2.localdomain>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
* Add determininstic mutator to fuzzer for easier testing
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
* adds checkpoint for converting angr state to icicle
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* fix ruff errors
* sync snapshot mapping/perms and added test
* lint fix
* changed test to use angr engine
* ruff
---------
Co-authored-by: rileyseefeldt <riley@evilcomputer2.localdomain>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: rileyseefeldt <seatbeltman@evilcomputer.localdomain>
* WIP Fuzzer
* Cargo fmt
* Set breakpoint at return address
* Add basic monitor support
* Add some access parameters
* Remove print message
* Update to pyo3 0.26
* Fix deprecations
* Remove commented cargo entries
* Improve pyi file coverage
* Fix linter and type checker issues
* Properly get return address register from calling convention
* Improve test
* Refactor monitors into more flexible callback
* Add run method to run fuzzer on loop
* Fix Fuzzer init arg in pyi file
* FCP: Get default cc from project factory
* Make PyInMemoryCorpus Sendable
* Use an on-disk corpus
* Add submodule imports to rustylib pyi
* Dynamic Corpus that allows for OnDiskCorpus and InMemoryCorpus
* Run formatters
* Add some type asserts
* Refactor test_fuzzer.py to be unittest
* Add pylint ignore
* Add tests for serialization
---------
Co-authored-by: rileyseefeldt <riley@evilcomputer2>