mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GP-4748 Updated RttiUtil's find end of vftable to be more accurate.
This commit is contained in:
parent
220d6d9f58
commit
f657b11c1d
3 changed files with 150 additions and 47 deletions
|
@ -2662,8 +2662,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
if (numAddressRanges == 1) {
|
if (numAddressRanges == 1) {
|
||||||
fixupContiguousDeletingDestructorSymbols(function);
|
fixupContiguousDeletingDestructorSymbols(function);
|
||||||
processedFunctions.add(function);
|
processedFunctions.add(function);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else if (numAddressRanges == 2) {
|
if (numAddressRanges == 2) {
|
||||||
// else fixup split dd function
|
// else fixup split dd function
|
||||||
Function scalarDeletingDestructor = createSplitDeletingDestructorFunction(body);
|
Function scalarDeletingDestructor = createSplitDeletingDestructorFunction(body);
|
||||||
if (scalarDeletingDestructor == null) {
|
if (scalarDeletingDestructor == null) {
|
||||||
|
@ -2674,7 +2675,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
fixupSplitDeletingDestructorSymbols(function, scalarDeletingDestructor);
|
fixupSplitDeletingDestructorSymbols(function, scalarDeletingDestructor);
|
||||||
processedFunctions.add(function);
|
processedFunctions.add(function);
|
||||||
}
|
}
|
||||||
// else if > 2 do nothing - not sure how to handle or even if they exist
|
// if > 2 do nothing - not sure how to handle or even if they exist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -426,6 +426,22 @@ public class RecoveredClassHelper {
|
||||||
// of number of CALL instructions even if the call reg type
|
// of number of CALL instructions even if the call reg type
|
||||||
functionCallMap.put(instruction.getMinAddress(), calledFunction);
|
functionCallMap.put(instruction.getMinAddress(), calledFunction);
|
||||||
}
|
}
|
||||||
|
if(instruction.getFlowOverride().equals(FlowOverride.CALL_RETURN)) {
|
||||||
|
Reference reference = instruction.getPrimaryReference(0);
|
||||||
|
if (reference == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Address functionAddress = reference.getFromAddress();
|
||||||
|
Function secondHalfOfFunction = extendedFlatAPI.getReferencedFunction(functionAddress);
|
||||||
|
if(secondHalfOfFunction != null){
|
||||||
|
Map<Address,Function> functionCallMap2 = getFunctionCallMap(secondHalfOfFunction,false);
|
||||||
|
for(Address addr : functionCallMap2.keySet()) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
functionCallMap.put(addr, functionCallMap2.get(addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return functionCallMap;
|
return functionCallMap;
|
||||||
}
|
}
|
||||||
|
@ -946,9 +962,9 @@ public class RecoveredClassHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to get a list of addresses that reference the given vftable address
|
* Method to get a list of addresses that reference the given vftable address (only non-offcut ones)
|
||||||
* @param vftableAddress the given vftable address
|
* @param vftableAddress the given vftable address
|
||||||
* @return list of addresses that reference the given vftable address
|
* @return list of non-offcut addresses that reference the given vftable address
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
public List<Address> getReferencesToVftable(Address vftableAddress) throws CancelledException {
|
public List<Address> getReferencesToVftable(Address vftableAddress) throws CancelledException {
|
||||||
|
@ -2239,41 +2255,62 @@ public class RecoveredClassHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to determine if the given function calls a known constructor or inlined constructor
|
* Method to determine if the given function calls a known constructor or inlined constructor
|
||||||
* @param callingFunction the given calling function
|
* @param Set of called functions
|
||||||
* @return true if calling function calls a known constructor or inlined constructor, false otherwise
|
* @return true if calling function calls a known constructor or inlined constructor, false otherwise
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
public boolean callsKnownConstructor(Function callingFunction) throws CancelledException {
|
public boolean callsKnownConstructor(Set<Function> calledFunctions) throws CancelledException {
|
||||||
|
|
||||||
InstructionIterator instructions = callingFunction.getProgram()
|
for (Function calledFunction : calledFunctions) {
|
||||||
.getListing()
|
|
||||||
.getInstructions(callingFunction.getBody(), true);
|
|
||||||
while (instructions.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Instruction instruction = instructions.next();
|
|
||||||
if (instruction.getFlowType().isCall()) {
|
|
||||||
|
|
||||||
Function calledFunction =
|
if (getAllConstructors().contains(calledFunction) || getAllInlinedConstructors().contains(calledFunction)) {
|
||||||
extendedFlatAPI.getReferencedFunction(instruction.getMinAddress(), true);
|
|
||||||
if (calledFunction == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (getAllConstructors().contains(calledFunction) ||
|
|
||||||
getAllInlinedConstructors().contains(calledFunction)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to determine if the given function calls a known constructor or inlined constructor
|
* Method to determine if the given function calls a known denstructor or inlined destructor
|
||||||
* @param callingFunction the given calling function
|
* @param Set of called functions
|
||||||
* @return true if function calls a known constructor or inlined constructor, false otherwise
|
* @return true if function calls a known constructor or inlined constructor, false otherwise
|
||||||
|
* of its own or none
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
public boolean callsKnownDestructor(Function callingFunction) throws CancelledException {
|
public boolean callsKnownDestructor(Set<Function> calledFunctions) throws CancelledException {
|
||||||
|
|
||||||
|
for (Function calledFunction : calledFunctions) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
|
||||||
|
if (getAllDestructors().contains(calledFunction) || getAllInlinedDestructors().contains(calledFunction)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean callsOwnFunction(RecoveredClass recoveredClass, Set<Function> calledFunctions) throws CancelledException {
|
||||||
|
|
||||||
|
for (Function calledFunction : calledFunctions) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
|
||||||
|
if(recoveredClass.getConstructorOrDestructorFunctions().contains(calledFunction)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Set<Function> getCalledFunctions(Function callingFunction) throws CancelledException {
|
||||||
|
|
||||||
|
|
||||||
|
Set<Function> calledFunctions = new HashSet<Function>();
|
||||||
|
|
||||||
InstructionIterator instructions = callingFunction.getProgram()
|
InstructionIterator instructions = callingFunction.getProgram()
|
||||||
.getListing()
|
.getListing()
|
||||||
|
@ -2288,13 +2325,12 @@ public class RecoveredClassHelper {
|
||||||
if (calledFunction == null) {
|
if (calledFunction == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (getAllDestructors().contains(calledFunction) ||
|
|
||||||
getAllInlinedDestructors().contains(calledFunction)) {
|
calledFunctions.add(calledFunction);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return calledFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2535,7 +2571,7 @@ public class RecoveredClassHelper {
|
||||||
* @param recoveredClass the given class object
|
* @param recoveredClass the given class object
|
||||||
* @return true if class has a vbase destructor, false if not
|
* @return true if class has a vbase destructor, false if not
|
||||||
*/
|
*/
|
||||||
private boolean hasVbaseDestructor(RecoveredClass recoveredClass) throws CancelledException {
|
private boolean hasValidVbaseDestructor(RecoveredClass recoveredClass) throws CancelledException {
|
||||||
Function vBaseDestructor = recoveredClass.getVBaseDestructor();
|
Function vBaseDestructor = recoveredClass.getVBaseDestructor();
|
||||||
|
|
||||||
StringBuffer string = new StringBuffer();
|
StringBuffer string = new StringBuffer();
|
||||||
|
@ -5384,16 +5420,35 @@ public class RecoveredClassHelper {
|
||||||
|
|
||||||
// if inline, put on separate list and remove from indeterminate list
|
// if inline, put on separate list and remove from indeterminate list
|
||||||
// process later
|
// process later
|
||||||
|
if(callsOwnConstructorOrDestructor(recoveredClass, indeterminateFunction)) {
|
||||||
|
recoveredClass.addIndeterminateInline(indeterminateFunction);
|
||||||
|
indeterminateIterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (vftableReferenceList.size() > 1) {
|
if (vftableReferenceList.size() > 1) {
|
||||||
if (!areVftablesInSameClass(vftableReferenceList)) {
|
if (!areVftablesInSameClass(vftableReferenceList)) {
|
||||||
recoveredClass.addIndeterminateInline(indeterminateFunction);
|
recoveredClass.addIndeterminateInline(indeterminateFunction);
|
||||||
indeterminateIterator.remove();
|
indeterminateIterator.remove();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
private boolean callsOwnConstructorOrDestructor(RecoveredClass recoveredClass, Function function) throws CancelledException {
|
||||||
}
|
|
||||||
|
Set<Function> calledFunctions = getCalledFunctions(function);
|
||||||
|
|
||||||
|
List<Function> constructorOrDestructorFunctions = recoveredClass.getConstructorOrDestructorFunctions();
|
||||||
|
for(Function cdFunction : constructorOrDestructorFunctions) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
|
||||||
|
if(calledFunctions.contains(cdFunction)) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6075,9 +6130,16 @@ public class RecoveredClassHelper {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Function indeterminateFunction = indeterminateIterator.next();
|
Function indeterminateFunction = indeterminateIterator.next();
|
||||||
|
|
||||||
// first try identifying useing known constructors and destructors
|
// weed out any that call own possible constructors and destructors
|
||||||
boolean callsKnownConstructor = callsKnownConstructor(indeterminateFunction);
|
// as they will not be const/dest (possibly may be inlined one though
|
||||||
boolean callsKnownDestructor = callsKnownDestructor(indeterminateFunction);
|
Set<Function> calledFunctions = getCalledFunctions(indeterminateFunction);
|
||||||
|
if(callsOwnFunction(recoveredClass, calledFunctions)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// first try identifying using known constructors and destructors
|
||||||
|
boolean callsKnownConstructor = callsKnownConstructor(calledFunctions);
|
||||||
|
boolean callsKnownDestructor = callsKnownDestructor(calledFunctions);
|
||||||
|
|
||||||
boolean callsAtexit =
|
boolean callsAtexit =
|
||||||
extendedFlatAPI.doesFunctionACallFunctionB(indeterminateFunction, atexit);
|
extendedFlatAPI.doesFunctionACallFunctionB(indeterminateFunction, atexit);
|
||||||
|
@ -6102,6 +6164,7 @@ public class RecoveredClassHelper {
|
||||||
// Next try identifying constructors using decompiler return type
|
// Next try identifying constructors using decompiler return type
|
||||||
DataType decompilerReturnType =
|
DataType decompilerReturnType =
|
||||||
decompilerUtils.getDecompilerReturnType(indeterminateFunction);
|
decompilerUtils.getDecompilerReturnType(indeterminateFunction);
|
||||||
|
|
||||||
if (decompilerReturnType != null) {
|
if (decompilerReturnType != null) {
|
||||||
|
|
||||||
String returnDataName = decompilerReturnType.getDisplayName();
|
String returnDataName = decompilerReturnType.getDisplayName();
|
||||||
|
@ -6149,7 +6212,7 @@ public class RecoveredClassHelper {
|
||||||
addConstructorToClass(recoveredClass, indeterminateFunction);
|
addConstructorToClass(recoveredClass, indeterminateFunction);
|
||||||
indeterminateIterator.remove();
|
indeterminateIterator.remove();
|
||||||
}
|
}
|
||||||
else if (stores.size() == 1 && loads.size() > 0) {
|
else if (stores.size() == 1 && loads.size() >= 0) {
|
||||||
addDestructorToClass(recoveredClass, indeterminateFunction);
|
addDestructorToClass(recoveredClass, indeterminateFunction);
|
||||||
indeterminateIterator.remove();
|
indeterminateIterator.remove();
|
||||||
}
|
}
|
||||||
|
@ -7093,7 +7156,9 @@ public class RecoveredClassHelper {
|
||||||
if (vBaseDestructor == null) {
|
if (vBaseDestructor == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!hasVbaseDestructor(recoveredClass)) {
|
// test whether the identified vbase destructor is valid and if not
|
||||||
|
// just make it a normal destructor
|
||||||
|
if (!hasValidVbaseDestructor(recoveredClass)) {
|
||||||
addDestructorToClass(recoveredClass, vBaseDestructor);
|
addDestructorToClass(recoveredClass, vBaseDestructor);
|
||||||
recoveredClass.setVBaseDestructor(null);
|
recoveredClass.setVBaseDestructor(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,6 @@ public class RttiUtil {
|
||||||
|
|
||||||
SymbolTable symbolTable = program.getSymbolTable();
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
|
||||||
|
|
||||||
// See if the symbol already exists for the RTTI data.
|
// See if the symbol already exists for the RTTI data.
|
||||||
Symbol matchingSymbol = symbolTable.getSymbol(rttiSuffix, rttiAddress, classNamespace);
|
Symbol matchingSymbol = symbolTable.getSymbol(rttiSuffix, rttiAddress, classNamespace);
|
||||||
if (matchingSymbol != null) {
|
if (matchingSymbol != null) {
|
||||||
|
@ -170,8 +169,9 @@ public class RttiUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// any references after the first one ends the table
|
// any non-computed source type references after the first one ends the table
|
||||||
if (tableSize > 0 && referenceManager.hasReferencesTo(currentVfPointerAddress)) {
|
if (tableSize > 0 &&
|
||||||
|
referenceIndicatesEndOfTable(referenceManager, currentVfPointerAddress)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +190,43 @@ public class RttiUtil {
|
||||||
return tableSize;
|
return tableSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to determine if there certain types of references to the given address that would
|
||||||
|
* indicate the end of a vftable
|
||||||
|
* @param address the address of a possible pointer in a vftable
|
||||||
|
* @return true if there are references to the given address and any of the references are
|
||||||
|
* types that would indicate the given pointer should not be in the vftable preceding it. In
|
||||||
|
* general most references would fall into this category such as ones created by user, importer,
|
||||||
|
* disassembler. Returns false if no references or if the only references are ones not
|
||||||
|
* indicative of the end of a vftable.
|
||||||
|
*/
|
||||||
|
private static boolean referenceIndicatesEndOfTable(ReferenceManager referenceManager,
|
||||||
|
Address address) {
|
||||||
|
|
||||||
|
boolean hasReferencesTo = referenceManager.hasReferencesTo(address);
|
||||||
|
if (!hasReferencesTo) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ReferenceIterator referenceIter = referenceManager.getReferencesTo(address);
|
||||||
|
while (referenceIter.hasNext()) {
|
||||||
|
Reference ref = referenceIter.next();
|
||||||
|
|
||||||
|
// if source type is any besides analysis then it is the kind of reference to stop
|
||||||
|
// the vftable
|
||||||
|
if (ref.getSource() != SourceType.ANALYSIS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// if it is analysis source type but reference is data that is not read this indicates
|
||||||
|
// it is not the kind of reference that should end a vftable
|
||||||
|
// For example something could be getting this address to figure out the address pointed
|
||||||
|
// to so that that address can be referenced.
|
||||||
|
if (ref.getReferenceType().isData() && !ref.getReferenceType().isRead()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the namespace referred to by the type descriptor model if it can determine the
|
* Gets the namespace referred to by the type descriptor model if it can determine the
|
||||||
* namespace. Otherwise it returns the empty string.
|
* namespace. Otherwise it returns the empty string.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue