GP-1055 Improvements to prototype RecoverClassesFromRTTIScript for stripped gcc binaries including improved finding and creating of virtual tables, some constructor/destructor determination, and improved class data creation.

This commit is contained in:
ghidra007 2021-07-30 18:50:08 -04:00
parent 19fa121b30
commit 6d5f30f448
9 changed files with 1160 additions and 574 deletions

View file

@ -63,6 +63,8 @@ import ghidra.app.plugin.core.analysis.DecompilerFunctionAnalyzer;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.services.Analyzer; import ghidra.app.services.Analyzer;
import ghidra.app.services.GraphDisplayBroker; import ghidra.app.services.GraphDisplayBroker;
import ghidra.app.util.bin.format.dwarf4.next.DWARFFunctionImporter;
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
import ghidra.app.util.bin.format.pdb.PdbParserConstants; import ghidra.app.util.bin.format.pdb.PdbParserConstants;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
@ -127,7 +129,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
private static final String INDETERMINATE_BOOKMARK = "INDETERMINATE"; private static final String INDETERMINATE_BOOKMARK = "INDETERMINATE";
boolean programHasRTTIApplied = false; boolean programHasRTTIApplied = false;
boolean isPDBLoaded; boolean hasDebugSymbols;
boolean isGcc = false; boolean isGcc = false;
boolean isWindows = false; boolean isWindows = false;
String ghidraVersion = null; String ghidraVersion = null;
@ -155,11 +157,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
if (isWindows()) { if (isWindows()) {
isPDBLoaded = isPDBLoadedInProgram(); hasDebugSymbols = isPDBLoadedInProgram();
nameVfunctions = !isPDBLoaded; nameVfunctions = !hasDebugSymbols;
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram, recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram,
currentLocation, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS, currentLocation, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, isPDBLoaded, monitor); USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
monitor);
} }
else if (isGcc()) { else if (isGcc()) {
@ -168,10 +171,18 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
if (!runGcc) { if (!runGcc) {
return; return;
} }
nameVfunctions = true;
hasDebugSymbols = isDwarfLoadedInProgram();
if (hasDwarf() && !hasDebugSymbols) {
println(
"The program contains DWARF but the DWARF analyzer has not been run. Please run the DWARF analyzer to get best results from this script.");
return;
}
nameVfunctions = !hasDebugSymbols;
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation, recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation,
state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, monitor); USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
monitor);
} }
else { else {
println("This script will not work on this program type"); println("This script will not work on this program type");
@ -245,7 +256,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
" class member functions to assign."); " class member functions to assign.");
if (!isPDBLoaded) { if (!hasDebugSymbols) {
if (BOOKMARK_FOUND_FUNCTIONS) { if (BOOKMARK_FOUND_FUNCTIONS) {
bookmarkFunctions(recoveredClasses); bookmarkFunctions(recoveredClasses);
@ -268,6 +279,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
decompilerUtils.disposeDecompilerInterface(); decompilerUtils.disposeDecompilerInterface();
} }
private boolean hasDwarf() {
return DWARFProgram.isDWARF(currentProgram);
}
/** /**
* Method to determine if pdb info has been applied to the program * Method to determine if pdb info has been applied to the program
* @return true if pdb info has been applied to program * @return true if pdb info has been applied to program
@ -277,6 +292,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return options.getBoolean(PdbParserConstants.PDB_LOADED, false); return options.getBoolean(PdbParserConstants.PDB_LOADED, false);
} }
private boolean isDwarfLoadedInProgram() {
return DWARFFunctionImporter.hasDWARFProgModule(currentProgram,
DWARFProgram.DWARF_ROOT_NAME);
}
public String validate() { public String validate() {
if (currentProgram == null) { if (currentProgram == null) {
@ -454,8 +475,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
/** /**
* Script only works on versions of ghidra after 9.2, but not 9.2.1 because a method was * Script works on versions of ghidra including and after 9.2 except for 9.2.1 because a method
* accidentally removed from FillOutStructureCmd that is needed * was accidentally removed from FillOutStructureCmd that is needed
* @return true if script will work and false otherwise * @return true if script will work and false otherwise
*/ */
private boolean checkGhidraVersion() { private boolean checkGhidraVersion() {
@ -571,9 +592,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
private String getVersionOfGhidra() { private String getVersionOfGhidra() {
Options options = currentProgram.getOptions("Program Information"); Options options = currentProgram.getOptions("Program Information");
Object ghidraVersionObject = options.getObject("Created With Ghidra Version", null); return options.getString("Created With Ghidra Version", null);
return ghidraVersionObject.toString();
} }

View file

@ -1,19 +1,3 @@
/* ###
* 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.
*/
package classrecovery;
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* *
@ -30,6 +14,7 @@ package classrecovery;
* limitations under the License. * limitations under the License.
*/ */
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
package classrecovery;
import ghidra.app.decompiler.*; import ghidra.app.decompiler.*;
import ghidra.framework.options.ToolOptions; import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;

View file

@ -1,19 +1,3 @@
/* ###
* 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.
*/
package classrecovery;
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* *
@ -30,6 +14,8 @@ package classrecovery;
* limitations under the License. * limitations under the License.
*/ */
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. //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.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
@ -347,6 +333,10 @@ public class EditStructureUtils {
public int getNumberOfUndefinedsBeforeOffset(Structure structure, int offset, public int getNumberOfUndefinedsBeforeOffset(Structure structure, int offset,
TaskMonitor monitor) throws CancelledException { TaskMonitor monitor) throws CancelledException {
if (structure.getNumComponents() == 0) {
return -1;
}
int numUndefineds = 0; int numUndefineds = 0;
int index = offset - 1; int index = offset - 1;

View file

@ -13,23 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
package classrecovery; package classrecovery;
/* ###
* 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.
import java.util.*; import java.util.*;
import ghidra.app.cmd.function.CreateFunctionCmd; import ghidra.app.cmd.function.CreateFunctionCmd;
@ -110,8 +96,8 @@ public class ExtraScriptUtils extends FlatProgramAPI {
return null; return null;
} }
Address possibleFunctionPointer = address.getNewAddress(offset); Address possiblePointer = address.getNewAddress(offset);
return possibleFunctionPointer; return possiblePointer;
} }
catch (MemoryAccessException e) { catch (MemoryAccessException e) {
@ -686,6 +672,11 @@ public class ExtraScriptUtils extends FlatProgramAPI {
public boolean doesFunctionACallAnyListedFunction(Function aFunction, List<Function> bFunctions) public boolean doesFunctionACallAnyListedFunction(Function aFunction, List<Function> bFunctions)
throws CancelledException { throws CancelledException {
if (aFunction == null) {
return false;
}
Iterator<Function> bFunctionsIterator = bFunctions.iterator(); Iterator<Function> bFunctionsIterator = bFunctions.iterator();
while (bFunctionsIterator.hasNext()) { while (bFunctionsIterator.hasNext()) {
monitor.checkCanceled(); monitor.checkCanceled();
@ -798,6 +789,14 @@ public class ExtraScriptUtils extends FlatProgramAPI {
public boolean doesFunctionACallFunctionB(Function aFunction, Function bFunction) public boolean doesFunctionACallFunctionB(Function aFunction, Function bFunction)
throws CancelledException { throws CancelledException {
if (aFunction == null) {
return false;
}
if (bFunction == null) {
return false;
}
Set<Function> calledFunctions = aFunction.getCalledFunctions(monitor); Set<Function> calledFunctions = aFunction.getCalledFunctions(monitor);
if (calledFunctions.contains(bFunction)) { if (calledFunctions.contains(bFunction)) {
return true; return true;

View file

@ -1,19 +1,3 @@
/* ###
* 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.
*/
package classrecovery;
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* *
@ -30,6 +14,8 @@ package classrecovery;
* limitations under the License. * limitations under the License.
*/ */
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. //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.*;
import ghidra.app.util.NamespaceUtils; import ghidra.app.util.NamespaceUtils;
@ -52,10 +38,11 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
String ghidraVersion; String ghidraVersion;
Program program; Program program;
TaskMonitor monitor; TaskMonitor monitor;
boolean hasDebugSymbols;
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool, RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, boolean nameVfunctions, boolean hasDebugSymbols,
TaskMonitor monitor) { TaskMonitor monitor) {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions, super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
@ -69,6 +56,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
this.createBookmarks = createBookmarks; this.createBookmarks = createBookmarks;
this.useShortTemplates = useShortTemplates; this.useShortTemplates = useShortTemplates;
this.nameVfunctions = nameVfunctions; this.nameVfunctions = nameVfunctions;
this.hasDebugSymbols = hasDebugSymbols;
ghidraVersion = getVersionOfGhidra(); ghidraVersion = getVersionOfGhidra();
} }
@ -109,9 +97,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
public String getVersionOfGhidra() { public String getVersionOfGhidra() {
Options options = program.getOptions("Program Information"); Options options = program.getOptions("Program Information");
Object ghidraVersionObject = options.getObject("Created With Ghidra Version", null); return options.getString("Created With Ghidra Version", null);
return ghidraVersionObject.toString();
} }

View file

@ -13,23 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
package classrecovery; package classrecovery;
/* ###
* 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.
import java.util.*; import java.util.*;
import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd; import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd;
@ -89,7 +75,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
TaskMonitor monitor) throws CancelledException { TaskMonitor monitor) throws CancelledException {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions, super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions,
monitor); isPDBLoaded, monitor);
this.isPDBLoaded = isPDBLoaded; this.isPDBLoaded = isPDBLoaded;

View file

@ -1,19 +1,3 @@
/* ###
* 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.
*/
package classrecovery;
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* *
@ -30,6 +14,8 @@ package classrecovery;
* limitations under the License. * limitations under the License.
*/ */
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. //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.*;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -97,6 +83,7 @@ public class RecoveredClass {
private boolean inheritsVirtualAncestor = false; private boolean inheritsVirtualAncestor = false;
private boolean isPublicClass = false; private boolean isPublicClass = false;
private boolean isDiamondShaped = false;
private Structure existingClassStructure = null; private Structure existingClassStructure = null;
private Structure computedClassStructure = null; private Structure computedClassStructure = null;
@ -283,6 +270,14 @@ public class RecoveredClass {
return isPublicClass; return isPublicClass;
} }
public void setIsDiamondShaped(boolean setting) {
isDiamondShaped = setting;
}
public boolean isDiamondShaped() {
return isDiamondShaped;
}
public void setHasVftable(boolean setting) { public void setHasVftable(boolean setting) {
hasVftable = setting; hasVftable = setting;
} }

View file

@ -1,19 +1,3 @@
/* ###
* 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.
*/
package classrecovery;
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* *
@ -30,6 +14,8 @@ package classrecovery;
* limitations under the License. * limitations under the License.
*/ */
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. //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.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -1512,7 +1498,7 @@ public class RecoveredClassUtils {
/** /**
* Method to get ancestors that do not have vfunctions * Method to get ancestors that do not have vfunctions
* @param recoveredClass the given class * @param recoveredClass the given class
* @return true if any of the given class's ancestors are inherited virtually, false otherwise * @return List of ancestors without vfunctions
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
*/ */
public List<RecoveredClass> getAncestorsWithoutVfunctions(RecoveredClass recoveredClass) public List<RecoveredClass> getAncestorsWithoutVfunctions(RecoveredClass recoveredClass)
@ -2772,7 +2758,6 @@ public class RecoveredClassUtils {
} }
// add it to the vftableAddress to Class map // add it to the vftableAddress to Class map
//vftableToClassMap.put(vftableAddress, recoveredClass);
updateVftableToClassMap(vftableAddress, recoveredClass); updateVftableToClassMap(vftableAddress, recoveredClass);
List<Address> referencesToVftable = getReferencesToVftable(vftableAddress); List<Address> referencesToVftable = getReferencesToVftable(vftableAddress);