From 34102ed146e97d1e8a155293dcf4baf65cef52a6 Mon Sep 17 00:00:00 2001 From: hasherezade Date: Mon, 29 Aug 2022 02:42:56 +0200 Subject: [PATCH] [FEATURE] Implemented parsing CodeView Info --- .../include/bearparser/pe/DebugDirWrapper.h | 48 ++++- parser/include/bearparser/pe/pe_undoc.h | 51 ++++++ parser/pe/DebugDirWrapper.cpp | 172 +++++++++++++++++- 3 files changed, 267 insertions(+), 4 deletions(-) diff --git a/parser/include/bearparser/pe/DebugDirWrapper.h b/parser/include/bearparser/pe/DebugDirWrapper.h index b29d29c6e..fbacb4a09 100644 --- a/parser/include/bearparser/pe/DebugDirWrapper.h +++ b/parser/include/bearparser/pe/DebugDirWrapper.h @@ -1,6 +1,7 @@ #pragma once #include "DataDirEntryWrapper.h" +#include "pe_undoc.h" class DebugDirWrapper : public DataDirEntryWrapper { @@ -39,9 +40,52 @@ class DebugDirWrapper : public DataDirEntryWrapper QString translateType(int type); QString translateFieldContent(size_t fieldId); -private: +protected: + BYTE* getDebugStruct(); + pe::DEBUG_RSDSI* getRDSI(); + pe::DEBUG_NB10* getNB10(); + IMAGE_DEBUG_DIRECTORY* debugDir(); - void clear() {} +friend class DebugDirCVEntryWrapper; }; + +class DebugDirCVEntryWrapper : public ExeNodeWrapper +{ +public: + // fields : + enum FieldID { + NONE = FIELD_NONE, + F_CVDBG_SIGN, + F_CVDBG_GUID, + F_CVDBG_AGE, + F_CVDBG_PDB, + FIELD_COUNTER + }; + + DebugDirCVEntryWrapper(Executable* pe, DebugDirWrapper *_parentDir) + : ExeNodeWrapper(pe, _parentDir, 0) + { + this->parentDir = _parentDir; + } + + // full structure boundaries + virtual void* getPtr(); + virtual bufsize_t getSize(); + + virtual QString getName() { return "CodeView Info"; } + virtual size_t getFieldsCount() { return getPtr() ? FIELD_COUNTER : 0; } + virtual size_t getSubFieldsCount() { return 1; } + + // specific field boundaries + virtual void* getFieldPtr(size_t fieldId, size_t subField = FIELD_NONE); + virtual QString getFieldName(size_t fieldId); + virtual Executable::addr_type containsAddrType(size_t fieldId, size_t subField) { return Executable::NOT_ADDR; } + + //this wrapper only: + QString getGuidString(); + QString getSignature(); +private: + DebugDirWrapper* parentDir; +}; diff --git a/parser/include/bearparser/pe/pe_undoc.h b/parser/include/bearparser/pe/pe_undoc.h index 23b111d1e..c41758406 100644 --- a/parser/include/bearparser/pe/pe_undoc.h +++ b/parser/include/bearparser/pe/pe_undoc.h @@ -35,6 +35,57 @@ typedef struct _IMAGE_RICH_HEADER { RICH_SIGNATURE richSign; } IMAGE_RICH_HEADER, *PIMAGE_RICH_HEADER; + +///--- + +//Debug Directory type: CodeView +#pragma pack (1) + +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +#define CV_SIGNATURE_RSDS 0x53445352 +#define CV_SIGNATURE_NB10 0x3031424E + +typedef struct _RSDSI_GUID { + DWORD Data1; + WORD Data2; + WORD Data3; + BYTE Data4[2]; + BYTE Data5[6]; +} RSDSI_GUID; + + +// CodeView header +struct CV_HEADER +{ + DWORD CvSignature; // NBxx + LONG Offset; // Always 0 for NB10 +}; + +typedef struct _DEBUG_NB10 +{ + CV_HEADER cvHdr; + DWORD Signature; // seconds since 01.01.1970 + DWORD Age; // an always-incrementing value + BYTE PdbFileName[1]; // zero terminated string with the name of the PDB file +} DEBUG_NB10, *PDEBUG_NB10; + +typedef struct _DEBUG_RSDSI +{ + /*000*/ DWORD dwSig; + /*004*/ RSDSI_GUID guidSig; + /*014*/ DWORD age; + /*018*/ BYTE szPdb[1]; + /*324*/ +} DEBUG_RSDSI, *PDEBUG_RSDSI; + +#define RSDSI_SIZE sizeof (RSDSI) + +#pragma pack () //#pragma pack (1) + + }; //namespace pe #include "../win_hdrs/poppack.h" diff --git a/parser/pe/DebugDirWrapper.cpp b/parser/pe/DebugDirWrapper.cpp index 3cb933ddd..7d2b30698 100644 --- a/parser/pe/DebugDirWrapper.cpp +++ b/parser/pe/DebugDirWrapper.cpp @@ -1,5 +1,7 @@ #include "pe/DebugDirWrapper.h" +#include +using namespace pe; /* typedef struct _IMAGE_DEBUG_DIRECTORY { DWORD Characteristics; @@ -19,16 +21,21 @@ IMAGE_DEBUG_DIRECTORY* DebugDirWrapper::debugDir() offset_t rva = getDirEntryAddress(); BYTE *ptr = m_Exe->getContentAt(rva, Executable::RVA, sizeof(IMAGE_DEBUG_DIRECTORY)); - if (ptr == NULL) return NULL; + if (!ptr) return NULL; return (IMAGE_DEBUG_DIRECTORY*) ptr; } bool DebugDirWrapper::wrap() { + if (this->getDebugStruct()) { + DebugDirCVEntryWrapper *cvWrapper = new DebugDirCVEntryWrapper(m_Exe, this); + this->entries.push_back(cvWrapper); + } return true; } + void* DebugDirWrapper::getPtr() { return debugDir(); @@ -36,7 +43,7 @@ void* DebugDirWrapper::getPtr() bufsize_t DebugDirWrapper::getSize() { - if (getPtr() == NULL) return 0; + if (!getPtr()) return 0; return sizeof(IMAGE_DEBUG_DIRECTORY); } @@ -122,3 +129,164 @@ QString DebugDirWrapper::translateFieldContent(size_t fieldId) return translateType(d->Type); } +BYTE* DebugDirWrapper::getDebugStruct() +{ + IMAGE_DEBUG_DIRECTORY* d = debugDir(); + if (d == NULL) return NULL; + if (d->Type != DT_CODEVIEW) { + return NULL; + } + offset_t rva = d->PointerToRawData; + size_t dirSize = d->SizeOfData; + return m_Exe->getContentAt(rva, Executable::RAW, dirSize); +} + +DEBUG_RSDSI* DebugDirWrapper::getRDSI() +{ + BYTE* debugStr = getDebugStruct(); + IMAGE_DEBUG_DIRECTORY* d = debugDir(); + if (!debugStr || !d) return NULL; + if (d->SizeOfData < sizeof(DEBUG_RSDSI)) { + return NULL; + } + DEBUG_RSDSI* rdsi = (DEBUG_RSDSI*)debugStr; + if (rdsi->dwSig == CV_SIGNATURE_RSDS) { + return rdsi; + } + return NULL; +} + +pe::DEBUG_NB10* DebugDirWrapper::getNB10() +{ + BYTE* debugStr = getDebugStruct(); + IMAGE_DEBUG_DIRECTORY* d = debugDir(); + if (!debugStr || !d) return NULL; + if (d->SizeOfData < sizeof(DEBUG_NB10)) { + return NULL; + } + DEBUG_NB10* nb = (DEBUG_NB10*)debugStr; + if (nb->cvHdr.CvSignature == CV_SIGNATURE_NB10) { + return nb; + } + return NULL; +} +//------------------------- + +void* DebugDirCVEntryWrapper::getPtr() +{ + DEBUG_RSDSI* rdsi = parentDir->getRDSI(); + if (rdsi) { + return rdsi; + } + return parentDir->getNB10(); +} + +bufsize_t DebugDirCVEntryWrapper::getSize() +{ + IMAGE_DEBUG_DIRECTORY* d = parentDir->debugDir(); + if (d == NULL) return 0; + return d->SizeOfData; +} + +void* DebugDirCVEntryWrapper::getFieldPtr(size_t fId, size_t subField) +{ + DEBUG_RSDSI* rdsi = parentDir->getRDSI(); + if (rdsi) { + switch (fId) { + case F_CVDBG_SIGN: return &rdsi->dwSig; + case F_CVDBG_GUID: return &rdsi->guidSig; + case F_CVDBG_AGE: return &rdsi->age; + case F_CVDBG_PDB: return &rdsi->szPdb; + } + return rdsi; + } + DEBUG_NB10* dbg = parentDir->getNB10(); + if (dbg) { + switch (fId) { + case F_CVDBG_SIGN: return &dbg->cvHdr.CvSignature; + case F_CVDBG_GUID: return &dbg->Signature; + case F_CVDBG_AGE: return &dbg->Age; + case F_CVDBG_PDB: return &dbg->PdbFileName; + } + return dbg; + } + return NULL; +} + +QString DebugDirCVEntryWrapper::getGuidString() +{ + DEBUG_RSDSI* rdsi = parentDir->getRDSI(); + if (rdsi) { + QString chunk4 = ""; + for (size_t i = 0; i < sizeof(rdsi->guidSig.Data4); i++) { + QString out; +#if QT_VERSION >= 0x050000 + out = QString().asprintf("%02X", rdsi->guidSig.Data4[i]); +#else + out = QString().sprintf("%02X", rdsi->guidSig.Data4[i]); +#endif + chunk4 += out; + } + QString chunk5 = ""; + for (size_t i = 0; i < sizeof(rdsi->guidSig.Data5); i++) { + QString out; +#if QT_VERSION >= 0x050000 + out = QString().asprintf("%02X", rdsi->guidSig.Data5[i]); +#else + out = QString().sprintf("%02X", rdsi->guidSig.Data5[i]); +#endif + chunk5 += out; + } + QString out; +#if QT_VERSION >= 0x050000 + out = QString().asprintf("%08X-%04X-%04X-", + rdsi->guidSig.Data1, + rdsi->guidSig.Data2, + rdsi->guidSig.Data3); +#else + out = QString().sprintf("%08X-%04X-%04X-", + rdsi->guidSig.Data1, + rdsi->guidSig.Data2, + rdsi->guidSig.Data3); +#endif + return "{" + out + chunk4 + "-" + chunk5 + "}"; + } + + DEBUG_NB10* dbg = parentDir->getNB10(); + if (dbg) { + QString out; +#if QT_VERSION >= 0x050000 + out = QString().asprintf("%04X", dbg->Signature); +#else + out = QString().sprintf("%04X", dbg->Signature); +#endif + return out; + } + return ""; +} + +QString DebugDirCVEntryWrapper::getSignature() +{ + DEBUG_RSDSI* rdsi = (DEBUG_RSDSI*)this->getPtr(); + if (!rdsi) return ""; + + QString out; +#if QT_VERSION >= 0x050000 + out = QString().asprintf("%.4s", (char*)&rdsi->dwSig); +#else + out = QString().sprintf("%.4s", (char*)&rdsi->dwSig); +#endif + return out; +} + +QString DebugDirCVEntryWrapper::getFieldName(size_t fId) +{ + switch (fId) { + case F_CVDBG_SIGN: return "CvSig"; + case F_CVDBG_GUID: return "Signature"; + case F_CVDBG_AGE: return "Age"; + case F_CVDBG_PDB: return "PDB"; + } + return ""; +} +