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();
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<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);
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<T> 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<String> dict
final List<String> 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<String> dict
final List<String> 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<String> dict
final List<String> 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";
}