Skip to content

Commit

Permalink
Merge pull request #16 from Nalen98/patch
Browse files Browse the repository at this point in the history
Improvements for upcoming release
  • Loading branch information
Nalen98 committed Feb 13, 2024
2 parents 0062a55 + 02b8d77 commit 85f01ed
Show file tree
Hide file tree
Showing 16 changed files with 1,860 additions and 1,458 deletions.
40 changes: 25 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,42 @@
# AngryGhidra

<p align="center"><img src="./images/angryGhidraIcon.png" width="360" height="250">
<p align="center"><img src="./images/Icon.png" width="360" height="250">

The plugin allows you to use [angr](https://github.com/angr/angr) for binary analysis and symbolic execution from Ghidra interface.
The plugin allows you to use [angr](https://github.com/angr/angr) for binary analysis and symbolic execution in Ghidra interface.

Solving [CTF challenge from SecurityFest 2016 "fairlight"](https://github.com/angr/angr-doc/blob/master/examples/securityfest_fairlight/fairlight) with AngryGhidra plugin:

![AngryGhidra Plugin](./images/AngryGhidraPlugin.gif)
![AngryGhidra Plugin](./images/AngryPluginDemo.gif)

# Screenshots

![AngryGhidraView](./images/AngryGhidraView.png)
# Hotkeys

Apply patched bytes to write them to the memory of angr project:

![ApplyPatchedBytes](./images/ApplyPatchedBytes.png)
##### Set:
`Z`**destination** address
`X`**start** address
`J`**avoid** address (multiple choice)

# Installation

- `pip3 install angr` at first
- Make sure that python3 directory added to the `PATH` (required, `python3` only)
- Download Release version of extension and install it in Ghidra `File → Install Extensions...`
- Use gradle to build extension: `GHIDRA_INSTALL_DIR=${GHIDRA_HOME} gradle` and use Ghidra to install it: `File → Install Extensions...`
##### Reset:
`K`**destination** address
`T`**start** address
`P`**avoid** address

##### Apply bytes:
`U` – apply patched bytes to angr project memory

# Screenshots

Let's keygen:

![AngryGhidraView](./images/View.png)

Apply patched bytes to write them into the memory of angr project:

![ApplyPatchedBytes](./images/ApplyPatchedBytes.png)

# Installation

1) `pip3 install angr`
2) Make sure `python3` directory is added to the `PATH` (required, `Python 3` only)
3) Download the release version of the plugin and install it in Ghidra `File → Install Extensions...`
4) Use Gradle to build the plugin: `GHIDRA_INSTALL_DIR=${GHIDRA_HOME} gradle` and use Ghidra to install it: `File → Install Extensions...`
5) Check the box in the "New Plugins Found" window to apply AngryGhidra plugin to your project
50 changes: 28 additions & 22 deletions angryghidra_script/angryghidra.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
import angr
import claripy
import json
import time

EXPLORE_OPT = {} # Explore options
REGISTERS = [] # Main registers of your binary
EXPLORE_OPT = {}
REGISTERS = []
SYMVECTORS = []


def hook_function(state):
global SYMVECTORS
for object in EXPLORE_OPT["hooks"]:
for frame in object.items():
if frame[0] == str(hex(state.solver.eval(state.regs.ip))):
if frame[0] == hex(state.solver.eval(state.regs.ip)):
for option, data in frame[1].items():
if "sv" in data:
symbvector_length = int(data[2:], 0)
Expand All @@ -26,14 +25,18 @@ def hook_function(state):
setattr(state.regs, option, data)
break


def main(file):
global EXPLORE_OPT
global REGISTERS
global SYMVECTORS
find = None
avoid = None
blank_state = None
vectors = None

with open(file, encoding='utf-8') as json_file:
global EXPLORE_OPT
EXPLORE_OPT = json.load(json_file)

# Options parser
# JSON can't handle with hex values, so we need to do it manually
if "blank_state" in EXPLORE_OPT:
blank_state = int(EXPLORE_OPT["blank_state"], 16)

Expand Down Expand Up @@ -61,12 +64,11 @@ def main(file):
else:
p = angr.Project(EXPLORE_OPT["binary_file"], load_options={'main_opts': {'base_addr': base_address}, "auto_load_libs": EXPLORE_OPT["auto_load_libs"]})

global REGISTERS
REGISTERS = p.arch.default_symbolic_registers

if len(argv) > 1:
state = p.factory.entry_state(args=argv)
elif "blank_state" in locals():
elif blank_state != None:
state = p.factory.blank_state(addr=blank_state)
else:
state = p.factory.entry_state()
Expand All @@ -89,7 +91,7 @@ def main(file):
store_length = len(value) - 2
state.memory.store(store_addr, state.solver.BVV(store_value, 4 * store_length))

# Handle Symbolic Registers
# Handle symbolic registers
if "regs_vals" in EXPLORE_OPT:
for register, data in EXPLORE_OPT["regs_vals"].items():
if "sv" in data:
Expand All @@ -104,43 +106,48 @@ def main(file):
setattr(state.regs, register, data)
break

# Handle Hooks
# Handle hooks
if "hooks" in EXPLORE_OPT:
for object in EXPLORE_OPT["hooks"]:
for frame in object.items():
hook_address = frame[0]
for option, data in frame[1].items():
data = int(str(data), 0)
if option == "Length":
if option == "length":
hook_length = data
break
p.hook(int(hook_address, 16), hook_function, length=hook_length)

simgr = p.factory.simulation_manager(state)
if "avoid_address" in locals():
if avoid != None:
simgr.use_technique(angr.exploration_techniques.Explorer(find=find, avoid=avoid))
else:
simgr.use_technique(angr.exploration_techniques.Explorer(find=find))

simgr.run()

if simgr.found:
found_path = simgr.found[0]

win_sequence = ""
finishedTracing = False
for win_block in found_path.history.bbl_addrs.hardcopy:
win_block = p.factory.block(win_block)
addresses = win_block.instruction_addrs
for address in addresses:
win_sequence += hex(address) + ","
win_sequence += 't:' + hex(address) + '\n'
if address == find:
# Prevent sending the rest of the block addresses that aren't desired
finishedTracing = True
break
if finishedTracing:
break
win_sequence = win_sequence[:-1]
print("Trace:" + win_sequence)
print(win_sequence)

if len(argv) > 1:
for i in range(1, len(argv)):
print("argv[{id}] = {solution}".format(id=i, solution=found_path.solver.eval(argv[i], cast_to=bytes)))

if "vectors" in locals() and len(vectors) != 0:
if vectors != None and len(vectors) != 0:
for address, length in vectors.items():
print("{addr} = {value}".format(addr=hex(address),
value=found_path.solver.eval(found_path.memory.load(address, length),
Expand All @@ -167,5 +174,4 @@ def main(file):
if len(sys.argv) < 2:
print("Usage: *thisScript.py* angr_options.json")
exit()
file = sys.argv[1]
main(file)
main(sys.argv[1])
Binary file removed images/AngryGhidraPlugin.gif
Binary file not shown.
Binary file removed images/AngryGhidraView.png
Binary file not shown.
Binary file added images/AngryPluginDemo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/ApplyPatchedBytes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file added images/View.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 85f01ed

Please sign in to comment.