Ported from sacredK with module-relative addresses, hooks by exported name and a SHA-256 check of the six game modules (Community Patch 2.65.1). Borderless windowed at monitor size replaces exclusive fullscreen, whose focus loss during loading made the game quit and crash on exit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
87 lines
3.5 KiB
Java
87 lines
3.5 KiB
Java
// Apply function names from tools/names.txt to the persistent Ghidra project
|
|
// (run on every program; each line names its module).
|
|
//
|
|
// Headless usage (see tools/rename.ps1):
|
|
// analyzeHeadless <projectDir> sacred2 -process -noanalysis
|
|
// -scriptPath tools/ghidra -postScript Rename.java <namesFile>
|
|
//
|
|
// names.txt: one "module 0xADDRESS Name" per line (module as the program
|
|
// name, e.g. s2logic.dll; the address at its preferred base), "Class::Method" puts the function
|
|
// into a class namespace; "#" starts a comment. Functions are created where
|
|
// none starts at the address yet. Names starting with "g_" label data
|
|
// (globals, tables) instead of functions.
|
|
// @category sacred2K
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
|
|
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
|
import ghidra.app.script.GhidraScript;
|
|
import ghidra.program.model.address.Address;
|
|
import ghidra.program.model.listing.Function;
|
|
import ghidra.program.model.symbol.Namespace;
|
|
import ghidra.program.model.symbol.SourceType;
|
|
import ghidra.program.model.symbol.SymbolTable;
|
|
|
|
public class Rename extends GhidraScript {
|
|
|
|
@Override
|
|
protected void run() throws Exception {
|
|
String[] args = getScriptArgs();
|
|
if (args.length != 1) {
|
|
printerr("usage: Rename.java <namesFile>");
|
|
return;
|
|
}
|
|
SymbolTable symbols = currentProgram.getSymbolTable();
|
|
int renamed = 0;
|
|
int labelled = 0;
|
|
for (String raw : Files.readAllLines(Paths.get(args[0]), StandardCharsets.UTF_8)) {
|
|
String line = raw.replaceAll("#.*", "").trim();
|
|
if (line.isEmpty()) {
|
|
continue;
|
|
}
|
|
String[] parts = line.split("\\s+");
|
|
if (parts.length != 3) {
|
|
printerr("bad line: " + raw);
|
|
continue;
|
|
}
|
|
if (!parts[0].equalsIgnoreCase(currentProgram.getName())) {
|
|
continue;
|
|
}
|
|
parts = new String[] {parts[1], parts[2]};
|
|
Address address = toAddr(parts[0]);
|
|
if (parts[1].startsWith("g_")) {
|
|
createLabel(address, parts[1], true, SourceType.USER_DEFINED);
|
|
labelled++;
|
|
continue;
|
|
}
|
|
Function function = getFunctionAt(address);
|
|
if (function == null) {
|
|
new DisassembleCommand(address, null, true).applyTo(currentProgram, monitor);
|
|
function = createFunction(address, null);
|
|
}
|
|
if (function == null) {
|
|
printerr("no function at " + parts[0]);
|
|
continue;
|
|
}
|
|
String name = parts[1];
|
|
Namespace namespace = currentProgram.getGlobalNamespace();
|
|
int separator = name.lastIndexOf("::");
|
|
if (separator >= 0) {
|
|
String className = name.substring(0, separator);
|
|
name = name.substring(separator + 2);
|
|
namespace = symbols.getNamespace(className, currentProgram.getGlobalNamespace());
|
|
if (namespace == null) {
|
|
namespace = symbols.createClass(currentProgram.getGlobalNamespace(), className,
|
|
SourceType.USER_DEFINED);
|
|
}
|
|
}
|
|
function.setParentNamespace(namespace);
|
|
function.setName(name, SourceType.USER_DEFINED);
|
|
renamed++;
|
|
}
|
|
println(currentProgram.getName() + ": renamed " + renamed + " functions, labelled " + labelled + " data addresses");
|
|
}
|
|
}
|