From f4241a14ad593ebc70de9311036255e6cd07a795 Mon Sep 17 00:00:00 2001 From: Jason White Date: Sun, 11 Sep 2016 12:47:03 -0700 Subject: [PATCH] Normalize "/names" stream string table --- src/patch_image.cpp | 104 +++++++++++++++++++++++++++++++++++++++----- src/pdb.h | 23 ++++++++++ 2 files changed, 115 insertions(+), 12 deletions(-) diff --git a/src/patch_image.cpp b/src/patch_image.cpp index b67fd1a..e2d9cce 100644 --- a/src/patch_image.cpp +++ b/src/patch_image.cpp @@ -72,6 +72,7 @@ #include #include +#include #include #include #include @@ -367,10 +368,9 @@ NameMapTable readNameMapTable(const uint8_t* data, const uint8_t* dataEnd) { } /** - * Patches the LinkInfo named stream. + * Patches the "/LinkInfo" named stream. */ void patchLinkInfoStream(MsfMemoryStream* stream) { - uint8_t* data = stream->data(); const size_t length = stream->length(); @@ -383,6 +383,69 @@ void patchLinkInfoStream(MsfMemoryStream* stream) { stream->resize(linkInfo->size); } +/** + * Patches the "/names" stream. + */ +void patchNamesStream(MsfMemoryStream* stream) { + uint8_t* data = stream->data(); + uint8_t* dataEnd = data + stream->length(); + + // Parse the header + if (size_t(dataEnd - data) < sizeof(StringTableHeader)) + throw InvalidPdb("missing string table header"); + + StringTableHeader* header = (StringTableHeader*)data; + + data += sizeof(*header); + + if (header->signature != kHashTableSignature) + throw InvalidPdb("got invalid string table signature"); + + if (header->version != 1 && header->version != 2) + throw InvalidPdb("got invalid or unsupported string table version"); + + if (size_t(dataEnd - data) < header->stringsSize) + throw InvalidPdb("got partial string table data"); + + data += header->stringsSize; + + if (size_t(dataEnd - data) < sizeof(uint32_t)) + throw InvalidPdb("missing string table offset array length"); + + // Offsets array length + uint32_t offsetsLength = *(uint32_t*)data; + + data += sizeof(offsetsLength); + + if (size_t(dataEnd - data) < offsetsLength * sizeof(uint32_t)) + throw InvalidPdb("got partial string table offsets array"); + + uint32_t* offsets = (uint32_t*)data; + + data += offsetsLength * sizeof(uint32_t); + + // Sort the offsets. There is some non-determinism creeping in here somehow. + std::sort(offsets, offsets + offsetsLength); + + for (size_t i = 0; i < offsetsLength; ++i) { + const size_t offset = offsets[i]; + + if (offset == 0) + continue; + + if (offset >= header->stringsSize) + throw InvalidPdb("got invalid offset into string table"); + + char* str = &header->strings[offset]; + size_t len = strlen(str); + + if (offset + len + 1 > header->stringsSize) + throw InvalidPdb("got invalid offset into string table"); + + normalizeFileNameGuid(str, len); + } +} + /** * Patches the PDB header stream. */ @@ -414,21 +477,38 @@ void patchHeaderStream(MsfFile& msf, MsfMemoryStream* stream, const CV_INFO_PDB7 const auto table = readNameMapTable(data, dataEnd); // Patch the LinkInfo stream. - const auto it = table.find("/LinkInfo"); - if (it != table.end()) { - auto origLinkInfoStream = msf.getStream(it->second); - if (!origLinkInfoStream) - throw InvalidPdb("missing named LinkInfo stream"); + { + const auto it = table.find("/LinkInfo"); + if (it != table.end()) { + auto origLinkInfoStream = msf.getStream(it->second); + if (!origLinkInfoStream) + throw InvalidPdb("missing '/LinkInfo' stream"); - auto linkInfoStream = std::shared_ptr( - new MsfMemoryStream(origLinkInfoStream.get())); + auto linkInfoStream = std::shared_ptr( + new MsfMemoryStream(origLinkInfoStream.get())); - patchLinkInfoStream(linkInfoStream.get()); + patchLinkInfoStream(linkInfoStream.get()); - msf.replaceStream(it->second, linkInfoStream); + msf.replaceStream(it->second, linkInfoStream); + } } - // TODO: Rewrite /names hash table + // Rewrite /names hash table + { + const auto it = table.find("/names"); + if (it != table.end()) { + auto origNamesStream = msf.getStream(it->second); + if (!origNamesStream) + throw InvalidPdb("missing '/names' stream"); + + auto namesStream = std::shared_ptr( + new MsfMemoryStream(origNamesStream.get())); + + patchNamesStream(namesStream.get()); + + msf.replaceStream(it->second, namesStream); + } + } } /** diff --git a/src/pdb.h b/src/pdb.h index 1d609a3..032dafb 100644 --- a/src/pdb.h +++ b/src/pdb.h @@ -467,6 +467,29 @@ struct LinkInfo { } }; +static_assert(sizeof(LinkInfo) == 24, "invalid struct size"); + +const uint32_t kHashTableSignature = 0xeffeeffe; + +/** + * The header that is present at the start of string tables. + */ +struct StringTableHeader { + // Should be equal to kHashTableSignature + uint32_t signature; + + // Either 1 or 2 + uint32_t version; + + // Size of the string data that follows + uint32_t stringsSize; + + // The strings + char strings[]; +}; + +static_assert(sizeof(StringTableHeader) == 12, "invalid struct size"); + /** * Thrown when a PDB is found to be invalid or unsupported. */