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

Side by Side 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, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/safe_browsing/module_integrity_verifier.h" 5 #include "chrome/browser/safe_browsing/module_integrity_verifier.h"
6 6
7 #include <set>
8
7 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
8 #include "base/files/memory_mapped_file.h" 10 #include "base/files/memory_mapped_file.h"
9 #include "base/scoped_native_library.h" 11 #include "base/scoped_native_library.h"
10 #include "base/win/pe_image.h" 12 #include "base/win/pe_image.h"
11 13
12 namespace safe_browsing { 14 namespace safe_browsing {
13 15
14 namespace { 16 namespace {
15 17
16 struct RelocEnumerationState { 18 struct Export {
17 explicit RelocEnumerationState(HMODULE hModule); 19 Export(void* addr, std::string name);
18 ~RelocEnumerationState(); 20 ~Export();
21
22 bool operator<(const Export& other) const;
23
24 void* addr;
25 std::string name;
26 };
27
28 Export::Export(void* addr, std::string name) : addr(addr), name(name) {
29 }
30
31 Export::~Export() {
32 }
33
34 bool Export::operator<(const Export& other) const {
35 return addr < other.addr;
36 }
37
38 struct ModuleVerificationState {
39 explicit ModuleVerificationState(HMODULE hModule);
40 ~ModuleVerificationState();
19 41
20 base::win::PEImageAsData disk_peimage; 42 base::win::PEImageAsData disk_peimage;
21 43
22 // The number of bytes made equivalent between memory and disk due to 44 // The module's preferred base address minus the base address it actually
23 // relocations. 45 // loaded at.
24 int bytes_corrected_by_reloc; 46 uintptr_t image_base_delta;
47
48 // The location of the disk_peimage module's code section minus that of the
49 // mem_peimage module's code section.
50 uintptr_t code_section_delta;
51
52 // The bytes corrected by relocs.
53 base::hash_set<uintptr_t> reloc_addr;
25 54
26 // Set true if the relocation table contains a reloc of type that we don't 55 // Set true if the relocation table contains a reloc of type that we don't
27 // currently handle. 56 // currently handle.
28 bool unknown_reloc_type; 57 bool unknown_reloc_type;
29 58
30 DISALLOW_COPY_AND_ASSIGN(RelocEnumerationState); 59 DISALLOW_COPY_AND_ASSIGN(ModuleVerificationState);
31 }; 60 };
32 61
33 RelocEnumerationState::RelocEnumerationState(HMODULE hModule) 62 ModuleVerificationState::ModuleVerificationState(HMODULE hModule)
34 : disk_peimage(hModule), 63 : disk_peimage(hModule),
35 bytes_corrected_by_reloc(0), 64 image_base_delta(0),
65 code_section_delta(0),
66 reloc_addr(),
36 unknown_reloc_type(false) { 67 unknown_reloc_type(false) {
37 } 68 }
38 69
39 RelocEnumerationState::~RelocEnumerationState() { 70 ModuleVerificationState::~ModuleVerificationState() {
40 } 71 }
41 72
42 int CountBytesDiffInMemory(uint8_t* disk_code_start, 73 bool ByteAccountedForByReloc(uint8_t* byte_addr,
43 uint8_t* memory_code_start, 74 ModuleVerificationState* state) {
44 uint32_t code_size) { 75 return ((state->reloc_addr.count(reinterpret_cast<uintptr_t>(byte_addr))) >
45 int counter = 0; 76 0);
46 for (int i = 0; i < static_cast<int>(code_size); ++i) { 77 }
47 if (*(disk_code_start + i) != *(memory_code_start + i)) 78
48 ++counter; 79 // Checks each byte in the module's code section again the corresponding byte on
80 // disk. Returns a list of the functions who may have been modified.
81 int ExamineBytesDiffInMemory(uint8_t* disk_code_start,
82 uint8_t* mem_code_start,
83 uint32_t code_size,
84 std::vector<Export> exports,
85 ModuleVerificationState* state,
86 std::set<std::string>* modified_exports) {
87 int bytes_different = 0;
88 std::vector<Export>::iterator export_it = exports.begin();
89
90 for (uint32_t i = 0; i < code_size; ++i) {
91 if (*(disk_code_start + i) != *(mem_code_start + i) &&
92 !ByteAccountedForByReloc(mem_code_start + i, state)) {
93 // We get the largest export address still smaller than |addr|. It is
94 // possible that |addr| belongs to some nonexported function located
95 // between this export and the following one.
96 Export addr =
97 Export(reinterpret_cast<void*>(mem_code_start + i), std::string());
98 std::vector<Export>::iterator modified_export_it =
99 std::upper_bound(export_it, exports.end(), addr);
100
101 if (modified_export_it != exports.begin())
102 modified_exports->insert((modified_export_it - 1)->name);
103 ++bytes_different;
104
105 // No later byte can belong to an earlier export.
106 export_it = modified_export_it;
107 }
49 } 108 }
50 return counter; 109 return bytes_different;
110 }
111
112 // Adds to |reloc_addr| the bytes of the pointer at |address| that are corrected
113 // by adding |image_base_delta|.
114 void AddBytesCorrectedByReloc(ModuleVerificationState* state,
115 uintptr_t address) {
116 uintptr_t orig_value = *reinterpret_cast<uintptr_t*>(address);
117 uintptr_t fixed_mem_value = orig_value + state->image_base_delta;
118 uintptr_t disk_value =
119 *reinterpret_cast<uintptr_t*>(address + state->code_section_delta);
120
121 for (int i = 0; i < sizeof(address); ++i) {
122 if ((orig_value & 0xFF) != (disk_value & 0xFF) &&
123 (fixed_mem_value & 0xFF) == (disk_value & 0xFF)) {
124 state->reloc_addr.insert(address + i);
125 }
126 orig_value >>= 8;
127 fixed_mem_value >>= 8;
128 disk_value >>= 8;
129 }
51 } 130 }
52 131
53 bool AddrIsInCodeSection(void* address, 132 bool AddrIsInCodeSection(void* address,
54 uint8_t* code_addr, 133 uint8_t* code_addr,
55 uint32_t code_size) { 134 uint32_t code_size) {
56 return (code_addr <= address && address < code_addr + code_size); 135 return (code_addr <= address && address < code_addr + code_size);
57 } 136 }
58 137
59 bool EnumRelocsCallback(const base::win::PEImage& mem_peimage, 138 bool EnumRelocsCallback(const base::win::PEImage& mem_peimage,
60 WORD type, 139 WORD type,
61 void* address, 140 void* address,
62 void* cookie) { 141 void* cookie) {
63 RelocEnumerationState* reloc_enum_state = 142 ModuleVerificationState* state =
64 reinterpret_cast<RelocEnumerationState*>(cookie); 143 reinterpret_cast<ModuleVerificationState*>(cookie);
65 const base::win::PEImageAsData* disk_peimage_ptr = 144
66 &reloc_enum_state->disk_peimage;
67 uint8_t* mem_code_addr = NULL; 145 uint8_t* mem_code_addr = NULL;
68 uint8_t* disk_code_addr = NULL; 146 uint8_t* disk_code_addr = NULL;
69 uint32_t code_size = 0; 147 uint32_t code_size = 0;
70 if (!GetCodeAddrsAndSize(mem_peimage, 148 if (!GetCodeAddrsAndSize(mem_peimage,
71 *disk_peimage_ptr, 149 state->disk_peimage,
72 &mem_code_addr, 150 &mem_code_addr,
73 &disk_code_addr, 151 &disk_code_addr,
74 &code_size)) 152 &code_size))
75 return false; 153 return false;
76 154
77 // If not in the code section return true to continue to the next reloc. 155 // If not in the code section return true to continue to the next reloc.
78 if (!AddrIsInCodeSection(address, mem_code_addr, code_size)) 156 if (!AddrIsInCodeSection(address, mem_code_addr, code_size))
79 return true; 157 return true;
80 158
81 switch (type) { 159 switch (type) {
82 case IMAGE_REL_BASED_HIGHLOW: { 160 case IMAGE_REL_BASED_HIGHLOW: {
83 uint8_t* preferred_image_base = reinterpret_cast<uint8_t*>( 161 AddBytesCorrectedByReloc(state, reinterpret_cast<uintptr_t>(address));
84 disk_peimage_ptr->GetNTHeaders()->OptionalHeader.ImageBase);
85 uintptr_t delta = preferred_image_base -
86 reinterpret_cast<uint8_t*>(mem_peimage.module());
87 uint8_t* new_value = (*reinterpret_cast<uint8_t**>(address)) + delta;
88 int bytes_corrected =
89 CountBytesDiffInPtr(reinterpret_cast<uintptr_t>(new_value),
90 *reinterpret_cast<uintptr_t*>(address));
91
92 // Check that the adding delta corrected the value to agree with disk.
93 uint8_t** disk_address = reinterpret_cast<uint8_t**>(
94 reinterpret_cast<uint8_t*>(address) - mem_code_addr + disk_code_addr);
95 if (new_value == *disk_address) {
96 reloc_enum_state->bytes_corrected_by_reloc += bytes_corrected;
97 }
98 break; 162 break;
99 } 163 }
100 case IMAGE_REL_BASED_ABSOLUTE: 164 case IMAGE_REL_BASED_ABSOLUTE:
101 // Absolute type relocations are a noop, sometimes used to pad a section 165 // Absolute type relocations are a noop, sometimes used to pad a section
102 // of relocations. 166 // of relocations.
103 break; 167 break;
104 default: { 168 default: {
105 // TODO(krstnmnlsn): Find a reliable description of the behaviour of the 169 // TODO(krstnmnlsn): Find a reliable description of the behaviour of the
106 // remaining types of relocation and handle them. 170 // remaining types of relocation and handle them.
107 reloc_enum_state->unknown_reloc_type = true; 171 state->unknown_reloc_type = true;
108 break; 172 break;
109 } 173 }
110 } 174 }
111 return true; 175 return true;
112 } 176 }
113 177
178 bool EnumExportsCallback(const base::win::PEImage& mem_peimage,
179 DWORD ordinal,
180 DWORD hint,
181 LPCSTR name,
182 PVOID function_addr,
183 LPCSTR forward,
184 PVOID cookie) {
185 std::vector<Export>* exports = reinterpret_cast<std::vector<Export>*>(cookie);
186 if (name) {
187 exports->push_back(Export(function_addr, std::string(name)));
188 }
189 return true;
190 }
191
114 } // namespace 192 } // namespace
115 193
116 bool GetCodeAddrsAndSize(const base::win::PEImage& mem_peimage, 194 bool GetCodeAddrsAndSize(const base::win::PEImage& mem_peimage,
117 const base::win::PEImageAsData& disk_peimage, 195 const base::win::PEImageAsData& disk_peimage,
118 uint8_t** mem_code_addr, 196 uint8_t** mem_code_addr,
119 uint8_t** disk_code_addr, 197 uint8_t** disk_code_addr,
120 uint32_t* code_size) { 198 uint32_t* code_size) {
121 DWORD base_of_code = mem_peimage.GetNTHeaders()->OptionalHeader.BaseOfCode; 199 DWORD base_of_code = mem_peimage.GetNTHeaders()->OptionalHeader.BaseOfCode;
122 200
123 // Get the address and size of the code section in the loaded module image. 201 // Get the address and size of the code section in the loaded module image.
124 PIMAGE_SECTION_HEADER mem_code_header = 202 PIMAGE_SECTION_HEADER mem_code_header =
125 mem_peimage.GetImageSectionFromAddr(mem_peimage.RVAToAddr(base_of_code)); 203 mem_peimage.GetImageSectionFromAddr(mem_peimage.RVAToAddr(base_of_code));
126 if (mem_code_header == NULL) 204 if (mem_code_header == NULL)
127 return false; 205 return false;
128 *mem_code_addr = reinterpret_cast<uint8_t*>( 206 *mem_code_addr = reinterpret_cast<uint8_t*>(
129 mem_peimage.RVAToAddr(mem_code_header->VirtualAddress)); 207 mem_peimage.RVAToAddr(mem_code_header->VirtualAddress));
130 *code_size = mem_code_header->Misc.VirtualSize; 208 *code_size = mem_code_header->Misc.VirtualSize;
131 209
132 // Get the address of the code section in the module mapped as data from disk. 210 // Get the address of the code section in the module mapped as data from disk.
133 // Section size will be the same as in the loaded module. 211 // Section size will be the same as in the loaded module.
134 DWORD disk_code_offset = 0; 212 DWORD disk_code_offset = 0;
135 if (!mem_peimage.ImageAddrToOnDiskOffset( 213 if (!mem_peimage.ImageAddrToOnDiskOffset(
136 reinterpret_cast<void*>(*mem_code_addr), &disk_code_offset)) 214 reinterpret_cast<void*>(*mem_code_addr), &disk_code_offset))
137 return false; 215 return false;
138 *disk_code_addr = 216 *disk_code_addr =
139 reinterpret_cast<uint8_t*>(disk_peimage.module()) + disk_code_offset; 217 reinterpret_cast<uint8_t*>(disk_peimage.module()) + disk_code_offset;
140 return true; 218 return true;
141 } 219 }
142 220
143 int CountBytesDiffInPtr(uintptr_t num_a, uintptr_t num_b) { 221 ModuleState VerifyModule(const wchar_t* module_name,
144 int num_bytes = 0; 222 std::set<std::string>* modified_exports) {
145 for (int i = 0; i < sizeof(num_a); ++i) { 223 // Get module handle, load a copy from disk as data and create PEImages.
146 if ((num_a & 0xFF) != (num_b & 0xFF))
147 ++num_bytes;
148 num_a >>= 8;
149 num_b >>= 8;
150 }
151 return num_bytes;
152 }
153
154 ModuleState VerifyModule(const wchar_t* module_name) {
155 HMODULE module_handle = NULL; 224 HMODULE module_handle = NULL;
156 if (!GetModuleHandleEx(0, module_name, &module_handle)) 225 if (!GetModuleHandleEx(0, module_name, &module_handle))
157 return MODULE_STATE_UNKNOWN; 226 return MODULE_STATE_UNKNOWN;
158 base::ScopedNativeLibrary native_library(module_handle); 227 base::ScopedNativeLibrary native_library(module_handle);
159 228
160 WCHAR module_path[MAX_PATH] = {}; 229 WCHAR module_path[MAX_PATH] = {};
161 DWORD length = 230 DWORD length =
162 GetModuleFileName(module_handle, module_path, arraysize(module_path)); 231 GetModuleFileName(module_handle, module_path, arraysize(module_path));
163 if (!length || length == arraysize(module_path)) 232 if (!length || length == arraysize(module_path))
164 return MODULE_STATE_UNKNOWN; 233 return MODULE_STATE_UNKNOWN;
165 234
166 base::MemoryMappedFile mapped_module; 235 base::MemoryMappedFile mapped_module;
167 if (!mapped_module.Initialize(base::FilePath(module_path))) 236 if (!mapped_module.Initialize(base::FilePath(module_path)))
168 return MODULE_STATE_UNKNOWN; 237 return MODULE_STATE_UNKNOWN;
169 RelocEnumerationState reloc_enum_state( 238 ModuleVerificationState state(
170 reinterpret_cast<HMODULE>(const_cast<uint8*>(mapped_module.data()))); 239 reinterpret_cast<HMODULE>(const_cast<uint8*>(mapped_module.data())));
171 240
172 base::win::PEImage mem_peimage(module_handle); 241 base::win::PEImage mem_peimage(module_handle);
173 if (!mem_peimage.VerifyMagic() || 242 if (!mem_peimage.VerifyMagic() || !state.disk_peimage.VerifyMagic())
174 !reloc_enum_state.disk_peimage.VerifyMagic())
175 return MODULE_STATE_UNKNOWN; 243 return MODULE_STATE_UNKNOWN;
176 244
245 // Get the list of exports.
246 std::vector<Export> exports;
247 mem_peimage.EnumExports(EnumExportsCallback, &exports);
248 std::sort(exports.begin(), exports.end());
249
250 // Get the addresses of the code sections then calculate |code_section_delta|
251 // and |image_base_delta|.
177 uint8_t* mem_code_addr = NULL; 252 uint8_t* mem_code_addr = NULL;
178 uint8_t* disk_code_addr = NULL; 253 uint8_t* disk_code_addr = NULL;
179 uint32_t code_size = 0; 254 uint32_t code_size = 0;
180 if (!GetCodeAddrsAndSize(mem_peimage, 255 if (!GetCodeAddrsAndSize(mem_peimage,
181 reloc_enum_state.disk_peimage, 256 state.disk_peimage,
182 &mem_code_addr, 257 &mem_code_addr,
183 &disk_code_addr, 258 &disk_code_addr,
184 &code_size)) 259 &code_size))
185 return MODULE_STATE_UNKNOWN; 260 return MODULE_STATE_UNKNOWN;
186 261
187 mem_peimage.EnumRelocs(EnumRelocsCallback, &reloc_enum_state); 262 state.code_section_delta = disk_code_addr - mem_code_addr;
188 if (reloc_enum_state.unknown_reloc_type) 263
264 uint8_t* preferred_image_base = reinterpret_cast<uint8_t*>(
265 state.disk_peimage.GetNTHeaders()->OptionalHeader.ImageBase);
266 state.image_base_delta =
267 preferred_image_base - reinterpret_cast<uint8_t*>(mem_peimage.module());
268
269 // Get the relocations.
270 mem_peimage.EnumRelocs(EnumRelocsCallback, &state);
271 if (state.unknown_reloc_type)
189 return MODULE_STATE_UNKNOWN; 272 return MODULE_STATE_UNKNOWN;
190 273
191 int num_bytes_different = 274 // Count the modified bytes (after accounting for relocs) and get the set of
192 CountBytesDiffInMemory(disk_code_addr, mem_code_addr, code_size); 275 // modified functions.
193 if (num_bytes_different == reloc_enum_state.bytes_corrected_by_reloc) 276 int num_bytes_different = ExamineBytesDiffInMemory(disk_code_addr,
277 mem_code_addr,
278 code_size,
279 exports,
280 &state,
281 modified_exports);
282
283 if (num_bytes_different == 0)
194 return MODULE_STATE_UNMODIFIED; 284 return MODULE_STATE_UNMODIFIED;
195 return MODULE_STATE_MODIFIED; 285 return MODULE_STATE_MODIFIED;
196 } 286 }
197 287
198 } // namespace safe_browsing 288 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698