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); |