diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index fde1893169..488f4abecd 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java @@ -54,18 +54,10 @@ import java.io.File; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; -import classrecovery.DecompilerScriptUtils; -import classrecovery.RTTIClassRecoverer; -import classrecovery.RTTIGccClassRecoverer; -import classrecovery.RTTIWindowsClassRecoverer; -import classrecovery.RecoveredClass; -import classrecovery.RecoveredClassHelper; +import classrecovery.*; import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.decompiler.DecompInterface; import ghidra.app.plugin.core.analysis.AutoAnalysisManager; @@ -83,30 +75,15 @@ import ghidra.app.util.importer.MessageLog; import ghidra.app.util.opinion.PeLoader; import ghidra.framework.options.Options; import ghidra.framework.plugintool.PluginTool; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSet; -import ghidra.program.model.address.AddressSetView; -import ghidra.program.model.data.CategoryPath; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeComponent; -import ghidra.program.model.data.DataTypeManager; -import ghidra.program.model.data.Structure; -import ghidra.program.model.listing.Function; -import ghidra.program.model.listing.Parameter; -import ghidra.program.model.listing.Program; +import ghidra.program.model.address.*; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.reloc.Relocation; +import ghidra.program.model.reloc.RelocationTable; import ghidra.program.model.symbol.Symbol; import ghidra.program.util.GhidraProgramUtilities; -import ghidra.service.graph.AttributedEdge; -import ghidra.service.graph.AttributedGraph; -import ghidra.service.graph.AttributedVertex; -import ghidra.service.graph.GraphDisplay; -import ghidra.service.graph.GraphDisplayOptions; -import ghidra.service.graph.GraphDisplayOptionsBuilder; -import ghidra.service.graph.GraphDisplayProvider; -import ghidra.service.graph.GraphType; -import ghidra.service.graph.GraphTypeBuilder; -import ghidra.service.graph.VertexShape; +import ghidra.service.graph.*; import ghidra.util.exception.CancelledException; import ghidra.util.exception.GraphException; import ghidra.util.task.TaskMonitor; @@ -184,16 +161,16 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { @Override public void run() throws Exception { - + String errorMsg = validate(); - + if (!errorMsg.isEmpty()) { println(errorMsg); return; } - + if (!isGcc() && isWindows()) { - + if (!isRttiAnalyzed()) { println("Running the RTTIAnalyzer..."); analysisMode = AnalysisMode.ENABLED; @@ -218,8 +195,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols, monitor); } - else if (isPE() && isGcc()){ - + else if (isPE() && isGcc()) { + println("Program is a gcc compiled PE."); boolean runGcc; @@ -250,7 +227,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } else { 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."); + "I understand that Gcc class recovery is still under development and my results will be incomplete but want to run this anyway."); } if (!runGcc) { @@ -439,26 +416,54 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (defaultPointerSize != 4 && defaultPointerSize != 8) { return ("This script only works on 32 or 64 bit programs"); } - + // check that gcc loader or mingw analyzer has fixed the relocations correctly - if(isGcc()) { + if (isGcc()) { // first check that there is even rtti by searching the special string in memory if (!isStringInProgramMemory("class_type_info")) { return ("This program does not contain RTTI."); } - + // then check to see if the special typeinfo namespace is in external space // if so then relocations are present and have not been fixed up because when fixed up // the namespace gets moved to inside program space - if(isExternalNamespace("__cxxabiv1::__class_type_info")) { + if (isExternalNamespace("__cxxabiv1::__class_type_info")) { return ("This program's relocations were not correctly fixed so the script cannot " + - "continue. If this program is mingw this is a known issue and " + - "will be fixed in a later release. For all other gcc programs please " + - "contact the Ghidra team so this issue can be fixed."); + "continue. If this program is mingw this is a known issue and " + + "will be fixed in a later release. For all other gcc programs please " + + "contact the Ghidra team so this issue can be fixed."); + } + + if (hasUnhandledRelocations()) { + return ("This program has unhandled elf relocations so cannot continue. Please " + + "contact the Ghidra team for assistance."); } } + return new String(); + + } + + private boolean hasUnhandledRelocations() throws CancelledException { + + RelocationTable relocationTable = currentProgram.getRelocationTable(); + + Iterator relocations = relocationTable.getRelocations(); + + while (relocations.hasNext()) { + monitor.checkCancelled(); + Relocation r = relocations.next(); + + if (r.getSymbolName().contains("class_type_info") && + (r.getStatus() != Relocation.Status.APPLIED && + r.getStatus() != Relocation.Status.APPLIED_OTHER && + r.getStatus() != Relocation.Status.SKIPPED)) { + return true; + } + + } + return false; } private void analyzeProgramChanges(AddressSetView beforeChanges) throws Exception { @@ -641,18 +646,17 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } return false; } - - + /** * Method to check if executable format is PE */ private boolean isPE() { - + if (!PeLoader.PE_NAME.equals(currentProgram.getExecutableFormat())) { return false; } return true; - + } /** @@ -669,9 +673,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (isCompilerSpecGcc) { return true; } - + String compiler = currentProgram.getCompiler(); - if(compiler != null && compiler.contains("gcc")) { + if (compiler != null && compiler.contains("gcc")) { return true; } @@ -700,7 +704,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return isGcc; } - /** * Method to set the global variable isWindows @@ -1575,7 +1578,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return stringBuffer; } - + private boolean isStringInProgramMemory(String string) { byte[] byteArrray = string.getBytes(); @@ -1587,19 +1590,19 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } return false; } - + private boolean isExternalNamespace(String path) throws CancelledException { - + List symbols = NamespaceUtils.getSymbols(path, currentProgram, true); - for(Symbol symbol : symbols) { + for (Symbol symbol : symbols) { monitor.checkCancelled(); - if(symbol.isExternal() && symbol.getSymbolType().isNamespace()) { + if (symbol.isExternal() && symbol.getSymbolType().isNamespace()) { return true; } } - - return false; - } + + return false; + } }