security/sandbox/win/src/sidestep_resolver.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) 2006-2008 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 #include "sandbox/win/src/sidestep_resolver.h"
michael@0 6
michael@0 7 #include "base/win/pe_image.h"
michael@0 8 #include "sandbox/win/src/sandbox_nt_util.h"
michael@0 9 #include "sandbox/win/src/sidestep/preamble_patcher.h"
michael@0 10
michael@0 11 namespace {
michael@0 12
michael@0 13 const size_t kSizeOfSidestepStub = sidestep::kMaxPreambleStubSize;
michael@0 14
michael@0 15 struct SidestepThunk {
michael@0 16 char sidestep[kSizeOfSidestepStub]; // Storage for the sidestep stub.
michael@0 17 int internal_thunk; // Dummy member to the beginning of the internal thunk.
michael@0 18 };
michael@0 19
michael@0 20 struct SmartThunk {
michael@0 21 const void* module_base; // Target module's base.
michael@0 22 const void* interceptor; // Real interceptor.
michael@0 23 SidestepThunk sidestep; // Standard sidestep thunk.
michael@0 24 };
michael@0 25
michael@0 26 } // namespace
michael@0 27
michael@0 28 namespace sandbox {
michael@0 29
michael@0 30 NTSTATUS SidestepResolverThunk::Setup(const void* target_module,
michael@0 31 const void* interceptor_module,
michael@0 32 const char* target_name,
michael@0 33 const char* interceptor_name,
michael@0 34 const void* interceptor_entry_point,
michael@0 35 void* thunk_storage,
michael@0 36 size_t storage_bytes,
michael@0 37 size_t* storage_used) {
michael@0 38 NTSTATUS ret = Init(target_module, interceptor_module, target_name,
michael@0 39 interceptor_name, interceptor_entry_point,
michael@0 40 thunk_storage, storage_bytes);
michael@0 41 if (!NT_SUCCESS(ret))
michael@0 42 return ret;
michael@0 43
michael@0 44 SidestepThunk* thunk = reinterpret_cast<SidestepThunk*>(thunk_storage);
michael@0 45
michael@0 46 size_t internal_bytes = storage_bytes - kSizeOfSidestepStub;
michael@0 47 if (!SetInternalThunk(&thunk->internal_thunk, internal_bytes, thunk_storage,
michael@0 48 interceptor_))
michael@0 49 return STATUS_BUFFER_TOO_SMALL;
michael@0 50
michael@0 51 AutoProtectMemory memory;
michael@0 52 ret = memory.ChangeProtection(target_, kSizeOfSidestepStub, PAGE_READWRITE);
michael@0 53 if (!NT_SUCCESS(ret))
michael@0 54 return ret;
michael@0 55
michael@0 56 sidestep::SideStepError rv = sidestep::PreamblePatcher::Patch(
michael@0 57 target_, reinterpret_cast<void*>(&thunk->internal_thunk), thunk_storage,
michael@0 58 kSizeOfSidestepStub);
michael@0 59
michael@0 60 if (sidestep::SIDESTEP_INSUFFICIENT_BUFFER == rv)
michael@0 61 return STATUS_BUFFER_TOO_SMALL;
michael@0 62
michael@0 63 if (sidestep::SIDESTEP_SUCCESS != rv)
michael@0 64 return STATUS_UNSUCCESSFUL;
michael@0 65
michael@0 66 if (storage_used)
michael@0 67 *storage_used = GetThunkSize();
michael@0 68
michael@0 69 return ret;
michael@0 70 }
michael@0 71
michael@0 72 size_t SidestepResolverThunk::GetThunkSize() const {
michael@0 73 return GetInternalThunkSize() + kSizeOfSidestepStub;
michael@0 74 }
michael@0 75
michael@0 76 // This is basically a wrapper around the normal sidestep patch that extends
michael@0 77 // the thunk to use a chained interceptor. It uses the fact that
michael@0 78 // SetInternalThunk generates the code to pass as the first parameter whatever
michael@0 79 // it receives as original_function; we let SidestepResolverThunk set this value
michael@0 80 // to its saved code, and then we change it to our thunk data.
michael@0 81 NTSTATUS SmartSidestepResolverThunk::Setup(const void* target_module,
michael@0 82 const void* interceptor_module,
michael@0 83 const char* target_name,
michael@0 84 const char* interceptor_name,
michael@0 85 const void* interceptor_entry_point,
michael@0 86 void* thunk_storage,
michael@0 87 size_t storage_bytes,
michael@0 88 size_t* storage_used) {
michael@0 89 if (storage_bytes < GetThunkSize())
michael@0 90 return STATUS_BUFFER_TOO_SMALL;
michael@0 91
michael@0 92 SmartThunk* thunk = reinterpret_cast<SmartThunk*>(thunk_storage);
michael@0 93 thunk->module_base = target_module;
michael@0 94
michael@0 95 NTSTATUS ret;
michael@0 96 if (interceptor_entry_point) {
michael@0 97 thunk->interceptor = interceptor_entry_point;
michael@0 98 } else {
michael@0 99 ret = ResolveInterceptor(interceptor_module, interceptor_name,
michael@0 100 &thunk->interceptor);
michael@0 101 if (!NT_SUCCESS(ret))
michael@0 102 return ret;
michael@0 103 }
michael@0 104
michael@0 105 // Perform a standard sidestep patch on the last part of the thunk, but point
michael@0 106 // to our internal smart interceptor.
michael@0 107 size_t standard_bytes = storage_bytes - offsetof(SmartThunk, sidestep);
michael@0 108 ret = SidestepResolverThunk::Setup(target_module, interceptor_module,
michael@0 109 target_name, NULL, &SmartStub,
michael@0 110 &thunk->sidestep, standard_bytes, NULL);
michael@0 111 if (!NT_SUCCESS(ret))
michael@0 112 return ret;
michael@0 113
michael@0 114 // Fix the internal thunk to pass the whole buffer to the interceptor.
michael@0 115 SetInternalThunk(&thunk->sidestep.internal_thunk, GetInternalThunkSize(),
michael@0 116 thunk_storage, &SmartStub);
michael@0 117
michael@0 118 if (storage_used)
michael@0 119 *storage_used = GetThunkSize();
michael@0 120
michael@0 121 return ret;
michael@0 122 }
michael@0 123
michael@0 124 size_t SmartSidestepResolverThunk::GetThunkSize() const {
michael@0 125 return GetInternalThunkSize() + kSizeOfSidestepStub +
michael@0 126 offsetof(SmartThunk, sidestep);
michael@0 127 }
michael@0 128
michael@0 129 // This code must basically either call the intended interceptor or skip the
michael@0 130 // call and invoke instead the original function. In any case, we are saving
michael@0 131 // the registers that may be trashed by our c++ code.
michael@0 132 //
michael@0 133 // This function is called with a first parameter inserted by us, that points
michael@0 134 // to our SmartThunk. When we call the interceptor we have to replace this
michael@0 135 // parameter with the one expected by that function (stored inside our
michael@0 136 // structure); on the other hand, when we skip the interceptor we have to remove
michael@0 137 // that extra argument before calling the original function.
michael@0 138 //
michael@0 139 // When we skip the interceptor, the transformation of the stack looks like:
michael@0 140 // On Entry: On Use: On Exit:
michael@0 141 // [param 2] = first real argument [param 2] (esp+1c) [param 2]
michael@0 142 // [param 1] = our SmartThunk [param 1] (esp+18) [ret address]
michael@0 143 // [ret address] = real caller [ret address] (esp+14) [xxx]
michael@0 144 // [xxx] [addr to jump to] (esp+10) [xxx]
michael@0 145 // [xxx] [saved eax] [xxx]
michael@0 146 // [xxx] [saved ebx] [xxx]
michael@0 147 // [xxx] [saved ecx] [xxx]
michael@0 148 // [xxx] [saved edx] [xxx]
michael@0 149 __declspec(naked)
michael@0 150 void SmartSidestepResolverThunk::SmartStub() {
michael@0 151 __asm {
michael@0 152 push eax // Space for the jump.
michael@0 153 push eax // Save registers.
michael@0 154 push ebx
michael@0 155 push ecx
michael@0 156 push edx
michael@0 157 mov ebx, [esp + 0x18] // First parameter = SmartThunk.
michael@0 158 mov edx, [esp + 0x14] // Get the return address.
michael@0 159 mov eax, [ebx]SmartThunk.module_base
michael@0 160 push edx
michael@0 161 push eax
michael@0 162 call SmartSidestepResolverThunk::IsInternalCall
michael@0 163 add esp, 8
michael@0 164
michael@0 165 test eax, eax
michael@0 166 lea edx, [ebx]SmartThunk.sidestep // The original function.
michael@0 167 jz call_interceptor
michael@0 168
michael@0 169 // Skip this call
michael@0 170 mov ecx, [esp + 0x14] // Return address.
michael@0 171 mov [esp + 0x18], ecx // Remove first parameter.
michael@0 172 mov [esp + 0x10], edx
michael@0 173 pop edx // Restore registers.
michael@0 174 pop ecx
michael@0 175 pop ebx
michael@0 176 pop eax
michael@0 177 ret 4 // Jump to original function.
michael@0 178
michael@0 179 call_interceptor:
michael@0 180 mov ecx, [ebx]SmartThunk.interceptor
michael@0 181 mov [esp + 0x18], edx // Replace first parameter.
michael@0 182 mov [esp + 0x10], ecx
michael@0 183 pop edx // Restore registers.
michael@0 184 pop ecx
michael@0 185 pop ebx
michael@0 186 pop eax
michael@0 187 ret // Jump to original function.
michael@0 188 }
michael@0 189 }
michael@0 190
michael@0 191 bool SmartSidestepResolverThunk::IsInternalCall(const void* base,
michael@0 192 void* return_address) {
michael@0 193 DCHECK_NT(base);
michael@0 194 DCHECK_NT(return_address);
michael@0 195
michael@0 196 base::win::PEImage pe(base);
michael@0 197 if (pe.GetImageSectionFromAddr(return_address))
michael@0 198 return true;
michael@0 199 return false;
michael@0 200 }
michael@0 201
michael@0 202 } // namespace sandbox

mercurial