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
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
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
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 85f01ed

Please sign in to comment.