mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-1464 RecoverClassesFromRTTIScript now consistently applies its class structures in programs that have PDB information applied. Also, an option was added so users can decide whether to replace existing class data in thiscall functions regardless of whether they originated as PDB or not.
This commit is contained in:
parent
2c561c875b
commit
0766c30048
7 changed files with 207 additions and 36 deletions
|
@ -144,10 +144,11 @@ public class RecoveredClassUtils {
|
|||
boolean createBookmarks;
|
||||
boolean useShortTemplates;
|
||||
boolean nameVfunctions;
|
||||
boolean replaceClassStructures;
|
||||
|
||||
public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool,
|
||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||
boolean nameVfunctions, TaskMonitor monitor) {
|
||||
boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor) {
|
||||
|
||||
this.monitor = monitor;
|
||||
this.program = program;
|
||||
|
@ -162,7 +163,8 @@ public class RecoveredClassUtils {
|
|||
|
||||
this.createBookmarks = createBookmarks;
|
||||
this.useShortTemplates = useShortTemplates;
|
||||
this.nameVfunctions = nameVfunctions;
|
||||
this.nameVfunctions = nameVunctions;
|
||||
this.replaceClassStructures = replaceClassStructures;
|
||||
|
||||
globalNamespace = (GlobalNamespace) program.getGlobalNamespace();
|
||||
|
||||
|
@ -3294,12 +3296,17 @@ public class RecoveredClassUtils {
|
|||
monitor.checkCanceled();
|
||||
Function constructorFunction = constructorsIterator.next();
|
||||
|
||||
createNewSymbolAtFunction(constructorFunction, className, classNamespace, true, true);
|
||||
if (nameVfunctions) {
|
||||
createNewSymbolAtFunction(constructorFunction, className, classNamespace, true,
|
||||
true);
|
||||
}
|
||||
|
||||
// check to see if the "this" data type is an empty placeholder for the class
|
||||
// structure and replace it with the one that was just created by the script
|
||||
//deleteEmptyClassStructure(constructorFunction, className);
|
||||
replaceEmptyClassStructure(constructorFunction, className, classStruct);
|
||||
//NEW
|
||||
if (replaceClassStructures) {
|
||||
replaceClassStructure(constructorFunction, className, classStruct);
|
||||
}
|
||||
|
||||
// if current decompiler function return type is a pointer then set the return type
|
||||
// to a pointer to the class structure, otherwise if it is a void, make it a void so the
|
||||
|
@ -3337,9 +3344,11 @@ public class RecoveredClassUtils {
|
|||
/**
|
||||
* Method to name class destructors and add them to class namespace
|
||||
* @param recoveredClass current class
|
||||
* @param classStruct the class structure for the given class
|
||||
* @throws Exception when cancelled
|
||||
*/
|
||||
public void addDestructorsToClassNamespace(RecoveredClass recoveredClass) throws Exception {
|
||||
public void addDestructorsToClassNamespace(RecoveredClass recoveredClass, Structure classStruct)
|
||||
throws Exception {
|
||||
|
||||
Namespace classNamespace = recoveredClass.getClassNamespace();
|
||||
String className = recoveredClass.getName();
|
||||
|
@ -3351,8 +3360,17 @@ public class RecoveredClassUtils {
|
|||
Function destructorFunction = destructorIterator.next();
|
||||
String destructorName = "~" + className;
|
||||
|
||||
createNewSymbolAtFunction(destructorFunction, destructorName, classNamespace, true,
|
||||
true);
|
||||
if (nameVfunctions) {
|
||||
createNewSymbolAtFunction(destructorFunction, destructorName, classNamespace, true,
|
||||
true);
|
||||
}
|
||||
|
||||
// check to see if the "this" data type is an empty placeholder for the class
|
||||
// structure and replace it with the one that was just created by the script
|
||||
//NEW
|
||||
if (replaceClassStructures) {
|
||||
replaceClassStructure(destructorFunction, className, classStruct);
|
||||
}
|
||||
|
||||
destructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
|
||||
}
|
||||
|
@ -3384,9 +3402,11 @@ public class RecoveredClassUtils {
|
|||
/**
|
||||
* Method to name class vbase destructors and add them to class namespace
|
||||
* @param recoveredClass current class
|
||||
* @param classStruct the class structure for the given class
|
||||
* @throws Exception when cancelled
|
||||
*/
|
||||
public void addVbaseDestructorsToClassNamespace(RecoveredClass recoveredClass)
|
||||
public void addVbaseDestructorsToClassNamespace(RecoveredClass recoveredClass,
|
||||
Structure classStruct)
|
||||
throws Exception {
|
||||
|
||||
Namespace classNamespace = recoveredClass.getClassNamespace();
|
||||
|
@ -3395,8 +3415,18 @@ public class RecoveredClassUtils {
|
|||
if (vbaseDestructorFunction != null) {
|
||||
String destructorName = VBASE_DESTRUCTOR_LABEL;
|
||||
|
||||
createNewSymbolAtFunction(vbaseDestructorFunction, destructorName, classNamespace, true,
|
||||
true);
|
||||
if (nameVfunctions) {
|
||||
createNewSymbolAtFunction(vbaseDestructorFunction, destructorName, classNamespace,
|
||||
true, true);
|
||||
}
|
||||
|
||||
// check to see if the "this" data type is an empty placeholder for the class
|
||||
// structure and replace it with the one that was just created by the script
|
||||
//NEW
|
||||
if (replaceClassStructures) {
|
||||
replaceClassStructure(vbaseDestructorFunction, recoveredClass.getName(),
|
||||
classStruct);
|
||||
}
|
||||
|
||||
vbaseDestructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
|
||||
}
|
||||
|
@ -3505,6 +3535,106 @@ public class RecoveredClassUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to replace the program's current class structure, only if an empty placeholder structure,
|
||||
* with the one generated by this script
|
||||
* @param function a class method with current class structure applied
|
||||
* @param className the given class name
|
||||
* @param newClassStructure the new structure to replace the old with
|
||||
* @throws DataTypeDependencyException if there is a data dependency exception when replacing
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public void replaceClassStructure(Function function, String className,
|
||||
Structure newClassStructure) throws DataTypeDependencyException, CancelledException {
|
||||
|
||||
Parameter thisParam = function.getParameter(0);
|
||||
if (thisParam == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataType dataType = thisParam.getDataType();
|
||||
if (dataType instanceof Pointer) {
|
||||
Pointer ptr = (Pointer) dataType;
|
||||
DataType baseDataType = ptr.getDataType();
|
||||
if (!baseDataType.equals(newClassStructure) &&
|
||||
baseDataType.getName().equals(className)) {
|
||||
|
||||
// check if fid demangler or pdb - don't replace user ones
|
||||
if (!isReplaceableType(function.getEntryPoint(), baseDataType)) {
|
||||
return;
|
||||
}
|
||||
// create copy of existing one
|
||||
DataType baseDataTypeCopy = baseDataType.copy(dataTypeManager);
|
||||
|
||||
renameDataType(baseDataTypeCopy, baseDataType.getName() + "_REPLACED");
|
||||
|
||||
// replace the other with the new one
|
||||
dataTypeManager.replaceDataType(baseDataType, newClassStructure, false);
|
||||
|
||||
// // remove original folder if it is empty after the replace
|
||||
// in future if decide to just remove the other ones, then do the following
|
||||
// CategoryPath originalPath = baseDataType.getCategoryPath();
|
||||
// Category category = dataTypeManager.getCategory(originalPath);
|
||||
// Category parentCategory = category.getParent();
|
||||
// if (parentCategory != null) {
|
||||
// parentCategory.removeEmptyCategory(category.getName(), monitor);
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void renameDataType(DataType dataType, String name) throws CancelledException {
|
||||
|
||||
boolean renamed = false;
|
||||
int oneup = 2;
|
||||
while (!renamed) {
|
||||
monitor.checkCanceled();
|
||||
try {
|
||||
dataType.setName(name);
|
||||
dataTypeManager.resolve(dataType, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
renamed = true;
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
name = name + oneup++;
|
||||
renamed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isReplaceableType(Address address, DataType dataType) {
|
||||
|
||||
// return false if it isn't even a structure
|
||||
if (!(dataType instanceof Structure)) {
|
||||
return false;
|
||||
}
|
||||
String categoryPath = dataType.getPathName();
|
||||
if (categoryPath.startsWith("/Demangler")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (categoryPath.contains(".pdb")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO: decide whether to replace dwarf or not
|
||||
|
||||
// test to see if the data type is an empty structure with "PlaceHolder Class Structure" in
|
||||
// the description
|
||||
Structure structure = (Structure) dataType;
|
||||
if (structure.isNotYetDefined() &&
|
||||
structure.getDescription().equals("PlaceHolder Class Structure")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (program.getBookmarkManager().getBookmark(address, BookmarkType.ANALYSIS,
|
||||
"Function ID Analyzer") != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a new symbol at the given function
|
||||
* @param function the given function
|
||||
|
@ -4435,11 +4565,12 @@ public class RecoveredClassUtils {
|
|||
* Method to fill in the vftable structure with pointers to virtual function signature data types
|
||||
* @param recoveredClass the current class to be processed
|
||||
* @param vftableToStructureMap the map from the class's vftables to the correct vftable structure data type
|
||||
* @param classStruct the class structure for the given class
|
||||
* @throws CancelledException when cancelled
|
||||
* @throws Exception if other exception
|
||||
*/
|
||||
public void fillInAndApplyVftableStructAndNameVfunctions(RecoveredClass recoveredClass,
|
||||
Map<Address, DataType> vftableToStructureMap) throws CancelledException, Exception {
|
||||
Map<Address, DataType> vftableToStructureMap, Structure classStruct) throws CancelledException, Exception {
|
||||
|
||||
//create function definition for each virtual function and put in vftable structure and
|
||||
// data subfolder
|
||||
|
@ -4468,6 +4599,7 @@ public class RecoveredClassUtils {
|
|||
nameVfunctions(recoveredClass, vftableAddress, vftableStructureName);
|
||||
}
|
||||
|
||||
|
||||
List<Function> vFunctions = recoveredClass.getVirtualFunctions(vftableAddress);
|
||||
int vfunctionNumber = 1;
|
||||
Iterator<Function> vfIterator = vFunctions.iterator();
|
||||
|
@ -4483,6 +4615,13 @@ public class RecoveredClassUtils {
|
|||
continue;
|
||||
}
|
||||
|
||||
// check to see if the "this" data type is an empty placeholder for the class
|
||||
// structure and replace it with the one that was just created by the script
|
||||
//NEW
|
||||
if (replaceClassStructures) {
|
||||
replaceClassStructure(vfunction, recoveredClass.getName(), classStruct);
|
||||
}
|
||||
|
||||
// get the classPath of highest level parent with vfAddress in their vftable
|
||||
classPath =
|
||||
getCategoryPathForFunctionSignature(vfunction, recoveredClass, vftableAddress);
|
||||
|
@ -5008,9 +5147,11 @@ public class RecoveredClassUtils {
|
|||
/**
|
||||
* Method to add label on constructor or destructors but couldn't tell which
|
||||
* @param recoveredClass current class
|
||||
* @param classStruct the class structure for the given class
|
||||
* @throws Exception when cancelled
|
||||
*/
|
||||
public void createIndeterminateLabels(RecoveredClass recoveredClass) throws Exception {
|
||||
public void createIndeterminateLabels(RecoveredClass recoveredClass, Structure classStruct)
|
||||
throws Exception {
|
||||
|
||||
Namespace classNamespace = recoveredClass.getClassNamespace();
|
||||
String className = recoveredClass.getName();
|
||||
|
@ -5020,8 +5161,18 @@ public class RecoveredClassUtils {
|
|||
while (unknownsIterator.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
Function indeterminateFunction = unknownsIterator.next();
|
||||
createNewSymbolAtFunction(indeterminateFunction,
|
||||
className + "_Constructor_or_Destructor", classNamespace, false, false);
|
||||
|
||||
if (nameVfunctions) {
|
||||
createNewSymbolAtFunction(indeterminateFunction,
|
||||
className + "_Constructor_or_Destructor", classNamespace, false, false);
|
||||
}
|
||||
|
||||
// check to see if the "this" data type is an empty placeholder for the class
|
||||
// structure and replace it with the one that was just created by the script
|
||||
//NEW
|
||||
if (replaceClassStructures) {
|
||||
replaceClassStructure(indeterminateFunction, className, classStruct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue