1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/service_resolver_64.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,193 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "sandbox/win/src/service_resolver.h" 1.9 + 1.10 +#include "base/logging.h" 1.11 +#include "base/memory/scoped_ptr.h" 1.12 +#include "sandbox/win/src/win_utils.h" 1.13 + 1.14 +namespace { 1.15 +#pragma pack(push, 1) 1.16 + 1.17 +const ULONG kMmovR10EcxMovEax = 0xB8D18B4C; 1.18 +const USHORT kSyscall = 0x050F; 1.19 +const BYTE kRetNp = 0xC3; 1.20 +const ULONG64 kMov1 = 0x54894808244C8948; 1.21 +const ULONG64 kMov2 = 0x4C182444894C1024; 1.22 +const ULONG kMov3 = 0x20244C89; 1.23 + 1.24 +// Service code for 64 bit systems. 1.25 +struct ServiceEntry { 1.26 + // This struct contains roughly the following code: 1.27 + // 00 mov r10,rcx 1.28 + // 03 mov eax,52h 1.29 + // 08 syscall 1.30 + // 0a ret 1.31 + // 0b xchg ax,ax 1.32 + // 0e xchg ax,ax 1.33 + 1.34 + ULONG mov_r10_rcx_mov_eax; // = 4C 8B D1 B8 1.35 + ULONG service_id; 1.36 + USHORT syscall; // = 0F 05 1.37 + BYTE ret; // = C3 1.38 + BYTE pad; // = 66 1.39 + USHORT xchg_ax_ax1; // = 66 90 1.40 + USHORT xchg_ax_ax2; // = 66 90 1.41 +}; 1.42 + 1.43 +// Service code for 64 bit Windows 8. 1.44 +struct ServiceEntryW8 { 1.45 + // This struct contains the following code: 1.46 + // 00 48894c2408 mov [rsp+8], rcx 1.47 + // 05 4889542410 mov [rsp+10], rdx 1.48 + // 0a 4c89442418 mov [rsp+18], r8 1.49 + // 0f 4c894c2420 mov [rsp+20], r9 1.50 + // 14 4c8bd1 mov r10,rcx 1.51 + // 17 b825000000 mov eax,25h 1.52 + // 1c 0f05 syscall 1.53 + // 1e c3 ret 1.54 + // 1f 90 nop 1.55 + 1.56 + ULONG64 mov_1; // = 48 89 4C 24 08 48 89 54 1.57 + ULONG64 mov_2; // = 24 10 4C 89 44 24 18 4C 1.58 + ULONG mov_3; // = 89 4C 24 20 1.59 + ULONG mov_r10_rcx_mov_eax; // = 4C 8B D1 B8 1.60 + ULONG service_id; 1.61 + USHORT syscall; // = 0F 05 1.62 + BYTE ret; // = C2 1.63 + BYTE nop; // = 90 1.64 +}; 1.65 + 1.66 +// We don't have an internal thunk for x64. 1.67 +struct ServiceFullThunk { 1.68 + union { 1.69 + ServiceEntry original; 1.70 + ServiceEntryW8 original_w8; 1.71 + }; 1.72 +}; 1.73 + 1.74 +#pragma pack(pop) 1.75 + 1.76 +bool IsService(const void* source) { 1.77 + const ServiceEntry* service = 1.78 + reinterpret_cast<const ServiceEntry*>(source); 1.79 + 1.80 + return (kMmovR10EcxMovEax == service->mov_r10_rcx_mov_eax && 1.81 + kSyscall == service->syscall && kRetNp == service->ret); 1.82 +} 1.83 + 1.84 +}; // namespace 1.85 + 1.86 +namespace sandbox { 1.87 + 1.88 +NTSTATUS ServiceResolverThunk::Setup(const void* target_module, 1.89 + const void* interceptor_module, 1.90 + const char* target_name, 1.91 + const char* interceptor_name, 1.92 + const void* interceptor_entry_point, 1.93 + void* thunk_storage, 1.94 + size_t storage_bytes, 1.95 + size_t* storage_used) { 1.96 + NTSTATUS ret = Init(target_module, interceptor_module, target_name, 1.97 + interceptor_name, interceptor_entry_point, 1.98 + thunk_storage, storage_bytes); 1.99 + if (!NT_SUCCESS(ret)) 1.100 + return ret; 1.101 + 1.102 + size_t thunk_bytes = GetThunkSize(); 1.103 + scoped_ptr<char[]> thunk_buffer(new char[thunk_bytes]); 1.104 + ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>( 1.105 + thunk_buffer.get()); 1.106 + 1.107 + if (!IsFunctionAService(&thunk->original)) 1.108 + return STATUS_UNSUCCESSFUL; 1.109 + 1.110 + ret = PerformPatch(thunk, thunk_storage); 1.111 + 1.112 + if (NULL != storage_used) 1.113 + *storage_used = thunk_bytes; 1.114 + 1.115 + return ret; 1.116 +} 1.117 + 1.118 +size_t ServiceResolverThunk::GetThunkSize() const { 1.119 + return sizeof(ServiceFullThunk); 1.120 +} 1.121 + 1.122 +bool ServiceResolverThunk::IsFunctionAService(void* local_thunk) const { 1.123 + ServiceFullThunk function_code; 1.124 + SIZE_T read; 1.125 + if (!::ReadProcessMemory(process_, target_, &function_code, 1.126 + sizeof(function_code), &read)) 1.127 + return false; 1.128 + 1.129 + if (sizeof(function_code) != read) 1.130 + return false; 1.131 + 1.132 + if (!IsService(&function_code)) { 1.133 + // See if it's the Win8 signature. 1.134 + ServiceEntryW8* w8_service = &function_code.original_w8; 1.135 + if (!IsService(&w8_service->mov_r10_rcx_mov_eax) || 1.136 + w8_service->mov_1 != kMov1 || w8_service->mov_1 != kMov1 || 1.137 + w8_service->mov_1 != kMov1) { 1.138 + return false; 1.139 + } 1.140 + } 1.141 + 1.142 + // Save the verified code. 1.143 + memcpy(local_thunk, &function_code, sizeof(function_code)); 1.144 + 1.145 + return true; 1.146 +} 1.147 + 1.148 +NTSTATUS ServiceResolverThunk::PerformPatch(void* local_thunk, 1.149 + void* remote_thunk) { 1.150 + ServiceFullThunk* full_local_thunk = reinterpret_cast<ServiceFullThunk*>( 1.151 + local_thunk); 1.152 + ServiceFullThunk* full_remote_thunk = reinterpret_cast<ServiceFullThunk*>( 1.153 + remote_thunk); 1.154 + 1.155 + // Patch the original code. 1.156 + ServiceEntry local_service; 1.157 + DCHECK_GE(GetInternalThunkSize(), sizeof(local_service)); 1.158 + if (!SetInternalThunk(&local_service, sizeof(local_service), NULL, 1.159 + interceptor_)) 1.160 + return STATUS_UNSUCCESSFUL; 1.161 + 1.162 + // Copy the local thunk buffer to the child. 1.163 + SIZE_T actual; 1.164 + if (!::WriteProcessMemory(process_, remote_thunk, local_thunk, 1.165 + sizeof(ServiceFullThunk), &actual)) 1.166 + return STATUS_UNSUCCESSFUL; 1.167 + 1.168 + if (sizeof(ServiceFullThunk) != actual) 1.169 + return STATUS_UNSUCCESSFUL; 1.170 + 1.171 + // And now change the function to intercept, on the child. 1.172 + if (NULL != ntdll_base_) { 1.173 + // Running a unit test. 1.174 + if (!::WriteProcessMemory(process_, target_, &local_service, 1.175 + sizeof(local_service), &actual)) 1.176 + return STATUS_UNSUCCESSFUL; 1.177 + } else { 1.178 + if (!WriteProtectedChildMemory(process_, target_, &local_service, 1.179 + sizeof(local_service))) 1.180 + return STATUS_UNSUCCESSFUL; 1.181 + } 1.182 + 1.183 + return STATUS_SUCCESS; 1.184 +} 1.185 + 1.186 +bool Wow64ResolverThunk::IsFunctionAService(void* local_thunk) const { 1.187 + NOTREACHED(); 1.188 + return false; 1.189 +} 1.190 + 1.191 +bool Win2kResolverThunk::IsFunctionAService(void* local_thunk) const { 1.192 + NOTREACHED(); 1.193 + return false; 1.194 +} 1.195 + 1.196 +} // namespace sandbox