Init
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
# Lofi12XT_Map.py — Ghidra-side script (Jython2 + Ghidrathon compatible).
|
||||
# Run headless as -postScript. Two modes:
|
||||
# Mode A (map): Lofi12XT_Map.py <unpack_dir>
|
||||
# Creates one memory block per sect*.bin at its DDR address (from headers.json),
|
||||
# marks mmtd entry point, disassembles + makes a function there.
|
||||
# Mode B (vtables): Lofi12XT_Map.py vtables <vtables.csv>
|
||||
# Labels each vtable run, converts entries to pointers, bookmarks them.
|
||||
# No f-strings (Jython 2.7 safe). No third-party deps.
|
||||
import json
|
||||
import os
|
||||
|
||||
from ghidra.program.model.symbol import SourceType
|
||||
from ghidra.program.model.data import PointerDataType
|
||||
from java.io import File
|
||||
|
||||
|
||||
def log(msg):
|
||||
print("[Lofi12XT] " + msg)
|
||||
|
||||
|
||||
def map_sects(unpack_dir):
|
||||
info = json.load(open(os.path.join(unpack_dir, "headers.json")))
|
||||
mem = currentProgram.getMemory()
|
||||
for s in info["sects"]:
|
||||
name = "sect%d" % s["index"]
|
||||
addr = toAddr(s["addr_hex"])
|
||||
fn = os.path.join(unpack_dir,
|
||||
"sect%d_addr%s.bin" % (s["index"], s["addr_hex"]))
|
||||
size = s["len"]
|
||||
if mem.getBlock(addr) is not None:
|
||||
log(name + " already mapped at " + s["addr_hex"] + ", skip")
|
||||
continue
|
||||
mem.createInitializedBlock(name, addr, File(fn), size,
|
||||
"from lofi_unpack", "", False)
|
||||
blk = mem.getBlock(addr)
|
||||
is_code = (size > 1000000) # only the big sect is code
|
||||
blk.setRead(True)
|
||||
blk.setWrite(not is_code)
|
||||
blk.setExecute(is_code)
|
||||
log("mapped %s %s len=%d exec=%s" % (name, s["addr_hex"], size, is_code))
|
||||
|
||||
entry = toAddr(info["mmtd"]["entry_hex"])
|
||||
currentProgram.getSymbolTable().addExternalEntryPoint(entry)
|
||||
createLabel(entry, "fw_entry", True, SourceType.IMPORTED)
|
||||
disassemble(entry)
|
||||
createFunction(entry, "fw_entry")
|
||||
log("entry " + info["mmtd"]["entry_hex"] + " marked + function created")
|
||||
|
||||
|
||||
def map_vtables(csv_path):
|
||||
st = currentProgram.getSymbolTable()
|
||||
bm = currentProgram.getBookmarkManager()
|
||||
count = 0
|
||||
with open(csv_path) as f:
|
||||
header = f.readline()
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split(",", 3)
|
||||
load = toAddr(parts[1])
|
||||
entries = parts[3].split(";")
|
||||
createLabel(load, "vtable_%s" % parts[1], True,
|
||||
SourceType.ANALYSIS)
|
||||
for k, e in enumerate(entries):
|
||||
ea = load.add(k * 4)
|
||||
try:
|
||||
createData(ea, PointerDataType.dataType)
|
||||
except Exception:
|
||||
try:
|
||||
createDword(ea)
|
||||
except Exception:
|
||||
pass # labels/bookmarks below still land
|
||||
try:
|
||||
createLabel(toAddr(e), "vfunc_%s_%d" % (parts[1], k),
|
||||
False, SourceType.ANALYSIS)
|
||||
except Exception:
|
||||
pass
|
||||
bm.setBookmark(load, "Note", "vtable",
|
||||
"vtable %s n=%d" % (parts[1], len(entries)))
|
||||
count += 1
|
||||
log("labeled %d vtables from %s" % (count, csv_path))
|
||||
|
||||
|
||||
args = getScriptArgs()
|
||||
if len(args) == 1:
|
||||
map_sects(args[0])
|
||||
elif len(args) == 2 and args[0] == "vtables":
|
||||
map_vtables(args[1])
|
||||
else:
|
||||
log("usage: Lofi12XT_Map.py <unpack_dir> OR Lofi12XT_Map.py vtables <csv>")
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Offline helper (runs HERE, stdlib-only): cluster vtable candidates.
|
||||
|
||||
A vtable = run of >=3 consecutive LE32 words in rodata, each pointing
|
||||
into the code sect. Output CSV is consumed by the Ghidra-side script.
|
||||
|
||||
Usage:
|
||||
python3 ghidra/gen_vtable_csv.py "Lofi-12XT_v1.5.205/.../Lofi-12 XT.bin" /tmp/vtables-1.5.205.csv
|
||||
"""
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'tools'))
|
||||
from lofi_image import parse_image, find_sect_by_role
|
||||
|
||||
|
||||
def main():
|
||||
image, out = sys.argv[1], sys.argv[2]
|
||||
d = open(image, 'rb').read()
|
||||
info = parse_image(d)
|
||||
code = find_sect_by_role(info, 'code')
|
||||
ro = find_sect_by_role(info, 'rodata')
|
||||
print("code sect%d %08X..%08X" % (code['index'], code['addr'], code['end']))
|
||||
print("rodata sect%d %08X..%08X" % (ro['index'], ro['addr'], ro['end']))
|
||||
|
||||
p = ro['payload']
|
||||
words = [struct.unpack('<I', p[i:i + 4])[0]
|
||||
for i in range(0, len(p) - 3, 4)]
|
||||
is_code_ptr = [code['addr'] <= w < code['end'] for w in words]
|
||||
|
||||
runs = []
|
||||
i = 0
|
||||
n = len(words)
|
||||
while i < n:
|
||||
if is_code_ptr[i]:
|
||||
j = i
|
||||
while j < n and is_code_ptr[j]:
|
||||
j += 1
|
||||
if j - i >= 3:
|
||||
runs.append((i * 4, j - i, words[i:j]))
|
||||
i = j
|
||||
else:
|
||||
i += 1
|
||||
|
||||
with open(out, 'w') as f:
|
||||
f.write("rodata_off,load_addr,nentries,entries\n")
|
||||
for off, cnt, ws in runs:
|
||||
f.write("%d,%08X,%d,%s\n"
|
||||
% (off, ro['addr'] + off, cnt,
|
||||
";".join("%08X" % w for w in ws)))
|
||||
to_code = sum(is_code_ptr)
|
||||
print("rodata LE words -> code: %d, vtable runs(>=3): %d -> %s"
|
||||
% (to_code, len(runs), out))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,104 @@
|
||||
import ghidra.app.decompiler.DecompInterface;
|
||||
import ghidra.app.decompiler.DecompileResults;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.listing.InstructionIterator;
|
||||
import ghidra.program.model.listing.Listing;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* DumpAIS.java — Ghidra headless postScript. Decompiles + disassembles
|
||||
* checksum-hunt targets into /tmp/opencode/ghidra-lab/out/.
|
||||
*/
|
||||
public class DumpAIS extends GhidraScript {
|
||||
|
||||
static final String OUT = "/tmp/opencode/ghidra-lab/out";
|
||||
static final String[] TARGETS = {
|
||||
"C70A0A60", "C708E4E4", "C7086400", "C70A28A0", "C707841C"
|
||||
};
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
new java.io.File(OUT).mkdirs();
|
||||
AddressSpace space = currentProgram.getAddressFactory()
|
||||
.getDefaultAddressSpace();
|
||||
Listing listing = currentProgram.getListing();
|
||||
DecompInterface iface = new DecompInterface();
|
||||
iface.openProgram(currentProgram);
|
||||
|
||||
for (String t : TARGETS) {
|
||||
Address addr = space.getAddress(t);
|
||||
Function fn = getFunctionAt(addr);
|
||||
if (fn == null) {
|
||||
try {
|
||||
disassemble(addr);
|
||||
}
|
||||
catch (Exception e) {
|
||||
println("[DumpAIS] " + t + " disassemble: " + e);
|
||||
}
|
||||
try {
|
||||
fn = createFunction(addr, "sub_" + t);
|
||||
}
|
||||
catch (Exception e) {
|
||||
println("[DumpAIS] " + t + " createFunction: " + e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
println("[DumpAIS] " + t + " fn=" + fn.getName());
|
||||
}
|
||||
// disassembly window: 64B back, ~120 insns forward
|
||||
try {
|
||||
Address start = addr.addNoWrap(-64);
|
||||
InstructionIterator it = listing.getInstructions(start, true);
|
||||
PrintWriter pw = new PrintWriter(new FileWriter(
|
||||
OUT + "/dis_" + t + ".txt"));
|
||||
int n = 0;
|
||||
while (it.hasNext() && n < 150) {
|
||||
Instruction ins = it.next();
|
||||
pw.println(String.format("%08X %s %s",
|
||||
ins.getAddress().getOffset(),
|
||||
ins.getMnemonicString(), ins.toString()));
|
||||
n++;
|
||||
if (ins.getAddress().compareTo(addr) > 0
|
||||
&& n > 100) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pw.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
println("[DumpAIS] " + t + " disasm dump: " + e);
|
||||
}
|
||||
if (fn != null) {
|
||||
try {
|
||||
DecompileResults res = iface.decompileFunction(
|
||||
fn, 120, getMonitor());
|
||||
String c = (res != null
|
||||
&& res.getDecompiledFunction() != null)
|
||||
? res.getDecompiledFunction().getC()
|
||||
: "DECOMPILE_NULL";
|
||||
PrintWriter pw = new PrintWriter(new FileWriter(
|
||||
OUT + "/dec_" + t + ".txt"));
|
||||
pw.print(c);
|
||||
pw.close();
|
||||
println("[DumpAIS] " + t + " decompiled "
|
||||
+ (c == null ? 0 : c.length()) + " chars");
|
||||
}
|
||||
catch (Exception e) {
|
||||
println("[DumpAIS] " + t + " decompile: " + e);
|
||||
PrintWriter pw = new PrintWriter(new FileWriter(
|
||||
OUT + "/dec_" + t + ".txt"));
|
||||
pw.print("DECOMPILE_ERROR: " + e);
|
||||
pw.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
iface.dispose();
|
||||
println("[DumpAIS] done -> " + OUT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* MapAIS.java — Ghidra headless preScript. Creates one memory block per
|
||||
* AIS section of ic300_1.bin at its DDR load address, marks the AIS
|
||||
* entry point. Paths are hardcoded (see tools/ais_unpack.py output).
|
||||
*/
|
||||
public class MapAIS extends GhidraScript {
|
||||
|
||||
static final String UNPACK = "/tmp/ais-unpack";
|
||||
// {name, addrHex, len, file}
|
||||
static final String[][] SEGS = {
|
||||
{"ais0", "C7074630", "464", "ais_sect0_addrC7074630.bin"},
|
||||
{"ais1", "C7074800", "211712", "ais_sect1_addrC7074800.bin"},
|
||||
{"ais2", "C70A8300", "10444", "ais_sect2_addrC70A8300.bin"},
|
||||
{"ais3", "C70AABD0", "12", "ais_sect3_addrC70AABD0.bin"},
|
||||
{"ais4", "C70AABE0", "12", "ais_sect4_addrC70AABE0.bin"},
|
||||
{"ais5", "C70AABF0", "3396", "ais_sect5_addrC70AABF0.bin"},
|
||||
{"ais6", "C70AF000", "512", "ais_sect6_addrC70AF000.bin"},
|
||||
{"ais7", "C70AF4E8", "260", "ais_sect7_addrC70AF4E8.bin"},
|
||||
{"ais8", "C70AF5EC", "112", "ais_sect8_addrC70AF5EC.bin"},
|
||||
{"ais9", "C70AF660", "3896", "ais_sect9_addrC70AF660.bin"},
|
||||
};
|
||||
static final String ENTRY = "C70A28A0";
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
AddressSpace space = currentProgram.getAddressFactory()
|
||||
.getDefaultAddressSpace();
|
||||
Memory mem = currentProgram.getMemory();
|
||||
for (String[] s : SEGS) {
|
||||
Address addr = space.getAddress(s[1]);
|
||||
if (mem.getBlock(addr) != null) {
|
||||
println("[MapAIS] " + s[0] + " already mapped, skip");
|
||||
continue;
|
||||
}
|
||||
File f = new File(UNPACK + "/" + s[3]);
|
||||
long len = Long.parseLong(s[2]);
|
||||
try {
|
||||
mem.createInitializedBlock(s[0], addr, f, len,
|
||||
"ais_unpack", "", false);
|
||||
MemoryBlock blk = mem.getBlock(addr);
|
||||
blk.setRead(true);
|
||||
blk.setWrite(false);
|
||||
blk.setExecute(true);
|
||||
println("[MapAIS] mapped " + s[0] + " " + s[1]
|
||||
+ " len=" + len);
|
||||
}
|
||||
catch (Exception e) {
|
||||
println("[MapAIS] FAILED " + s[0] + ": " + e);
|
||||
}
|
||||
}
|
||||
Address entry = space.getAddress(ENTRY);
|
||||
currentProgram.getSymbolTable().addExternalEntryPoint(entry);
|
||||
createLabel(entry, "ais_entry", true, SourceType.IMPORTED);
|
||||
disassemble(entry);
|
||||
createFunction(entry, "ais_entry");
|
||||
println("[MapAIS] entry " + ENTRY + " marked");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# Headless Ghidra drivers (C6000 AIS analysis)
|
||||
|
||||
These drove the checksum extraction in `RE-PROCESS.md`. They need a local lab
|
||||
that is **not** in this repo (too big, machine-specific):
|
||||
|
||||
- Temurin JDK 21, Ghidra 12.1.3, [geepot/ghidra-c6000](https://github.com/geepot/ghidra-c6000)
|
||||
release built for that exact Ghidra version (`C6000:LE:32:default`).
|
||||
- `pip install pyghidra` (project venv), `GHIDRA_INSTALL_DIR` + `JAVA_HOME` set.
|
||||
|
||||
Files:
|
||||
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| `MapAIS.java` / `DumpAIS.java` | Reference only — Ghidra **12 headless cannot run `.java`
|
||||
outside an OSGi bundle** here (not even the extension's own scripts); kept for GUI use |
|
||||
| `pyais.py` | The working driver: map AIS sections at DDR bases → analyze → decompile
|
||||
targets (`C70A0A60`, `C708E4E4`, `C7086400`, entry, CRC-16) into `out/` |
|
||||
| `pyais4.py` | Dense disassembly seeding + full-range listing dumps |
|
||||
| `pyais5.py` | Batch create-function + decompile for a target list |
|
||||
|
||||
Prepare segments with `../tools/ais_unpack.py ic300.bin /tmp/ais-unpack`
|
||||
(IC300 dump stays local — never commit it), then adapt the hardcoded paths at
|
||||
the top of `pyais.py` to your machine.
|
||||
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
"""PyGhidra driver: map AIS sections, analyze, decompile checksum targets.
|
||||
|
||||
Runs with the project venv (has pyghidra): ./venv/bin/python /tmp/opencode/ghidra-lab/pyais.py
|
||||
Env: GHIDRA_INSTALL_DIR + JAVA_HOME must be set (see launch command).
|
||||
Writes /tmp/opencode/ghidra-lab/out/{dis,dec}_<ADDR>.txt
|
||||
Stdlib + pyghidra + jpype only.
|
||||
"""
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
||||
UNPACK = "/tmp/ais-unpack"
|
||||
OUT = "/tmp/opencode/ghidra-lab/out"
|
||||
SECT_IMAGE = "/tmp/ais-unpack/ais_sect1_addrC7074800.bin"
|
||||
PROJ_LOC = "/tmp/opencode/ghidra-lab/pyproj"
|
||||
PROJ_NAME = "LofiPy"
|
||||
LANG = "C6000:LE:32:default"
|
||||
ENTRY = "C70A28A0"
|
||||
TARGETS = ["C70A0A60", "C708E4E4", "C7086400", "C70A28A0", "C707841C"]
|
||||
|
||||
|
||||
def parse_ais(path):
|
||||
d = open(path, "rb").read()
|
||||
assert d[:4] == b"TIPA", "bad AIS magic"
|
||||
segs, i, n = [], 4, len(d)
|
||||
entry = None
|
||||
while i + 12 <= n:
|
||||
op = d[i:i + 4]
|
||||
if op == bytes([0x01, 0x59, 0x53, 0x58]):
|
||||
addr, sz = struct.unpack("<II", d[i + 4:i + 12])
|
||||
segs.append((addr, d[i + 12:i + 12 + sz]))
|
||||
i += 12 + sz
|
||||
elif op == bytes([0x06, 0x59, 0x53, 0x58]):
|
||||
entry = struct.unpack("<I", d[i + 4:i + 8])[0]
|
||||
break
|
||||
else:
|
||||
i += 4
|
||||
return segs, entry
|
||||
|
||||
|
||||
def main():
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
import jpype
|
||||
import pyghidra
|
||||
|
||||
segs, entry = parse_ais("/var/home/dejvino/Downloads/Lofi-12XT/ic300.bin")
|
||||
print("segs=%d entry=%08X" % (len(segs), entry), flush=True)
|
||||
|
||||
pyghidra.start()
|
||||
with pyghidra.open_program(
|
||||
SECT_IMAGE,
|
||||
project_location=PROJ_LOC,
|
||||
project_name=PROJ_NAME,
|
||||
analyze=False,
|
||||
language=LANG,
|
||||
) as flat:
|
||||
program = flat.getCurrentProgram()
|
||||
print("program=" + program.getName()
|
||||
+ " lang=" + program.getLanguageID().toString(), flush=True)
|
||||
JByte = jpype.JArray(jpype.JByte)
|
||||
try:
|
||||
from java.io import ByteArrayInputStream
|
||||
except ImportError:
|
||||
import jpype.imports # noqa
|
||||
from java.io import ByteArrayInputStream
|
||||
from ghidra.util.task import TaskMonitor
|
||||
from ghidra.program.model.symbol import SourceType
|
||||
|
||||
# 1. map blocks at DDR addresses
|
||||
with pyghidra.transaction(program, "map AIS"):
|
||||
mem = program.getMemory()
|
||||
for idx, (addr_int, blob) in enumerate(segs):
|
||||
addr = flat.toAddr("0x%08X" % addr_int)
|
||||
if mem.getBlock(addr) is not None:
|
||||
print("ais%d already mapped" % idx, flush=True)
|
||||
continue
|
||||
stream = ByteArrayInputStream(JByte(bytes(blob)))
|
||||
blk = mem.createInitializedBlock(
|
||||
"ais%d" % idx, addr, stream, len(blob),
|
||||
TaskMonitor.DUMMY, False)
|
||||
blk.setRead(True)
|
||||
blk.setWrite(False)
|
||||
blk.setExecute(True)
|
||||
print("mapped ais%d %08X len=%d"
|
||||
% (idx, addr_int, len(blob)), flush=True)
|
||||
# 2. entry + analyze
|
||||
with pyghidra.transaction(program, "entry"):
|
||||
eaddr = flat.toAddr("0x" + ENTRY)
|
||||
try:
|
||||
program.getSymbolTable().addExternalEntryPoint(eaddr)
|
||||
except Exception as e:
|
||||
print("entry point: " + str(e), flush=True)
|
||||
flat.disassemble(eaddr)
|
||||
if flat.getFunctionAt(eaddr) is None:
|
||||
flat.createFunction(eaddr, "ais_entry")
|
||||
print("analyzing...", flush=True)
|
||||
flat.analyzeAll(program)
|
||||
print("analysis done", flush=True)
|
||||
# 3. decompile + disassembly dump per target
|
||||
from ghidra.app.decompiler.flatapi import FlatDecompilerAPI
|
||||
|
||||
dapi = FlatDecompilerAPI(flat)
|
||||
try:
|
||||
for t in TARGETS:
|
||||
addr = flat.toAddr("0x" + t)
|
||||
try:
|
||||
fn = flat.getFunctionAt(addr)
|
||||
if fn is None:
|
||||
flat.disassemble(addr)
|
||||
try:
|
||||
fn = flat.createFunction(addr, "sub_" + t)
|
||||
except Exception as e:
|
||||
print(t + " createFunction: " + str(e),
|
||||
flush=True)
|
||||
# disassembly window
|
||||
try:
|
||||
start = flat.toAddr("0x%08X"
|
||||
% (int(t, 16) - 64))
|
||||
it = program.getListing().getInstructions(start,
|
||||
True)
|
||||
lines, n = [], 0
|
||||
while it.hasNext() and n < 150:
|
||||
ins = it.next()
|
||||
lines.append("%08X %s %s" % (
|
||||
ins.getAddress().getOffset(),
|
||||
ins.getMnemonicString(), ins.toString()))
|
||||
n += 1
|
||||
open(os.path.join(OUT, "dis_" + t + ".txt"),
|
||||
"w").write("\n".join(lines) + "\n")
|
||||
except Exception as e:
|
||||
print(t + " disasm: " + str(e), flush=True)
|
||||
# decompile
|
||||
if fn is not None:
|
||||
try:
|
||||
c = dapi.decompile(fn)
|
||||
if not c:
|
||||
c = "DECOMPILE_NULL"
|
||||
open(os.path.join(OUT, "dec_" + t + ".txt"),
|
||||
"w").write(c if c else "DECOMPILE_NULL")
|
||||
print(t + " decompiled %d chars"
|
||||
% (len(c) if c else 0), flush=True)
|
||||
except Exception as e:
|
||||
print(t + " decompile: " + str(e), flush=True)
|
||||
open(os.path.join(OUT, "dec_" + t + ".txt"),
|
||||
"w").write("DECOMPILE_ERROR: " + str(e))
|
||||
except Exception as e:
|
||||
print(t + " FAILED: " + str(e), flush=True)
|
||||
finally:
|
||||
dapi.dispose()
|
||||
print("ALL_DONE -> " + OUT, flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""PyGhidra pass 4: dense disassembly seeding + full-range listing dumps.
|
||||
|
||||
Reuses /tmp/opencode/ghidra-lab/pyproj/LofiPy.
|
||||
Writes /tmp/opencode/ghidra-lab/out/gfull_<name>.txt
|
||||
"""
|
||||
import os
|
||||
|
||||
OUT = "/tmp/opencode/ghidra-lab/out"
|
||||
PROJ_LOC = "/tmp/opencode/ghidra-lab/pyproj/LofiPy"
|
||||
PROJ_NAME = "LofiPy"
|
||||
PROG = "/ais_sect1_addrC7074800.bin"
|
||||
RANGES = {
|
||||
"eloop": ("C708E400", 0x400),
|
||||
"callers2": ("C709E700", 0x500),
|
||||
"orch": ("C7086300", 0x900),
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
import pyghidra
|
||||
|
||||
pyghidra.start()
|
||||
with pyghidra.open_project(PROJ_LOC, PROJ_NAME) as project:
|
||||
with pyghidra.program_context(project, PROG) as program:
|
||||
from ghidra.program.flatapi import FlatProgramAPI
|
||||
|
||||
flat = FlatProgramAPI(program)
|
||||
with pyghidra.transaction(program, "seed"):
|
||||
for name, (t, size) in RANGES.items():
|
||||
base = int(t, 16)
|
||||
n = 0
|
||||
a = base
|
||||
while a < base + size:
|
||||
try:
|
||||
flat.disassemble(flat.toAddr("0x%08X" % a))
|
||||
n += 1
|
||||
except Exception:
|
||||
pass
|
||||
a += 8
|
||||
print("%s seeded %d" % (name, n), flush=True)
|
||||
for name, (t, size) in RANGES.items():
|
||||
try:
|
||||
base = int(t, 16)
|
||||
it = program.getListing().getInstructions(
|
||||
flat.toAddr("0x%08X" % base), True)
|
||||
lines = []
|
||||
while it.hasNext():
|
||||
ins = it.next()
|
||||
off = ins.getAddress().getOffset()
|
||||
if off >= base + size:
|
||||
break
|
||||
lines.append("%08X %s %s" % (
|
||||
off, ins.getMnemonicString(), ins.toString()))
|
||||
if len(lines) > 4000:
|
||||
break
|
||||
open(os.path.join(OUT, "gfull_" + name + ".txt"),
|
||||
"w").write("\n".join(lines) + "\n")
|
||||
print("%s: %d insns" % (name, len(lines)), flush=True)
|
||||
except Exception as e:
|
||||
print(name + " FAILED: " + str(e)[:200], flush=True)
|
||||
print("GFULL_DONE", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python3
|
||||
"""PyGhidra pass 5: create + decompile check/orchestrator functions.
|
||||
|
||||
Reuses /tmp/opencode/ghidra-lab/pyproj/LofiPy.
|
||||
Writes /tmp/opencode/ghidra-lab/out/fn_<ADDR>.c.txt
|
||||
"""
|
||||
import os
|
||||
|
||||
OUT = "/tmp/opencode/ghidra-lab/out"
|
||||
PROJ_LOC = "/tmp/opencode/ghidra-lab/pyproj/LofiPy"
|
||||
PROJ_NAME = "LofiPy"
|
||||
PROG = "/ais_sect1_addrC7074800.bin"
|
||||
FNS = ["C709E7C0", "C7086788", "C708E4A4", "C708E790", "C708E860",
|
||||
"C709E888", "C708E468", "C709E990"]
|
||||
|
||||
|
||||
def main():
|
||||
import pyghidra
|
||||
|
||||
pyghidra.start()
|
||||
with pyghidra.open_project(PROJ_LOC, PROJ_NAME) as project:
|
||||
with pyghidra.program_context(project, PROG) as program:
|
||||
from ghidra.program.flatapi import FlatProgramAPI
|
||||
from ghidra.app.decompiler.flatapi import FlatDecompilerAPI
|
||||
|
||||
flat = FlatProgramAPI(program)
|
||||
with pyghidra.transaction(program, "mkfn2"):
|
||||
for t in FNS:
|
||||
a = flat.toAddr("0x" + t)
|
||||
try:
|
||||
flat.disassemble(a)
|
||||
except Exception as e:
|
||||
print(t + " dis: " + str(e)[:100], flush=True)
|
||||
try:
|
||||
if flat.getFunctionAt(a) is None:
|
||||
flat.createFunction(a, "fn_" + t)
|
||||
print(t + " fn created", flush=True)
|
||||
except Exception as e:
|
||||
print(t + " mkfn: " + str(e)[:150], flush=True)
|
||||
dapi = FlatDecompilerAPI(flat)
|
||||
try:
|
||||
for t in FNS:
|
||||
try:
|
||||
fn = flat.getFunctionAt(flat.toAddr("0x" + t))
|
||||
if fn is None:
|
||||
print(t + " no fn", flush=True)
|
||||
continue
|
||||
c = dapi.decompile(fn)
|
||||
open(os.path.join(OUT, "fn_" + t + ".c.txt"),
|
||||
"w").write(c if c else "DECOMPILE_NULL")
|
||||
print(t + " %d chars" % (len(c) if c else 0),
|
||||
flush=True)
|
||||
except Exception as e:
|
||||
print(t + " dec: " + str(e)[:200], flush=True)
|
||||
finally:
|
||||
dapi.dispose()
|
||||
print("FN_DONE", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user