From 4076cb9ec91c3b7a024b9c770d0ec23adeaa4034 Mon Sep 17 00:00:00 2001 From: ghidra007 Date: Wed, 30 Aug 2023 15:44:00 +0000 Subject: [PATCH] GP-3777 added code to RTTI script to update any class functions not already using new class struct to use it. --- .../classrecovery/RTTIGccClassRecoverer.java | 78 +++++++- .../RTTIWindowsClassRecoverer.java | 53 +++++- .../classrecovery/RecoveredClassHelper.java | 169 +++++++++++++++++- 3 files changed, 276 insertions(+), 24 deletions(-) diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index 94e164dd80..cf2a16d977 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -17,7 +17,15 @@ package classrecovery; import java.io.UnsupportedEncodingException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; import ghidra.app.cmd.label.DemanglerCmd; import ghidra.app.plugin.core.analysis.ReferenceAddressPair; @@ -26,20 +34,67 @@ import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemanglerUtil; import ghidra.framework.plugintool.PluginTool; import ghidra.program.flatapi.FlatProgramAPI; -import ghidra.program.model.address.*; -import ghidra.program.model.data.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressIterator; +import ghidra.program.model.address.AddressOutOfBoundsException; +import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressRangeIterator; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.data.ArrayDataType; +import ghidra.program.model.data.CategoryPath; +import ghidra.program.model.data.CharDataType; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeComponent; +import ghidra.program.model.data.DataTypeConflictHandler; +import ghidra.program.model.data.DataUtilities; import ghidra.program.model.data.DataUtilities.ClearDataMode; +import ghidra.program.model.data.InvalidDataTypeException; +import ghidra.program.model.data.LongDataType; +import ghidra.program.model.data.LongLongDataType; +import ghidra.program.model.data.Pointer; +import ghidra.program.model.data.PointerDataType; +import ghidra.program.model.data.PointerTypedef; +import ghidra.program.model.data.StringDataType; +import ghidra.program.model.data.Structure; +import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.data.TerminatedStringDataType; +import ghidra.program.model.data.UnsignedIntegerDataType; import ghidra.program.model.lang.Register; -import ghidra.program.model.listing.*; -import ghidra.program.model.mem.*; +import ghidra.program.model.listing.Bookmark; +import ghidra.program.model.listing.BookmarkType; +import ghidra.program.model.listing.CircularDependencyException; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.FunctionManager; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.InstructionIterator; +import ghidra.program.model.listing.Listing; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.DumbMemBufferImpl; +import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.mem.Memory; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.scalar.Scalar; -import ghidra.program.model.symbol.*; +import ghidra.program.model.symbol.Namespace; +import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.ReferenceIterator; +import ghidra.program.model.symbol.ReferenceManager; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolIterator; import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramMemoryUtil; import ghidra.util.Msg; -import ghidra.util.bytesearch.*; -import ghidra.util.exception.*; +import ghidra.util.bytesearch.GenericByteSequencePattern; +import ghidra.util.bytesearch.GenericMatchAction; +import ghidra.util.bytesearch.Match; +import ghidra.util.bytesearch.MemoryBytePatternSearcher; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; public class RTTIGccClassRecoverer extends RTTIClassRecoverer { @@ -4508,12 +4563,16 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } if (!recoveredClass.hasVftable()) { + Structure classStructure = createSimpleClassStructure(recoveredClass, null); if (classStructure == null) { Msg.error(this, "Could not create class structure for " + recoveredClass.getClassNamespace().getName(true)); } - // return here because if there is no vftable for a class the script cannot + + updateClassFunctionsNotUsingNewClassStructure(recoveredClass, + classStructure); + // return in this case because if there is no vftable for a class the script cannot // identify any member functions so there is no need to process the rest of this // method return; @@ -4559,6 +4618,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { fillInAndApplyVftableStructAndNameVfunctions(recoveredClass, vfPointerDataTypes, classStruct); + updateClassFunctionsNotUsingNewClassStructure(recoveredClass, classStruct); } private Structure createSimpleClassStructure(RecoveredClass recoveredClass, diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java index 3221326652..ff289c0587 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java @@ -16,7 +16,14 @@ //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. package classrecovery; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd; import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd.OffsetPcodeOpPair; @@ -24,17 +31,41 @@ import ghidra.app.util.opinion.PeLoader; import ghidra.app.util.opinion.PeLoader.CompilerOpinion.CompilerEnum; import ghidra.framework.plugintool.PluginTool; import ghidra.program.flatapi.FlatProgramAPI; -import ghidra.program.model.address.*; -import ghidra.program.model.data.*; -import ghidra.program.model.listing.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressOutOfBoundsException; +import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.data.ArrayDataType; +import ghidra.program.model.data.Category; +import ghidra.program.model.data.CategoryPath; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeConflictHandler; +import ghidra.program.model.data.IntegerDataType; +import ghidra.program.model.data.PointerDataType; +import ghidra.program.model.data.Structure; +import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.listing.CircularDependencyException; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.FlowOverride; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.pcode.HighFunction; import ghidra.program.model.pcode.HighVariable; -import ghidra.program.model.symbol.*; +import ghidra.program.model.symbol.Namespace; +import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolIterator; +import ghidra.program.model.symbol.SymbolType; import ghidra.program.util.ProgramLocation; import ghidra.util.Msg; -import ghidra.util.exception.*; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { @@ -2180,7 +2211,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { throws CancelledException, Exception { if (!recoveredClass.hasVftable()) { - createClassStructureUsingRTTI(recoveredClass, null); + Structure classStruct = createClassStructureUsingRTTI(recoveredClass, null); + + if (classStruct != null) { + updateClassFunctionsNotUsingNewClassStructure(recoveredClass, classStruct); + } // return in this case because if there is no vftable for a class the script cannot // identify any member functions so there is no need to process the rest of this method return; @@ -2226,6 +2261,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { fillInAndApplyVftableStructAndNameVfunctions(recoveredClass, vfPointerDataTypes, classStruct); + if (classStruct != null) { + updateClassFunctionsNotUsingNewClassStructure(recoveredClass, classStruct); + } + } /** diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java index d64ba2e946..5a4ee33f65 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java @@ -16,7 +16,17 @@ //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. package classrecovery; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import ghidra.app.cmd.function.ApplyFunctionSignatureCmd; @@ -30,21 +40,80 @@ import ghidra.app.util.NamespaceUtils; import ghidra.framework.plugintool.PluginTool; import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.flatapi.FlatProgramAPI; -import ghidra.program.model.address.*; -import ghidra.program.model.data.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressOutOfBoundsException; +import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressRangeIterator; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.address.GlobalNamespace; +import ghidra.program.model.data.ArrayDataType; +import ghidra.program.model.data.Category; +import ghidra.program.model.data.CategoryPath; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeComponent; +import ghidra.program.model.data.DataTypeConflictHandler; +import ghidra.program.model.data.DataTypeDependencyException; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.FunctionDefinition; +import ghidra.program.model.data.FunctionDefinitionDataType; +import ghidra.program.model.data.NoisyStructureBuilder; +import ghidra.program.model.data.ParameterDefinition; +import ghidra.program.model.data.Pointer; +import ghidra.program.model.data.PointerDataType; +import ghidra.program.model.data.Structure; +import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.data.Undefined1DataType; +import ghidra.program.model.data.Undefined4DataType; +import ghidra.program.model.data.Undefined8DataType; +import ghidra.program.model.data.VoidDataType; import ghidra.program.model.lang.CompilerSpec; -import ghidra.program.model.listing.*; +import ghidra.program.model.lang.PrototypeModel; +import ghidra.program.model.listing.Bookmark; +import ghidra.program.model.listing.BookmarkManager; +import ghidra.program.model.listing.BookmarkType; +import ghidra.program.model.listing.CircularDependencyException; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.FlowOverride; +import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function.FunctionUpdateType; +import ghidra.program.model.listing.FunctionManager; +import ghidra.program.model.listing.FunctionSignature; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.InstructionIterator; +import ghidra.program.model.listing.Listing; +import ghidra.program.model.listing.Parameter; +import ghidra.program.model.listing.Program; +import ghidra.program.model.listing.ReturnParameterImpl; +import ghidra.program.model.listing.Variable; import ghidra.program.model.mem.MemoryBlock; -import ghidra.program.model.pcode.*; -import ghidra.program.model.symbol.*; +import ghidra.program.model.pcode.HighFunction; +import ghidra.program.model.pcode.HighVariable; +import ghidra.program.model.pcode.PcodeOp; +import ghidra.program.model.pcode.PcodeOpAST; +import ghidra.program.model.pcode.Varnode; +import ghidra.program.model.symbol.Namespace; +import ghidra.program.model.symbol.RefType; +import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.ReferenceIterator; +import ghidra.program.model.symbol.ReferenceManager; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolIterator; +import ghidra.program.model.symbol.SymbolTable; +import ghidra.program.model.symbol.SymbolType; import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramMemoryUtil; import ghidra.util.InvalidNameException; import ghidra.util.Msg; -import ghidra.util.bytesearch.*; +import ghidra.util.bytesearch.GenericByteSequencePattern; +import ghidra.util.bytesearch.GenericMatchAction; +import ghidra.util.bytesearch.Match; +import ghidra.util.bytesearch.MemoryBytePatternSearcher; import ghidra.util.datastruct.ListAccumulator; -import ghidra.util.exception.*; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; public class RecoveredClassHelper { @@ -4772,6 +4841,90 @@ public class RecoveredClassHelper { return vfunctionSuffix; } + /** + * Method to update any class functions that are not already using it to use the given + * class structure + * @param recoveredClass the given class + * @param classStructure the given class structure + * @throws CancelledException if cancelled + */ + protected void updateClassFunctionsNotUsingNewClassStructure(RecoveredClass recoveredClass, + Structure classStructure) throws CancelledException { + + if (classStructure == null) { + return; + } + + Namespace classNamespace = recoveredClass.getClassNamespace(); + + SymbolIterator symbols = symbolTable.getSymbols(classNamespace); + + FunctionManager functionManager = program.getFunctionManager(); + + while (symbols.hasNext()) { + monitor.checkCancelled(); + + Symbol symbol = symbols.next(); + + Function function = functionManager.getFunctionAt(symbol.getAddress()); + + if (function == null) { + continue; + } + + if (function.isThunk()) { + continue; + } + + PrototypeModel callingConvention = function.getCallingConvention(); + if (callingConvention == null) { + Msg.debug(this, "no calling convention for: " + function.getEntryPoint()); + continue; + } + + if (!callingConvention.hasThisPointer()) { + continue; + } + + Parameter[] parameters = function.getParameters(); + if (parameters.length == 0) { + continue; + } + + DataType dataType = parameters[0].getDataType(); + if (!(dataType instanceof Pointer pointer)) { + continue; + } + + DataType pointedToDt = pointer.getDataType(); + if (!pointedToDt.equals(classStructure)) { + Pointer classStructurePointer = new PointerDataType(classStructure); + try { + List newParamList = new ArrayList<>(); + for (Parameter param : parameters) { + + newParamList.add(param); + } + + FunctionUpdateType updateType = FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS; + if (function.hasCustomVariableStorage()) { + updateType = FunctionUpdateType.CUSTOM_STORAGE; + } + + newParamList.get(0).setDataType(classStructurePointer, SourceType.ANALYSIS); + function.replaceParameters(newParamList, + updateType, false, SourceType.ANALYSIS); + } + catch (InvalidInputException | DuplicateNameException e) { + Msg.error(this, "Could not update function at " + function.getEntryPoint() + + " with new class structure due to exception: " + e.getMessage()); + } + + } + + } + } + private boolean hasDeletingDestructorInNamespace(Address address, Namespace namespace) throws CancelledException {