# Decompile main() to readable C
import angr
proj = angr.Project("fauxware")
cfg = proj.analyses.CFGFast(normalize=True)// open-source binary analysis
Demystify binaries.
angr is a powerful Python platform for analyzing binaries, combining decompilation, symbolic execution, and more into one scriptable toolkit.
- BSD
- licensed
- 8+
- guest architectures
- 1
- pip install away
dec = proj.analyses.Decompiler("main")
print(dec.codegen.text)int main(unsigned int a0, unsigned long long a1)
{
unsigned long long v0; // [bp-0x48]
unsigned int v1; // [bp-0x3c]
char v2; // [bp-0x2c], Other Possible Types: unsigned int
char v3; // [bp-0x28]
char v4; // [bp-0x20]
char v5; // [bp-0x18]
char v6; // [bp-0x10]
v1 = a0;
v0 = a1;
v6 = 0;
v4 = 0;
puts("Username: ");
read(0, &v5, 8);
read(0, &v2, 1);
puts("Password: ");
read(0, &v3, 8);
read(0, &v2, 1);
v2 = authenticate(&v5, &v3, &v3);
if (!v2)
rejected(); /* do not return */
return accepted();
}# Disassemble a function with its CFG edges
import angr
proj = angr.Project("fauxware")
proj.analyses.CFGFast(normalize=True)
proj.kb.functions["authenticate"].pp()authenticate: 400664 push rbp 400665 mov rbp, rsp 400668 sub rsp, 0x20 40066c mov qword ptr [rbp-0x18], rdi 400670 mov qword ptr [rbp-0x20], rsi 400674 mov byte ptr [rbp-0x8], 0x0 400678 mov rdx, qword ptr [sneaky] 40067f mov rax, qword ptr [rbp-0x20] 400683 mov rsi, rdx 400686 mov rdi, rax 400689 call strcmp 40068e test eax, eax ╭╴400690 jne 0x400699 │ │ 400692 mov eax, 0x1 ╭──╴│ 400697 jmp 0x4006eb │ │ │ ╰▸400699 mov rax, qword ptr [rbp-0x18] │ 40069d mov esi, 0x0 │ 4006a2 mov rdi, rax │ 4006a5 mov eax, 0x0 │ 4006aa call open │ │ 4006af mov dword ptr [rbp-0x4], eax │ 4006b2 lea rcx, [rbp-0x10] │ 4006b6 mov eax, dword ptr [rbp-0x4] │ 4006b9 mov edx, 0x8 │ 4006be mov rsi, rcx │ 4006c1 mov edi, eax │ 4006c3 call read │ │ 4006c8 lea rdx, [rbp-0x10] │ 4006cc mov rax, qword ptr [rbp-0x20] │ 4006d0 mov rsi, rdx │ 4006d3 mov rdi, rax │ 4006d6 call strcmp │ │ 4006db test eax, eax │ ╭──╴4006dd jne 0x4006e6 │ │ │ │ 4006df mov eax, 0x1 │ │ ╭╴4006e4 jmp 0x4006eb │ │ │ │ ╰▸│ 4006e6 mov eax, 0x0 │ │ ╰──▸╰▸4006eb leave 4006ec ret
# Find the input that gets accepted
import angr
proj = angr.Project("fauxware")
simgr = proj.factory.simgr()accepted = proj.loader.find_symbol("accepted").rebased_addr
simgr.explore(find=accepted)<SimulationManager with 1 active, 1 found>
print(simgr.found[0].posix.dumps(0))b'\x00\x00\x00\x00\x00\x00\x00\x00\x00SOSNEAKY\x00'
# Decompile a Go binary's main.main — back to Go
import angr
proj = angr.Project("fauxware")
cfg = proj.analyses.CFGFast(normalize=True)proj.analyses.CompleteCallingConventions()
dec = proj.analyses.Decompiler("main.main", flavor="go")
print(dec.codegen.text)func main.main() {
v0 := 0
v1 := 0
v2 := 0
v3 := 0
v4 := 0
v10 := "Username: \nPassword: \nbad addressfile existsbroken pipebad messageassistQueuenetpollInitreflectOffsglobalAllocmSpanManualstart traceclobberfreegccheckmarkscheddetailunspecified"
syscall.RawSyscall(1, 1, "Username: \n", 11)
v9 := &v0
syscall.RawSyscall(0, 0, &v0, 8)
v8 := &v4
syscall.RawSyscall(0, 0, &v4, 1)
v7 := "Password: \nbad addressfile existsbroken pipebad messageassistQueuenetpollInitreflectOffsglobalAllocmSpanManualstart traceclobberfreegccheckmarkscheddetailunspecified"
syscall.RawSyscall(1, 1, "Password: \n", 11)
v6 := &v2
syscall.RawSyscall(0, 0, &v2, 8)
v5 := &v4
syscall.RawSyscall(0, 0, &v4, 1)
ok, v13 := main.authenticate(&v0, 9, 9, &v2, 8, 9)
if !ok {
main.rejected()
return
}
main.accepted()
return
}# Disassemble a Go function with its CFG edges
import angr
proj = angr.Project("fauxware")
proj.analyses.CFGFast(normalize=True)
proj.kb.functions["main.authenticate"].pp()main.authenticate: ╭────────▸47c5c0 cmp rsp, qword ptr [r14+0x10] │ ╭──────╴47c5c4 jbe 0x47c67a │ │ │ │ 47c5ca push rbp │ │ 47c5cb mov rbp, rsp │ │ 47c5ce sub rsp, 0x38 │ │ 47c5d2 mov qword ptr [rsp+0x48], rax │ │ 47c5d7 mov qword ptr [rsp+0x60], rdi │ │ 47c5dc nop dword ptr [rax] │ │ 47c5e0 cmp rsi, 0x8 │ │ ╭──╴47c5e4 jne 0x47c601 │ │ │ │ │ │ 47c5e6 movabs rdx, 0x594b41454e534f53 │ │ │ 47c5f0 cmp qword ptr [rdi], rdx │ │ │ ╭╴47c5f3 jne 0x47c601 │ │ │ │ │ │ │ │ 47c5f5 mov eax, 0x1 │ │ │ │ 47c5fa add rsp, 0x38 │ │ │ │ 47c5fe pop rbp │ │ │ │ 47c5ff nop │ │ │ │ 47c600 ret │ │ │ │ │ │ ╰▸╰▸47c601 mov qword ptr [rsp+0x20], 0x0 │ │ 47c60a nop │ │ 47c60b test rbx, rbx │ │ ╭────╴47c60e jbe 0x47c674 │ │ │ │ │ │ 47c610 mov qword ptr [rsp+0x68], rsi │ │ │ 47c615 mov qword ptr [rsp+0x60], rdi │ │ │ 47c61a mov qword ptr [rsp+0x30], rax │ │ │ 47c61f mov rbx, rax │ │ │ 47c622 xor ecx, ecx │ │ │ 47c624 mov rdi, rcx │ │ │ 47c627 mov eax, 0x2 │ │ │ 47c62c call syscall.RawSyscall │ │ │ │ │ │ 47c631 nop │ │ │ 47c632 lea rcx, [rsp+0x20] │ │ │ 47c637 mov qword ptr [rsp+0x28], rcx │ │ │ 47c63c mov rbx, rax │ │ │ 47c63f mov edi, 0x8 │ │ │ 47c644 xor eax, eax │ │ │ 47c646 call syscall.RawSyscall │ │ │ │ │ │ 47c64b mov rdx, qword ptr [rsp+0x68] │ │ │ 47c650 cmp rdx, 0x8 │ │ │ ╭╴47c654 je 0x47c65a │ │ │ │ │ │ │ │ 47c656 xor eax, eax │ │ │ ╭╴│ 47c658 jmp 0x47c66e │ │ │ │ │ │ │ │ │ ╰▸47c65a mov rax, qword ptr [rsp+0x60] │ │ │ │ 47c65f lea rbx, [rsp+0x20] │ │ │ │ 47c664 mov ecx, 0x8 │ │ │ │ 47c669 call runtime.memequal │ │ │ │ │ │ │ ╰──▸47c66e add rsp, 0x38 │ │ │ 47c672 pop rbp │ │ │ 47c673 ret │ │ │ │ │ ╰────▸47c674 call runtime.panicBounds │ │ │ ╰──────▸47c67a mov qword ptr [rsp+0x8], rax │ 47c67f mov qword ptr [rsp+0x10], rbx │ 47c684 mov qword ptr [rsp+0x18], rcx │ 47c689 mov qword ptr [rsp+0x20], rdi │ 47c68e mov qword ptr [rsp+0x28], rsi │ 47c693 mov qword ptr [rsp+0x30], r8 │ 47c698 call runtime.morestack_noctxt.abi0 │ │ 47c69d mov rax, qword ptr [rsp+0x8] │ 47c6a2 mov rbx, qword ptr [rsp+0x10] │ 47c6a7 mov rcx, qword ptr [rsp+0x18] │ 47c6ac mov rdi, qword ptr [rsp+0x20] │ 47c6b1 mov rsi, qword ptr [rsp+0x28] │ 47c6b6 mov r8, qword ptr [rsp+0x30] │ 47c6bb nop dword ptr [rax+rax] ╰────────╴47c6c0 jmp main.authenticate
# Find the input that gets accepted
import angr
proj = angr.Project("fauxware")
main = proj.loader.find_symbol("main.main").rebased_addr
accepted = proj.loader.find_symbol("main.accepted").rebased_addr
morestack = proj.loader.find_symbol("runtime.morestack_noctxt.abi0").rebased_addr# skip the Go runtime's bootstrap: start right at main.main
state = proj.factory.blank_state(addr=main)
simgr = proj.factory.simgr(state)
simgr.explore(find=accepted, avoid=morestack)<SimulationManager with 1 active, 1 found, 2 avoid>
print(simgr.found[0].posix.dumps(0))b'\x00\x00\x00\x00\x00\x00\x00\x00\x00SOSNEAKY\x00'
# Decompile a Rust binary's main — back to Rust
import angr
proj = angr.Project("fauxware")
cfg = proj.analyses.CFGFast(normalize=True)proj.analyses.CompleteCallingConventions()
proj.analyses.RustSymbolRecovery()
proj.analyses.TypeDBLoader()
funcs = {f.demangled_name: f for f in cfg.functions.values()}dec = proj.analyses.Decompiler(funcs["fauxware::main"], flavor="rust")
print(dec.codegen.text)fn fauxware::main() -> u0 {
let v0: std::io::stdio::Stdin; // [bp-0x60]
let v1: u8; // [bp-0x51]
let v2: u8; // [bp-0x49]
let v3: u8; // [bp-0x41]
let v4: u64; // [bp-0x38]
let v5: u64; // [bp-0x28]
let v6: u64; // [bp-0x18]
let v7: u64; // [bp-0x8]
let v10: struct16; // rax:rdx
let v11: core::result::Result<usize, std::io::error::Error>; // rax:rdx
let v12: core::result::Result<usize, std::io::error::Error>; // rax:rdx
let v13: core::result::Result<usize, std::io::error::Error>; // rax:rdx
let v14: core::result::Result<usize, std::io::error::Error>; // rax:rdx
let v15: struct16; // rax:rdx
v0 = std::io::stdio::stdin();
memset(&v1, 0, 8);
memset(&v2, 0, 8);
v3 = 0;
v10 = <core::fmt::Arguments>::from_str("Username: \n");
std::io::stdio::_print(v10 as u64);
v13 = <std::io::stdio::Stdin as std::io::Read>::read(&v0, &v1, 8);
v4 = *((&v13 as &char + 8) as &i64);
core::ptr::drop_glue::<core::result::Result<usize, core::io::error::Error>>(&v13 as i64);
v14 = <std::io::stdio::Stdin as std::io::Read>::read(&v0, &v3, 1);
v5 = *((&v14 as &char + 8) as &i64);
core::ptr::drop_glue::<core::result::Result<usize, core::io::error::Error>>(&v14 as i64);
v15 = <core::fmt::Arguments>::from_str("Password: \n");
std::io::stdio::_print(v15 as u64);
v12 = <std::io::stdio::Stdin as std::io::Read>::read(&v0, &v2, 8);
v6 = *((&v12 as &char + 8) as &i64);
core::ptr::drop_glue::<core::result::Result<usize, core::io::error::Error>>(&v12 as i64);
v11 = <std::io::stdio::Stdin as std::io::Read>::read(&v0, &v3, 1);
v7 = *((&v11 as &char + 8) as &i64);
core::ptr::drop_glue::<core::result::Result<usize, core::io::error::Error>>(&v11 as i64);
if fauxware::authenticate(&v1, &v2) as char {
fauxware::accepted();
return;
}
fauxware::rejected(); /* do not return */
}# Disassemble a Rust function — angr demangles the symbols
import angr
proj = angr.Project("fauxware")
cfg = proj.analyses.CFGFast(normalize=True)
funcs = {f.demangled_name: f for f in cfg.functions.values()}
funcs["fauxware::authenticate"].pp()_RNvCsfJzwR3Dz023_8fauxware12authenticate: 40a840 sub rsp, 0x68 40a844 mov qword ptr [rsp], rdi 40a848 mov qword ptr [rsp+0x8], rsi 40a84d lea rdi, [rsp+0x8] 40a852 lea rsi, [0x4613b8] 40a859 call <&[u8; 8] as core::cmp::PartialEq>::eq 40a85e test al, 0x1 ╭────╴40a860 jne 0x40a8b9 │ │ 40a862 lea rdi, [rsp+0x18] │ 40a867 xor esi, esi │ 40a869 mov edx, 0x8 │ 40a86e call memset │ │ 40a873 mov rsi, qword ptr [rsp] │ 40a877 lea rdi, [rsp+0x20] │ 40a87c mov edx, 0x8 │ 40a881 call qword ptr [0x463ca0] │ │ 40a887 lea rdi, [rsp+0x20] │ 40a88c call <alloc::borrow::Cow<str> as core::ops::deref::Deref>::deref │ │ 40a891 mov rdi, rax │ 40a894 mov rsi, rdx │ 40a897 xor edx, edx │ 40a899 call <str>::trim_end_matches::<char> │ │ 40a89e mov rsi, rax │ 40a8a1 lea rdi, [rsp+0x38] │ 40a8a6 call <std::fs::File>::open::<&str> │ │ 40a8ab mov eax, dword ptr [rsp+0x38] │ 40a8af test rax, 0x1 │ ╭╴40a8b5 jne 0x40a8c0 │ │ │ ╭╴│ 40a8b7 jmp 0x40a8ce │ │ │ ╰▸│ │ 40a8b9 mov byte ptr [rsp+0x17], 0x1 ╭──────╴│ │ 40a8be jmp 0x40a93e │ │ │ │ ╭──▸│ ╰▸40a8c0 mov eax, dword ptr [rsp+0x38] │ │ │ 40a8c4 test rax, 0x1 │ │ ╭╴│ 40a8ca jne 0x40a90b │ │ │ │ │ ╭╴│ │ │ 40a8cc jmp 0x40a915 │ │ │ │ │ │ │ │ │ ╰──▸40a8ce mov eax, dword ptr [rsp+0x3c] │ │ │ │ 40a8d2 mov dword ptr [rsp+0x4c], eax │ │ │ │ 40a8d6 lea rdi, [rsp+0x4c] │ │ │ │ 40a8db lea rsi, [rsp+0x18] │ │ │ │ 40a8e0 mov edx, 0x8 │ │ │ │ 40a8e5 call qword ptr [0x463980] │ │ │ │ │ │ │ │ 40a8eb mov qword ptr [rsp+0x50], rax │ │ │ │ 40a8f0 mov qword ptr [rsp+0x58], rdx │ │ │ │ 40a8f5 lea rdi, [rsp+0x50] │ │ │ │ 40a8fa call core::ptr::drop_glue::<core::result::Result<usize, core::io::error::Error>> │ │ │ │ │ │ │ │ 40a8ff lea rdi, [rsp+0x4c] │ │ │ │ 40a904 call core::ptr::drop_glue::<std::fs::File> │ │ │ │ │ │ ╰╴│ 40a909 jmp 0x40a8c0 │ │ │ │ │ ╰────▸40a90b lea rdi, [rsp+0x38] │ │ 40a910 call core::ptr::drop_glue::<core::result::Result<std::fs::File, core::io::error::Error>> │ │ │ ╰────────▸40a915 lea rax, [rsp+0x18] │ 40a91a mov qword ptr [rsp+0x60], rax │ 40a91f lea rdi, [rsp+0x8] │ 40a924 lea rsi, [rsp+0x60] │ 40a929 call <&[u8; 8] as core::cmp::PartialEq>::eq │ │ 40a92e and al, 0x1 │ 40a930 mov byte ptr [rsp+0x17], al │ 40a934 lea rdi, [rsp+0x20] │ 40a939 call core::ptr::drop_glue::<alloc::borrow::Cow<str>> │ ╰──────────▸40a93e mov al, byte ptr [rsp+0x17] 40a942 and al, 0x1 40a944 add rsp, 0x68 40a948 ret
# Find the input that gets accepted
import angr
proj = angr.Project("fauxware")
cfg = proj.analyses.CFGFast(normalize=True)
funcs = {f.demangled_name: f for f in cfg.functions.values()}# skip the Rust runtime's startup: start right at fauxware::main
state = proj.factory.blank_state(addr=funcs["fauxware::main"].addr)
simgr = proj.factory.simgr(state)
simgr.explore(find=funcs["fauxware::accepted"].addr)<SimulationManager with 1 active, 1 found>
print(simgr.found[0].posix.dumps(0).rstrip(b"\x00"))b'\x00\x00\x00\x00\x00\x00\x00\x00\x00SOSNEAKY'


















angr decompile fauxware --functions main authenticate rejected accepted// the toolkit
Your new swiss army knife
angr provides static and dynamic techniques in a single library. Mix and match to solve your problems.
Symbolic Execution
A powerful concolic engine: explore every path at once, solve constraints, and reason about inputs that reach any state.
Decompilation
Lift machine code to angr's AIL and recover readable pseudocode as C or Rust.
CFG Recovery
Reconstruct control-flow graphs and call graphs with advanced static analyses, even on stripped and obfuscated targets.
Disassembly & Lifting
Disassemble and lift to AIL, the angr intermediate language, giving every architecture one uniform analysis surface.
Multi-Architecture
x86 / x86-64, ARM & AArch64, MIPS, PowerPC, and more — any host can analyze any guest.
Extensible by Design
Hook anything, register custom analyses, SimProcedures, and exploration techniques. If you can script it in Python, angr can run it.
Pythonic API
A clean, scriptable Python interface. Drop into a REPL, wire angr into your tooling, or build something entirely new on top.
Free & Open Source
Released under the permissive BSD license and developed in the open. Battle-tested in research, CTFs, and the DARPA CGC.
// get started
Up and running in seconds
angr is a Python 3.12+ package. Install it into a virtual environment and you're ready to analyze. Works on Linux, macOS, and Windows.
$ pip install angr# then import angr and go
// angr-management
A full GUI, powered by angr
Prefer to point and click? angr-management is the official graphical interface. Control the whole platform, made visual and interactive. Disassemble, decompile to C or Rust, patch, and explore, all without leaving the window. It runs natively on Linux, macOS, and Windows.
- Customizable decompilation to C or Rust
- Linear and graph-based disassembly
- Hex editor and interactive binary patching
- Plugins, scripting, and more...
// model context protocol
angr for your AI assistant
angr ships an MCP server, so assistants like Claude can drive it directly — loading binaries, recovering control-flow graphs, decompiling functions, and chasing xrefs. It's not just a natural language control interface, it's a meaningful expansion to your toolkit. And that's special.
# expose angr over MCP (stdio — for Claude Desktop, etc.)
$ python -m angr.mcp
# ...or over HTTP / SSE for remote clients
$ python -m angr.mcp --transport httpTools it exposes
- Decompilation
- Control-flow graphs
- Disassembly
- Cross-references
- Strings
- Imports & exports
- Call graphs
- Function search
Works with any MCP client. Point yours at the server and ask it to reverse a binary.
// modular design
The Power of Composition
angr is built from focused subprojects, each one usable on its own. Take the whole stack, or just the piece you need.
- angr
The binary analysis platform itself.
- angr-management
The graphical interface for angr.
- srcdump
Like objdump, but dumps decompiled source code.
- CLE
Loads binaries and their libraries into memory.
- PyVEX
Python bindings to the VEX intermediate language.
- pypcode
Python bindings to Ghidra's P-code lifter.
- archinfo
A library of CPU architecture descriptions.
- angrop
Automatic ROP chain generation.
// join in
With and For Our Community
angr is developed by researchers and hackers around the world. Ask questions, share what you've built, or send your first pull request. Find community and make a difference!
// professional support
angr, backed by its core team
Emotion Labs is the company behind angr. We, the same maintainers who build it, offer support, development, and training to put binary analysis to work for your team.
Visit Emotion LabsSupport
Expert help and maintenance from the humans behind angr.
Development
Custom analyses, features, and integrations built on top of angr.
Training
Hands-on courses in binary analysis and reverse engineering.

