From bd68ba418f2a9099dfc28fa1ea2e7b3f74e0917b Mon Sep 17 00:00:00 2001 From: Stefan Siegfried <8906941+stefansiegfried@users.noreply.github.com> Date: Sun, 17 Nov 2019 01:45:55 +0900 Subject: [PATCH] Populate Rich header version strings (#94) --- dump-pe/main.cpp | 261 +++++----- .../include/parser-library/nt-headers.h | 2 + .../include/parser-library/parse.h | 5 +- pe-parser-library/src/parse.cpp | 464 +++++++++++++++++- 4 files changed, 592 insertions(+), 140 deletions(-) diff --git a/dump-pe/main.cpp b/dump-pe/main.cpp index b2e589a..357809d 100644 --- a/dump-pe/main.cpp +++ b/dump-pe/main.cpp @@ -229,11 +229,12 @@ int printSymbols(void *N, int printRich(void *N, rich_entry r) { static_cast(N); - + std::cout << std::dec; std::cout << std::setw(10) << "ProdId:" << std::setw(7) << r.ProductId; std::cout << std::setw(10) << "Build:" << std::setw(7) << r.BuildNumber; - std::cout << std::setw(10) << "Name:" << std::setw(20) - << GetRichProductName(r.ProductId, r.BuildNumber); + std::cout << std::setw(10) << "Name:" << std::setw(40) + << GetRichProductName(r.BuildNumber) << " " + << GetRichObjectType(r.ProductId); std::cout << std::setw(10) << "Count:" << std::setw(7) << r.Count << "\n"; return 0; } @@ -282,10 +283,13 @@ int printSecs(void *N, #define DUMP_FIELD(x) \ std::cout << "" #x << ": 0x"; \ - std::cout << std::hex << static_cast(p->peHeader.nt.x) << "\n"; + std::cout << std::hex << static_cast(p->peHeader.x) << "\n"; #define DUMP_DEC_FIELD(x) \ std::cout << "" #x << ": "; \ - std::cout << std::dec << static_cast(p->peHeader.nt.x) << "\n"; + std::cout << std::dec << static_cast(p->peHeader.x) << "\n"; +#define DUMP_BOOL_FIELD(x) \ + std::cout << "" #x << ": "; \ + std::cout << std::boolalpha << static_cast(p->peHeader.x) << "\n"; int main(int argc, char *argv[]) { if (argc != 2 || (argc == 2 && std::strcmp(argv[1], "--help") == 0)) { @@ -303,120 +307,153 @@ int main(int argc, char *argv[]) { return 1; } - // Print Rich header info - if (p->peHeader.rich.isPresent) { - std::cout << "Rich header: present\n"; - IterRich(p, printRich, NULL); - } else { - std::cout << "Rich header: not present\n"; - } - // print out some things - DUMP_FIELD(Signature); - DUMP_FIELD(FileHeader.Machine); - DUMP_FIELD(FileHeader.NumberOfSections); - DUMP_DEC_FIELD(FileHeader.TimeDateStamp); - DUMP_FIELD(FileHeader.PointerToSymbolTable); - DUMP_DEC_FIELD(FileHeader.NumberOfSymbols); - DUMP_FIELD(FileHeader.SizeOfOptionalHeader); - DUMP_FIELD(FileHeader.Characteristics); - if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) { - DUMP_FIELD(OptionalHeader.Magic); - DUMP_DEC_FIELD(OptionalHeader.MajorLinkerVersion); - DUMP_DEC_FIELD(OptionalHeader.MinorLinkerVersion); - DUMP_FIELD(OptionalHeader.SizeOfCode); - DUMP_FIELD(OptionalHeader.SizeOfInitializedData); - DUMP_FIELD(OptionalHeader.SizeOfUninitializedData); - DUMP_FIELD(OptionalHeader.AddressOfEntryPoint); - DUMP_FIELD(OptionalHeader.BaseOfCode); - DUMP_FIELD(OptionalHeader.BaseOfData); - DUMP_FIELD(OptionalHeader.ImageBase); - DUMP_FIELD(OptionalHeader.SectionAlignment); - DUMP_FIELD(OptionalHeader.FileAlignment); - DUMP_DEC_FIELD(OptionalHeader.MajorOperatingSystemVersion); - DUMP_DEC_FIELD(OptionalHeader.MinorOperatingSystemVersion); - DUMP_DEC_FIELD(OptionalHeader.Win32VersionValue); - DUMP_FIELD(OptionalHeader.SizeOfImage); - DUMP_FIELD(OptionalHeader.SizeOfHeaders); - DUMP_FIELD(OptionalHeader.CheckSum); - DUMP_FIELD(OptionalHeader.Subsystem); - DUMP_FIELD(OptionalHeader.DllCharacteristics); - DUMP_FIELD(OptionalHeader.SizeOfStackReserve); - DUMP_FIELD(OptionalHeader.SizeOfStackCommit); - DUMP_FIELD(OptionalHeader.SizeOfHeapReserve); - DUMP_FIELD(OptionalHeader.SizeOfHeapCommit); - DUMP_FIELD(OptionalHeader.LoaderFlags); - DUMP_DEC_FIELD(OptionalHeader.NumberOfRvaAndSizes); - } else { - DUMP_FIELD(OptionalHeader64.Magic); - DUMP_DEC_FIELD(OptionalHeader64.MajorLinkerVersion); - DUMP_DEC_FIELD(OptionalHeader64.MinorLinkerVersion); - DUMP_FIELD(OptionalHeader64.SizeOfCode); - DUMP_FIELD(OptionalHeader64.SizeOfInitializedData); - DUMP_FIELD(OptionalHeader64.SizeOfUninitializedData); - DUMP_FIELD(OptionalHeader64.AddressOfEntryPoint); - DUMP_FIELD(OptionalHeader64.BaseOfCode); - DUMP_FIELD(OptionalHeader64.ImageBase); - DUMP_FIELD(OptionalHeader64.SectionAlignment); - DUMP_FIELD(OptionalHeader64.FileAlignment); - DUMP_DEC_FIELD(OptionalHeader64.MajorOperatingSystemVersion); - DUMP_DEC_FIELD(OptionalHeader64.MinorOperatingSystemVersion); - DUMP_DEC_FIELD(OptionalHeader64.Win32VersionValue); - DUMP_FIELD(OptionalHeader64.SizeOfImage); - DUMP_FIELD(OptionalHeader64.SizeOfHeaders); - DUMP_FIELD(OptionalHeader64.CheckSum); - DUMP_FIELD(OptionalHeader64.Subsystem); - DUMP_FIELD(OptionalHeader64.DllCharacteristics); - DUMP_FIELD(OptionalHeader64.SizeOfStackReserve); - DUMP_FIELD(OptionalHeader64.SizeOfStackCommit); - DUMP_FIELD(OptionalHeader64.SizeOfHeapReserve); - DUMP_FIELD(OptionalHeader64.SizeOfHeapCommit); - DUMP_FIELD(OptionalHeader64.LoaderFlags); - DUMP_DEC_FIELD(OptionalHeader64.NumberOfRvaAndSizes); - } + if (p != NULL) { + // Print DOS header + DUMP_FIELD(dos.e_magic); + DUMP_FIELD(dos.e_cp); + DUMP_FIELD(dos.e_crlc); + DUMP_FIELD(dos.e_cparhdr); + DUMP_FIELD(dos.e_minalloc); + DUMP_FIELD(dos.e_maxalloc); + DUMP_FIELD(dos.e_ss); + DUMP_FIELD(dos.e_sp); + DUMP_FIELD(dos.e_csum); + DUMP_FIELD(dos.e_ip); + DUMP_FIELD(dos.e_cs); + DUMP_FIELD(dos.e_lfarlc); + DUMP_FIELD(dos.e_ovno); + DUMP_FIELD(dos.e_res[0]); + DUMP_FIELD(dos.e_res[1]); + DUMP_FIELD(dos.e_res[2]); + DUMP_FIELD(dos.e_res[3]); + DUMP_FIELD(dos.e_oemid); + DUMP_FIELD(dos.e_oeminfo); + DUMP_FIELD(dos.e_res2[0]); + DUMP_FIELD(dos.e_res2[1]); + DUMP_FIELD(dos.e_res2[2]); + DUMP_FIELD(dos.e_res2[3]); + DUMP_FIELD(dos.e_res2[4]); + DUMP_FIELD(dos.e_res2[5]); + DUMP_FIELD(dos.e_res2[6]); + DUMP_FIELD(dos.e_res2[7]); + DUMP_FIELD(dos.e_res2[8]); + DUMP_FIELD(dos.e_res2[9]); + DUMP_FIELD(dos.e_lfanew); + // Print Rich header info + DUMP_BOOL_FIELD(rich.isPresent); + if (p->peHeader.rich.isPresent) { + DUMP_FIELD(rich.DecryptionKey); + DUMP_FIELD(rich.Checksum); + DUMP_BOOL_FIELD(rich.isValid); + IterRich(p, printRich, NULL); + } + // print out some things + DUMP_FIELD(nt.Signature); + DUMP_FIELD(nt.FileHeader.Machine); + DUMP_FIELD(nt.FileHeader.NumberOfSections); + DUMP_DEC_FIELD(nt.FileHeader.TimeDateStamp); + DUMP_FIELD(nt.FileHeader.PointerToSymbolTable); + DUMP_DEC_FIELD(nt.FileHeader.NumberOfSymbols); + DUMP_FIELD(nt.FileHeader.SizeOfOptionalHeader); + DUMP_FIELD(nt.FileHeader.Characteristics); + if (p->peHeader.nt.OptionalMagic == NT_OPTIONAL_32_MAGIC) { + DUMP_FIELD(nt.OptionalHeader.Magic); + DUMP_DEC_FIELD(nt.OptionalHeader.MajorLinkerVersion); + DUMP_DEC_FIELD(nt.OptionalHeader.MinorLinkerVersion); + DUMP_FIELD(nt.OptionalHeader.SizeOfCode); + DUMP_FIELD(nt.OptionalHeader.SizeOfInitializedData); + DUMP_FIELD(nt.OptionalHeader.SizeOfUninitializedData); + DUMP_FIELD(nt.OptionalHeader.AddressOfEntryPoint); + DUMP_FIELD(nt.OptionalHeader.BaseOfCode); + DUMP_FIELD(nt.OptionalHeader.BaseOfData); + DUMP_FIELD(nt.OptionalHeader.ImageBase); + DUMP_FIELD(nt.OptionalHeader.SectionAlignment); + DUMP_FIELD(nt.OptionalHeader.FileAlignment); + DUMP_DEC_FIELD(nt.OptionalHeader.MajorOperatingSystemVersion); + DUMP_DEC_FIELD(nt.OptionalHeader.MinorOperatingSystemVersion); + DUMP_DEC_FIELD(nt.OptionalHeader.Win32VersionValue); + DUMP_FIELD(nt.OptionalHeader.SizeOfImage); + DUMP_FIELD(nt.OptionalHeader.SizeOfHeaders); + DUMP_FIELD(nt.OptionalHeader.CheckSum); + DUMP_FIELD(nt.OptionalHeader.Subsystem); + DUMP_FIELD(nt.OptionalHeader.DllCharacteristics); + DUMP_FIELD(nt.OptionalHeader.SizeOfStackReserve); + DUMP_FIELD(nt.OptionalHeader.SizeOfStackCommit); + DUMP_FIELD(nt.OptionalHeader.SizeOfHeapReserve); + DUMP_FIELD(nt.OptionalHeader.SizeOfHeapCommit); + DUMP_FIELD(nt.OptionalHeader.LoaderFlags); + DUMP_DEC_FIELD(nt.OptionalHeader.NumberOfRvaAndSizes); + } else { + DUMP_FIELD(nt.OptionalHeader64.Magic); + DUMP_DEC_FIELD(nt.OptionalHeader64.MajorLinkerVersion); + DUMP_DEC_FIELD(nt.OptionalHeader64.MinorLinkerVersion); + DUMP_FIELD(nt.OptionalHeader64.SizeOfCode); + DUMP_FIELD(nt.OptionalHeader64.SizeOfInitializedData); + DUMP_FIELD(nt.OptionalHeader64.SizeOfUninitializedData); + DUMP_FIELD(nt.OptionalHeader64.AddressOfEntryPoint); + DUMP_FIELD(nt.OptionalHeader64.BaseOfCode); + DUMP_FIELD(nt.OptionalHeader64.ImageBase); + DUMP_FIELD(nt.OptionalHeader64.SectionAlignment); + DUMP_FIELD(nt.OptionalHeader64.FileAlignment); + DUMP_DEC_FIELD(nt.OptionalHeader64.MajorOperatingSystemVersion); + DUMP_DEC_FIELD(nt.OptionalHeader64.MinorOperatingSystemVersion); + DUMP_DEC_FIELD(nt.OptionalHeader64.Win32VersionValue); + DUMP_FIELD(nt.OptionalHeader64.SizeOfImage); + DUMP_FIELD(nt.OptionalHeader64.SizeOfHeaders); + DUMP_FIELD(nt.OptionalHeader64.CheckSum); + DUMP_FIELD(nt.OptionalHeader64.Subsystem); + DUMP_FIELD(nt.OptionalHeader64.DllCharacteristics); + DUMP_FIELD(nt.OptionalHeader64.SizeOfStackReserve); + DUMP_FIELD(nt.OptionalHeader64.SizeOfStackCommit); + DUMP_FIELD(nt.OptionalHeader64.SizeOfHeapReserve); + DUMP_FIELD(nt.OptionalHeader64.SizeOfHeapCommit); + DUMP_FIELD(nt.OptionalHeader64.LoaderFlags); + DUMP_DEC_FIELD(nt.OptionalHeader64.NumberOfRvaAndSizes); + } #undef DUMP_FIELD #undef DUMP_DEC_FIELD - std::cout << "Imports: " - << "\n"; - IterImpVAString(p, printImports, NULL); - std::cout << "Relocations: " - << "\n"; - IterRelocs(p, printRelocs, NULL); - std::cout << "Symbols (symbol table): " - << "\n"; - IterSymbols(p, printSymbols, NULL); - std::cout << "Sections: " - << "\n"; - IterSec(p, printSecs, NULL); - std::cout << "Exports: " - << "\n"; - IterExpVA(p, printExps, NULL); - - // read the first 8 bytes from the entry point and print them - VA entryPoint; - if (GetEntryPoint(p, entryPoint)) { - std::cout << "First 8 bytes from entry point (0x"; - - std::cout << std::hex << entryPoint << "):" + std::cout << "Imports: " << "\n"; - for (std::size_t i = 0; i < 8; i++) { - std::uint8_t b; - if (!ReadByteAtVA(p, i + entryPoint, b)) { - std::cout << " ERR"; - } else { - std::cout << " 0x" << std::hex << static_cast(b); + IterImpVAString(p, printImports, NULL); + std::cout << "Relocations: " + << "\n"; + IterRelocs(p, printRelocs, NULL); + std::cout << "Symbols (symbol table): " + << "\n"; + IterSymbols(p, printSymbols, NULL); + std::cout << "Sections: " + << "\n"; + IterSec(p, printSecs, NULL); + std::cout << "Exports: " + << "\n"; + IterExpVA(p, printExps, NULL); + + // read the first 8 bytes from the entry point and print them + VA entryPoint; + if (GetEntryPoint(p, entryPoint)) { + std::cout << "First 8 bytes from entry point (0x"; + std::cout << std::hex << entryPoint << "):" + << "\n"; + for (std::size_t i = 0; i < 8; i++) { + std::uint8_t b; + if (!ReadByteAtVA(p, i + entryPoint, b)) { + std::cout << " ERR"; + } else { + std::cout << " 0x" << std::hex << static_cast(b); + } } + + std::cout << "\n"; } - std::cout << "\n"; + std::cout << "Resources: " + << "\n"; + IterRsrc(p, printRsrc, NULL); + + DestructParsedPE(p); + + return 0; } - - std::cout << "Resources: " - << "\n"; - IterRsrc(p, printRsrc, NULL); - - DestructParsedPE(p); - - return 0; } diff --git a/pe-parser-library/include/parser-library/nt-headers.h b/pe-parser-library/include/parser-library/nt-headers.h index 583a7be..0056211 100644 --- a/pe-parser-library/include/parser-library/nt-headers.h +++ b/pe-parser-library/include/parser-library/nt-headers.h @@ -359,7 +359,9 @@ struct rich_header { std::vector Entries; std::uint32_t EndSignature; std::uint32_t DecryptionKey; + std::uint32_t Checksum; bool isPresent; + bool isValid; }; /* diff --git a/pe-parser-library/include/parser-library/parse.h b/pe-parser-library/include/parser-library/parse.h index ed86c0e..0a20d85 100644 --- a/pe-parser-library/include/parser-library/parse.h +++ b/pe-parser-library/include/parser-library/parse.h @@ -157,6 +157,7 @@ uint64_t bufLen(bounded_buffer *b); struct parsed_pe_internal; typedef struct _pe_header { + dos_header dos; rich_header rich; nt_header_32 nt; } pe_header; @@ -170,8 +171,8 @@ typedef struct _parsed_pe { // Resolve a Rich header product id / build number pair to a known // product name typedef std::pair ProductKey; -const std::string &GetRichProductName(std::uint16_t prodId, - std::uint16_t buildNum); +const std::string &GetRichObjectType(std::uint16_t prodId); +const std::string &GetRichProductName(std::uint16_t buildNum); // get parser error status as integer std::uint32_t GetPEErr(); diff --git a/pe-parser-library/src/parse.cpp b/pe-parser-library/src/parse.cpp index 340c9be..106e8f0 100644 --- a/pe-parser-library/src/parse.cpp +++ b/pe-parser-library/src/parse.cpp @@ -123,20 +123,347 @@ struct parsed_pe_internal { std::vector symbols; }; -// The mapping of Rich header product id / build number pairs -// to strings -static const std::map ProductMap = { - {std::make_pair(static_cast(1), - static_cast(0)), - "Imported Functions"}}; +// String representation of Rich header object types +static const std::string kProdId_C = "[ C ]"; +static const std::string kProdId_CPP = "[C++]"; +static const std::string kProdId_RES = "[RES]"; +static const std::string kProdId_IMP = "[IMP]"; +static const std::string kProdId_EXP = "[EXP]"; +static const std::string kProdId_ASM = "[ASM]"; +static const std::string kProdId_LNK = "[LNK]"; +static const std::string kProdId_UNK = "[ ? ]"; + +// Mapping of Rich header Product ID to object type string +// Source: https://github.com/dishather/richprint/blob/master/comp_id.txt +static const std::map ProductIdMap = { + {std::make_pair(static_cast(0x0000), kProdId_UNK)}, + {std::make_pair(static_cast(0x0002), kProdId_IMP)}, + {std::make_pair(static_cast(0x0004), kProdId_LNK)}, + {std::make_pair(static_cast(0x0006), kProdId_RES)}, + {std::make_pair(static_cast(0x000A), kProdId_C)}, + {std::make_pair(static_cast(0x000B), kProdId_CPP)}, + {std::make_pair(static_cast(0x000F), kProdId_ASM)}, + {std::make_pair(static_cast(0x0015), kProdId_C)}, + {std::make_pair(static_cast(0x0016), kProdId_CPP)}, + {std::make_pair(static_cast(0x0019), kProdId_IMP)}, + {std::make_pair(static_cast(0x001C), kProdId_C)}, + {std::make_pair(static_cast(0x001D), kProdId_CPP)}, + {std::make_pair(static_cast(0x003D), kProdId_LNK)}, + {std::make_pair(static_cast(0x003F), kProdId_EXP)}, + {std::make_pair(static_cast(0x0040), kProdId_ASM)}, + {std::make_pair(static_cast(0x0045), kProdId_RES)}, + {std::make_pair(static_cast(0x005A), kProdId_LNK)}, + {std::make_pair(static_cast(0x005C), kProdId_EXP)}, + {std::make_pair(static_cast(0x005D), kProdId_IMP)}, + {std::make_pair(static_cast(0x005E), kProdId_RES)}, + {std::make_pair(static_cast(0x005F), kProdId_C)}, + {std::make_pair(static_cast(0x0060), kProdId_CPP)}, + {std::make_pair(static_cast(0x006D), kProdId_C)}, + {std::make_pair(static_cast(0x006E), kProdId_CPP)}, + {std::make_pair(static_cast(0x0078), kProdId_LNK)}, + {std::make_pair(static_cast(0x007A), kProdId_EXP)}, + {std::make_pair(static_cast(0x007B), kProdId_IMP)}, + {std::make_pair(static_cast(0x007C), kProdId_RES)}, + {std::make_pair(static_cast(0x007D), kProdId_ASM)}, + {std::make_pair(static_cast(0x0083), kProdId_C)}, + {std::make_pair(static_cast(0x0084), kProdId_CPP)}, + {std::make_pair(static_cast(0x0091), kProdId_LNK)}, + {std::make_pair(static_cast(0x0092), kProdId_EXP)}, + {std::make_pair(static_cast(0x0093), kProdId_IMP)}, + {std::make_pair(static_cast(0x0094), kProdId_RES)}, + {std::make_pair(static_cast(0x0095), kProdId_ASM)}, + {std::make_pair(static_cast(0x009A), kProdId_RES)}, + {std::make_pair(static_cast(0x009B), kProdId_EXP)}, + {std::make_pair(static_cast(0x009C), kProdId_IMP)}, + {std::make_pair(static_cast(0x009D), kProdId_LNK)}, + {std::make_pair(static_cast(0x009E), kProdId_ASM)}, + {std::make_pair(static_cast(0x00AA), kProdId_C)}, + {std::make_pair(static_cast(0x00AB), kProdId_CPP)}, + {std::make_pair(static_cast(0x00C9), kProdId_RES)}, + {std::make_pair(static_cast(0x00CA), kProdId_EXP)}, + {std::make_pair(static_cast(0x00CB), kProdId_IMP)}, + {std::make_pair(static_cast(0x00CC), kProdId_LNK)}, + {std::make_pair(static_cast(0x00CD), kProdId_ASM)}, + {std::make_pair(static_cast(0x00CE), kProdId_C)}, + {std::make_pair(static_cast(0x00CF), kProdId_CPP)}, + {std::make_pair(static_cast(0x00DB), kProdId_RES)}, + {std::make_pair(static_cast(0x00DC), kProdId_EXP)}, + {std::make_pair(static_cast(0x00DD), kProdId_IMP)}, + {std::make_pair(static_cast(0x00DE), kProdId_LNK)}, + {std::make_pair(static_cast(0x00DF), kProdId_ASM)}, + {std::make_pair(static_cast(0x00E0), kProdId_C)}, + {std::make_pair(static_cast(0x00E1), kProdId_CPP)}, + {std::make_pair(static_cast(0x00FF), kProdId_RES)}, + {std::make_pair(static_cast(0x0100), kProdId_EXP)}, + {std::make_pair(static_cast(0x0101), kProdId_IMP)}, + {std::make_pair(static_cast(0x0102), kProdId_LNK)}, + {std::make_pair(static_cast(0x0103), kProdId_ASM)}, + {std::make_pair(static_cast(0x0104), kProdId_C)}, + {std::make_pair(static_cast(0x0105), kProdId_CPP)}}; + +// Mapping of Rich header build number to version strings +static const std::map ProductMap = { + // Source: https://github.com/dishather/richprint/blob/master/comp_id.txt + {std::make_pair(static_cast(0x0000), "Imported Functions")}, + {std::make_pair(static_cast(0x0684), + "VS97 v5.0 SP3 cvtres 5.00.1668")}, + {std::make_pair(static_cast(0x06B8), + "VS98 v6.0 cvtres build 1720")}, + {std::make_pair(static_cast(0x06C8), + "VS98 v6.0 SP6 cvtres build 1736")}, + {std::make_pair(static_cast(0x1C87), + "VS97 v5.0 SP3 link 5.10.7303")}, + {std::make_pair(static_cast(0x5E92), + "VS2015 v14.0 UPD3 build 24210")}, + {std::make_pair(static_cast(0x5E95), + "VS2015 UPD3 build 24213")}, + + // http://bytepointer.com/articles/the_microsoft_rich_header.htm + {std::make_pair(static_cast(0x0BEC), + "VS2003 v7.1 Free Toolkit .NET build 3052")}, + {std::make_pair(static_cast(0x0C05), + "VS2003 v7.1 .NET build 3077")}, + {std::make_pair(static_cast(0x0FC3), + "VS2003 v7.1 | Windows Server 2003 SP1 DDK build 4035")}, + {std::make_pair(static_cast(0x1C83), "MASM 6.13.7299")}, + {std::make_pair(static_cast(0x178E), + "VS2003 v7.1 SP1 .NET build 6030")}, + {std::make_pair(static_cast(0x1FE8), + "VS98 v6.0 RTM/SP1/SP2 build 8168")}, + {std::make_pair(static_cast(0x1FE9), + "VB 6.0/SP1/SP2 build 8169")}, + {std::make_pair(static_cast(0x20FC), "MASM 6.14.8444")}, + {std::make_pair(static_cast(0x20FF), + "VC++ 6.0 SP3 build 8447")}, + {std::make_pair(static_cast(0x212F), + "VB 6.0 SP3 build 8495")}, + {std::make_pair(static_cast(0x225F), + "VS 6.0 SP4 build 8799")}, + {std::make_pair(static_cast(0x2263), "MASM 6.15.8803")}, + {std::make_pair(static_cast(0x22AD), + "VB 6.0 SP4 build 8877")}, + {std::make_pair(static_cast(0x2304), + "VB 6.0 SP5 build 8964")}, + {std::make_pair(static_cast(0x2306), + "VS 6.0 SP5 build 8966")}, + // {std::make_pair(static_cast(0x2346), "MASM 6.15.9030 + // (VS.NET 7.0 BETA 1)")}, + {std::make_pair(static_cast(0x2346), + "VS 7.0 2000 Beta 1 build 9030")}, + {std::make_pair(static_cast(0x2354), + "VS 6.0 SP5 Processor Pack build 9044")}, + {std::make_pair(static_cast(0x2426), + "VS2001 v7.0 Beta 2 build 9254")}, + {std::make_pair(static_cast(0x24FA), + "VS2002 v7.0 .NET build 9466")}, + {std::make_pair(static_cast(0x2636), + "VB 6.0 SP6 / VC++ build 9782")}, + {std::make_pair(static_cast(0x26E3), + "VS2002 v7.0 SP1 build 9955")}, + {std::make_pair(static_cast(0x520D), + "VS2013 v12.[0,1] build 21005")}, + {std::make_pair(static_cast(0x521E), + "VS2008 v9.0 build 21022")}, + {std::make_pair(static_cast(0x56C7), + "VS2015 v14.0 build 22215")}, + {std::make_pair(static_cast(0x59F2), + "VS2015 v14.0 build 23026")}, + {std::make_pair(static_cast(0x5BD2), + "VS2015 v14.0 UPD1 build 23506")}, + {std::make_pair(static_cast(0x5D10), + "VS2015 v14.0 UPD2 build 23824")}, + {std::make_pair(static_cast(0x5E97), + "VS2015 v14.0 UPD3.1 build 24215")}, + {std::make_pair(static_cast(0x7725), + "VS2013 v12.0 UPD2 build 30501")}, + {std::make_pair(static_cast(0x766F), + "VS2010 v10.0 build 30319")}, + {std::make_pair(static_cast(0x7809), + "VS2008 v9.0 SP1 build 30729")}, + {std::make_pair(static_cast(0x797D), + "VS2013 v12.0 UPD4 build 31101")}, + {std::make_pair(static_cast(0x9D1B), + "VS2010 v10.0 SP1 build 40219")}, + {std::make_pair(static_cast(0x9EB5), + "VS2013 v12.0 UPD5 build 40629")}, + {std::make_pair(static_cast(0xC497), + "VS2005 v8.0 (Beta) build 50327")}, + {std::make_pair(static_cast(0xC627), + "VS2005 v8.0 | VS2012 v11.0 build 50727")}, + {std::make_pair(static_cast(0xC751), + "VS2012 v11.0 Nov CTP build 51025")}, + {std::make_pair(static_cast(0xC7A2), + "VS2012 v11.0 UPD1 build 51106")}, + {std::make_pair(static_cast(0xEB9B), + "VS2012 v11.0 UPD2 build 60315")}, + {std::make_pair(static_cast(0xECC2), + "VS2012 v11.0 UPD3 build 60610")}, + {std::make_pair(static_cast(0xEE66), + "VS2012 v11.0 UPD4 build 61030")}, + {std::make_pair(static_cast(0x5E9A), + "VS2015 v14.0 build 24218")}, + {std::make_pair(static_cast(0x61BB), + "VS2017 v14.1 build 25019")}, + + // https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd + {std::make_pair(static_cast(0x2264), + "VS 6 [SP5,SP6] build 8804")}, + {std::make_pair(static_cast(0x23D8), "Windows XP SP1 DDK")}, + {std::make_pair(static_cast(0x0883), + "Windows Server 2003 DDK")}, + {std::make_pair(static_cast(0x08F4), + "VS2003 v7.1 .NET Beta build 2292")}, + {std::make_pair(static_cast(0x9D76), + "Windows Server 2003 SP1 DDK (for AMD64)")}, + {std::make_pair(static_cast(0x9E9F), + "VS2005 v8.0 Beta 1 build 40607")}, + {std::make_pair(static_cast(0xC427), + "VS2005 v8.0 Beta 2 build 50215")}, + {std::make_pair(static_cast(0xC490), + "VS2005 v8.0 build 50320")}, + {std::make_pair(static_cast(0x50E2), + "VS2008 v9.0 Beta 2 build 20706")}, + {std::make_pair(static_cast(0x501A), + "VS2010 v10.0 Beta 1 build 20506")}, + {std::make_pair(static_cast(0x520B), + "VS2010 v10.0 Beta 2 build 21003")}, + {std::make_pair(static_cast(0x5089), + "VS2013 v12.0 Preview build 20617")}, + {std::make_pair(static_cast(0x515B), + "VS2013 v12.0 RC build 20827")}, + {std::make_pair(static_cast(0x527A), + "VS2013 v12.0 Nov CTP build 21114")}, + {std::make_pair(static_cast(0x63A3), + "VS2017 v15.3.3 build 25507")}, + {std::make_pair(static_cast(0x63C6), + "VS2017 v15.4.4 build 25542")}, + {std::make_pair(static_cast(0x63CB), + "VS2017 v15.4.5 build 25547")}, + {std::make_pair(static_cast(0x7674), + "VS2013 v12.0 UPD2 RC build 30324")}, + + // https://walbourn.github.io/visual-studio-2015-update-2/ + {std::make_pair(static_cast(0x5D6E), + "VS2015 v14.0 UPD2 build 23918")}, + + // https://walbourn.github.io/visual-studio-2017/ + {std::make_pair(static_cast(0x61B9), + "VS2017 v15.[0,1] build 25017")}, + {std::make_pair(static_cast(0x63A2), + "VS2017 v15.2 build 25019")}, + + // https://walbourn.github.io/vs-2017-15-5-update/ + {std::make_pair(static_cast(0x64E6), + "VS2017 v15 build 25830")}, + {std::make_pair(static_cast(0x64E7), + "VS2017 v15.5.2 build 25831")}, + {std::make_pair(static_cast(0x64EA), + "VS2017 v15.5.[3,4] build 25834")}, + {std::make_pair(static_cast(0x64EB), + "VS2017 v15.5.[5,6,7] build 25835")}, + + // https://walbourn.github.io/vs-2017-15-6-update/ + {std::make_pair(static_cast(0x6610), + "VS2017 v15.6.[0,1,2] build 26128")}, + {std::make_pair(static_cast(0x6611), + "VS2017 v15.6.[3,4] build 26129")}, + {std::make_pair(static_cast(0x6613), + "VS2017 v15.6.6 build 26131")}, + {std::make_pair(static_cast(0x6614), + "VS2017 v15.6.7 build 26132")}, + + // https://devblogs.microsoft.com/visualstudio/visual-studio-2017-update/ + {std::make_pair(static_cast(0x6723), + "VS2017 v15.1 build 26403")}, + + // https://walbourn.github.io/vs-2017-15-7-update/ + {std::make_pair(static_cast(0x673C), + "VS2017 v15.7.[0,1] build 26428")}, + {std::make_pair(static_cast(0x673D), + "VS2017 v15.7.2 build 26429")}, + {std::make_pair(static_cast(0x673E), + "VS2017 v15.7.3 build 26430")}, + {std::make_pair(static_cast(0x673F), + "VS2017 v15.7.4 build 26431")}, + {std::make_pair(static_cast(0x6741), + "VS2017 v15.7.5 build 26433")}, + + // https://walbourn.github.io/visual-studio-2019/ + {std::make_pair(static_cast(0x6B74), + "VS2019 v16.0.0 build 27508")}, + + // https://walbourn.github.io/vs-2017-15-8-update/ + {std::make_pair(static_cast(0x6866), + "VS2017 v15.8.0 build 26726")}, + {std::make_pair(static_cast(0x6869), + "VS2017 v15.8.4 build 26729")}, + {std::make_pair(static_cast(0x686A), + "VS2017 v15.8.9 build 26730")}, + {std::make_pair(static_cast(0x686C), + "VS2017 v15.8.5 build 26732")}, + + // https://walbourn.github.io/vs-2017-15-9-update/ + {std::make_pair(static_cast(0x698F), + "VS2017 v15.9.[0,1] build 27023")}, + {std::make_pair(static_cast(0x6990), + "VS2017 v15.9.2 build 27024")}, + {std::make_pair(static_cast(0x6991), + "VS2017 v15.9.4 build 27025")}, + {std::make_pair(static_cast(0x6992), + "VS2017 v15.9.5 build 27026")}, + {std::make_pair(static_cast(0x6993), + "VS2017 v15.9.7 build 27027")}, + {std::make_pair(static_cast(0x6996), + "VS2017 v15.9.11 build 27030")}, + {std::make_pair(static_cast(0x6997), + "VS2017 v15.9.12 build 27031")}, + {std::make_pair(static_cast(0x6998), + "VS2017 v15.9.14 build 27032")}, + {std::make_pair(static_cast(0x699A), + "VS2017 v15.9.16 build 27034")}, + + // https://walbourn.github.io/visual-studio-2019/ + {std::make_pair(static_cast(0x6B74), + "VS2019 v16.0.0 RTM build 27508")}, + + // https://walbourn.github.io/vs-2019-update-1/ + {std::make_pair(static_cast(0x6C36), + "VS2019 v16.1.2 UPD1 build 27702")}, + + // https://walbourn.github.io/vs-2019-update-2/ + {std::make_pair(static_cast(0x6D01), + "VS2019 v16.2.3 UPD2 build 27905")}, + + // https://walbourn.github.io/vs-2019-update-3/ + {std::make_pair(static_cast(0x6DC9), + "VS2019 v16.3.2 UPD3 build 28105")}, + + // https://walbourn.github.io/visual-studio-2013-update-3/ + {std::make_pair(static_cast(0x7803), + "VS2013 v12.0 UPD3 build 30723")}, + + // experimentation + {std::make_pair(static_cast(0x685B), + "VS2017 v15.8.? build 26715")}, +}; static const std::string kUnknownProduct = ""; -// Resolve a Rich header product id / build number pair to a known -// product name -const std::string &GetRichProductName(std::uint16_t prodId, - std::uint16_t buildNum) { - auto it = ProductMap.find(std::make_pair(prodId, buildNum)); +// Returns a stringified Rich header object type given a product id +const std::string &GetRichObjectType(std::uint16_t prodId) { + + auto it = ProductIdMap.find(prodId); + if (it != ProductIdMap.end()) { + return it->second; + } else { + return kProdId_UNK; + } +} + +// Returns a stringified Rich header product name given a build number +const std::string &GetRichProductName(std::uint16_t buildNum) { + + auto it = ProductMap.find(buildNum); if (it != ProductMap.end()) { return it->second; } else { @@ -836,6 +1163,41 @@ bool readNtHeader(bounded_buffer *b, nt_header_32 &header) { return true; } +// zero extends its first argument to 32 bits and then performs a rotate left +// operation equal to the second arguments value of the first argument’s bits +static inline std::uint32_t rol(std::uint32_t val, std::uint32_t num) { + return ((val << num) & 0xffffffff) | (val >> (32 - num)); +} + +std::uint32_t calculateRichChecksum(const bounded_buffer *b, pe_header &p) { + + // First, calculate the sum of the DOS header bytes each rotated left the + // number of times their position relative to the start of the DOS header e.g. + // second byte is rotated left 2x using rol operation + std::uint32_t checksum = 0; + + for (uint8_t i = 0; i < RICH_OFFSET; i++) { + + // skip over dos e_lfanew field at offset 0x3C + if (i >= 0x3C && i <= 0x3F) { + continue; + } + checksum += rol(b->buf[i], i); + } + + // Next, take summation of each Rich header entry by combining its ProductId + // and BuildNumber into a single 32 bit number and rotating by its count. + for (rich_entry entry : p.rich.Entries) { + std::uint32_t num = + static_cast((entry.ProductId << 16) | entry.BuildNumber); + checksum += rol(num, entry.Count & 0x1F); + } + + checksum += RICH_OFFSET; + + return checksum; +} + bool readRichHeader(bounded_buffer *rich_buf, std::uint32_t key, rich_header &rich_hdr) { @@ -914,30 +1276,62 @@ bool readRichHeader(bounded_buffer *rich_buf, return true; } +bool readDosHeader(bounded_buffer *file, dos_header &dos_hdr) { + if (file == nullptr) { + return false; + } + + READ_WORD(file, 0, dos_hdr, e_magic); + READ_WORD(file, 0, dos_hdr, e_cblp); + READ_WORD(file, 0, dos_hdr, e_cp); + READ_WORD(file, 0, dos_hdr, e_crlc); + READ_WORD(file, 0, dos_hdr, e_cparhdr); + READ_WORD(file, 0, dos_hdr, e_minalloc); + READ_WORD(file, 0, dos_hdr, e_maxalloc); + READ_WORD(file, 0, dos_hdr, e_ss); + READ_WORD(file, 0, dos_hdr, e_sp); + READ_WORD(file, 0, dos_hdr, e_csum); + READ_WORD(file, 0, dos_hdr, e_ip); + READ_WORD(file, 0, dos_hdr, e_cs); + READ_WORD(file, 0, dos_hdr, e_lfarlc); + READ_WORD(file, 0, dos_hdr, e_ovno); + READ_WORD(file, 0, dos_hdr, e_res[0]); + READ_WORD(file, 0, dos_hdr, e_res[1]); + READ_WORD(file, 0, dos_hdr, e_res[2]); + READ_WORD(file, 0, dos_hdr, e_res[3]); + READ_WORD(file, 0, dos_hdr, e_oemid); + READ_WORD(file, 0, dos_hdr, e_oeminfo); + READ_WORD(file, 0, dos_hdr, e_res2[0]); + READ_WORD(file, 0, dos_hdr, e_res2[1]); + READ_WORD(file, 0, dos_hdr, e_res2[2]); + READ_WORD(file, 0, dos_hdr, e_res2[3]); + READ_WORD(file, 0, dos_hdr, e_res2[4]); + READ_WORD(file, 0, dos_hdr, e_res2[5]); + READ_WORD(file, 0, dos_hdr, e_res2[6]); + READ_WORD(file, 0, dos_hdr, e_res2[7]); + READ_WORD(file, 0, dos_hdr, e_res2[8]); + READ_WORD(file, 0, dos_hdr, e_res2[9]); + READ_DWORD(file, 0, dos_hdr, e_lfanew); + + return true; +} + bool getHeader(bounded_buffer *file, pe_header &p, bounded_buffer *&rem) { if (file == nullptr) { return false; } - // start by reading MZ - std::uint16_t tmp = 0; - std::uint32_t curOffset = 0; - if (!readWord(file, curOffset, tmp)) { - PE_ERR(PEERR_READ); - return false; - } - if (tmp != MZ_MAGIC) { + // read the DOS header + readDosHeader(file, p.dos); + + if (p.dos.e_magic != MZ_MAGIC) { PE_ERR(PEERR_MAGIC); return false; } - // read the offset to the NT headers - std::uint32_t offset; - if (!readDword(file, _offset(dos_header, e_lfanew), offset)) { - PE_ERR(PEERR_READ); - return false; - } - curOffset += offset; + // get the offset to the NT headers + std::uint32_t offset = p.dos.e_lfanew; + std::uint32_t curOffset = offset; // read rich header std::uint32_t dword; @@ -983,6 +1377,24 @@ bool getHeader(bounded_buffer *file, pe_header &p, bounded_buffer *&rem) { deleteBuffer(richBuf); } + // Split the DOS header into a separate buffer which + // starts at offset 0 and has length 0x80 + bounded_buffer *dosBuf = splitBuffer(file, 0, RICH_OFFSET); + if (dosBuf == nullptr) { + return false; + } + // Calculate checksum + p.rich.Checksum = calculateRichChecksum(dosBuf, p); + if (p.rich.Checksum == p.rich.DecryptionKey) { + p.rich.isValid = true; + } else { + p.rich.isValid = false; + } + if (dosBuf != nullptr) { + deleteBuffer(dosBuf); + } + + // Rich header not present } else { p.rich.isPresent = false; }