Skip to main content
angr Management provides powerful patching capabilities that allow you to modify binary code and data, test changes interactively, and export patched binaries.

Overview

Patching in angr Management lets you:

Modify Code

Change assembly instructions, replace with NOPs, or rewrite logic

Edit Data

Modify strings, constants, and data structures

Test Changes

Verify patches with debugging before exporting

Export Binary

Save patched binary for deployment

Patch Types

angr Management supports several patching approaches:

Assembly Patching

Replace instructions with new assembly code:
1

Select Instruction

Right-click on instruction in disassembly view
2

Open Patch Dialog

Select “Patch Instruction”
3

Enter Assembly

Type new assembly (e.g., nop, xor eax, eax, jmp 0x401234)
4

Apply

Click OK to apply the patch
Examples:
# NOP out an instruction
nop

# Change return value
mov rax, 1
ret

# Skip a call
nop
nop
nop
nop
nop

# Redirect execution
jmp 0x401000

Hex Patching

Directly modify bytes in the hex view:
1

Open Hex View

View → Hex
2

Navigate to Address

Press G and enter address, or scroll
3

Edit Bytes

  • Click on hex bytes section
  • Type new hex values (e.g., 90 for NOP)
  • Or click ASCII section to edit as text
4

Automatic Patch

Patch is created automatically when you edit

Programmatic Patching

Use the Python console for complex patches:
# Patch via console
workspace.patch(0x401000, "nop", pad=True)

# Patch with raw bytes
from angr.knowledge_plugins.patches import Patch
addr = 0x401000
new_bytes = b'\x90\x90\x90\x90\x90'  # 5 NOPs
patch = Patch(addr, new_bytes)
workspace.instance.patches.add_patch_obj(patch)

# Multiple instruction patch
asm_code = """mov rax, 0
ret"""
workspace.patch(0x401000, asm_code)

Patch Management

Viewing Patches

Open the Patches View (View → Patches) to see all patches:
ColumnDescription
AddressLocation of patch in hex
SizeNumber of bytes modified
OriginalOriginal byte values
PatchedNew byte values
CommentOptional description

Patch Highlighting

Patches are visually marked throughout the interface:
  • Disassembly View: Yellow background on patched instructions
  • Hex View: Yellow highlight on patched bytes
  • Patches View: Complete list with details

Editing Patches

Modify existing patches:
  1. Double-click patch in Patches view
  2. Modify bytes or comment
  3. Click OK to save

Reverting Patches

In Patches View:
  1. Right-click patch
  2. Select “Revert Patch”
  3. Confirm reversion
In Hex View:
  1. Right-click yellow highlight
  2. Select “Revert”
  3. Patch is removed
Via Console:
# Remove all patches
pm = workspace.instance.patches
for addr in list(pm.keys()):
    pm.remove_patch(addr)
pm.am_event()

Patch Comments

Document your patches:
  1. Right-click patch (in Hex View or Patches View)
  2. Select “Set Comment”
  3. Enter description (e.g., “Bypass license check”)
  4. Comment appears in Patches view

Common Patching Patterns

NOPing Instructions

Remove unwanted instructions:
call check_license
test eax, eax
jz invalid_license
How to:
  1. Right-click call instruction
  2. Patch Instruction → nop
  3. Repeat for test and jz
  4. Or use multi-byte NOP for efficiency

Changing Conditionals

Flip conditional logic:
jz fail_case    ; Jump if zero

Forcing Return Values

Change function results:
call expensive_check
test eax, eax

Redirecting Calls

Change call targets:
call 0x401000   ; Original function
Ensure the new target has a compatible calling convention and signature.

Patching Data

Modify strings and constants:
In Hex View:
  1. Navigate to string address
  2. Click in ASCII column
  3. Type new text
  4. Null terminator handled automatically
Example: Change “Error” to “OK ”

Advanced Patching

Multi-Instruction Patches

Replace multiple instructions:
# Via console - more control
addr = 0x401000

# Assemble new code
ks = workspace.instance.project.arch.keystone
new_asm = """
mov rax, 0
test rax, rax
ret
"""
new_bytes = ks.asm(new_asm, addr)[0]

# Create patch
from angr.knowledge_plugins.patches import Patch
patch = Patch(addr, new_bytes)
workspace.instance.patches.add_patch_obj(patch)

Conditional Patching

Apply patches based on conditions:
# Patch all calls to a specific function
target_func = 0x404000
for func in workspace.instance.kb.functions.values():
    for block in func.blocks:
        for insn_addr in block.instruction_addrs:
            insn = block.capstone.insns[insn_addr]
            if insn.mnemonic == 'call':
                # Check if calling target_func
                operand = insn.op_str
                if hex(target_func) in operand:
                    # NOP out this call
                    workspace.patch(insn_addr, 'nop', pad=True)

Patch Merging

Combine adjacent patches:
  1. Apply patch at address A
  2. Apply patch at address A+N (adjacent)
  3. In Hex View, right-click first patch
  4. Select “Merge with next”
  5. Patches combine into single patch
Merging patches can simplify patch management and reduce overhead.

Patch Splitting

Split large patches:
  1. Navigate to middle of patch in Hex View
  2. Right-click on patch highlight
  3. Select “Split”
  4. Two independent patches created
Use case: You want to revert only part of a large patch.

Testing Patches

Debug Patched Code

1

Apply Patches

Make your modifications
2

Set Breakpoint

Break before or at patched code
3

Create State

Right-click → “New State”
4

Step Through

Press F7 to step through patched instructions
5

Verify

Check registers, memory, and control flow

Decompile Patched Code

View patches in pseudocode:
  1. Apply patches in disassembly
  2. Press Tab to switch to pseudocode
  3. Decompiler shows patched code
  4. Verify logic changes
Decompiler uses patched bytes, so you see the modified logic in C code.

Exporting Patched Binaries

Save Patched Binary

1

Open Save Dialog

File → Save Patched Binary As…
2

Choose Location

Select output file path (e.g., program.patched)
3

Save

Click Save
4

Verify

Test the patched binary externally
What Gets Saved:
  • All applied patches
  • Preserved file structure
  • Updated checksums (where applicable)
  • Original file format maintained

Patch Persistence

Patches are stored in:
  1. angr database (.adb): When you save the database
  2. Patched binary: When you export
  3. Memory only: Until you save (lost on exit)
Always save your database (File → Save angr database) to preserve patches across sessions.

Patch Limitations

Patches cannot exceed original instruction sizeIf your new code is longer:
  • Use a jump to a code cave
  • Place new code in unused space
  • Jump back when done
Example:
# At original location (5 bytes)
jmp code_cave

# At code_cave (unused space)
; Your long patch here
; ...
jmp return_address
Some binaries have relocations:
  • PIE executables
  • DLLs/shared libraries
  • Position-independent code
Considerations:
  • Patched addresses may change at runtime
  • Use relative addressing when possible
  • Test at expected load address
Signed binaries:
  • Patches invalidate signatures
  • Binary won’t verify after patching
  • May need to re-sign (platform-dependent)
Solution: Remove/disable signature verification or re-sign.

Best Practices

Document Patches

  • Add comments to every patch
  • Explain why the patch was needed
  • Note any side effects
  • Keep a patch log

Test Thoroughly

  • Use debugger to verify patches
  • Test edge cases
  • Check for unintended effects
  • Validate with decompiler

Backup First

  • Save original binary
  • Save angr database frequently
  • Version your patches
  • Test on copies, not originals

Minimal Changes

  • Patch only what’s necessary
  • Preserve original behavior where possible
  • Avoid cascading changes
  • Keep patches simple

Troubleshooting

Patch doesn’t appear in binary:Solutions:
  • Check Patches view for the patch
  • Verify address is correct
  • Ensure you exported after patching
  • Check file permissions
Patched binary crashes:Causes:
  • Incorrect instruction encoding
  • Changed stack alignment
  • Broken calling convention
  • Invalid jump target
Debug:
  • Revert patches one by one
  • Use debugger to find crash location
  • Verify instruction bytes are correct
Patch assembles incorrectly:Solutions:
  • Check architecture (x86 vs x64, ARM mode)
  • Verify syntax (AT&T vs Intel)
  • Use hex bytes directly if needed
  • Consult instruction reference

Next Steps

Debugging

Test patches with the debugger

Scripting

Automate patching workflows

Advanced Topics

Advanced binary modification techniques

Disassembly

Return to disassembly guide

Build docs developers (and LLMs) love