16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 26e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 36e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// found in the LICENSE file. 46e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/module_integrity_verifier_win.h" 66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/containers/hash_tables.h" 86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/file_path.h" 96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/memory_mapped_file.h" 106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/metrics/sparse_histogram.h" 116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/scoped_native_library.h" 126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/win/pe_image.h" 136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "build/build_config.h" 146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace safe_browsing { 166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)struct ModuleVerificationState { 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) explicit ModuleVerificationState(HMODULE hModule); 196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ~ModuleVerificationState(); 206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::win::PEImageAsData disk_peimage; 226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // The module's preferred base address minus the base address it actually 246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // loaded at. 256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) intptr_t image_base_delta; 266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // The location of the disk_peimage module's code section minus that of the 286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // mem_peimage module's code section. 296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) intptr_t code_section_delta; 306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // The bytes corrected by relocs. 326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::hash_set<uintptr_t> reloc_addr; 336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Set true if the relocation table contains a reloc of type that we don't 356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // currently handle. 366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) bool unknown_reloc_type; 376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) private: 396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ModuleVerificationState); 406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ModuleVerificationState::ModuleVerificationState(HMODULE hModule) 436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) : disk_peimage(hModule), 446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) image_base_delta(0), 456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) code_section_delta(0), 466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reloc_addr(), 476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) unknown_reloc_type(false) { 486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ModuleVerificationState::~ModuleVerificationState() { 516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace { 546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)struct Export { 566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Export(void* addr, const std::string& name); 576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ~Export(); 586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) bool operator<(const Export& other) const; 606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void* addr; 626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::string name; 636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)Export::Export(void* addr, const std::string& name) : addr(addr), name(name) { 666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)Export::~Export() { 696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool Export::operator<(const Export& other) const { 726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return addr < other.addr; 736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool ByteAccountedForByReloc(uint8_t* byte_addr, 766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const ModuleVerificationState& state) { 776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return ((state.reloc_addr.count(reinterpret_cast<uintptr_t>(byte_addr))) > 0); 786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Checks each byte in the module's code section again the corresponding byte on 816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// disk, returning the number of bytes differing between the two. Also adds the 826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// names of any modfied functions exported by name to |modified_exports|. 836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// |exports| must be sorted. 846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)int ExamineBytesDiffInMemory(uint8_t* disk_code_start, 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* mem_code_start, 866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t code_size, 876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const std::vector<Export>& exports, 886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const ModuleVerificationState& state, 896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::set<std::string>* modified_exports) { 906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) int bytes_different = 0; 916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::vector<Export>::const_iterator export_it = exports.begin(); 926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (uint8_t* end = mem_code_start + code_size; mem_code_start != end; 946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ++mem_code_start) { 956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if ((*disk_code_start++ != *mem_code_start) && 966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) !ByteAccountedForByReloc(mem_code_start, state)) { 976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // We get the largest export address still smaller than |addr|. It is 986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // possible that |addr| belongs to some nonexported function located 996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // between this export and the following one. 1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Export addr(reinterpret_cast<void*>(mem_code_start), std::string()); 1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::vector<Export>::const_iterator modified_export_it = 1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::upper_bound(export_it, exports.end(), addr); 1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (modified_export_it != exports.begin()) 1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) modified_exports->insert((modified_export_it - 1)->name); 1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ++bytes_different; 1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // No later byte can belong to an earlier export. 1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) export_it = modified_export_it; 1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return bytes_different; 1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Adds to |state->reloc_addr| the bytes of the pointer at |address| that are 1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// corrected by adding |image_base_delta|. 1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void AddBytesCorrectedByReloc(uintptr_t address, 1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ModuleVerificationState* state) { 1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#if defined(ARCH_CPU_LITTLE_ENDIAN) 1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)# define OFFSET(i) i 1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#else 1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)# define OFFSET(i) (sizeof(uintptr_t) - i) 1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#endif 1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uintptr_t orig_mem_value = *reinterpret_cast<uintptr_t*>(address); 1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uintptr_t fixed_mem_value = orig_mem_value + state->image_base_delta; 1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uintptr_t disk_value = 1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) *reinterpret_cast<uintptr_t*>(address + state->code_section_delta); 1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uintptr_t diff_before = orig_mem_value ^ disk_value; 1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uintptr_t shared_after = ~(fixed_mem_value ^ disk_value); 1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) int i = 0; 1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (uintptr_t fixed = diff_before & shared_after; fixed; fixed >>= 8, ++i) { 1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (fixed & 0xFF) 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state->reloc_addr.insert(address + OFFSET(i)); 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#undef OFFSET 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool AddrIsInCodeSection(void* address, 1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* code_addr, 1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t code_size) { 1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return (code_addr <= address && address < code_addr + code_size); 1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool EnumRelocsCallback(const base::win::PEImage& mem_peimage, 1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) WORD type, 1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void* address, 1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void* cookie) { 1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ModuleVerificationState* state = 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reinterpret_cast<ModuleVerificationState*>(cookie); 1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* mem_code_addr = NULL; 1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* disk_code_addr = NULL; 1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t code_size = 0; 1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!GetCodeAddrsAndSize(mem_peimage, 1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state->disk_peimage, 1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &mem_code_addr, 1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &disk_code_addr, 1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &code_size)) 1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If not in the code section return true to continue to the next reloc. 1646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!AddrIsInCodeSection(address, mem_code_addr, code_size)) 1656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return true; 1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) switch (type) { 1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case IMAGE_REL_BASED_ABSOLUTE: // 0 1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Absolute type relocations are a noop, sometimes used to pad a section 1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // of relocations. 1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) break; 1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case IMAGE_REL_BASED_HIGHLOW: // 3 1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // The base relocation applies all 32 bits of the difference to the 32-bit 1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // field at offset. 1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AddBytesCorrectedByReloc(reinterpret_cast<uintptr_t>(address), state); 1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci break; 1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case IMAGE_REL_BASED_DIR64: // 10 1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // The base relocation applies the difference to the 64-bit field at 1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // offset. 1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // TODO(robertshield): Handle this type of reloc. 1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci break; 1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci default: 1836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // TODO(robertshield): Find a reliable description of the behaviour of the 1846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // remaining types of relocation and handle them. 1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.ModuleBaseRelocation", type); 1866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state->unknown_reloc_type = true; 1876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) break; 1886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return true; 1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool EnumExportsCallback(const base::win::PEImage& mem_peimage, 1936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DWORD ordinal, 1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DWORD hint, 1956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) LPCSTR name, 1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) PVOID function_addr, 1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) LPCSTR forward, 1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) PVOID cookie) { 1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::vector<Export>* exports = reinterpret_cast<std::vector<Export>*>(cookie); 2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (name) 2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) exports->push_back(Export(function_addr, std::string(name))); 2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return true; 2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 2046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} // namespace 2066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool GetCodeAddrsAndSize(const base::win::PEImage& mem_peimage, 2086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const base::win::PEImageAsData& disk_peimage, 2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t** mem_code_addr, 2106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t** disk_code_addr, 2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t* code_size) { 2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DWORD base_of_code = mem_peimage.GetNTHeaders()->OptionalHeader.BaseOfCode; 2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Get the address and size of the code section in the loaded module image. 2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) PIMAGE_SECTION_HEADER mem_code_header = 2166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) mem_peimage.GetImageSectionFromAddr(mem_peimage.RVAToAddr(base_of_code)); 2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (mem_code_header == NULL) 2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) *mem_code_addr = reinterpret_cast<uint8_t*>( 2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) mem_peimage.RVAToAddr(mem_code_header->VirtualAddress)); 2216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If the section is padded with zeros when mapped then |VirtualSize| can be 2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // larger. Alternatively, |SizeOfRawData| can be rounded up to align 2236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // according to OptionalHeader.FileAlignment. 2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) *code_size = std::min(mem_code_header->Misc.VirtualSize, 2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) mem_code_header->SizeOfRawData); 2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Get the address of the code section in the module mapped as data from disk. 2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DWORD disk_code_offset = 0; 2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!mem_peimage.ImageAddrToOnDiskOffset( 2306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reinterpret_cast<void*>(*mem_code_addr), &disk_code_offset)) 2316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 2326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) *disk_code_addr = 2336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reinterpret_cast<uint8_t*>(disk_peimage.module()) + disk_code_offset; 2346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return true; 2356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 2366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ModuleState VerifyModule(const wchar_t* module_name, 2386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::set<std::string>* modified_exports) { 2396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Get module handle, load a copy from disk as data and create PEImages. 2406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HMODULE module_handle = NULL; 2416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!GetModuleHandleEx(0, module_name, &module_handle)) 2426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return MODULE_STATE_UNKNOWN; 2436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::ScopedNativeLibrary native_library(module_handle); 2446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) WCHAR module_path[MAX_PATH] = {}; 2466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DWORD length = 2476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) GetModuleFileName(module_handle, module_path, arraysize(module_path)); 2486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!length || length == arraysize(module_path)) 2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return MODULE_STATE_UNKNOWN; 2506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::MemoryMappedFile mapped_module; 2526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!mapped_module.Initialize(base::FilePath(module_path))) 2536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return MODULE_STATE_UNKNOWN; 2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ModuleVerificationState state( 2556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reinterpret_cast<HMODULE>(const_cast<uint8*>(mapped_module.data()))); 2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::win::PEImage mem_peimage(module_handle); 2586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!mem_peimage.VerifyMagic() || !state.disk_peimage.VerifyMagic()) 2596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return MODULE_STATE_UNKNOWN; 2606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Get the list of exports. 2626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::vector<Export> exports; 2636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) mem_peimage.EnumExports(EnumExportsCallback, &exports); 2646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::sort(exports.begin(), exports.end()); 2656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Get the addresses of the code sections then calculate |code_section_delta| 2676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // and |image_base_delta|. 2686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* mem_code_addr = NULL; 2696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* disk_code_addr = NULL; 2706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint32_t code_size = 0; 2716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!GetCodeAddrsAndSize(mem_peimage, 2726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state.disk_peimage, 2736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &mem_code_addr, 2746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &disk_code_addr, 2756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &code_size)) 2766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return MODULE_STATE_UNKNOWN; 2776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state.code_section_delta = disk_code_addr - mem_code_addr; 2796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* preferred_image_base = reinterpret_cast<uint8_t*>( 2816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state.disk_peimage.GetNTHeaders()->OptionalHeader.ImageBase); 2826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state.image_base_delta = 2836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) preferred_image_base - reinterpret_cast<uint8_t*>(mem_peimage.module()); 2846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Get the relocations. 2866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) mem_peimage.EnumRelocs(EnumRelocsCallback, &state); 2876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (state.unknown_reloc_type) 2886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return MODULE_STATE_UNKNOWN; 2896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Count the modified bytes (after accounting for relocs) and get the set of 2916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // modified functions. 2926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) int num_bytes_different = ExamineBytesDiffInMemory(disk_code_addr, 2936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) mem_code_addr, 2946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) code_size, 2956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) exports, 2966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state, 2976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) modified_exports); 2986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return num_bytes_different ? MODULE_STATE_MODIFIED : MODULE_STATE_UNMODIFIED; 3006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 3016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} // namespace safe_browsing 303