/* ### * IP: GHIDRA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. package classrecovery; import java.util.*; import ghidra.app.util.NamespaceUtils; import ghidra.framework.options.Options; import ghidra.framework.plugintool.PluginTool; import ghidra.program.flatapi.FlatProgramAPI; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.SymbolType; import ghidra.program.util.ProgramLocation; import ghidra.util.Msg; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; public class RTTIClassRecoverer extends RecoveredClassHelper { boolean programHasRTTIApplied = false; String ghidraVersion; Program program; TaskMonitor monitor; boolean hasDebugSymbols; RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions, boolean hasDebugSymbols, boolean replaceClassStructures, TaskMonitor monitor) throws Exception { super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions, replaceClassStructures, monitor); this.program = program; this.monitor = monitor; this.location = location; this.tool = tool; this.api = api; this.createBookmarks = createBookmarks; this.useShortTemplates = useShortTemplates; this.nameVfunctions = nameVfunctions; this.hasDebugSymbols = hasDebugSymbols; ghidraVersion = getVersionOfGhidra(); } public DecompilerScriptUtils getDecompilerUtils() { return decompilerUtils; } public int getDefaultPointerSize() { return defaultPointerSize; } public DataTypeManager getDataTypeManager() { return dataTypeManager; } public boolean containsRTTI() throws CancelledException, InvalidInputException { return true; } public boolean isValidProgramType() { return true; } public boolean isValidProgramSize() { if (defaultPointerSize != 4 && defaultPointerSize != 8) { return false; } return true; } /** * Get the version of Ghidra that was used to analyze this program * @return a string containing the version number of Ghidra used to analyze the current program */ public String getVersionOfGhidra() { Options options = program.getOptions("Program Information"); return options.getString("Created With Ghidra Version", null); } public void fixUpProgram() throws CancelledException, Exception { return; } public List createRecoveredClasses() throws Exception { return new ArrayList(); } /** * Method to promote the namespace is a class namespace. * @param namespace the namespace for the vftable * @return true if namespace is (now) a class namespace or false if it could not be promoted. * @throws InvalidInputException if namespace was contained in function and could not be promoted */ public Namespace promoteToClassNamespace(Namespace namespace) throws InvalidInputException { Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace); SymbolType symbolType = newClass.getSymbol().getSymbolType(); if (symbolType == SymbolType.CLASS) { return newClass; } Msg.debug(this, "Could not promote " + namespace.getName() + " to a class namespace"); return null; } /** * Method to iterate over all the RecoveredClass objects and see if there is an existing class structure data type already * if so, add it to the RecoveredClass object * @param recoveredClasses List of RecoveredClass objects * @throws CancelledException when cancelled */ public void retrieveExistingClassStructures(List recoveredClasses) throws CancelledException { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { monitor.checkCanceled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); // if class is non-virtual have to search for an existing class datatype if (!recoveredClass.hasVftable()) { DataType[] possibleExistingClassStructures = extendedFlatAPI.getDataTypes(recoveredClass.getName()); if (possibleExistingClassStructures.length == 0) { continue; } for (int i = 0; i < possibleExistingClassStructures.length; i++) { monitor.checkCanceled(); if (!(possibleExistingClassStructures[i] instanceof Structure)) { continue; } if (possibleExistingClassStructures[i].isNotYetDefined()) { continue; } Structure existingClassStructure = (Structure) possibleExistingClassStructures[i]; recoveredClass.addExistingClassStructure(existingClassStructure); break; } } //Iterate over constructor/destructor functions List constructorOrDestructorFunctions = recoveredClass.getConstructorOrDestructorFunctions(); Iterator constDestIterator = constructorOrDestructorFunctions.iterator(); while (constDestIterator.hasNext()) { monitor.checkCanceled(); Function constDestFunction = constDestIterator.next(); Namespace parentNamespace = constDestFunction.getParentNamespace(); if (!parentNamespace.equals(recoveredClass.getClassNamespace())) { continue; } if (recoveredClass.hasExistingClassStructure()) { continue; } int parameterCount = constDestFunction.getParameterCount(); if (parameterCount == 0) { continue; } DataType dataType = constDestFunction.getParameter(0).getDataType(); CategoryPath dataTypePath = dataType.getDataTypePath().getCategoryPath(); if (!(dataType instanceof Pointer)) { continue; } String dataTypeName = dataType.getName(); dataTypeName = dataTypeName.replace(" *", ""); if (!dataTypeName.equals(recoveredClass.getName())) { continue; } Structure existingClassStructure = (Structure) dataTypeManager.getDataType(dataTypePath, dataTypeName); if (existingClassStructure != null && !existingClassStructure.isNotYetDefined()) { recoveredClass.addExistingClassStructure(existingClassStructure); break; } } } } /** * Method to get class data information from destructors if a class has no constructors * @param recoveredClasses list of classes * @throws CancelledException if cancelled * @throws InvalidInputException if issues setting function return * @throws DuplicateNameException if try to create same symbol name already in namespace * @throws CircularDependencyException if parent namespace is descendent of given namespace */ public void figureOutClassDataMembers(List recoveredClasses) throws CancelledException, DuplicateNameException, InvalidInputException, CircularDependencyException { Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { monitor.checkCanceled(); RecoveredClass recoveredClass = classIterator.next(); // we can only figure out structure info for functions with vftable since that is // what we use to determine which variable is being used to store the class structure if (!recoveredClass.hasVftable()) { continue; } // if the class already has an existing class structure from pdb then no need to process if (recoveredClass.hasExistingClassStructure()) { continue; } List memberFunctionsToProcess = new ArrayList(); memberFunctionsToProcess.addAll(recoveredClass.getConstructorList()); memberFunctionsToProcess.addAll(recoveredClass.getDestructorList()); memberFunctionsToProcess.addAll(recoveredClass.getIndeterminateList()); memberFunctionsToProcess.addAll(recoveredClass.getInlinedConstructorList()); Iterator memberFunctionIterator = memberFunctionsToProcess.iterator(); while (memberFunctionIterator.hasNext()) { monitor.checkCanceled(); Function memberFunction = memberFunctionIterator.next(); if (getVftableReferences(memberFunction) == null) { continue; } // skip if other classes contain this function as an inline inlined destructor or // inlined indeterminate if (isInlineDestructorOrIndeterminateInAnyClass(memberFunction)) { continue; } gatherClassMemberDataInfoForFunction(recoveredClass, memberFunction); } } } }