GP-4371 Added check to RecoverClassesFromRTTIScript to not run when there are unhandled relocations.

This commit is contained in:
ghidra007 2024-03-04 18:23:46 +00:00
parent 59a048fdf2
commit fd8fcebe09

View file

@ -54,18 +54,10 @@
import java.io.File; import java.io.File;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import classrecovery.DecompilerScriptUtils; import classrecovery.*;
import classrecovery.RTTIClassRecoverer;
import classrecovery.RTTIGccClassRecoverer;
import classrecovery.RTTIWindowsClassRecoverer;
import classrecovery.RecoveredClass;
import classrecovery.RecoveredClassHelper;
import generic.theme.GThemeDefaults.Colors.Palette; import generic.theme.GThemeDefaults.Colors.Palette;
import ghidra.app.decompiler.DecompInterface; import ghidra.app.decompiler.DecompInterface;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager; 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.app.util.opinion.PeLoader;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.data.*;
import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.*;
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.mem.MemoryBlock; 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.model.symbol.Symbol;
import ghidra.program.util.GhidraProgramUtilities; import ghidra.program.util.GhidraProgramUtilities;
import ghidra.service.graph.AttributedEdge; import ghidra.service.graph.*;
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.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.GraphException; import ghidra.util.exception.GraphException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -184,16 +161,16 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
@Override @Override
public void run() throws Exception { public void run() throws Exception {
String errorMsg = validate(); String errorMsg = validate();
if (!errorMsg.isEmpty()) { if (!errorMsg.isEmpty()) {
println(errorMsg); println(errorMsg);
return; return;
} }
if (!isGcc() && isWindows()) { if (!isGcc() && isWindows()) {
if (!isRttiAnalyzed()) { if (!isRttiAnalyzed()) {
println("Running the RTTIAnalyzer..."); println("Running the RTTIAnalyzer...");
analysisMode = AnalysisMode.ENABLED; analysisMode = AnalysisMode.ENABLED;
@ -218,8 +195,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, monitor); nameVfunctions, hasDebugSymbols, monitor);
} }
else if (isPE() && isGcc()){ else if (isPE() && isGcc()) {
println("Program is a gcc compiled PE."); println("Program is a gcc compiled PE.");
boolean runGcc; boolean runGcc;
@ -250,7 +227,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
else { else {
runGcc = askYesNo("Gcc Class Recovery Still Under Development", 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) { if (!runGcc) {
@ -439,26 +416,54 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
if (defaultPointerSize != 4 && defaultPointerSize != 8) { if (defaultPointerSize != 4 && defaultPointerSize != 8) {
return ("This script only works on 32 or 64 bit programs"); return ("This script only works on 32 or 64 bit programs");
} }
// check that gcc loader or mingw analyzer has fixed the relocations correctly // 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 // first check that there is even rtti by searching the special string in memory
if (!isStringInProgramMemory("class_type_info")) { if (!isStringInProgramMemory("class_type_info")) {
return ("This program does not contain RTTI."); return ("This program does not contain RTTI.");
} }
// then check to see if the special typeinfo namespace is in external space // 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 // if so then relocations are present and have not been fixed up because when fixed up
// the namespace gets moved to inside program space // 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 " + 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 " + "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 " + "will be fixed in a later release. For all other gcc programs please " +
"contact the Ghidra team so this issue can be fixed."); "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(); return new String();
}
private boolean hasUnhandledRelocations() throws CancelledException {
RelocationTable relocationTable = currentProgram.getRelocationTable();
Iterator<Relocation> 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 { private void analyzeProgramChanges(AddressSetView beforeChanges) throws Exception {
@ -641,18 +646,17 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
return false; return false;
} }
/** /**
* Method to check if executable format is PE * Method to check if executable format is PE
*/ */
private boolean isPE() { private boolean isPE() {
if (!PeLoader.PE_NAME.equals(currentProgram.getExecutableFormat())) { if (!PeLoader.PE_NAME.equals(currentProgram.getExecutableFormat())) {
return false; return false;
} }
return true; return true;
} }
/** /**
@ -669,9 +673,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
if (isCompilerSpecGcc) { if (isCompilerSpecGcc) {
return true; return true;
} }
String compiler = currentProgram.getCompiler(); String compiler = currentProgram.getCompiler();
if(compiler != null && compiler.contains("gcc")) { if (compiler != null && compiler.contains("gcc")) {
return true; return true;
} }
@ -700,7 +704,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return isGcc; return isGcc;
} }
/** /**
* Method to set the global variable isWindows * Method to set the global variable isWindows
@ -1575,7 +1578,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return stringBuffer; return stringBuffer;
} }
private boolean isStringInProgramMemory(String string) { private boolean isStringInProgramMemory(String string) {
byte[] byteArrray = string.getBytes(); byte[] byteArrray = string.getBytes();
@ -1587,19 +1590,19 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
} }
return false; return false;
} }
private boolean isExternalNamespace(String path) throws CancelledException { private boolean isExternalNamespace(String path) throws CancelledException {
List<Symbol> symbols = NamespaceUtils.getSymbols(path, currentProgram, true); List<Symbol> symbols = NamespaceUtils.getSymbols(path, currentProgram, true);
for(Symbol symbol : symbols) { for (Symbol symbol : symbols) {
monitor.checkCancelled(); monitor.checkCancelled();
if(symbol.isExternal() && symbol.getSymbolType().isNamespace()) { if (symbol.isExternal() && symbol.getSymbolType().isNamespace()) {
return true; return true;
} }
} }
return false; return false;
} }
} }