ChipBench packages Ghidra, radare2, binwalk, chip-programming tools,
simulators, and firmware-unpacking utilities into one reproducible container
for analyzing raw chip dumps entirely from the command line or an AI CLI.
Headless Jython scripts drive import, forced-disassembly sweeps, live
queries, and bulk decompilation exports without any GUI.
Derived from a private engagement environment, generalized for public
release under AGPLv3. No engagement-specific artifacts are included.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
69 lines
2.4 KiB
Python
69 lines
2.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# Part of ChipBench (AGPLv3). SPDX-FileCopyrightText: 2026 Starting Line Productions LLC
|
|
# Analyze8051.py -- force-disassemble a raw 8051 binary and re-run analysis.
|
|
# Raw binary imports leave no entry points, so Ghidra finds 0 functions.
|
|
# This script disassembles from the reset + interrupt vectors, re-analyzes,
|
|
# then sweeps remaining undefined bytes in populated code regions.
|
|
|
|
from ghidra.app.cmd.disassemble import DisassembleCommand
|
|
from ghidra.program.model.address import AddressSet
|
|
from ghidra.app.plugin.core.analysis import AutoAnalysisManager
|
|
|
|
prog = currentProgram
|
|
codeSpace = prog.getAddressFactory().getAddressSpace("CODE")
|
|
if codeSpace is None:
|
|
codeSpace = prog.getAddressFactory().getDefaultAddressSpace()
|
|
|
|
def A(x):
|
|
return codeSpace.getAddress(x)
|
|
|
|
# 8051 interrupt vectors (standard set; enhanced variants may extend)
|
|
vectors = [0x0000, 0x0003, 0x000B, 0x0013, 0x001B, 0x0023, 0x002B, 0x0033, 0x003B]
|
|
|
|
for v in vectors:
|
|
cmd = DisassembleCommand(A(v), None, True)
|
|
cmd.applyTo(prog, monitor)
|
|
|
|
instr = prog.getListing().getNumInstructions()
|
|
print("After vector disassembly:", instr, "instructions")
|
|
|
|
mgr = AutoAnalysisManager.getAnalysisManager(prog)
|
|
mgr.reAnalyzeAll(None)
|
|
mgr.startAnalysis(monitor)
|
|
|
|
instr = prog.getListing().getNumInstructions()
|
|
funcs = prog.getFunctionManager().getFunctionCount()
|
|
print("After analysis:", instr, "instructions,", funcs, "functions")
|
|
|
|
# Sweep remaining undefined bytes in all populated regions, 1KB at a time.
|
|
# String islands (0x9250-0x9F00, 0xEF00-0xF400) stay data; the rest is code.
|
|
listing = prog.getListing()
|
|
memory = prog.getMemory()
|
|
SKIP = set(range(0x9200, 0x9F00, 0x400)) | set(range(0xEE00, 0x10000, 0x400))
|
|
for base in range(0x0000, 0xF400, 0x400):
|
|
if base in SKIP:
|
|
continue
|
|
blk = memory.getBlock(A(base))
|
|
if blk is None:
|
|
continue
|
|
# skip fully-erased ranges
|
|
erased = True
|
|
for i in range(base, base + 0x400, 32):
|
|
b = memory.getByte(A(i))
|
|
if (b & 0xFF) != 0xFF:
|
|
erased = False
|
|
break
|
|
if erased:
|
|
continue
|
|
rng = AddressSet(A(base), A(min(base + 0x3FF, 0xF3FF)))
|
|
sweep = DisassembleCommand(A(base), rng, True)
|
|
sweep.applyTo(prog, monitor)
|
|
|
|
mgr.reAnalyzeAll(None)
|
|
mgr.startAnalysis(monitor)
|
|
|
|
instr = prog.getListing().getNumInstructions()
|
|
funcs = prog.getFunctionManager().getFunctionCount()
|
|
print("Final:", instr, "instructions,", funcs, "functions")
|