diff --git a/ghidra/ghidra_scripts/MSVC7Mangle.java b/ghidra/ghidra_scripts/MSVC7Mangle.java new file mode 100644 index 0000000..be76e65 --- /dev/null +++ b/ghidra/ghidra_scripts/MSVC7Mangle.java @@ -0,0 +1,111 @@ +// 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 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 + "@"; + } + } +}