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