Chromium Code Reviews| Index: snapshot/win/pe_image_reader.cc |
| diff --git a/snapshot/win/pe_image_reader.cc b/snapshot/win/pe_image_reader.cc |
| index 82bce0645ad57f82fcf6dc6f69b073660b20f9c1..2ebe7061f7322fbf6623b4200b48bb79600e46b2 100644 |
| --- a/snapshot/win/pe_image_reader.cc |
| +++ b/snapshot/win/pe_image_reader.cc |
| @@ -18,8 +18,8 @@ |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| -#include "base/strings/stringprintf.h" |
| #include "client/crashpad_info.h" |
| +#include "snapshot/win/pe_image_resource_reader.h" |
| #include "snapshot/win/process_reader_win.h" |
| #include "util/misc/pdb_structures.h" |
| #include "util/win/process_structs.h" |
| @@ -28,13 +28,6 @@ namespace crashpad { |
| namespace { |
| -std::string RangeToString(const CheckedWinAddressRange& range) { |
| - return base::StringPrintf("[0x%llx + 0x%llx (%s)]", |
| - range.Base(), |
| - range.Size(), |
| - range.Is64Bit() ? "64" : "32"); |
| -} |
| - |
| // Map from Traits to an IMAGE_NT_HEADERSxx. |
| template <class Traits> |
| struct NtHeadersForTraits; |
| @@ -71,7 +64,7 @@ bool PEImageReader::Initialize(ProcessReaderWin* process_reader, |
| module_range_.SetRange(process_reader_->Is64Bit(), address, size); |
| if (!module_range_.IsValid()) { |
| LOG(WARNING) << "invalid module range for " << module_name << ": " |
| - << RangeToString(module_range_); |
| + << module_range_.AsString(); |
| return false; |
| } |
| module_name_ = module_name; |
| @@ -101,7 +94,7 @@ bool PEImageReader::GetCrashpadInfo( |
| section.Misc.VirtualSize); |
| if (!crashpad_info_range.IsValid()) { |
| LOG(WARNING) << "invalid range for crashpad info: " |
| - << RangeToString(crashpad_info_range); |
| + << crashpad_info_range.AsString(); |
| return false; |
| } |
| @@ -130,37 +123,10 @@ bool PEImageReader::GetCrashpadInfo( |
| bool PEImageReader::DebugDirectoryInformation(UUID* uuid, |
| DWORD* age, |
| std::string* pdbname) const { |
| - if (process_reader_->Is64Bit()) { |
| - return ReadDebugDirectoryInformation<IMAGE_NT_HEADERS64>( |
| - uuid, age, pdbname); |
| - } else { |
| - return ReadDebugDirectoryInformation<IMAGE_NT_HEADERS32>( |
| - uuid, age, pdbname); |
| - } |
| -} |
| - |
| -template <class NtHeadersType> |
| -bool PEImageReader::ReadDebugDirectoryInformation(UUID* uuid, |
| - DWORD* age, |
| - std::string* pdbname) const { |
| - NtHeadersType nt_headers; |
| - if (!ReadNtHeaders(&nt_headers, nullptr)) |
| + IMAGE_DATA_DIRECTORY data_directory; |
| + if (!ImageDataDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG, &data_directory)) |
| return false; |
| - if (nt_headers.FileHeader.SizeOfOptionalHeader < |
| - offsetof(decltype(nt_headers.OptionalHeader), |
| - DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]) + |
| - sizeof(nt_headers.OptionalHeader |
| - .DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]) || |
| - nt_headers.OptionalHeader.NumberOfRvaAndSizes <= |
| - IMAGE_DIRECTORY_ENTRY_DEBUG) { |
| - return false; |
| - } |
| - |
| - const IMAGE_DATA_DIRECTORY& data_directory = |
| - nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]; |
| - if (data_directory.VirtualAddress == 0 || data_directory.Size == 0) |
| - return false; |
| IMAGE_DEBUG_DIRECTORY debug_directory; |
| if (data_directory.Size % sizeof(debug_directory) != 0) |
| return false; |
| @@ -216,6 +182,83 @@ bool PEImageReader::ReadDebugDirectoryInformation(UUID* uuid, |
| return false; |
| } |
| +bool PEImageReader::VSFixedFileInfo( |
| + VS_FIXEDFILEINFO* vs_fixed_file_info) const { |
| + IMAGE_DATA_DIRECTORY data_directory; |
| + if (!ImageDataDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE, |
| + &data_directory)) { |
| + return false; |
| + } |
| + |
| + PEImageResourceReader resource_reader; |
| + if (!resource_reader.Initialize( |
| + process_reader_, data_directory, module_range_, module_name_)) { |
| + return false; |
| + } |
| + |
| + WinVMAddress address; |
| + WinVMSize size; |
| + if (!resource_reader.FindResourceByID( |
| + reinterpret_cast<uint16_t>(VS_FILE_INFO), |
| + VS_VERSION_INFO, |
| + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), |
| + &address, |
| + &size, |
| + nullptr)) { |
| + return false; |
| + } |
| + |
| + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001.aspx |
| + struct VS_VERSIONINFO { |
| + WORD wLength; |
| + WORD wValueLength; |
| + WORD wType; |
| + |
| + // MSDN doesn’t show the [16], but this is in fact a 16-character string. |
| + WCHAR szKey[16]; |
| + |
| + WORD Padding1; |
| + VS_FIXEDFILEINFO Value; |
| + |
| + // Don’t include Children or the Padding2 that precedes it, because they may |
| + // not be present. |
| + // WORD Padding2; |
| + // WORD Children; |
| + }; |
| + VS_VERSIONINFO version_info; |
| + |
| + if (size < sizeof(version_info)) { |
| + LOG(WARNING) << "version info size " << size |
| + << " too small for structure of size " << sizeof(version_info) |
| + << " in " << module_name_; |
| + return false; |
| + } |
| + |
| + if (!CheckedReadMemory(address, sizeof(version_info), &version_info)) { |
| + return false; |
| + } |
| + |
| + if (version_info.wLength < sizeof(version_info) || |
| + version_info.wValueLength < sizeof(version_info.Value) || |
|
scottmg
2015/11/26 21:29:59
!= for this one rather than <, as if it's not our
Mark Mentovai
2015/12/01 18:48:00
scottmg wrote:
|
| + version_info.wType != 0 || |
| + wcsncmp(version_info.szKey, |
| + L"VS_VERSION_INFO", |
| + arraysize(version_info.szKey)) != 0) { |
| + LOG(WARNING) << "unexpected VS_VERSIONINFO"; |
| + return false; |
| + } |
| + |
| + if (version_info.Value.dwSignature != VS_FFI_SIGNATURE || |
| + version_info.Value.dwStrucVersion != VS_FFI_STRUCVERSION) { |
| + LOG(WARNING) << "unexpected VS_FIXEDFILEINFO"; |
| + return false; |
| + } |
| + |
| + *vs_fixed_file_info = version_info.Value; |
| + vs_fixed_file_info->dwFileFlags &= vs_fixed_file_info->dwFileFlagsMask; |
| + return true; |
| +} |
| + |
| template <class NtHeadersType> |
| bool PEImageReader::ReadNtHeaders(NtHeadersType* nt_headers, |
| WinVMAddress* nt_headers_address) const { |
| @@ -282,17 +325,49 @@ bool PEImageReader::GetSectionByName(const std::string& name, |
| return false; |
| } |
| +bool PEImageReader::ImageDataDirectoryEntry(size_t index, |
| + IMAGE_DATA_DIRECTORY* entry) const { |
| + bool rv; |
| + if (process_reader_->Is64Bit()) { |
| + rv = ImageDataDirectoryEntryT<IMAGE_NT_HEADERS64>(index, entry); |
| + } else { |
| + rv = ImageDataDirectoryEntryT<IMAGE_NT_HEADERS32>(index, entry); |
| + } |
| + |
| + return rv && entry->VirtualAddress != 0 && entry->Size != 0; |
| +} |
| + |
| +template <class NtHeadersType> |
| +bool PEImageReader::ImageDataDirectoryEntryT( |
| + size_t index, |
| + IMAGE_DATA_DIRECTORY* entry) const { |
| + NtHeadersType nt_headers; |
| + if (!ReadNtHeaders(&nt_headers, nullptr)) { |
| + return false; |
| + } |
| + |
| + if (nt_headers.FileHeader.SizeOfOptionalHeader < |
| + offsetof(decltype(nt_headers.OptionalHeader), DataDirectory[index]) + |
| + sizeof(nt_headers.OptionalHeader.DataDirectory[index]) || |
| + nt_headers.OptionalHeader.NumberOfRvaAndSizes <= index) { |
| + return false; |
| + } |
| + |
| + *entry = nt_headers.OptionalHeader.DataDirectory[index]; |
| + return true; |
| +} |
| + |
| bool PEImageReader::CheckedReadMemory(WinVMAddress address, |
| WinVMSize size, |
| void* into) const { |
| CheckedWinAddressRange read_range(process_reader_->Is64Bit(), address, size); |
| if (!read_range.IsValid()) { |
| - LOG(WARNING) << "invalid read range: " << RangeToString(read_range); |
| + LOG(WARNING) << "invalid read range: " << read_range.AsString(); |
| return false; |
| } |
| if (!module_range_.ContainsRange(read_range)) { |
| LOG(WARNING) << "attempt to read outside of module " << module_name_ |
| - << " at range: " << RangeToString(read_range); |
| + << " at range: " << read_range.AsString(); |
| return false; |
| } |
| return process_reader_->ReadMemory(address, size, into); |