mirror of
https://codeberg.org/KeybadeBlox/JSRF-Decompilation.git
synced 2026-02-20 02:07:02 +03:00
Add class fixup Ghidra script
This commit is contained in:
parent
adc30bb531
commit
e0313fa0ba
1 changed files with 106 additions and 0 deletions
106
ghidra/ghidra_scripts/ClassFixup.java
Normal file
106
ghidra/ghidra_scripts/ClassFixup.java
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Creates classes out namespaces with matching structs, and if they have a
|
||||
// vtable, sets the calling convention of the contained function typdefs to
|
||||
// __thiscall.
|
||||
//
|
||||
// For vtables to be found, they must be defined as structs with names ending
|
||||
// in "Vtbl" and be pointed to by the first member of a class struct.
|
||||
//
|
||||
// @category Data Types
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.DataTypeComponent;
|
||||
import ghidra.program.model.data.FunctionDefinition;
|
||||
import ghidra.program.model.data.Pointer;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.listing.GhidraClass;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
|
||||
|
||||
public class ClassFixup extends GhidraScript {
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
fixInNamespace(currentProgram.getGlobalNamespace());
|
||||
}
|
||||
|
||||
private void fixInNamespace(final Namespace parent) throws Exception {
|
||||
for (final Symbol s : currentProgram.getSymbolTable()
|
||||
.getChildren(parent.getSymbol()))
|
||||
if (s.getObject() instanceof Namespace ns) switch (ns.getType()) {
|
||||
case Namespace.Type.NAMESPACE:
|
||||
if (shouldBeClass(ns)) {
|
||||
println("Converting \"" + ns.getName(true) + "\" to class...");
|
||||
NamespaceUtils.convertNamespaceToClass(ns);
|
||||
|
||||
// Re-fetch namespace to get its new class version
|
||||
ns = getNamespace(parent, ns.getName());
|
||||
} else {
|
||||
fixInNamespace(ns);
|
||||
break;
|
||||
}
|
||||
case Namespace.Type.CLASS: // fallthrough
|
||||
// Any ns that makes it here should be a class
|
||||
// (can't bind via pattern match because of the
|
||||
// fallthrough)
|
||||
final GhidraClass cls = (GhidraClass)ns;
|
||||
|
||||
// Fix up methods if first member is a vtable
|
||||
if (
|
||||
DataTypeUtilities.findExistingClassStruct(
|
||||
currentProgram.getDataTypeManager(),
|
||||
cls
|
||||
) instanceof Structure struct &&
|
||||
struct.getDataTypeAt(0) instanceof DataTypeComponent memberType &&
|
||||
memberType.getDataType() instanceof Pointer ptrType &&
|
||||
ptrType .getDataType() instanceof Structure vtblT_maybe &&
|
||||
vtblT_maybe.getName().endsWith("Vtbl")
|
||||
) fixMethods(vtblT_maybe);
|
||||
break;
|
||||
|
||||
default: continue;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldBeClass(final Namespace ns) throws Exception {
|
||||
/* Determine if a namespace should be converted to a class
|
||||
The heuristic is whether Ghidra can find a struct that it would be
|
||||
linked with if it was a class. The process to do so is admittedly a
|
||||
bit byzantine.
|
||||
*/
|
||||
// Change name so the dummy class won't have a conflict
|
||||
final String name = ns.getName();
|
||||
ns.getSymbol()
|
||||
.setName("__" + ns.getName(), ns.getSymbol().getSource());
|
||||
|
||||
// Create a dummy class to check for a matching struct without
|
||||
// converting the namespace (as classes can't be reverted)
|
||||
final GhidraClass cls = createClass(ns.getParentNamespace(), name);
|
||||
|
||||
// Record whether Ghidra could find a matching struct
|
||||
final boolean ret = DataTypeUtilities.findExistingClassStruct(
|
||||
currentProgram.getDataTypeManager(),
|
||||
cls
|
||||
) != null;
|
||||
|
||||
// Clean up
|
||||
cls.getSymbol().delete();
|
||||
ns.getSymbol().setName(name, ns.getSymbol().getSource());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void fixMethods(final Structure vtbl) throws Exception {
|
||||
/* Set all the calling conventions in a vtable to __thiscall */
|
||||
for (final DataTypeComponent member : vtbl.getComponents())
|
||||
if (
|
||||
member.getDataType() instanceof Pointer ptr &&
|
||||
ptr .getDataType() instanceof FunctionDefinition method &&
|
||||
!method.getCallingConventionName().equals("__thiscall")
|
||||
) {
|
||||
println("Fixing calling convention of \"" + method.getDataTypePath().toString() + "\"...");
|
||||
method.setCallingConvention("__thiscall");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue