Skip to content

Interactive assembler for Ghidra processor modules

License

Notifications You must be signed in to change notification settings

nevesnunes/ghembler

Repository files navigation

Ghembler

Interactive assembler for Ghidra processor modules featuring auto-completion. Besides the intended pun in the name, it also suggests taking the risk of finding bugs. 🙂

Example using Toshiba TLCS-900/H:

Example using x86-64 (jump from origin offset 0xa to absolute address 0x5 vs relative address 0x2005 with label foo):

Save patch generates a Python script that applies instructions at the given base offset to an input file:

#!/usr/bin/env python3

import sys

with open(sys.argv[1], 'r+b') as f:
    b = b''
    # MOV AX,123
    b += b'\x66\xc7\xc0\x7b\x00'
    # NOP
    b += b'\x66\x48\x90'

    f.write(b)

    f.seek(0x8)

    b = b''
    # JMP 0x5
    b += b'\x48\xe9\xf7\xdf\xff\xff'  # relative to base offset 0x2000

    f.write(b)

Why not just use Ghidra?

We can modify a disassembled instruction or edit cleared bytes with action "Patch Instruction", which is fine once you change the default keybind to use a single key.

However, once there's the need for more common text editor operations (insert/delete/copy/paste), it becomes clunky, and any workarounds are very limited.

I'd also like to introduce some assembler-specific features (directives/macros/labels).

Running

Tested with Ghidra 10.3.2, on Debian GNU/Linux 12.

Backend (Ghidra script):

# Create zero-filled file so that the script has a program available
dd if=/dev/zero of=/tmp/0.bin bs=1024 iflag=count_bytes count=$((0x10000))

# Run script headless, wait until ready:
# INFO  AsmServer.java> Listening at port 18000... (GhidraScript)
GHIDRA_INSTALL_DIR=/home/foo/ghidra_10.3.2_PUBLIC # FIXME
GHIDRA_PROJECT_DIR=/home/foo/ghidra_projects # FIXME
GHIDRA_PROJECT_NAME=foo # FIXME
GHIDRA_PROCESSOR=x86:LE:64:default # FIXME
"$GHIDRA_INSTALL_DIR/support/analyzeHeadless" "$GHIDRA_PROJECT_DIR/" "$GHIDRA_PROJECT_NAME/_headless" \
        -import /tmp/0.bin \
        -overwrite \
        -processor "$GHIDRA_PROCESSOR" \
        -noanalysis \
        -scriptPath ./ghidra_scripts \
        -postScript AsmServer.java

Frontend:

npm install
npm run server
# Listening at http://localhost:8000

[Optional] Sanity check:

# Expecting two encodings returned when assembling the given instruction
curl -X POST -H "Content-Type: text/plain" --data "jp NZ/NE,XWA+1" http://localhost:18000/assemble | jq .
# [
#   {
#     "type": "bytes",
#     "data": "b8 01 de"
#   },
#   {
#     "type": "bytes",
#     "data": "f3 e1 01 00 de"
#   }
# ]

Testing

Run backend with -processor 'x86:LE:64:default', then:

# Headless Mode
npx playwright test --project=chromium

# UI Mode
npx playwright test --debug --ui --project=chromium

Related work

About

Interactive assembler for Ghidra processor modules

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published