mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-1104 - Fix PDB CLI bug for older imports without FileBytes
This commit is contained in:
parent
a80f046161
commit
fd2b5dadec
2 changed files with 90 additions and 19 deletions
|
@ -439,6 +439,23 @@ public class PdbApplicator {
|
||||||
Msg.info(originator, message);
|
Msg.info(originator, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts error message to {@link PdbLog} and to Msg.error() which will
|
||||||
|
* also log a stack trace if exception is specified.
|
||||||
|
* @param originator a Logger instance, "this", or YourClass.class
|
||||||
|
* @param message the error message to display/log
|
||||||
|
* @param exc exception whose stack trace should be reported or null
|
||||||
|
*/
|
||||||
|
void pdbLogAndErrorMessage(Object originator, String message, Exception exc) {
|
||||||
|
PdbLog.message(message);
|
||||||
|
if (exc != null) {
|
||||||
|
Msg.error(originator, message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.error(originator, message, exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link TaskMonitor} to available for this analyzer.
|
* Returns the {@link TaskMonitor} to available for this analyzer.
|
||||||
* @return the monitor.
|
* @return the monitor.
|
||||||
|
@ -928,6 +945,7 @@ public class PdbApplicator {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// CLI-Managed infor methods.
|
// CLI-Managed infor methods.
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
|
||||||
// Currently in CLI, but could move.
|
// Currently in CLI, but could move.
|
||||||
boolean isDll() {
|
boolean isDll() {
|
||||||
return pdbCliManagedInfoManager.isDll();
|
return pdbCliManagedInfoManager.isDll();
|
||||||
|
@ -938,6 +956,15 @@ public class PdbApplicator {
|
||||||
return pdbCliManagedInfoManager.isAslr();
|
return pdbCliManagedInfoManager.isAslr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get CLI metadata for specified tableNum and rowNum within the CLI
|
||||||
|
* metadata stream.
|
||||||
|
* @param tableNum CLI metadata stream table index
|
||||||
|
* @param rowNum table row number
|
||||||
|
* @return CLI metadata or null if specified tableNum not found
|
||||||
|
* @throws PdbException if CLI metadata stream is not found in program file bytes
|
||||||
|
* @throws IndexOutOfBoundsException if specified rowNum is invalid
|
||||||
|
*/
|
||||||
CliAbstractTableRow getCliTableRow(int tableNum, int rowNum) throws PdbException {
|
CliAbstractTableRow getCliTableRow(int tableNum, int rowNum) throws PdbException {
|
||||||
return pdbCliManagedInfoManager.getCliTableRow(tableNum, rowNum);
|
return pdbCliManagedInfoManager.getCliTableRow(tableNum, rowNum);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@ import ghidra.program.model.listing.Program;
|
||||||
*/
|
*/
|
||||||
public class PdbCliInfoManager {
|
public class PdbCliInfoManager {
|
||||||
|
|
||||||
|
private PdbApplicator applicator;
|
||||||
|
|
||||||
|
private boolean initComplete = false;
|
||||||
private CliStreamMetadata metadataStream;
|
private CliStreamMetadata metadataStream;
|
||||||
|
|
||||||
// TODO: May move these out from this class to a higher level. Would mean passing in
|
// TODO: May move these out from this class to a higher level. Would mean passing in
|
||||||
|
@ -46,22 +49,43 @@ public class PdbCliInfoManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manager of CLI-related tables that we might need access to for PDB processing.
|
* Manager of CLI-related tables that we might need access to for PDB processing.
|
||||||
* @param applicator {@link PdbApplicator} for which this class is working.
|
* @param applicator {@link PdbApplicator} for which this class is working (used for logging purposes only).
|
||||||
*/
|
*/
|
||||||
PdbCliInfoManager(PdbApplicator applicator) {
|
PdbCliInfoManager(PdbApplicator applicator) {
|
||||||
Objects.requireNonNull(applicator, "applicator may not be null");
|
Objects.requireNonNull(applicator, "applicator may not be null");
|
||||||
metadataStream = getCliStreamMetadata(applicator);
|
this.applicator = applicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void initialize() {
|
||||||
|
if (initComplete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
initComplete = true;
|
||||||
|
metadataStream = getCliStreamMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isDll() {
|
boolean isDll() {
|
||||||
|
initialize();
|
||||||
return isDll;
|
return isDll;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isAslr() {
|
boolean isAslr() {
|
||||||
|
initialize();
|
||||||
return isAslr;
|
return isAslr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CliAbstractTableRow getCliTableRow(int tableNum, int rowNum) throws PdbException {
|
/**
|
||||||
|
* Get CLI metadata for specified tableNum and rowNum within the CLI
|
||||||
|
* metadata stream.
|
||||||
|
* @param tableNum CLI metadata stream table index
|
||||||
|
* @param rowNum table row number
|
||||||
|
* @return CLI metadata or null if specified tableNum not found
|
||||||
|
* @throws PdbException if CLI metadata stream is not found in program file bytes
|
||||||
|
* @throws IndexOutOfBoundsException if specified rowNum is invalid
|
||||||
|
*/
|
||||||
|
CliAbstractTableRow getCliTableRow(int tableNum, int rowNum)
|
||||||
|
throws PdbException, IndexOutOfBoundsException {
|
||||||
|
initialize();
|
||||||
if (metadataStream == null) {
|
if (metadataStream == null) {
|
||||||
throw new PdbException("CliStreamMetadata is null");
|
throw new PdbException("CliStreamMetadata is null");
|
||||||
}
|
}
|
||||||
|
@ -72,21 +96,34 @@ public class PdbCliInfoManager {
|
||||||
return table.getRow(rowNum);
|
return table.getRow(rowNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CliStreamMetadata getCliStreamMetadata(PdbApplicator applicator) {
|
/**
|
||||||
|
* Get CLI stream metadata
|
||||||
|
* @return CLI stream metadata or null if not found or error occured
|
||||||
|
*/
|
||||||
|
private CliStreamMetadata getCliStreamMetadata() {
|
||||||
Program program = applicator.getProgram();
|
Program program = applicator.getProgram();
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<FileBytes> allFileBytes = program.getMemory().getAllFileBytes();
|
List<FileBytes> allFileBytes = program.getMemory().getAllFileBytes();
|
||||||
|
if (allFileBytes.isEmpty()) {
|
||||||
|
applicator.pdbLogAndErrorMessage(this,
|
||||||
|
"Unable to retrieve CliStreamMetadata: no FileBytes", null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
FileBytes fileBytes = allFileBytes.get(0); // Should be that of main imported file
|
FileBytes fileBytes = allFileBytes.get(0); // Should be that of main imported file
|
||||||
ByteProvider provider = new FileBytesProvider(fileBytes);
|
ByteProvider provider = new FileBytesProvider(fileBytes); // close not required
|
||||||
PortableExecutable pe = null;
|
|
||||||
try {
|
try {
|
||||||
GenericFactory factory = MessageLogContinuesFactory.create(applicator.getMessageLog());
|
GenericFactory factory = MessageLogContinuesFactory.create(applicator.getMessageLog());
|
||||||
pe = PortableExecutable.createPortableExecutable(factory, provider, SectionLayout.FILE,
|
PortableExecutable pe = PortableExecutable.createPortableExecutable(factory, provider,
|
||||||
true, true);
|
SectionLayout.FILE, true, true);
|
||||||
NTHeader ntHeader = pe.getNTHeader();
|
NTHeader ntHeader = pe.getNTHeader(); // will be null if header parse fails
|
||||||
|
if (ntHeader == null) {
|
||||||
|
applicator.pdbLogAndErrorMessage(this,
|
||||||
|
"Unable to retrieve CliStreamMetadata: NTHeader file bytes not found", null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
OptionalHeader optionalHeader = ntHeader.getOptionalHeader();
|
OptionalHeader optionalHeader = ntHeader.getOptionalHeader();
|
||||||
int characteristics = ntHeader.getFileHeader().getCharacteristics();
|
int characteristics = ntHeader.getFileHeader().getCharacteristics();
|
||||||
isDll = (characteristics & FileHeader.IMAGE_FILE_DLL) == FileHeader.IMAGE_FILE_DLL;
|
isDll = (characteristics & FileHeader.IMAGE_FILE_DLL) == FileHeader.IMAGE_FILE_DLL;
|
||||||
|
@ -94,25 +131,32 @@ public class PdbCliInfoManager {
|
||||||
int optionalHeaderCharaceristics = optionalHeader.getDllCharacteristics();
|
int optionalHeaderCharaceristics = optionalHeader.getDllCharacteristics();
|
||||||
isAslr = (optionalHeaderCharaceristics &
|
isAslr = (optionalHeaderCharaceristics &
|
||||||
OptionalHeader.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) == OptionalHeader.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA;
|
OptionalHeader.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) == OptionalHeader.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA;
|
||||||
|
if (OptionalHeader.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR >= dataDirectory.length) {
|
||||||
|
applicator.pdbLogAndErrorMessage(this,
|
||||||
|
"Unable to retrieve CliStreamMetadata: Bad index (" +
|
||||||
|
OptionalHeader.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR +
|
||||||
|
") for COMDescriptorDataDirectory in DataDirectory array of size " +
|
||||||
|
dataDirectory.length,
|
||||||
|
null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
COMDescriptorDataDirectory comDir =
|
COMDescriptorDataDirectory comDir =
|
||||||
(COMDescriptorDataDirectory) dataDirectory[OptionalHeader.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
|
(COMDescriptorDataDirectory) dataDirectory[OptionalHeader.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
|
||||||
ImageCor20Header header = comDir.getHeader();
|
ImageCor20Header header = comDir.getHeader();
|
||||||
if (header == null) {
|
if (header == null) {
|
||||||
|
applicator.pdbLogAndErrorMessage(this,
|
||||||
|
"Unable to retrieve CliStreamMetadata: no COMDir header", null);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return header.getMetadata().getMetadataRoot().getMetadataStream();
|
return header.getMetadata().getMetadataRoot().getMetadataStream();
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (RuntimeException | IOException e) {
|
||||||
applicator.pdbLogAndInfoMessage(this, "Unable to retrieve CliStreamMetadata");
|
// We do not know what can go wrong. Some of the header parsing might have issues,
|
||||||
|
// and we'd rather log the error and limp on by with whatever other processing we can
|
||||||
|
// do than to fail here.
|
||||||
|
applicator.pdbLogAndErrorMessage(this,
|
||||||
|
"Unable to retrieve CliStreamMetadata: " + e.getMessage(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
try {
|
|
||||||
provider.close();
|
|
||||||
}
|
|
||||||
catch (IOException ioe) {
|
|
||||||
applicator.pdbLogAndInfoMessage(this, "Problem closing ByteProvider");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue