This source file includes following definitions.
- set_target
- Init
- CheckJump
- PatchNtdllWithResolver
- GetTestResolver
- PatchNtdll
- TEST
- TEST
- TEST
- TEST
- TEST
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/win/windows_version.h"
#include "sandbox/win/src/resolver.h"
#include "sandbox/win/src/sandbox_utils.h"
#include "sandbox/win/src/service_resolver.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
template<typename T>
class ResolverThunkTest : public T {
public:
explicit ResolverThunkTest(bool relaxed)
: T(::GetCurrentProcess(), relaxed) {}
void set_target(void* target) {
fake_target_ = target;
}
protected:
virtual NTSTATUS Init(const void* target_module,
const void* interceptor_module,
const char* target_name,
const char* interceptor_name,
const void* interceptor_entry_point,
void* thunk_storage,
size_t storage_bytes) {
NTSTATUS ret = STATUS_SUCCESS;
ret = ResolverThunk::Init(target_module, interceptor_module, target_name,
interceptor_name, interceptor_entry_point,
thunk_storage, storage_bytes);
EXPECT_EQ(STATUS_SUCCESS, ret);
target_ = fake_target_;
return ret;
};
private:
void* fake_target_;
DISALLOW_COPY_AND_ASSIGN(ResolverThunkTest);
};
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;
void CheckJump(void* source, void* target) {
#pragma pack(push)
#pragma pack(1)
struct Code {
BYTE jump;
ULONG delta;
};
#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,
sandbox::ServiceResolverThunk* resolver) {
HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
EXPECT_TRUE(NULL != ntdll_base);
void* target = ::GetProcAddress(ntdll_base, function);
EXPECT_TRUE(NULL != target);
if (NULL == target)
return STATUS_UNSUCCESSFUL;
BYTE service[50];
memcpy(service, target, sizeof(service));
static_cast<WinXpResolverTest*>(resolver)->set_target(service);
void* function_entry = resolver;
size_t thunk_size = resolver->GetThunkSize();
scoped_ptr<char[]> thunk(new char[thunk_size]);
size_t used;
resolver->AllowLocalPatches();
NTSTATUS ret = resolver->Setup(ntdll_base, NULL, function, NULL,
function_entry, thunk.get(), thunk_size,
&used);
if (NT_SUCCESS(ret)) {
EXPECT_EQ(thunk_size, used);
EXPECT_NE(0, memcmp(service, target, sizeof(service)));
EXPECT_NE(kJump32, service[0]);
if (relaxed) {
service[0] = kJump32;
ret = resolver->Setup(ntdll_base, NULL, function, NULL, function_entry,
thunk.get(), thunk_size, &used);
CheckJump(service, thunk.get());
}
}
return ret;
}
sandbox::ServiceResolverThunk* GetTestResolver(bool relaxed) {
#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) {
sandbox::ServiceResolverThunk* resolver = GetTestResolver(relaxed);
NTSTATUS ret = PatchNtdllWithResolver(function, relaxed, resolver);
delete resolver;
return ret;
}
TEST(ServiceResolverTest, PatchesServices) {
NTSTATUS ret = PatchNtdll("NtClose", false);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
ret = PatchNtdll("NtCreateFile", false);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
::GetLastError();
ret = PatchNtdll("NtCreateMutant", false);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
::GetLastError();
ret = PatchNtdll("NtMapViewOfSection", false);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
::GetLastError();
}
TEST(ServiceResolverTest, FailsIfNotService) {
#if !defined(_WIN64)
EXPECT_NE(STATUS_SUCCESS, PatchNtdll("RtlUlongByteSwap", false));
#endif
EXPECT_NE(STATUS_SUCCESS, PatchNtdll("LdrLoadDll", false));
}
TEST(ServiceResolverTest, PatchesPatchedServices) {
#if !defined(_WIN64)
NTSTATUS ret = PatchNtdll("NtClose", true);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
ret = PatchNtdll("NtCreateFile", true);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
::GetLastError();
ret = PatchNtdll("NtCreateMutant", true);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
::GetLastError();
ret = PatchNtdll("NtMapViewOfSection", true);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
::GetLastError();
#endif
}
TEST(ServiceResolverTest, MultiplePatchedServices) {
#if !defined(_WIN64)
sandbox::ServiceResolverThunk* resolver = GetTestResolver(true);
NTSTATUS ret = PatchNtdllWithResolver("NtClose", true, resolver);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
ret = PatchNtdllWithResolver("NtCreateFile", true, resolver);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
::GetLastError();
ret = PatchNtdllWithResolver("NtCreateMutant", true, resolver);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
::GetLastError();
ret = PatchNtdllWithResolver("NtMapViewOfSection", true, resolver);
EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
::GetLastError();
delete resolver;
#endif
}
TEST(ServiceResolverTest, LocalPatchesAllowed) {
sandbox::ServiceResolverThunk* resolver = GetTestResolver(true);
HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
ASSERT_TRUE(NULL != ntdll_base);
const char kFunctionName[] = "NtClose";
void* target = ::GetProcAddress(ntdll_base, kFunctionName);
ASSERT_TRUE(NULL != target);
BYTE service[50];
memcpy(service, target, sizeof(service));
static_cast<WinXpResolverTest*>(resolver)->set_target(service);
void* function_entry = resolver;
size_t thunk_size = resolver->GetThunkSize();
scoped_ptr<char[]> thunk(new char[thunk_size]);
size_t used;
NTSTATUS ret = STATUS_UNSUCCESSFUL;
ret = resolver->Setup(ntdll_base, NULL, kFunctionName, NULL,
function_entry, thunk.get(), thunk_size,
&used);
EXPECT_FALSE(NT_SUCCESS(ret));
resolver->AllowLocalPatches();
ret = resolver->Setup(ntdll_base, NULL, kFunctionName, NULL,
function_entry, thunk.get(), thunk_size,
&used);
EXPECT_EQ(STATUS_SUCCESS, ret);
}
}