GP-1044 Fixed promotion of namespaces to only verified classes and added creation of typeinfo structs in stripped gcc binaries

This commit is contained in:
ghidra007
2021-06-16 14:59:01 -04:00
committed by ghidra1
parent cde02a91eb
commit 020df708e2
5 changed files with 503 additions and 191 deletions
@@ -163,6 +163,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
else if (isGcc()) { else if (isGcc()) {
boolean runGcc = askYesNo("GCC Class Recovery Still Under Development",
"I understand that gcc class recovery is still under development and my results will be incomplete but want to run this anyway.");
if (!runGcc) {
return;
}
nameVfunctions = true; nameVfunctions = true;
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation, recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation,
state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
@@ -545,25 +550,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return true; return true;
} }
//TODO: call this before create data in debug mode from script
private void findClassesWithErrors(List<RecoveredClass> recoveredClasses)
throws CancelledException {
Iterator<RecoveredClass> iterator = recoveredClasses.iterator();
while (iterator.hasNext()) {
monitor.checkCanceled();
RecoveredClass recoveredClass = iterator.next();
if (hasConstructorDestructorDiscrepancy(recoveredClass)) {
println(recoveredClass.getName() + " has function on both c and d lists");
}
}
}
/** /**
* Method to analyze the program changes with the decompiler parameter ID analyzer * Method to analyze the program changes with the decompiler parameter ID analyzer
* @param set the set of addresses to analyze * @param set the set of addresses to analyze
@@ -131,25 +131,25 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
/** /**
* Method to promote the namespace is a class namespace. * Method to promote the namespace is a class namespace.
* @param vftableNamespace the namespace for the vftable * @param namespace the namespace for the vftable
* @return true if namespace is (now) a class namespace or false if it could not be promoted. * @return true if namespace is (now) a class namespace or false if it could not be promoted.
*/ */
public Namespace promoteToClassNamespace(Namespace vftableNamespace) { public Namespace promoteToClassNamespace(Namespace namespace) {
try { try {
Namespace newClass = NamespaceUtils.convertNamespaceToClass(vftableNamespace); Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
SymbolType symbolType = newClass.getSymbol().getSymbolType(); SymbolType symbolType = newClass.getSymbol().getSymbolType();
if (symbolType == SymbolType.CLASS) { if (symbolType == SymbolType.CLASS) {
return newClass; return newClass;
} }
Msg.debug(this, Msg.debug(this,
"Could not promote " + vftableNamespace.getName() + " to a class namespace"); "Could not promote " + namespace.getName() + " to a class namespace");
return null; return null;
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
Msg.debug(this, "Could not promote " + vftableNamespace.getName() + Msg.debug(this, "Could not promote " + namespace.getName() +
" to a class namespace because " + e.getMessage()); " to a class namespace because " + e.getMessage());
return null; return null;
} }
File diff suppressed because it is too large Load Diff
@@ -47,6 +47,7 @@ import ghidra.program.model.pcode.HighFunction;
import ghidra.program.model.pcode.HighVariable; import ghidra.program.model.pcode.HighVariable;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramLocation;
import ghidra.util.Msg;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@@ -937,10 +938,13 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace(); Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace();
if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) { if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
// println("RTTI_Class_Hierarchy_Descriptor at " + classNamespace = promoteToClassNamespace(classNamespace);
// classHierarchyDescriptorAddress.toString() + if(classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
// " is not in a class namespace. Cannot process."); Msg.debug(this,
continue; classHierarchyDescriptorAddress.toString() + " Could not promote " +
classNamespace.getName(true) + " to a class namespace.");
continue;
}
} }
List<Symbol> vftableSymbolsInNamespace = List<Symbol> vftableSymbolsInNamespace =
@@ -975,12 +979,12 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
List<RecoveredClass> classesWithVftablesInNamespace = List<RecoveredClass> classesWithVftablesInNamespace =
recoverClassesFromVftables(vftableSymbolsInNamespace, false, false); recoverClassesFromVftables(vftableSymbolsInNamespace, false, false);
if (classesWithVftablesInNamespace.size() == 0) { if (classesWithVftablesInNamespace.size() == 0) {
//println("No class recovered for namespace " + classNamespace.getName()); Msg.debug(this,"No class recovered for namespace " + classNamespace.getName());
continue; continue;
} }
if (classesWithVftablesInNamespace.size() > 1) { if (classesWithVftablesInNamespace.size() > 1) {
// println("Unexpected multiple classes recovered for namespace " + Msg.debug(this,"Unexpected multiple classes recovered for namespace " +
// classNamespace.getName()); classNamespace.getName());
continue; continue;
} }
@@ -1232,7 +1236,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// if the namespace isn't in the map then it is a class // if the namespace isn't in the map then it is a class
// without a vftable and a new RecoveredClass object needs to be created // without a vftable and a new RecoveredClass object needs to be created
if (getClass(pointedToNamespace) == null) { if (getClass(pointedToNamespace) == null) {
addNoVftableClass(pointedToNamespace); createNewClass(pointedToNamespace, false);
} }
RecoveredClass pointedToClass = getClass(pointedToNamespace); RecoveredClass pointedToClass = getClass(pointedToNamespace);
@@ -2672,26 +2672,29 @@ public class RecoveredClassUtils {
return false; return false;
} }
/** /**
* Method to add class with no vftable to the namespace map * Method to create a new recovered class object and add it to the namespaceToClassMap
* @param namespace the namespace to put the new class in * @param namespace the namespace to put the new class in
* @return the recovered class\ * @param hasVftable true if class has at least one vftable, false otherwise
* @return the RecoveredClass object
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
*/ */
public RecoveredClass addNoVftableClass(Namespace namespace) throws CancelledException { public RecoveredClass createNewClass(Namespace namespace, boolean hasVftable)
throws CancelledException {
String className = namespace.getName(); String className = namespace.getName();
String classNameWithNamespace = namespace.getName(true); String classNameWithNamespace = namespace.getName(true);
CategoryPath classPath =
extraUtils.createDataTypeCategoryPath(classDataTypesCategoryPath,
classNameWithNamespace);
RecoveredClass nonVftableClass = CategoryPath classPath = extraUtils.createDataTypeCategoryPath(classDataTypesCategoryPath,
classNameWithNamespace);
RecoveredClass newClass =
new RecoveredClass(className, classPath, namespace, dataTypeManager); new RecoveredClass(className, classPath, namespace, dataTypeManager);
nonVftableClass.setHasVftable(false); newClass.setHasVftable(hasVftable);
updateNamespaceToClassMap(namespace, nonVftableClass); updateNamespaceToClassMap(namespace, newClass);
return nonVftableClass; return newClass;
} }
@@ -2735,24 +2738,7 @@ public class RecoveredClassUtils {
} }
continue; continue;
} }
// promote any non-class namespaces in the vftableNamespace path to class namespaces
boolean success = promoteNamespaces(vftableNamespace.getSymbol());
if (!success) {
if (DEBUG) {
Msg.debug(this, "Unable to promote all non-class namespaces for " +
vftableNamespace.getName(true));
}
}
String className = vftableNamespace.getName();
String classNameWithNamespace = vftableNamespace.getName(true);
// Create Data Type Manager Category for given class
CategoryPath classPath =
extraUtils.createDataTypeCategoryPath(classDataTypesCategoryPath,
classNameWithNamespace);
// get only the functions from the ones that are not already processed structures // get only the functions from the ones that are not already processed structures
// return null if not an unprocessed table // return null if not an unprocessed table
List<Function> virtualFunctions = getFunctionsFromVftable(vftableAddress, vftableSymbol, List<Function> virtualFunctions = getFunctionsFromVftable(vftableAddress, vftableSymbol,
@@ -2764,24 +2750,24 @@ public class RecoveredClassUtils {
} }
// Check to see if already have an existing RecoveredClass object for the // Check to see if already have an existing RecoveredClass object for the
// class associated with the current vftable. If so, it indicates multi-inheritance // class associated with the current vftable.
RecoveredClass recoveredClass = getClass(vftableNamespace); RecoveredClass recoveredClass = getClass(vftableNamespace);
if (recoveredClass == null) { if (recoveredClass == null) {
// Create a RecoveredClass object for the current class // Create a RecoveredClass object for the current class
recoveredClass = recoveredClass = createNewClass(vftableNamespace, true);
new RecoveredClass(className, classPath, vftableNamespace, dataTypeManager);
recoveredClass.addVftableAddress(vftableAddress); recoveredClass.addVftableAddress(vftableAddress);
recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions); recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions);
// add recovered class to map
updateNamespaceToClassMap(vftableNamespace, recoveredClass);
// add it to the running list of RecoveredClass objects // add it to the running list of RecoveredClass objects
recoveredClasses.add(recoveredClass); recoveredClasses.add(recoveredClass);
} }
else { else {
recoveredClass.addVftableAddress(vftableAddress); recoveredClass.addVftableAddress(vftableAddress);
recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions); recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions);
if (!recoveredClasses.contains(recoveredClass)) {
recoveredClasses.add(recoveredClass);
}
} }
@@ -2795,8 +2781,6 @@ public class RecoveredClassUtils {
Map<Address, Function> vftableReferenceToFunctionMapping = Map<Address, Function> vftableReferenceToFunctionMapping =
createVftableReferenceToFunctionMapping(referencesToVftable); createVftableReferenceToFunctionMapping(referencesToVftable);
// add this smaller mapping set to the global map
//vftableRefToFunctionMap.putAll(vftableReferenceToFunctionMapping);
//vftableReferenceToFunctionMapping //vftableReferenceToFunctionMapping
List<Function> possibleConstructorDestructorsForThisClass = List<Function> possibleConstructorDestructorsForThisClass =
@@ -2819,25 +2803,38 @@ public class RecoveredClassUtils {
return recoveredClasses; return recoveredClasses;
} }
private boolean promoteNamespaces(Symbol symbol) throws CancelledException { public void promoteClassNamespaces(List<RecoveredClass> recoveredClasses)
throws CancelledException {
Iterator<RecoveredClass> classIterator = recoveredClasses.iterator();
while (classIterator.hasNext()) {
monitor.checkCanceled();
RecoveredClass recoveredClass = classIterator.next();
Namespace classNamespace = recoveredClass.getClassNamespace();
promoteNamespaces(classNamespace);
}
}
private boolean promoteNamespaces(Namespace namespace) throws CancelledException {
Namespace namespace = symbol.getParentNamespace();
while (!namespace.isGlobal()) { while (!namespace.isGlobal()) {
monitor.checkCanceled(); monitor.checkCanceled();
SymbolType namespaceType = namespace.getSymbol().getSymbolType(); SymbolType namespaceType = namespace.getSymbol().getSymbolType();
if (namespaceType != SymbolType.CLASS) { // if it is a namespace but not a class and it is in our namespace map (which makes
// if it is a namespace but not a class we need to promote it to a class namespace // it a valid class) we need to promote it to a class namespace
if (namespaceType == SymbolType.NAMESPACE) { if (namespaceType != SymbolType.CLASS && namespaceType == SymbolType.NAMESPACE &&
namespace = promoteToClassNamespace(namespace); namespaceToClassMap.get(namespace) != null) {
if (namespace == null) {
return false; namespace = promoteToClassNamespace(namespace);
} if (namespace == null) {
if (DEBUG) { return false;
Msg.debug(this,
"Promoted namespace " + namespace.getName() + " to a class namespace");
}
} }
//if (DEBUG) {
Msg.debug(this,
"Promoted namespace " + namespace.getName(true) + " to a class namespace");
//}
} }
else { else {
namespace = namespace.getParentNamespace(); namespace = namespace.getParentNamespace();
@@ -2852,11 +2849,20 @@ public class RecoveredClassUtils {
*/ */
private Namespace promoteToClassNamespace(Namespace namespace) { private Namespace promoteToClassNamespace(Namespace namespace) {
SymbolType symbolType = namespace.getSymbol().getSymbolType();
if (symbolType == SymbolType.CLASS) {
return namespace;
}
if (symbolType != SymbolType.NAMESPACE) {
return namespace;
}
try { try {
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace); Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
SymbolType symbolType = newClass.getSymbol().getSymbolType(); SymbolType newSymbolType = newClass.getSymbol().getSymbolType();
if (symbolType == SymbolType.CLASS) { if (newSymbolType == SymbolType.CLASS) {
return newClass; return newClass;
} }
if (DEBUG) { if (DEBUG) {
@@ -3246,7 +3252,8 @@ public class RecoveredClassUtils {
if (parentClasses.isEmpty()) { if (parentClasses.isEmpty()) {
throw new Exception( throw new Exception(
recoveredClass.getName() + " should not have an empty class hierarchy"); recoveredClass.getClassNamespace().getName(true) +
" should not have an empty class hierarchy");
} }
// if size one it only includes self // if size one it only includes self