Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(686)

Unified Diff: chrome/browser/safe_browsing/module_integrity_verifier.cc

Issue 434163002: Changes to module_integrity_verifier.cc that allow the function VerifyModule (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@patchHunting2
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/safe_browsing/module_integrity_verifier.cc
diff --git a/chrome/browser/safe_browsing/module_integrity_verifier.cc b/chrome/browser/safe_browsing/module_integrity_verifier.cc
index 82b9aca1c0dc193117db9641c95224b45415d15f..906e97a9e3805d094906cfc8e77a645fc6e11882 100644
--- a/chrome/browser/safe_browsing/module_integrity_verifier.cc
+++ b/chrome/browser/safe_browsing/module_integrity_verifier.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/safe_browsing/module_integrity_verifier.h"
+#include <set>
+
#include "base/files/file_path.h"
#include "base/files/memory_mapped_file.h"
#include "base/scoped_native_library.h"
@@ -13,41 +15,118 @@ namespace safe_browsing {
namespace {
-struct RelocEnumerationState {
- explicit RelocEnumerationState(HMODULE hModule);
- ~RelocEnumerationState();
+struct Export {
+ Export(void* addr, std::string name);
+ ~Export();
+
+ bool operator<(const Export& other) const;
+
+ void* addr;
+ std::string name;
+};
+
+Export::Export(void* addr, std::string name) : addr(addr), name(name) {
+}
+
+Export::~Export() {
+}
+
+bool Export::operator<(const Export& other) const {
+ return addr < other.addr;
+}
+
+struct ModuleVerificationState {
+ explicit ModuleVerificationState(HMODULE hModule);
+ ~ModuleVerificationState();
base::win::PEImageAsData disk_peimage;
- // The number of bytes made equivalent between memory and disk due to
- // relocations.
- int bytes_corrected_by_reloc;
+ // The module's preferred base address minus the base address it actually
+ // loaded at.
+ uintptr_t image_base_delta;
+
+ // The location of the disk_peimage module's code section minus that of the
+ // mem_peimage module's code section.
+ uintptr_t code_section_delta;
+
+ // The bytes corrected by relocs.
+ base::hash_set<uintptr_t> reloc_addr;
// Set true if the relocation table contains a reloc of type that we don't
// currently handle.
bool unknown_reloc_type;
- DISALLOW_COPY_AND_ASSIGN(RelocEnumerationState);
+ DISALLOW_COPY_AND_ASSIGN(ModuleVerificationState);
};
-RelocEnumerationState::RelocEnumerationState(HMODULE hModule)
+ModuleVerificationState::ModuleVerificationState(HMODULE hModule)
: disk_peimage(hModule),
- bytes_corrected_by_reloc(0),
+ image_base_delta(0),
+ code_section_delta(0),
+ reloc_addr(),
unknown_reloc_type(false) {
}
-RelocEnumerationState::~RelocEnumerationState() {
+ModuleVerificationState::~ModuleVerificationState() {
+}
+
+bool ByteAccountedForByReloc(uint8_t* byte_addr,
+ ModuleVerificationState* state) {
+ return ((state->reloc_addr.count(reinterpret_cast<uintptr_t>(byte_addr))) >
+ 0);
+}
+
+// Checks each byte in the module's code section again the corresponding byte on
+// disk. Returns a list of the functions who may have been modified.
+int ExamineBytesDiffInMemory(uint8_t* disk_code_start,
+ uint8_t* mem_code_start,
+ uint32_t code_size,
+ std::vector<Export> exports,
+ ModuleVerificationState* state,
+ std::set<std::string>* modified_exports) {
+ int bytes_different = 0;
+ std::vector<Export>::iterator export_it = exports.begin();
+
+ for (uint32_t i = 0; i < code_size; ++i) {
+ if (*(disk_code_start + i) != *(mem_code_start + i) &&
+ !ByteAccountedForByReloc(mem_code_start + i, state)) {
+ // We get the largest export address still smaller than |addr|. It is
+ // possible that |addr| belongs to some nonexported function located
+ // between this export and the following one.
+ Export addr =
+ Export(reinterpret_cast<void*>(mem_code_start + i), std::string());
+ std::vector<Export>::iterator modified_export_it =
+ std::upper_bound(export_it, exports.end(), addr);
+
+ if (modified_export_it != exports.begin())
+ modified_exports->insert((modified_export_it - 1)->name);
+ ++bytes_different;
+
+ // No later byte can belong to an earlier export.
+ export_it = modified_export_it;
+ }
+ }
+ return bytes_different;
}
-int CountBytesDiffInMemory(uint8_t* disk_code_start,
- uint8_t* memory_code_start,
- uint32_t code_size) {
- int counter = 0;
- for (int i = 0; i < static_cast<int>(code_size); ++i) {
- if (*(disk_code_start + i) != *(memory_code_start + i))
- ++counter;
+// Adds to |reloc_addr| the bytes of the pointer at |address| that are corrected
+// by adding |image_base_delta|.
+void AddBytesCorrectedByReloc(ModuleVerificationState* state,
+ uintptr_t address) {
+ uintptr_t orig_value = *reinterpret_cast<uintptr_t*>(address);
+ uintptr_t fixed_mem_value = orig_value + state->image_base_delta;
+ uintptr_t disk_value =
+ *reinterpret_cast<uintptr_t*>(address + state->code_section_delta);
+
+ for (int i = 0; i < sizeof(address); ++i) {
+ if ((orig_value & 0xFF) != (disk_value & 0xFF) &&
+ (fixed_mem_value & 0xFF) == (disk_value & 0xFF)) {
+ state->reloc_addr.insert(address + i);
+ }
+ orig_value >>= 8;
+ fixed_mem_value >>= 8;
+ disk_value >>= 8;
}
- return counter;
}
bool AddrIsInCodeSection(void* address,
@@ -60,15 +139,14 @@ bool EnumRelocsCallback(const base::win::PEImage& mem_peimage,
WORD type,
void* address,
void* cookie) {
- RelocEnumerationState* reloc_enum_state =
- reinterpret_cast<RelocEnumerationState*>(cookie);
- const base::win::PEImageAsData* disk_peimage_ptr =
- &reloc_enum_state->disk_peimage;
+ ModuleVerificationState* state =
+ reinterpret_cast<ModuleVerificationState*>(cookie);
+
uint8_t* mem_code_addr = NULL;
uint8_t* disk_code_addr = NULL;
uint32_t code_size = 0;
if (!GetCodeAddrsAndSize(mem_peimage,
- *disk_peimage_ptr,
+ state->disk_peimage,
&mem_code_addr,
&disk_code_addr,
&code_size))
@@ -80,21 +158,7 @@ bool EnumRelocsCallback(const base::win::PEImage& mem_peimage,
switch (type) {
case IMAGE_REL_BASED_HIGHLOW: {
- uint8_t* preferred_image_base = reinterpret_cast<uint8_t*>(
- disk_peimage_ptr->GetNTHeaders()->OptionalHeader.ImageBase);
- uintptr_t delta = preferred_image_base -
- reinterpret_cast<uint8_t*>(mem_peimage.module());
- uint8_t* new_value = (*reinterpret_cast<uint8_t**>(address)) + delta;
- int bytes_corrected =
- CountBytesDiffInPtr(reinterpret_cast<uintptr_t>(new_value),
- *reinterpret_cast<uintptr_t*>(address));
-
- // Check that the adding delta corrected the value to agree with disk.
- uint8_t** disk_address = reinterpret_cast<uint8_t**>(
- reinterpret_cast<uint8_t*>(address) - mem_code_addr + disk_code_addr);
- if (new_value == *disk_address) {
- reloc_enum_state->bytes_corrected_by_reloc += bytes_corrected;
- }
+ AddBytesCorrectedByReloc(state, reinterpret_cast<uintptr_t>(address));
break;
}
case IMAGE_REL_BASED_ABSOLUTE:
@@ -104,13 +168,27 @@ bool EnumRelocsCallback(const base::win::PEImage& mem_peimage,
default: {
// TODO(krstnmnlsn): Find a reliable description of the behaviour of the
// remaining types of relocation and handle them.
- reloc_enum_state->unknown_reloc_type = true;
+ state->unknown_reloc_type = true;
break;
}
}
return true;
}
+bool EnumExportsCallback(const base::win::PEImage& mem_peimage,
+ DWORD ordinal,
+ DWORD hint,
+ LPCSTR name,
+ PVOID function_addr,
+ LPCSTR forward,
+ PVOID cookie) {
+ std::vector<Export>* exports = reinterpret_cast<std::vector<Export>*>(cookie);
+ if (name) {
+ exports->push_back(Export(function_addr, std::string(name)));
+ }
+ return true;
+}
+
} // namespace
bool GetCodeAddrsAndSize(const base::win::PEImage& mem_peimage,
@@ -140,18 +218,9 @@ bool GetCodeAddrsAndSize(const base::win::PEImage& mem_peimage,
return true;
}
-int CountBytesDiffInPtr(uintptr_t num_a, uintptr_t num_b) {
- int num_bytes = 0;
- for (int i = 0; i < sizeof(num_a); ++i) {
- if ((num_a & 0xFF) != (num_b & 0xFF))
- ++num_bytes;
- num_a >>= 8;
- num_b >>= 8;
- }
- return num_bytes;
-}
-
-ModuleState VerifyModule(const wchar_t* module_name) {
+ModuleState VerifyModule(const wchar_t* module_name,
+ std::set<std::string>* modified_exports) {
+ // Get module handle, load a copy from disk as data and create PEImages.
HMODULE module_handle = NULL;
if (!GetModuleHandleEx(0, module_name, &module_handle))
return MODULE_STATE_UNKNOWN;
@@ -166,31 +235,52 @@ ModuleState VerifyModule(const wchar_t* module_name) {
base::MemoryMappedFile mapped_module;
if (!mapped_module.Initialize(base::FilePath(module_path)))
return MODULE_STATE_UNKNOWN;
- RelocEnumerationState reloc_enum_state(
+ ModuleVerificationState state(
reinterpret_cast<HMODULE>(const_cast<uint8*>(mapped_module.data())));
base::win::PEImage mem_peimage(module_handle);
- if (!mem_peimage.VerifyMagic() ||
- !reloc_enum_state.disk_peimage.VerifyMagic())
+ if (!mem_peimage.VerifyMagic() || !state.disk_peimage.VerifyMagic())
return MODULE_STATE_UNKNOWN;
+ // Get the list of exports.
+ std::vector<Export> exports;
+ mem_peimage.EnumExports(EnumExportsCallback, &exports);
+ std::sort(exports.begin(), exports.end());
+
+ // Get the addresses of the code sections then calculate |code_section_delta|
+ // and |image_base_delta|.
uint8_t* mem_code_addr = NULL;
uint8_t* disk_code_addr = NULL;
uint32_t code_size = 0;
if (!GetCodeAddrsAndSize(mem_peimage,
- reloc_enum_state.disk_peimage,
+ state.disk_peimage,
&mem_code_addr,
&disk_code_addr,
&code_size))
return MODULE_STATE_UNKNOWN;
- mem_peimage.EnumRelocs(EnumRelocsCallback, &reloc_enum_state);
- if (reloc_enum_state.unknown_reloc_type)
+ state.code_section_delta = disk_code_addr - mem_code_addr;
+
+ uint8_t* preferred_image_base = reinterpret_cast<uint8_t*>(
+ state.disk_peimage.GetNTHeaders()->OptionalHeader.ImageBase);
+ state.image_base_delta =
+ preferred_image_base - reinterpret_cast<uint8_t*>(mem_peimage.module());
+
+ // Get the relocations.
+ mem_peimage.EnumRelocs(EnumRelocsCallback, &state);
+ if (state.unknown_reloc_type)
return MODULE_STATE_UNKNOWN;
- int num_bytes_different =
- CountBytesDiffInMemory(disk_code_addr, mem_code_addr, code_size);
- if (num_bytes_different == reloc_enum_state.bytes_corrected_by_reloc)
+ // Count the modified bytes (after accounting for relocs) and get the set of
+ // modified functions.
+ int num_bytes_different = ExamineBytesDiffInMemory(disk_code_addr,
+ mem_code_addr,
+ code_size,
+ exports,
+ &state,
+ modified_exports);
+
+ if (num_bytes_different == 0)
return MODULE_STATE_UNMODIFIED;
return MODULE_STATE_MODIFIED;
}

Powered by Google App Engine
This is Rietveld 408576698