mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
168 lines
5.6 KiB
Java
168 lines
5.6 KiB
Java
/* ###
|
|
* 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.MessageType;
|
|
import ghidra.util.StatusListener;
|
|
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);
|
|
});
|
|
setReusePreviousChoices(false); // false for second pass... want our default output
|
|
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())) {
|
|
println("Operation canceled");
|
|
return;
|
|
}
|
|
}
|
|
|
|
String message = "Processing PDB Dump of: " + pdbFileName;
|
|
monitor.setMessage(message);
|
|
println(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) {
|
|
println(ioe.getMessage());
|
|
popup(ioe.getMessage());
|
|
}
|
|
message = "Results located in: " + dumpFile.getAbsoluteFile();
|
|
monitor.setMessage(message);
|
|
println(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");
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|