Miscellaneous name mangling improvements

Improved error reporting, skipping undesirable symbols like jump tables,
skipping special symbols like intrinsics, etc.
This commit is contained in:
KeybadeBlox 2026-02-12 21:15:52 -05:00
parent 78127e64ef
commit d372c17094

View file

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