mirror of
https://codeberg.org/KeybadeBlox/JSRF-Decompilation.git
synced 2026-02-20 02:07:02 +03:00
Looks like we'll be writing our own Ghidra scripts. At least these should enable pretty thorough sharing of work and decent UX.
111 lines
3.3 KiB
Java
111 lines
3.3 KiB
Java
// Applies Visual C++ 7.0 name mangling to the symbols within the selected
|
|
// address range (or the whole program if nothing is selected).
|
|
//
|
|
// Be aware that the mangling implementation is only partial.
|
|
//
|
|
// @category Symbol
|
|
|
|
import ghidra.app.script.GhidraScript;
|
|
import ghidra.program.model.listing.Data;
|
|
import ghidra.program.model.listing.Function;
|
|
import ghidra.program.model.data.DataType;
|
|
import ghidra.program.model.data.Enum;
|
|
import ghidra.program.model.data.IntegerDataType;
|
|
import ghidra.program.model.data.VoidDataType;
|
|
import ghidra.program.model.symbol.Reference;
|
|
import ghidra.program.model.symbol.SourceType;
|
|
import ghidra.program.model.symbol.Symbol;
|
|
import ghidra.program.model.symbol.SymbolIterator;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
|
|
public class MSVC7Mangle extends GhidraScript{
|
|
@Override
|
|
public void run() throws Exception {
|
|
final SymbolIterator iter = currentProgram.getSymbolTable()
|
|
.getPrimarySymbolIterator(currentSelection, true);
|
|
|
|
while (iter.hasNext() && !monitor.isCancelled()) {
|
|
final Symbol s = iter.next();
|
|
|
|
switch (s.getObject()) {
|
|
case Function f -> demangleFn(f);
|
|
case Data d -> demangleData(s);
|
|
default -> {}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void demangleFn(final Function f) throws Exception {
|
|
// Gather everything needed for mangling
|
|
final List<String> name = Arrays.asList(f.getName(true)
|
|
.split("::"));
|
|
Collections.reverse(name);
|
|
final String callc = f.getCallingConventionName();
|
|
final DataType ret = f.getReturnType();
|
|
final DataType[] args = Arrays.stream(f.getSignature(true)
|
|
.getArguments())
|
|
.map(x -> x.getDataType())
|
|
.toArray(DataType[]::new);
|
|
|
|
// Construct mangled name
|
|
final String mangled =
|
|
"?" + String.join("@", name) + "@@" +
|
|
switch (callc) {
|
|
case "__cdecl" -> "YA";
|
|
case "__thiscall" -> isVirtual(f) ? "UAE" :
|
|
"QAE";
|
|
case "__fastcall" -> ""; // TODO
|
|
default -> throw new Exception(
|
|
"Need to specify calling convention"
|
|
);
|
|
} +
|
|
mangleType(ret) +
|
|
mangleArgs(args) +
|
|
"Z";
|
|
|
|
f.setName(mangled, SourceType.USER_DEFINED);
|
|
}
|
|
|
|
private void demangleData(final Symbol s) {
|
|
// TODO
|
|
printf("TODO: data symbol \"%s\"\n", s.getName(true));
|
|
}
|
|
|
|
private boolean isVirtual(final Function f) {
|
|
/* Attempt to determine whether a method is virtual
|
|
We essentially try to figure out if any references are from a vtable.
|
|
*/
|
|
final Reference[] refs = getReferencesTo(f.getEntryPoint());
|
|
|
|
// TODO
|
|
|
|
return false;
|
|
}
|
|
|
|
private String mangleType(final DataType t) throws Exception {
|
|
/* Mangle a data type in a function name */
|
|
return switch(t) {
|
|
case Enum e -> "W4" + e.getName() + "@@";
|
|
case IntegerDataType x -> "H";
|
|
case VoidDataType x -> "X";
|
|
default -> throw new Exception(
|
|
"Unhandled data type \"" + t.toString() + "\""
|
|
);
|
|
};
|
|
}
|
|
|
|
private String mangleArgs(final DataType[] args) throws Exception {
|
|
/* Mangle the arguments for a function */
|
|
if (args.length == 0) return "X";
|
|
else {
|
|
String encoded = "";
|
|
for (int i = 0; i < args.length; i++)
|
|
encoded += mangleType(args[i]);
|
|
return encoded + "@";
|
|
}
|
|
}
|
|
}
|