mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-10-23 05:31:02 +00:00
GP-4625 - Modify dev PDB Dump script and add scripts to dump PDB mangled names; realign mangled name for complex type hierarchy
This commit is contained in:
parent
a29a59488a
commit
cb3a6ced93
|
@ -0,0 +1,166 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
// Dump PDB mangled symbol names for PDB developer use
|
||||
//
|
||||
//@category PDB
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import docking.widgets.values.GValuesMap;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
|
||||
import ghidra.app.util.pdb.pdbapplicator.SymbolGroup;
|
||||
import ghidra.features.base.values.GhidraValuesMap;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
public class PdbDeveloperDumpMangledSymbolNamesScript extends GhidraScript {
|
||||
|
||||
private static final String TITLE = "Dump PDB Mangled Symbol Names";
|
||||
private static final String PDB_PROMPT = "Choose a PDB file";
|
||||
private static final String OUTPUT_PROMPT = "Choose an output file";
|
||||
|
||||
private static boolean validatePdb(GValuesMap valueMap, StatusListener status) {
|
||||
File file = valueMap.getFile(PDB_PROMPT);
|
||||
if (file == null) {
|
||||
status.setStatusText("PDB file must be selected.", MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
if (!file.exists()) {
|
||||
status.setStatusText(file.getAbsolutePath() + " is not a valid file.",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
String fileName = file.getAbsolutePath();
|
||||
if (!fileName.endsWith(".pdb") && !fileName.endsWith(".PDB")) {
|
||||
status.setStatusText("Expected .pdb file extenstion (got '" + fileName + "').",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
// We do not need to check the existence of an image base because we provide a default
|
||||
// value
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean validateOutput(GValuesMap valueMap, StatusListener status) {
|
||||
File file = valueMap.getFile(OUTPUT_PROMPT);
|
||||
// File will exist, as we supplied a default value
|
||||
String fileName = file.getAbsolutePath();
|
||||
if (fileName.endsWith(".pdb") || fileName.endsWith(".PDB")) {
|
||||
status.setStatusText("Output file may not end with .pdb (got '" + fileName + "').",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
|
||||
GhidraValuesMap values = new GhidraValuesMap();
|
||||
|
||||
values.defineFile(PDB_PROMPT, null);
|
||||
values.setValidator((valueMap, status) -> {
|
||||
return validatePdb(valueMap, status);
|
||||
});
|
||||
values = askValues(TITLE, null, values);
|
||||
File pdbFile = values.getFile(PDB_PROMPT);
|
||||
String pdbFileName = pdbFile.getAbsolutePath();
|
||||
|
||||
// creating a default output and asking again; PDB file should retain its current value
|
||||
// from above
|
||||
String outputFileName = pdbFileName + ".MangledSymbolNames.txt";
|
||||
values.defineFile(OUTPUT_PROMPT, new File(outputFileName));
|
||||
values.setValidator((valueMap, status) -> {
|
||||
return validatePdb(valueMap, status) && validateOutput(valueMap, status);
|
||||
});
|
||||
values = askValues(TITLE, null, values);
|
||||
pdbFile = values.getFile(PDB_PROMPT); // might have changed
|
||||
pdbFileName = pdbFile.getAbsolutePath(); // might have changed
|
||||
File dumpFile = values.getFile(OUTPUT_PROMPT);
|
||||
|
||||
if (dumpFile.exists()) {
|
||||
if (!askYesNo("Confirm Overwrite", "Overwrite file: " + dumpFile.getName())) {
|
||||
Msg.info(this, "Operation canceled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String message = "Processing PDB Dump of: " + pdbFileName;
|
||||
monitor.setMessage(message);
|
||||
Msg.info(this, message);
|
||||
try (AbstractPdb pdb = PdbParser.parse(pdbFile, new PdbReaderOptions(), monitor)) {
|
||||
pdb.deserialize();
|
||||
FileWriter fileWriter = new FileWriter(dumpFile);
|
||||
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
|
||||
dumpMangledSymbolNames(pdb, bufferedWriter);
|
||||
bufferedWriter.close();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
Msg.info(this, ioe.getMessage());
|
||||
popup(ioe.getMessage());
|
||||
}
|
||||
message = "Results located in: " + dumpFile.getAbsoluteFile();
|
||||
monitor.setMessage(message);
|
||||
Msg.info(this, message);
|
||||
}
|
||||
|
||||
private void dumpMangledSymbolNames(AbstractPdb pdb, Writer myWriter)
|
||||
throws PdbException, CancelledException, IOException {
|
||||
|
||||
PdbDebugInfo debugInfo = pdb.getDebugInfo();
|
||||
if (debugInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int num = debugInfo.getNumModules();
|
||||
for (int moduleNumber = 0; moduleNumber <= num; moduleNumber++) {
|
||||
monitor.checkCancelled();
|
||||
SymbolGroup symbolGroup = new SymbolGroup(pdb, moduleNumber);
|
||||
MsSymbolIterator iter = symbolGroup.getSymbolIterator();
|
||||
dumpIteratedMangledSymbolNames(iter, myWriter);
|
||||
}
|
||||
}
|
||||
|
||||
private void dumpIteratedMangledSymbolNames(MsSymbolIterator iter, Writer myWriter)
|
||||
throws CancelledException, IOException {
|
||||
while (iter.hasNext()) {
|
||||
monitor.checkCancelled();
|
||||
AbstractMsSymbol symbol = iter.next();
|
||||
if (symbol == null) {
|
||||
throw new AssertionError("null symbol");
|
||||
}
|
||||
if (!(symbol instanceof NameMsSymbol s)) {
|
||||
continue;
|
||||
}
|
||||
if (!(symbol instanceof AbstractDataMsSymbol ||
|
||||
symbol instanceof AbstractProcedureMsSymbol ||
|
||||
symbol instanceof AbstractUserDefinedTypeMsSymbol ||
|
||||
symbol instanceof AbstractPublicMsSymbol)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = s.getName();
|
||||
if (name.contains("?") || name.contains("@") || name.contains(".")) {
|
||||
myWriter.write(name);
|
||||
myWriter.write("\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
// Dump PDB mangled type names for PDB developer use
|
||||
//
|
||||
//@category PDB
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import docking.widgets.values.GValuesMap;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractComplexMsType;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||
import ghidra.features.base.values.GhidraValuesMap;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
public class PdbDeveloperDumpMangledTypeNamesScript extends GhidraScript {
|
||||
|
||||
private static final String TITLE = "Dump PDB Mangled Type Names";
|
||||
private static final String PDB_PROMPT = "Choose a PDB file";
|
||||
private static final String OUTPUT_PROMPT = "Choose an output file";
|
||||
|
||||
private static boolean validatePdb(GValuesMap valueMap, StatusListener status) {
|
||||
File file = valueMap.getFile(PDB_PROMPT);
|
||||
if (file == null) {
|
||||
status.setStatusText("PDB file must be selected.", MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
if (!file.exists()) {
|
||||
status.setStatusText(file.getAbsolutePath() + " is not a valid file.",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
String fileName = file.getAbsolutePath();
|
||||
if (!fileName.endsWith(".pdb") && !fileName.endsWith(".PDB")) {
|
||||
status.setStatusText("Expected .pdb file extenstion (got '" + fileName + "').",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
// We do not need to check the existence of an image base because we provide a default
|
||||
// value
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean validateOutput(GValuesMap valueMap, StatusListener status) {
|
||||
File file = valueMap.getFile(OUTPUT_PROMPT);
|
||||
// File will exist, as we supplied a default value
|
||||
String fileName = file.getAbsolutePath();
|
||||
if (fileName.endsWith(".pdb") || fileName.endsWith(".PDB")) {
|
||||
status.setStatusText("Output file may not end with .pdb (got '" + fileName + "').",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
|
||||
GhidraValuesMap values = new GhidraValuesMap();
|
||||
|
||||
values.defineFile(PDB_PROMPT, null);
|
||||
values.setValidator((valueMap, status) -> {
|
||||
return validatePdb(valueMap, status);
|
||||
});
|
||||
values = askValues(TITLE, null, values);
|
||||
File pdbFile = values.getFile(PDB_PROMPT);
|
||||
String pdbFileName = pdbFile.getAbsolutePath();
|
||||
|
||||
// creating a default output and asking again; PDB file should retain its current value
|
||||
// from above
|
||||
String outputFileName = pdbFileName + ".MangledTypeNames.txt";
|
||||
values.defineFile(OUTPUT_PROMPT, new File(outputFileName));
|
||||
values.setValidator((valueMap, status) -> {
|
||||
return validatePdb(valueMap, status) && validateOutput(valueMap, status);
|
||||
});
|
||||
values = askValues(TITLE, null, values);
|
||||
pdbFile = values.getFile(PDB_PROMPT); // might have changed
|
||||
pdbFileName = pdbFile.getAbsolutePath(); // might have changed
|
||||
File dumpFile = values.getFile(OUTPUT_PROMPT);
|
||||
|
||||
if (dumpFile.exists()) {
|
||||
if (!askYesNo("Confirm Overwrite", "Overwrite file: " + dumpFile.getName())) {
|
||||
Msg.info(this, "Operation canceled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String message = "Processing PDB Dump of: " + pdbFileName;
|
||||
Msg.info(this, message);
|
||||
try (AbstractPdb pdb = PdbParser.parse(pdbFile, new PdbReaderOptions(), monitor)) {
|
||||
pdb.deserialize();
|
||||
FileWriter fileWriter = new FileWriter(dumpFile);
|
||||
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
|
||||
dumpMangledTypeNames(pdb, bufferedWriter);
|
||||
bufferedWriter.close();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
Msg.info(this, ioe.getMessage());
|
||||
popup(ioe.getMessage());
|
||||
}
|
||||
message = "Results located in: " + dumpFile.getAbsoluteFile();
|
||||
Msg.info(this, message);
|
||||
}
|
||||
|
||||
private void dumpMangledTypeNames(AbstractPdb pdb, Writer myWriter)
|
||||
throws CancelledException, IOException {
|
||||
TypeProgramInterface tpi = pdb.getTypeProgramInterface();
|
||||
if (tpi == null) {
|
||||
return;
|
||||
}
|
||||
for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi
|
||||
.getTypeIndexMaxExclusive(); indexNumber++) {
|
||||
monitor.checkCancelled();
|
||||
RecordNumber recordNumber = RecordNumber.typeRecordNumber(indexNumber);
|
||||
AbstractMsType msType = pdb.getTypeRecord(recordNumber);
|
||||
if (msType instanceof AbstractComplexMsType type) {
|
||||
String mangled = type.getMangledName();
|
||||
if (mangled != null) {
|
||||
myWriter.write(mangled);
|
||||
myWriter.write("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@ import ghidra.util.*;
|
|||
|
||||
public class PdbDeveloperDumpScript extends GhidraScript {
|
||||
|
||||
private static final String TITLE = "PDB Dump";
|
||||
private static final String PDB_PROMPT = "Choose a PDB file";
|
||||
private static final String OUTPUT_PROMPT = "Choose an output file";
|
||||
|
||||
|
@ -73,7 +74,7 @@ public class PdbDeveloperDumpScript extends GhidraScript {
|
|||
values.setValidator((valueMap, status) -> {
|
||||
return validatePdb(valueMap, status);
|
||||
});
|
||||
values = askValues("Enter Values", null, values);
|
||||
values = askValues(TITLE, null, values);
|
||||
File pdbFile = values.getFile(PDB_PROMPT);
|
||||
String pdbFileName = pdbFile.getAbsolutePath();
|
||||
|
||||
|
@ -82,12 +83,9 @@ public class PdbDeveloperDumpScript extends GhidraScript {
|
|||
String outputFileName = pdbFileName + ".txt";
|
||||
values.defineFile(OUTPUT_PROMPT, new File(outputFileName));
|
||||
values.setValidator((valueMap, status) -> {
|
||||
if (!validatePdb(valueMap, status)) {
|
||||
return false;
|
||||
}
|
||||
return validateOutput(valueMap, status);
|
||||
return validatePdb(valueMap, status) && validateOutput(valueMap, status);
|
||||
});
|
||||
values = askValues("Enter Values", null, values);
|
||||
values = askValues(TITLE, null, values);
|
||||
pdbFile = values.getFile(PDB_PROMPT); // might have changed
|
||||
pdbFileName = pdbFile.getAbsolutePath(); // might have changed
|
||||
File dumpFile = values.getFile(OUTPUT_PROMPT);
|
||||
|
|
|
@ -32,6 +32,8 @@ public abstract class AbstractComplexMsType extends AbstractMsType {
|
|||
protected RecordNumber fieldDescriptorListRecordNumber;
|
||||
protected MsProperty property;
|
||||
protected String name;
|
||||
// Used by MsType and 19MsType; maybe by StMsType; not by 16MsType
|
||||
protected String mangledName;
|
||||
|
||||
/**
|
||||
* Constructor for this type.
|
||||
|
@ -100,6 +102,14 @@ public abstract class AbstractComplexMsType extends AbstractMsType {
|
|||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mangled name within this complex type
|
||||
* @return Mangled name
|
||||
*/
|
||||
public String getMangledName() {
|
||||
return mangledName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type name of this complex type.
|
||||
* @return Type of the complex type.
|
||||
|
|
|
@ -31,7 +31,6 @@ public abstract class AbstractCompositeMsType extends AbstractComplexMsType {
|
|||
protected RecordNumber vShapeTableRecordNumber; // Not used by union.
|
||||
//TODO: has more... guessing below
|
||||
protected BigInteger size;
|
||||
protected String mangledName; // Used by MsType (not used by 16MsType or StMsType?)
|
||||
|
||||
/**
|
||||
* Constructor for this type.
|
||||
|
@ -69,14 +68,6 @@ public abstract class AbstractCompositeMsType extends AbstractComplexMsType {
|
|||
this.vShapeTableRecordNumber = vShapeTableRecordNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mangled name within this composite.
|
||||
* @return Mangled name.
|
||||
*/
|
||||
public String getMangledName() {
|
||||
return mangledName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record number of the derived-from list of types.
|
||||
* @return Record number of the derived-from list of types.
|
||||
|
|
|
@ -37,8 +37,6 @@ public class Enum19MsType extends AbstractEnumMsType {
|
|||
|
||||
public static final int PDB_ID = 0x160b;
|
||||
|
||||
protected String mangledName;
|
||||
|
||||
/**
|
||||
* Constructor for this type.
|
||||
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||
|
@ -72,12 +70,4 @@ public class Enum19MsType extends AbstractEnumMsType {
|
|||
return PDB_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mangled name field
|
||||
* @return Mangled name.
|
||||
*/
|
||||
public String getMangledName() {
|
||||
return mangledName;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@ public class EnumMsType extends AbstractEnumMsType {
|
|||
|
||||
public static final int PDB_ID = 0x1507;
|
||||
|
||||
protected String mangledName;
|
||||
|
||||
/**
|
||||
* Constructor for this type.
|
||||
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||
|
@ -62,12 +60,4 @@ public class EnumMsType extends AbstractEnumMsType {
|
|||
return PDB_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mangled name field
|
||||
* @return Mangled name.
|
||||
*/
|
||||
public String getMangledName() {
|
||||
return mangledName;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user