diff --git a/ghidra/ghidra_scripts/MSVC7Mangle.java b/ghidra/ghidra_scripts/MSVC7Mangle.java index 4657ef4..13e45b2 100644 --- a/ghidra/ghidra_scripts/MSVC7Mangle.java +++ b/ghidra/ghidra_scripts/MSVC7Mangle.java @@ -107,7 +107,10 @@ public class MSVC7Mangle extends GhidraScript{ final Reference[] refs = ins.getReferencesFrom(); for (int i = 0; i < refs.length; i++) { final Symbol symbol = getSymbolAt(refs[i].getToAddress()); - if (symbol != null) mangle(symbol); + if ( // Guard against spurious references to nonexisting things + symbol != null && + symbol.getObject() != null + ) mangle(symbol); } } } @@ -116,13 +119,17 @@ public class MSVC7Mangle extends GhidraScript{ private void mangle(final Symbol s) throws Exception { /* Set the given symbol's name to its mangled version */ - // Skip if already mangled - if (s.getName().charAt(0) == '?') return; + // Skip if already mangled; skip jump tables + final String name = s.getName(true); + if ( + name.charAt(0) == '?' || + name.startsWith("switchD_") + ) return; // Get mangled name final String mangled = switch (s.getObject()) { case Function f -> mangleFn (f); - case Data d -> mangleData(d, s.getName(true)); + case Data d -> mangleData(d, name); default -> null; }; @@ -145,17 +152,21 @@ public class MSVC7Mangle extends GhidraScript{ private String mangleFn(final Function f) throws Exception { /* Generate a mangled name for a function */ - // Special cases for main() - if (f.getName(true).equals("main" )) return "_main"; - if (f.getName(true).equals("___CxxFrameHandler")) return "___CxxFrameHandler"; + final String nameRaw = f.getName(true); + + // Special case for main() + if (nameRaw.equals("main")) return "_main"; + + // Special symbols like intrinsics aren't mangled + if (nameRaw.startsWith("__")) return nameRaw; final ArrayList dict = new ArrayList<>(); - final List nameParts = Arrays.asList(f.getName(true).split("::")); + final List nameParts = Arrays.asList(nameRaw.split("::")); Collections.reverse(nameParts); final boolean isMethod = f.getCallingConventionName().equals("__thiscall") && nameParts.size() >= 2; - final String name = mangleIdentifier(f.getName(true), isMethod, f.getReturnType(), dict); + final String name = mangleIdentifier(nameRaw, isMethod, f.getReturnType(), dict); // Special methods with unique formats if (isMethod) { @@ -163,14 +174,16 @@ public class MSVC7Mangle extends GhidraScript{ final String clsName = nameParts.get(1); if (unqualified.equals( clsName)) { // Constructor - return "?" + name + "QAE@" + mangleArgs(f.getSignature(true), dict) + "Z"; + return "?" + name + "QAE@" + + mangleArgs(f.getSignature(true), dict, nameRaw + "()") + + "Z"; } else if (unqualified.equals("~" + clsName)) { // Destructor return "?" + name + (isVirtual(f) ? "UAE" : "QAE") + "@XZ"; } } return "?" + name + mangleFnAttrs(f, nameParts) + - mangleFnType(f.getSignature(true), dict); + mangleFnType(f.getSignature(true), dict, nameRaw + "()"); } private static String mangleIdentifier( @@ -272,7 +285,9 @@ public class MSVC7Mangle extends GhidraScript{ final List dict ) { /* Produce a backreference string if x is found in dict */ - switch (Integer.valueOf(dict.indexOf(x))) { + if (x instanceof String s && s.startsWith("?")) + return Optional.empty(); // No matching special names + else switch (Integer.valueOf(dict.indexOf(x))) { case -1: dict.add(x); return Optional.empty(); @@ -303,12 +318,15 @@ public class MSVC7Mangle extends GhidraScript{ final Function func = getFunctionContaining(refs[i].getFromAddress()); if (data != null) { - final String name = getSymbolAt(data.getRoot() - .getAddress()).getName(false); - if ( - name.equals("`vftable'") || - name.startsWith("??_7") - ) return true; + final Symbol s = getSymbolAt(data.getRoot() + .getAddress()); + if (s != null) { + final String name = s.getName(false); + if ( + name.equals("`vftable'") || + name.startsWith("??_7") + ) return true; + } } else if (func != null) { final String name = func.getName(false); if ( @@ -334,12 +352,13 @@ public class MSVC7Mangle extends GhidraScript{ private static String mangleFnType( final FunctionSignature f, - final List dict + final List dict, + final String loc ) throws Exception { /* Mangle everything in f but its name and visibility/linkage */ - - return mangleCallC(f) + mangleType(f.getReturnType(), dict) + - mangleArgs(f, dict) + "Z"; + return mangleCallC(f) + + mangleType(f.getReturnType(), dict, loc) + + mangleArgs(f, dict, loc) + "Z"; } private static String mangleCallC(final FunctionSignature f) throws Exception { @@ -358,15 +377,16 @@ public class MSVC7Mangle extends GhidraScript{ private static String mangleType( final DataType t, - final List dict + final List dict, + final String loc ) throws Exception { /* Mangle a data type in a function name All types are assumed to have no CV qualifiers. */ if (t == null) throw new Exception ( - "A data type was reported as null. Ensure that all " + - "data types in the code/data to mangle have been " + - "defined." + "A data type at " + loc + " was reported as null. " + + "Ensure that all data types in the code/data to " + + "mangle have been defined." ); return switch(t) { @@ -384,7 +404,7 @@ public class MSVC7Mangle extends GhidraScript{ case LongDoubleDataType _ -> "O"; case Pointer p -> "P" + (p.getDataType() instanceof FunctionSignature ? "6" : "A") + - mangleType(p.getDataType(), dict); + mangleType(p.getDataType(), dict, loc); case Union u -> "T" + mangleIdentifier(u.getName(), false, null, dict); case Structure s -> "U" + mangleIdentifier(s.getName(), false, null, dict); case Enum e -> "W4" + mangleIdentifier(e.getName(), false, null, dict); @@ -393,12 +413,12 @@ public class MSVC7Mangle extends GhidraScript{ case UnsignedLongLongDataType _ -> "_K"; case BooleanDataType _ -> "_N"; case WideCharDataType _ -> "_W"; - case Array a -> "PA" + mangleArrDims(a) + mangleType(arrType(a), dict); - case FunctionSignature f -> mangleFnType(f, dict); - case TypeDef d -> mangleType(d.getBaseDataType(), dict); - case DefaultDataType _ -> throw new Exception ("Encountered data marked \"undefined\". Ensure that all data types in the code/data to mangle have been defined."); - case Undefined _ -> throw new Exception ("Encountered data marked \"undefined\". Ensure that all data types in the code/data to mangle have been defined."); - default -> throw new Exception ("Unknown type \"" + t.getClass().getName() + "\""); + case Array a -> "PA" + mangleArrDims(a) + mangleType(arrType(a), dict, loc); + case FunctionSignature f -> mangleFnType(f, dict, "function typedef \"" + f.getName() + "\""); + case TypeDef d -> mangleType(d.getBaseDataType(), dict, "typedef \"" + d.getName() + "\""); + case DefaultDataType _ -> throw new Exception ("Encountered data marked \"undefined\" at " + loc + ". Ensure that all data types in the code/data to mangle have been defined."); + case Undefined _ -> throw new Exception ("Encountered data marked \"undefined\" at " + loc + ". Ensure that all data types in the code/data to mangle have been defined."); + default -> throw new Exception ("Unknown type \"" + t.getClass().getName() + "\" at " + loc); }; } @@ -446,7 +466,8 @@ public class MSVC7Mangle extends GhidraScript{ private static String mangleArgs( final FunctionSignature f, - final List dict + final List dict, + final String loc ) throws Exception { /* Mangle the arguments for a function */ final DataType[] args = Arrays.stream(f.getArguments()) @@ -469,10 +490,15 @@ public class MSVC7Mangle extends GhidraScript{ // It turns out that academic-sounding stuff everyone // freaks out at is actually useful (and Optional still // helped us out here) - String mangled = ""; - for (int i = 0; i < args.length; i++) - mangled += backref(args[i], argDict).orElse(mangleType(args[i], dict)); - return mangled + (f.hasVarArgs() ? "Z" : "@"); + String mangledArgs = ""; + for (int i = 0; i < args.length; i++) { + final String mangledArg = mangleType(args[i], dict, loc); + + mangledArgs += mangledArg.length() == 1 ? + mangledArg : + backref(args[i], argDict).orElse(mangledArg); + } + return mangledArgs + (f.hasVarArgs() ? "Z" : "@"); } } @@ -495,7 +521,8 @@ public class MSVC7Mangle extends GhidraScript{ // vtable if (ident.startsWith("?_7")) return "?" + ident + "6B@"; - return "?" + ident + "3" + mangleType(d.getDataType(), dict) + + return "?" + ident + "3" + + mangleType(d.getDataType(), dict, "0x" + d.getAddress().toString()) + "A"; }