diff options
author | rvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-17 22:35:31 +0000 |
---|---|---|
committer | rvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-17 22:35:31 +0000 |
commit | a71ca488b1b2e666a3faad68e8fa71fa1554f0a9 (patch) | |
tree | 8e13ec487ee9c3a193f3a22a1253f5d342d9fb4c /sandbox | |
parent | 3b36c1b893df91a00eec8ee98f01765c4097ca68 (diff) | |
download | chromium_src-a71ca488b1b2e666a3faad68e8fa71fa1554f0a9.zip chromium_src-a71ca488b1b2e666a3faad68e8fa71fa1554f0a9.tar.gz chromium_src-a71ca488b1b2e666a3faad68e8fa71fa1554f0a9.tar.bz2 |
Sandbox: Add support for interceptions on Windows 8.
BUG=123068
TEST=sbox_unittests, sbox_integration_tests
Review URL: https://chromiumcodereview.appspot.com/10021033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132680 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/src/interception.cc | 22 | ||||
-rw-r--r-- | sandbox/src/service_resolver.h | 32 | ||||
-rw-r--r-- | sandbox/src/service_resolver_32.cc | 111 | ||||
-rw-r--r-- | sandbox/src/service_resolver_unittest.cc | 29 |
4 files changed, 169 insertions, 25 deletions
diff --git a/sandbox/src/interception.cc b/sandbox/src/interception.cc index b66fddd..a873f4a 100644 --- a/sandbox/src/interception.cc +++ b/sandbox/src/interception.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -438,13 +438,23 @@ bool InterceptionManager::PatchClientFunctions(DllInterceptionData* thunks, #endif ServiceResolverThunk* thunk; - if (base::win::OSInfo::GetInstance()->wow64_status() == - base::win::OSInfo::WOW64_ENABLED) - thunk = new Wow64ResolverThunk(child_->Process(), relaxed_); - else if (!IsXPSP2OrLater()) +#if defined(_WIN64) + thunk = new ServiceResolverThunk(child_->Process(), relaxed_); +#else + base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); + if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) { + if (os_info->version() >= base::win::VERSION_WIN8) + thunk = new Wow64W8ResolverThunk(child_->Process(), relaxed_); + else + thunk = new Wow64ResolverThunk(child_->Process(), relaxed_); + } else if (!IsXPSP2OrLater()) { thunk = new Win2kResolverThunk(child_->Process(), relaxed_); - else + } else if (os_info->version() >= base::win::VERSION_WIN8) { + thunk = new Win8ResolverThunk(child_->Process(), relaxed_); + } else { thunk = new ServiceResolverThunk(child_->Process(), relaxed_); + } +#endif std::list<InterceptionData>::iterator it = interceptions_.begin(); for (; it != interceptions_.end(); ++it) { diff --git a/sandbox/src/service_resolver.h b/sandbox/src/service_resolver.h index 469080a..99eadb6 100644 --- a/sandbox/src/service_resolver.h +++ b/sandbox/src/service_resolver.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -96,6 +96,21 @@ class Wow64ResolverThunk : public ServiceResolverThunk { }; // This is the concrete resolver used to perform service-call type functions +// inside ntdll.dll on WOW64 for Windows 8. +class Wow64W8ResolverThunk : public ServiceResolverThunk { + public: + // The service resolver needs a child process to write to. + Wow64W8ResolverThunk(HANDLE process, bool relaxed) + : ServiceResolverThunk(process, relaxed) {} + virtual ~Wow64W8ResolverThunk() {} + + private: + virtual bool IsFunctionAService(void* local_thunk) const; + + DISALLOW_COPY_AND_ASSIGN(Wow64W8ResolverThunk); +}; + +// This is the concrete resolver used to perform service-call type functions // inside ntdll.dll on Windows 2000 and XP pre SP2. class Win2kResolverThunk : public ServiceResolverThunk { public: @@ -112,6 +127,21 @@ class Win2kResolverThunk : public ServiceResolverThunk { DISALLOW_COPY_AND_ASSIGN(Win2kResolverThunk); }; +// This is the concrete resolver used to perform service-call type functions +// inside ntdll.dll on Windows 8. +class Win8ResolverThunk : public ServiceResolverThunk { + public: + // The service resolver needs a child process to write to. + Win8ResolverThunk(HANDLE process, bool relaxed) + : ServiceResolverThunk(process, relaxed) {} + virtual ~Win8ResolverThunk() {} + + private: + virtual bool IsFunctionAService(void* local_thunk) const; + + DISALLOW_COPY_AND_ASSIGN(Win8ResolverThunk); +}; + } // namespace sandbox diff --git a/sandbox/src/service_resolver_32.cc b/sandbox/src/service_resolver_32.cc index ffe4d15..2f5597b 100644 --- a/sandbox/src/service_resolver_32.cc +++ b/sandbox/src/service_resolver_32.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,9 +13,12 @@ namespace { const BYTE kMovEax = 0xB8; const BYTE kMovEdx = 0xBA; +const USHORT kMovEdxEsp = 0xD48B; const USHORT kCallPtrEdx = 0x12FF; const USHORT kCallEdx = 0xD2FF; +const BYTE kCallEip = 0xE8; const BYTE kRet = 0xC2; +const BYTE kRet2 = 0xC3; const BYTE kNop = 0x90; const USHORT kJmpEdx = 0xE2FF; const USHORT kXorEcx = 0xC933; @@ -26,13 +29,14 @@ const BYTE kCallFs3 = 0; const BYTE kAddEsp1 = 0x83; const USHORT kAddEsp2 = 0x4C4; const BYTE kJmp32 = 0xE9; +const USHORT kSysenter = 0x340F; const int kMaxService = 1000; // Service code for 32 bit systems. // NOTE: on win2003 "call dword ptr [edx]" is "call edx". struct ServiceEntry { - // this struct contains roughly the following code: + // This struct contains roughly the following code: // 00 mov eax,25h // 05 mov edx,offset SharedUserData!SystemCallStub (7ffe0300) // 0a call dword ptr [edx] @@ -46,22 +50,42 @@ struct ServiceEntry { BYTE ret; // = C2 USHORT num_params; BYTE nop; - ULONG pad1; // Extend the structure to be the same size as the - ULONG pad2; // 64 version (Wow64Entry) +}; + +// Service code for 32 bit Windows 8. +struct ServiceEntryW8 { + // This struct contains the following code: + // 00 b825000000 mov eax,25h + // 05 e803000000 call eip+3 + // 0a c22c00 ret 2Ch + // 0d 8bd4 mov edx,esp + // 0f 0f34 sysenter + // 11 c3 ret + // 12 8bff mov edi,edi + BYTE mov_eax; // = B8 + ULONG service_id; + BYTE call_eip; // = E8 + ULONG call_offset; + BYTE ret_p; // = C2 + USHORT num_params; + USHORT mov_edx_esp; // = BD D4 + USHORT sysenter; // = 0F 34 + BYTE ret; // = C3 + USHORT nop; }; // Service code for a 32 bit process running on a 64 bit os. struct Wow64Entry { // This struct may contain one of two versions of code: // 1. For XP, Vista and 2K3: - // 00 b852000000 mov eax, 25h + // 00 b825000000 mov eax, 25h // 05 33c9 xor ecx, ecx // 07 8d542404 lea edx, [esp + 4] // 0b 64ff15c0000000 call dword ptr fs:[0C0h] // 12 c22c00 ret 2Ch // // 2. For Windows 7: - // 00 b852000000 mov eax, 25h + // 00 b825000000 mov eax, 25h // 05 33c9 xor ecx, ecx // 07 8d542404 lea edx, [esp + 4] // 0b 64ff15c0000000 call dword ptr fs:[0C0h] @@ -82,13 +106,34 @@ struct Wow64Entry { USHORT num_params; }; +// Service code for a 32 bit process running on 64 bit Windows 8. +struct Wow64EntryW8 { + // 00 b825000000 mov eax, 25h + // 05 64ff15c0000000 call dword ptr fs:[0C0h] + // 0b c22c00 ret 2Ch + // 0f 90 nop + BYTE mov_eax; // = B8 + ULONG service_id; + ULONG call_fs1; // = 64 FF 15 C0 + USHORT call_fs2; // = 00 00 + BYTE call_fs3; // = 00 + BYTE ret; // = C2 + USHORT num_params; + BYTE nop; +}; + // Make sure that relaxed patching works as expected. -COMPILE_ASSERT(sizeof(ServiceEntry) == sizeof(Wow64Entry), wrong_service_len); +const size_t kMinServiceSize = offsetof(ServiceEntry, ret); +COMPILE_ASSERT(sizeof(ServiceEntryW8) >= kMinServiceSize, wrong_service_len); +COMPILE_ASSERT(sizeof(Wow64Entry) >= kMinServiceSize, wrong_service_len); +COMPILE_ASSERT(sizeof(Wow64EntryW8) >= kMinServiceSize, wrong_service_len); struct ServiceFullThunk { union { ServiceEntry original; + ServiceEntryW8 original_w8; Wow64Entry wow_64; + Wow64EntryW8 wow_64_w8; }; int internal_thunk; // Dummy member to the beginning of the internal thunk. }; @@ -212,13 +257,7 @@ NTSTATUS ServiceResolverThunk::PerformPatch(void* local_thunk, intercepted_code.mov_edx = kMovEdx; intercepted_code.stub = bit_cast<ULONG>(&full_remote_thunk->internal_thunk); intercepted_code.call_ptr_edx = kJmpEdx; - if (!win2k_) { - intercepted_code.ret = kRet; - intercepted_code.num_params = full_local_thunk->original.num_params; - intercepted_code.nop = kNop; - } else { - bytes_to_write = offsetof(ServiceEntry, ret); - } + bytes_to_write = kMinServiceSize; if (relative_jump_) { intercepted_code.mov_eax = kJmp32; @@ -318,6 +357,27 @@ bool Wow64ResolverThunk::IsFunctionAService(void* local_thunk) const { return false; } +bool Wow64W8ResolverThunk::IsFunctionAService(void* local_thunk) const { + Wow64EntryW8 function_code; + SIZE_T read; + if (!::ReadProcessMemory(process_, target_, &function_code, + sizeof(function_code), &read)) + return false; + + if (sizeof(function_code) != read) + return false; + + if (kMovEax != function_code.mov_eax || kCallFs1 != function_code.call_fs1 || + kCallFs2 != function_code.call_fs2 || + kCallFs3 != function_code.call_fs3 || kRet != function_code.ret) { + return false; + } + + // Save the verified code + memcpy(local_thunk, &function_code, sizeof(function_code)); + return true; +} + bool Win2kResolverThunk::IsFunctionAService(void* local_thunk) const { ServiceEntry function_code; SIZE_T read; @@ -338,4 +398,27 @@ bool Win2kResolverThunk::IsFunctionAService(void* local_thunk) const { return true; } +bool Win8ResolverThunk::IsFunctionAService(void* local_thunk) const { + ServiceEntryW8 function_code; + SIZE_T read; + if (!::ReadProcessMemory(process_, target_, &function_code, + sizeof(function_code), &read)) + return false; + + if (sizeof(function_code) != read) + return false; + + if (kMovEax != function_code.mov_eax || kCallEip != function_code.call_eip || + function_code.call_offset != 3 || kRet != function_code.ret_p || + kMovEdxEsp != function_code.mov_edx_esp || + kSysenter != function_code.sysenter || kRet2 != function_code.ret) { + return false; + } + + // Save the verified code + memcpy(local_thunk, &function_code, sizeof(function_code)); + + return true; +} + } // namespace sandbox diff --git a/sandbox/src/service_resolver_unittest.cc b/sandbox/src/service_resolver_unittest.cc index 36ad1d0f..fc85c86 100644 --- a/sandbox/src/service_resolver_unittest.cc +++ b/sandbox/src/service_resolver_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -55,9 +55,14 @@ class ResolverThunkTest : public T { DISALLOW_COPY_AND_ASSIGN(ResolverThunkTest); }; -typedef ResolverThunkTest<sandbox::Win2kResolverThunk> Win2kResolverTest; typedef ResolverThunkTest<sandbox::ServiceResolverThunk> WinXpResolverTest; + +#if !defined(_WIN64) +typedef ResolverThunkTest<sandbox::Win2kResolverThunk> Win2kResolverTest; +typedef ResolverThunkTest<sandbox::Win8ResolverThunk> Win8ResolverTest; typedef ResolverThunkTest<sandbox::Wow64ResolverThunk> Wow64ResolverTest; +typedef ResolverThunkTest<sandbox::Wow64W8ResolverThunk> Wow64W8ResolverTest; +#endif const BYTE kJump32 = 0xE9; @@ -70,12 +75,16 @@ void CheckJump(void* source, void* target) { }; #pragma pack(pop) +#if defined(_WIN64) + FAIL() << "Running 32-bit codepath"; +#else Code* patched = reinterpret_cast<Code*>(source); EXPECT_EQ(kJump32, patched->jump); ULONG source_addr = bit_cast<ULONG>(source); ULONG target_addr = bit_cast<ULONG>(target); EXPECT_EQ(target_addr + 19 - source_addr, patched->delta); +#endif } NTSTATUS PatchNtdllWithResolver(const char* function, bool relaxed, @@ -120,12 +129,24 @@ NTSTATUS PatchNtdllWithResolver(const char* function, bool relaxed, } sandbox::ServiceResolverThunk* GetTestResolver(bool relaxed) { - if (base::win::OSInfo::GetInstance()->wow64_status() == - base::win::OSInfo::WOW64_ENABLED) +#if defined(_WIN64) + return new WinXpResolverTest(relaxed); +#else + base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); + if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) { + if (os_info->version() >= base::win::VERSION_WIN8) + return new Wow64W8ResolverTest(relaxed); return new Wow64ResolverTest(relaxed); + } + if (!sandbox::IsXPSP2OrLater()) return new Win2kResolverTest(relaxed); + + if (os_info->version() >= base::win::VERSION_WIN8) + return new Win8ResolverTest(relaxed); + return new WinXpResolverTest(relaxed); +#endif } NTSTATUS PatchNtdll(const char* function, bool relaxed) { |