security/sandbox/win/src/interception.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 // For information about interceptions as a whole see
michael@0 6 // http://dev.chromium.org/developers/design-documents/sandbox .
michael@0 7
michael@0 8 #include <set>
michael@0 9
michael@0 10 #include "sandbox/win/src/interception.h"
michael@0 11
michael@0 12 #include "base/logging.h"
michael@0 13 #include "base/memory/scoped_ptr.h"
michael@0 14 #include "base/win/pe_image.h"
michael@0 15 #include "base/win/windows_version.h"
michael@0 16 #include "sandbox/win/src/interception_internal.h"
michael@0 17 #include "sandbox/win/src/interceptors.h"
michael@0 18 #include "sandbox/win/src/sandbox.h"
michael@0 19 #include "sandbox/win/src/sandbox_utils.h"
michael@0 20 #include "sandbox/win/src/service_resolver.h"
michael@0 21 #include "sandbox/win/src/target_interceptions.h"
michael@0 22 #include "sandbox/win/src/target_process.h"
michael@0 23 #include "sandbox/win/src/wow64.h"
michael@0 24
michael@0 25 namespace {
michael@0 26
michael@0 27 const char kMapViewOfSectionName[] = "NtMapViewOfSection";
michael@0 28 const char kUnmapViewOfSectionName[] = "NtUnmapViewOfSection";
michael@0 29
michael@0 30 // Standard allocation granularity and page size for Windows.
michael@0 31 const size_t kAllocGranularity = 65536;
michael@0 32 const size_t kPageSize = 4096;
michael@0 33
michael@0 34 // Find a random offset within 64k and aligned to ceil(log2(size)).
michael@0 35 size_t GetGranularAlignedRandomOffset(size_t size) {
michael@0 36 CHECK_LE(size, kAllocGranularity);
michael@0 37 unsigned int offset;
michael@0 38
michael@0 39 do {
michael@0 40 rand_s(&offset);
michael@0 41 offset &= (kAllocGranularity - 1);
michael@0 42 } while (offset > (kAllocGranularity - size));
michael@0 43
michael@0 44 // Find an alignment between 64 and the page size (4096).
michael@0 45 size_t align_size = kPageSize;
michael@0 46 for (size_t new_size = align_size / 2; new_size >= size; new_size /= 2) {
michael@0 47 align_size = new_size;
michael@0 48 }
michael@0 49 return offset & ~(align_size - 1);
michael@0 50 }
michael@0 51
michael@0 52 } // namespace
michael@0 53
michael@0 54 namespace sandbox {
michael@0 55
michael@0 56 SANDBOX_INTERCEPT SharedMemory* g_interceptions;
michael@0 57
michael@0 58 // Table of the unpatched functions that we intercept. Mapped from the parent.
michael@0 59 SANDBOX_INTERCEPT OriginalFunctions g_originals = { NULL };
michael@0 60
michael@0 61 // Magic constant that identifies that this function is not to be patched.
michael@0 62 const char kUnloadDLLDummyFunction[] = "@";
michael@0 63
michael@0 64 InterceptionManager::InterceptionManager(TargetProcess* child_process,
michael@0 65 bool relaxed)
michael@0 66 : child_(child_process), names_used_(false), relaxed_(relaxed) {
michael@0 67 child_->AddRef();
michael@0 68 }
michael@0 69 InterceptionManager::~InterceptionManager() {
michael@0 70 child_->Release();
michael@0 71 }
michael@0 72
michael@0 73 bool InterceptionManager::AddToPatchedFunctions(
michael@0 74 const wchar_t* dll_name, const char* function_name,
michael@0 75 InterceptionType interception_type, const void* replacement_code_address,
michael@0 76 InterceptorId id) {
michael@0 77 InterceptionData function;
michael@0 78 function.type = interception_type;
michael@0 79 function.id = id;
michael@0 80 function.dll = dll_name;
michael@0 81 function.function = function_name;
michael@0 82 function.interceptor_address = replacement_code_address;
michael@0 83
michael@0 84 interceptions_.push_back(function);
michael@0 85 return true;
michael@0 86 }
michael@0 87
michael@0 88 bool InterceptionManager::AddToPatchedFunctions(
michael@0 89 const wchar_t* dll_name, const char* function_name,
michael@0 90 InterceptionType interception_type, const char* replacement_function_name,
michael@0 91 InterceptorId id) {
michael@0 92 InterceptionData function;
michael@0 93 function.type = interception_type;
michael@0 94 function.id = id;
michael@0 95 function.dll = dll_name;
michael@0 96 function.function = function_name;
michael@0 97 function.interceptor = replacement_function_name;
michael@0 98 function.interceptor_address = NULL;
michael@0 99
michael@0 100 interceptions_.push_back(function);
michael@0 101 names_used_ = true;
michael@0 102 return true;
michael@0 103 }
michael@0 104
michael@0 105 bool InterceptionManager::AddToUnloadModules(const wchar_t* dll_name) {
michael@0 106 InterceptionData module_to_unload;
michael@0 107 module_to_unload.type = INTERCEPTION_UNLOAD_MODULE;
michael@0 108 module_to_unload.dll = dll_name;
michael@0 109 // The next two are dummy values that make the structures regular, instead
michael@0 110 // of having special cases. They should not be used.
michael@0 111 module_to_unload.function = kUnloadDLLDummyFunction;
michael@0 112 module_to_unload.interceptor_address = reinterpret_cast<void*>(1);
michael@0 113
michael@0 114 interceptions_.push_back(module_to_unload);
michael@0 115 return true;
michael@0 116 }
michael@0 117
michael@0 118 bool InterceptionManager::InitializeInterceptions() {
michael@0 119 if (interceptions_.empty())
michael@0 120 return true; // Nothing to do here
michael@0 121
michael@0 122 size_t buffer_bytes = GetBufferSize();
michael@0 123 scoped_ptr<char[]> local_buffer(new char[buffer_bytes]);
michael@0 124
michael@0 125 if (!SetupConfigBuffer(local_buffer.get(), buffer_bytes))
michael@0 126 return false;
michael@0 127
michael@0 128 void* remote_buffer;
michael@0 129 if (!CopyDataToChild(local_buffer.get(), buffer_bytes, &remote_buffer))
michael@0 130 return false;
michael@0 131
michael@0 132 bool hot_patch_needed = (0 != buffer_bytes);
michael@0 133 if (!PatchNtdll(hot_patch_needed))
michael@0 134 return false;
michael@0 135
michael@0 136 g_interceptions = reinterpret_cast<SharedMemory*>(remote_buffer);
michael@0 137 ResultCode rc = child_->TransferVariable("g_interceptions",
michael@0 138 &g_interceptions,
michael@0 139 sizeof(g_interceptions));
michael@0 140 return (SBOX_ALL_OK == rc);
michael@0 141 }
michael@0 142
michael@0 143 size_t InterceptionManager::GetBufferSize() const {
michael@0 144 std::set<std::wstring> dlls;
michael@0 145 size_t buffer_bytes = 0;
michael@0 146
michael@0 147 std::list<InterceptionData>::const_iterator it = interceptions_.begin();
michael@0 148 for (; it != interceptions_.end(); ++it) {
michael@0 149 // skip interceptions that are performed from the parent
michael@0 150 if (!IsInterceptionPerformedByChild(*it))
michael@0 151 continue;
michael@0 152
michael@0 153 if (!dlls.count(it->dll)) {
michael@0 154 // NULL terminate the dll name on the structure
michael@0 155 size_t dll_name_bytes = (it->dll.size() + 1) * sizeof(wchar_t);
michael@0 156
michael@0 157 // include the dll related size
michael@0 158 buffer_bytes += RoundUpToMultiple(offsetof(DllPatchInfo, dll_name) +
michael@0 159 dll_name_bytes, sizeof(size_t));
michael@0 160 dlls.insert(it->dll);
michael@0 161 }
michael@0 162
michael@0 163 // we have to NULL terminate the strings on the structure
michael@0 164 size_t strings_chars = it->function.size() + it->interceptor.size() + 2;
michael@0 165
michael@0 166 // a new FunctionInfo is required per function
michael@0 167 size_t record_bytes = offsetof(FunctionInfo, function) + strings_chars;
michael@0 168 record_bytes = RoundUpToMultiple(record_bytes, sizeof(size_t));
michael@0 169 buffer_bytes += record_bytes;
michael@0 170 }
michael@0 171
michael@0 172 if (0 != buffer_bytes)
michael@0 173 // add the part of SharedMemory that we have not counted yet
michael@0 174 buffer_bytes += offsetof(SharedMemory, dll_list);
michael@0 175
michael@0 176 return buffer_bytes;
michael@0 177 }
michael@0 178
michael@0 179 // Basically, walk the list of interceptions moving them to the config buffer,
michael@0 180 // but keeping together all interceptions that belong to the same dll.
michael@0 181 // The config buffer is a local buffer, not the one allocated on the child.
michael@0 182 bool InterceptionManager::SetupConfigBuffer(void* buffer, size_t buffer_bytes) {
michael@0 183 if (0 == buffer_bytes)
michael@0 184 return true;
michael@0 185
michael@0 186 DCHECK(buffer_bytes > sizeof(SharedMemory));
michael@0 187
michael@0 188 SharedMemory* shared_memory = reinterpret_cast<SharedMemory*>(buffer);
michael@0 189 DllPatchInfo* dll_info = shared_memory->dll_list;
michael@0 190 int num_dlls = 0;
michael@0 191
michael@0 192 shared_memory->interceptor_base = names_used_ ? child_->MainModule() : NULL;
michael@0 193
michael@0 194 buffer_bytes -= offsetof(SharedMemory, dll_list);
michael@0 195 buffer = dll_info;
michael@0 196
michael@0 197 std::list<InterceptionData>::iterator it = interceptions_.begin();
michael@0 198 for (; it != interceptions_.end();) {
michael@0 199 // skip interceptions that are performed from the parent
michael@0 200 if (!IsInterceptionPerformedByChild(*it)) {
michael@0 201 ++it;
michael@0 202 continue;
michael@0 203 }
michael@0 204
michael@0 205 const std::wstring dll = it->dll;
michael@0 206 if (!SetupDllInfo(*it, &buffer, &buffer_bytes))
michael@0 207 return false;
michael@0 208
michael@0 209 // walk the interceptions from this point, saving the ones that are
michael@0 210 // performed on this dll, and removing the entry from the list.
michael@0 211 // advance the iterator before removing the element from the list
michael@0 212 std::list<InterceptionData>::iterator rest = it;
michael@0 213 for (; rest != interceptions_.end();) {
michael@0 214 if (rest->dll == dll) {
michael@0 215 if (!SetupInterceptionInfo(*rest, &buffer, &buffer_bytes, dll_info))
michael@0 216 return false;
michael@0 217 if (it == rest)
michael@0 218 ++it;
michael@0 219 rest = interceptions_.erase(rest);
michael@0 220 } else {
michael@0 221 ++rest;
michael@0 222 }
michael@0 223 }
michael@0 224 dll_info = reinterpret_cast<DllPatchInfo*>(buffer);
michael@0 225 ++num_dlls;
michael@0 226 }
michael@0 227
michael@0 228 shared_memory->num_intercepted_dlls = num_dlls;
michael@0 229 return true;
michael@0 230 }
michael@0 231
michael@0 232 // Fills up just the part that depends on the dll, not the info that depends on
michael@0 233 // the actual interception.
michael@0 234 bool InterceptionManager::SetupDllInfo(const InterceptionData& data,
michael@0 235 void** buffer,
michael@0 236 size_t* buffer_bytes) const {
michael@0 237 DCHECK(buffer_bytes);
michael@0 238 DCHECK(buffer);
michael@0 239 DCHECK(*buffer);
michael@0 240
michael@0 241 DllPatchInfo* dll_info = reinterpret_cast<DllPatchInfo*>(*buffer);
michael@0 242
michael@0 243 // the strings have to be zero terminated
michael@0 244 size_t required = offsetof(DllPatchInfo, dll_name) +
michael@0 245 (data.dll.size() + 1) * sizeof(wchar_t);
michael@0 246 required = RoundUpToMultiple(required, sizeof(size_t));
michael@0 247 if (*buffer_bytes < required)
michael@0 248 return false;
michael@0 249
michael@0 250 *buffer_bytes -= required;
michael@0 251 *buffer = reinterpret_cast<char*>(*buffer) + required;
michael@0 252
michael@0 253 // set up the dll info to be what we know about it at this time
michael@0 254 dll_info->unload_module = (data.type == INTERCEPTION_UNLOAD_MODULE);
michael@0 255 dll_info->record_bytes = required;
michael@0 256 dll_info->offset_to_functions = required;
michael@0 257 dll_info->num_functions = 0;
michael@0 258 data.dll._Copy_s(dll_info->dll_name, data.dll.size(), data.dll.size());
michael@0 259 dll_info->dll_name[data.dll.size()] = L'\0';
michael@0 260
michael@0 261 return true;
michael@0 262 }
michael@0 263
michael@0 264 bool InterceptionManager::SetupInterceptionInfo(const InterceptionData& data,
michael@0 265 void** buffer,
michael@0 266 size_t* buffer_bytes,
michael@0 267 DllPatchInfo* dll_info) const {
michael@0 268 DCHECK(buffer_bytes);
michael@0 269 DCHECK(buffer);
michael@0 270 DCHECK(*buffer);
michael@0 271
michael@0 272 if ((dll_info->unload_module) &&
michael@0 273 (data.function != kUnloadDLLDummyFunction)) {
michael@0 274 // Can't specify a dll for both patch and unload.
michael@0 275 NOTREACHED();
michael@0 276 }
michael@0 277
michael@0 278 FunctionInfo* function = reinterpret_cast<FunctionInfo*>(*buffer);
michael@0 279
michael@0 280 size_t name_bytes = data.function.size();
michael@0 281 size_t interceptor_bytes = data.interceptor.size();
michael@0 282
michael@0 283 // the strings at the end of the structure are zero terminated
michael@0 284 size_t required = offsetof(FunctionInfo, function) +
michael@0 285 name_bytes + interceptor_bytes + 2;
michael@0 286 required = RoundUpToMultiple(required, sizeof(size_t));
michael@0 287 if (*buffer_bytes < required)
michael@0 288 return false;
michael@0 289
michael@0 290 // update the caller's values
michael@0 291 *buffer_bytes -= required;
michael@0 292 *buffer = reinterpret_cast<char*>(*buffer) + required;
michael@0 293
michael@0 294 function->record_bytes = required;
michael@0 295 function->type = data.type;
michael@0 296 function->id = data.id;
michael@0 297 function->interceptor_address = data.interceptor_address;
michael@0 298 char* names = function->function;
michael@0 299
michael@0 300 data.function._Copy_s(names, name_bytes, name_bytes);
michael@0 301 names += name_bytes;
michael@0 302 *names++ = '\0';
michael@0 303
michael@0 304 // interceptor follows the function_name
michael@0 305 data.interceptor._Copy_s(names, interceptor_bytes, interceptor_bytes);
michael@0 306 names += interceptor_bytes;
michael@0 307 *names++ = '\0';
michael@0 308
michael@0 309 // update the dll table
michael@0 310 dll_info->num_functions++;
michael@0 311 dll_info->record_bytes += required;
michael@0 312
michael@0 313 return true;
michael@0 314 }
michael@0 315
michael@0 316 bool InterceptionManager::CopyDataToChild(const void* local_buffer,
michael@0 317 size_t buffer_bytes,
michael@0 318 void** remote_buffer) const {
michael@0 319 DCHECK(NULL != remote_buffer);
michael@0 320 if (0 == buffer_bytes) {
michael@0 321 *remote_buffer = NULL;
michael@0 322 return true;
michael@0 323 }
michael@0 324
michael@0 325 HANDLE child = child_->Process();
michael@0 326
michael@0 327 // Allocate memory on the target process without specifying the address
michael@0 328 void* remote_data = ::VirtualAllocEx(child, NULL, buffer_bytes,
michael@0 329 MEM_COMMIT, PAGE_READWRITE);
michael@0 330 if (NULL == remote_data)
michael@0 331 return false;
michael@0 332
michael@0 333 SIZE_T bytes_written;
michael@0 334 BOOL success = ::WriteProcessMemory(child, remote_data, local_buffer,
michael@0 335 buffer_bytes, &bytes_written);
michael@0 336 if (FALSE == success || bytes_written != buffer_bytes) {
michael@0 337 ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
michael@0 338 return false;
michael@0 339 }
michael@0 340
michael@0 341 *remote_buffer = remote_data;
michael@0 342
michael@0 343 return true;
michael@0 344 }
michael@0 345
michael@0 346 // Only return true if the child should be able to perform this interception.
michael@0 347 bool InterceptionManager::IsInterceptionPerformedByChild(
michael@0 348 const InterceptionData& data) const {
michael@0 349 if (INTERCEPTION_INVALID == data.type)
michael@0 350 return false;
michael@0 351
michael@0 352 if (INTERCEPTION_SERVICE_CALL == data.type)
michael@0 353 return false;
michael@0 354
michael@0 355 if (data.type >= INTERCEPTION_LAST)
michael@0 356 return false;
michael@0 357
michael@0 358 std::wstring ntdll(kNtdllName);
michael@0 359 if (ntdll == data.dll)
michael@0 360 return false; // ntdll has to be intercepted from the parent
michael@0 361
michael@0 362 return true;
michael@0 363 }
michael@0 364
michael@0 365 bool InterceptionManager::PatchNtdll(bool hot_patch_needed) {
michael@0 366 // Maybe there is nothing to do
michael@0 367 if (!hot_patch_needed && interceptions_.empty())
michael@0 368 return true;
michael@0 369
michael@0 370 if (hot_patch_needed) {
michael@0 371 #if SANDBOX_EXPORTS
michael@0 372 // Make sure the functions are not excluded by the linker.
michael@0 373 #if defined(_WIN64)
michael@0 374 #pragma comment(linker, "/include:TargetNtMapViewOfSection64")
michael@0 375 #pragma comment(linker, "/include:TargetNtUnmapViewOfSection64")
michael@0 376 #else
michael@0 377 #pragma comment(linker, "/include:_TargetNtMapViewOfSection@44")
michael@0 378 #pragma comment(linker, "/include:_TargetNtUnmapViewOfSection@12")
michael@0 379 #endif
michael@0 380 #endif
michael@0 381 ADD_NT_INTERCEPTION(NtMapViewOfSection, MAP_VIEW_OF_SECTION_ID, 44);
michael@0 382 ADD_NT_INTERCEPTION(NtUnmapViewOfSection, UNMAP_VIEW_OF_SECTION_ID, 12);
michael@0 383 }
michael@0 384
michael@0 385 // Reserve a full 64k memory range in the child process.
michael@0 386 HANDLE child = child_->Process();
michael@0 387 BYTE* thunk_base = reinterpret_cast<BYTE*>(
michael@0 388 ::VirtualAllocEx(child, NULL, kAllocGranularity,
michael@0 389 MEM_RESERVE, PAGE_NOACCESS));
michael@0 390
michael@0 391 // Find an aligned, random location within the reserved range.
michael@0 392 size_t thunk_bytes = interceptions_.size() * sizeof(ThunkData) +
michael@0 393 sizeof(DllInterceptionData);
michael@0 394 size_t thunk_offset = GetGranularAlignedRandomOffset(thunk_bytes);
michael@0 395
michael@0 396 // Split the base and offset along page boundaries.
michael@0 397 thunk_base += thunk_offset & ~(kPageSize - 1);
michael@0 398 thunk_offset &= kPageSize - 1;
michael@0 399
michael@0 400 // Make an aligned, padded allocation, and move the pointer to our chunk.
michael@0 401 size_t thunk_bytes_padded = (thunk_bytes + kPageSize - 1) & kPageSize;
michael@0 402 thunk_base = reinterpret_cast<BYTE*>(
michael@0 403 ::VirtualAllocEx(child, thunk_base, thunk_bytes_padded,
michael@0 404 MEM_COMMIT, PAGE_EXECUTE_READWRITE));
michael@0 405 CHECK(thunk_base); // If this fails we'd crash anyway on an invalid access.
michael@0 406 DllInterceptionData* thunks = reinterpret_cast<DllInterceptionData*>(
michael@0 407 thunk_base + thunk_offset);
michael@0 408
michael@0 409 DllInterceptionData dll_data;
michael@0 410 dll_data.data_bytes = thunk_bytes;
michael@0 411 dll_data.num_thunks = 0;
michael@0 412 dll_data.used_bytes = offsetof(DllInterceptionData, thunks);
michael@0 413
michael@0 414 // Reset all helpers for a new child.
michael@0 415 memset(g_originals, 0, sizeof(g_originals));
michael@0 416
michael@0 417 // this should write all the individual thunks to the child's memory
michael@0 418 if (!PatchClientFunctions(thunks, thunk_bytes, &dll_data))
michael@0 419 return false;
michael@0 420
michael@0 421 // and now write the first part of the table to the child's memory
michael@0 422 SIZE_T written;
michael@0 423 bool ok = FALSE != ::WriteProcessMemory(child, thunks, &dll_data,
michael@0 424 offsetof(DllInterceptionData, thunks),
michael@0 425 &written);
michael@0 426
michael@0 427 if (!ok || (offsetof(DllInterceptionData, thunks) != written))
michael@0 428 return false;
michael@0 429
michael@0 430 // Attempt to protect all the thunks, but ignore failure
michael@0 431 DWORD old_protection;
michael@0 432 ::VirtualProtectEx(child, thunks, thunk_bytes,
michael@0 433 PAGE_EXECUTE_READ, &old_protection);
michael@0 434
michael@0 435 ResultCode ret = child_->TransferVariable("g_originals", g_originals,
michael@0 436 sizeof(g_originals));
michael@0 437 return (SBOX_ALL_OK == ret);
michael@0 438 }
michael@0 439
michael@0 440 bool InterceptionManager::PatchClientFunctions(DllInterceptionData* thunks,
michael@0 441 size_t thunk_bytes,
michael@0 442 DllInterceptionData* dll_data) {
michael@0 443 DCHECK(NULL != thunks);
michael@0 444 DCHECK(NULL != dll_data);
michael@0 445
michael@0 446 HMODULE ntdll_base = ::GetModuleHandle(kNtdllName);
michael@0 447 if (!ntdll_base)
michael@0 448 return false;
michael@0 449
michael@0 450 base::win::PEImage ntdll_image(ntdll_base);
michael@0 451
michael@0 452 // Bypass purify's interception.
michael@0 453 wchar_t* loader_get = reinterpret_cast<wchar_t*>(
michael@0 454 ntdll_image.GetProcAddress("LdrGetDllHandle"));
michael@0 455 if (loader_get) {
michael@0 456 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
michael@0 457 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
michael@0 458 loader_get, &ntdll_base))
michael@0 459 return false;
michael@0 460 }
michael@0 461
michael@0 462 if (base::win::GetVersion() <= base::win::VERSION_VISTA) {
michael@0 463 Wow64 WowHelper(child_, ntdll_base);
michael@0 464 if (!WowHelper.WaitForNtdll())
michael@0 465 return false;
michael@0 466 }
michael@0 467
michael@0 468 char* interceptor_base = NULL;
michael@0 469
michael@0 470 #if SANDBOX_EXPORTS
michael@0 471 interceptor_base = reinterpret_cast<char*>(child_->MainModule());
michael@0 472 HMODULE local_interceptor = ::LoadLibrary(child_->Name());
michael@0 473 #endif
michael@0 474
michael@0 475 ServiceResolverThunk* thunk;
michael@0 476 #if defined(_WIN64)
michael@0 477 thunk = new ServiceResolverThunk(child_->Process(), relaxed_);
michael@0 478 #else
michael@0 479 base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
michael@0 480 if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
michael@0 481 if (os_info->version() >= base::win::VERSION_WIN8)
michael@0 482 thunk = new Wow64W8ResolverThunk(child_->Process(), relaxed_);
michael@0 483 else
michael@0 484 thunk = new Wow64ResolverThunk(child_->Process(), relaxed_);
michael@0 485 } else if (!IsXPSP2OrLater()) {
michael@0 486 thunk = new Win2kResolverThunk(child_->Process(), relaxed_);
michael@0 487 } else if (os_info->version() >= base::win::VERSION_WIN8) {
michael@0 488 thunk = new Win8ResolverThunk(child_->Process(), relaxed_);
michael@0 489 } else {
michael@0 490 thunk = new ServiceResolverThunk(child_->Process(), relaxed_);
michael@0 491 }
michael@0 492 #endif
michael@0 493
michael@0 494 std::list<InterceptionData>::iterator it = interceptions_.begin();
michael@0 495 for (; it != interceptions_.end(); ++it) {
michael@0 496 const std::wstring ntdll(kNtdllName);
michael@0 497 if (it->dll != ntdll)
michael@0 498 break;
michael@0 499
michael@0 500 if (INTERCEPTION_SERVICE_CALL != it->type)
michael@0 501 break;
michael@0 502
michael@0 503 #if SANDBOX_EXPORTS
michael@0 504 // We may be trying to patch by function name.
michael@0 505 if (NULL == it->interceptor_address) {
michael@0 506 const char* address;
michael@0 507 NTSTATUS ret = thunk->ResolveInterceptor(local_interceptor,
michael@0 508 it->interceptor.c_str(),
michael@0 509 reinterpret_cast<const void**>(
michael@0 510 &address));
michael@0 511 if (!NT_SUCCESS(ret))
michael@0 512 break;
michael@0 513
michael@0 514 // Translate the local address to an address on the child.
michael@0 515 it->interceptor_address = interceptor_base + (address -
michael@0 516 reinterpret_cast<char*>(local_interceptor));
michael@0 517 }
michael@0 518 #endif
michael@0 519 NTSTATUS ret = thunk->Setup(ntdll_base,
michael@0 520 interceptor_base,
michael@0 521 it->function.c_str(),
michael@0 522 it->interceptor.c_str(),
michael@0 523 it->interceptor_address,
michael@0 524 &thunks->thunks[dll_data->num_thunks],
michael@0 525 thunk_bytes - dll_data->used_bytes,
michael@0 526 NULL);
michael@0 527 if (!NT_SUCCESS(ret))
michael@0 528 break;
michael@0 529
michael@0 530 DCHECK(!g_originals[it->id]);
michael@0 531 g_originals[it->id] = &thunks->thunks[dll_data->num_thunks];
michael@0 532
michael@0 533 dll_data->num_thunks++;
michael@0 534 dll_data->used_bytes += sizeof(ThunkData);
michael@0 535 }
michael@0 536
michael@0 537 delete(thunk);
michael@0 538
michael@0 539 #if SANDBOX_EXPORTS
michael@0 540 if (NULL != local_interceptor)
michael@0 541 ::FreeLibrary(local_interceptor);
michael@0 542 #endif
michael@0 543
michael@0 544 if (it != interceptions_.end())
michael@0 545 return false;
michael@0 546
michael@0 547 return true;
michael@0 548 }
michael@0 549
michael@0 550 } // namespace sandbox

mercurial