#include "interception/interception.h"
#include "gtest/gtest.h"
#if !SANITIZER_DEBUG
#if SANITIZER_WINDOWS
# if !SANITIZER_WINDOWS_ARM64
# include <stdarg.h>
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
namespace __interception {
namespace {
enum FunctionPrefixKind {
FunctionPrefixNone,
FunctionPrefixPadding,
FunctionPrefixHotPatch,
FunctionPrefixDetour,
};
typedef bool (*TestOverrideFunction)(uptr, uptr, uptr*);
typedef int (*IdentityFunction)(int);
#if SANITIZER_WINDOWS64
const u8 kIdentityCodeWithPrologue[] = {
0x55,
0x48, 0x89, 0xE5,
0x8B, 0xC1,
0x5D,
0xC3,
};
const u8 kIdentityCodeWithPushPop[] = {
0x55,
0x48, 0x89, 0xE5,
0x53,
0x50,
0x58,
0x8B, 0xC1,
0x5B,
0x5D,
0xC3,
};
const u8 kIdentityTwiceOffset = 16;
const u8 kIdentityTwice[] = {
0x55,
0x48, 0x89, 0xE5,
0x8B, 0xC1,
0x5D,
0xC3,
0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90,
0x55,
0x48, 0x89, 0xE5,
0x8B, 0xC1,
0x5D,
0xC3,
};
const u8 kIdentityCodeWithMov[] = {
0x89, 0xC8,
0xC3,
};
const u8 kIdentityCodeWithJump[] = {
0xE9, 0x04, 0x00, 0x00,
0x00,
0xCC, 0xCC, 0xCC, 0xCC,
0x89, 0xC8,
0xC3,
};
const u8 kIdentityCodeWithJumpBackwards[] = {
0x89, 0xC8,
0xC3,
0xE9, 0xF8, 0xFF, 0xFF,
0xFF,
0xCC, 0xCC, 0xCC, 0xCC,
};
const u8 kIdentityCodeWithJumpBackwardsOffset = 3;
# else
const u8 kIdentityCodeWithPrologue[] = {
0x55,
0x8B, 0xEC,
0x8B, 0x45, 0x08,
0x5D,
0xC3,
};
const u8 kIdentityCodeWithPushPop[] = {
0x55,
0x8B, 0xEC,
0x53,
0x50,
0x58,
0x8B, 0x45, 0x08,
0x5B,
0x5D,
0xC3,
};
const u8 kIdentityTwiceOffset = 8;
const u8 kIdentityTwice[] = {
0x55,
0x8B, 0xEC,
0x8B, 0x45, 0x08,
0x5D,
0xC3,
0x55,
0x8B, 0xEC,
0x8B, 0x45, 0x08,
0x5D,
0xC3,
};
const u8 kIdentityCodeWithMov[] = {
0x8B, 0x44, 0x24, 0x04,
0xC3,
};
const u8 kIdentityCodeWithJump[] = {
0xE9, 0x04, 0x00, 0x00,
0x00,
0xCC, 0xCC, 0xCC, 0xCC,
0x8B, 0x44, 0x24, 0x04,
0xC3,
};
const u8 kIdentityCodeWithJumpBackwards[] = {
0x8B, 0x44, 0x24, 0x04,
0xC3,
0xE9, 0xF6, 0xFF, 0xFF,
0xFF,
0xCC, 0xCC, 0xCC, 0xCC,
};
const u8 kIdentityCodeWithJumpBackwardsOffset = 5;
# endif
const u8 kPatchableCode1[] = {
0xB8, 0x4B, 0x00, 0x00, 0x00,
0x33, 0xC9,
0xC3,
};
const u8 kPatchableCode2[] = {
0x55,
0x8B, 0xEC,
0x33, 0xC0,
0x5D,
0xC3,
};
const u8 kPatchableCode3[] = {
0x55,
0x8B, 0xEC,
0x6A, 0x00,
0xE8, 0x3D, 0xFF, 0xFF, 0xFF,
};
const u8 kPatchableCode4[] = {
0xE9, 0xCC, 0xCC, 0xCC, 0xCC,
0x90, 0x90, 0x90, 0x90,
};
const u8 kPatchableCode5[] = {
0x55,
0x8b, 0xec,
0x8d, 0xa4, 0x24, 0x30, 0xfd, 0xff, 0xff,
0x54,
};
#if SANITIZER_WINDOWS64
u8 kLoadGlobalCode[] = {
0x8B, 0x05, 0x00, 0x00, 0x00, 0x00,
0xC3,
};
#endif
const u8 kUnpatchableCode1[] = {
0xC3,
};
const u8 kUnpatchableCode2[] = {
0x33, 0xC9,
0xC3,
};
const u8 kUnpatchableCode3[] = {
0x75, 0xCC,
0x33, 0xC9,
0xC3,
};
const u8 kUnpatchableCode4[] = {
0x74, 0xCC,
0x33, 0xC9,
0xC3,
};
const u8 kUnpatchableCode5[] = {
0xEB, 0x02,
0x33, 0xC9,
0xC3,
};
const u8 kUnpatchableCode6[] = {
0xE8, 0xCC, 0xCC, 0xCC, 0xCC,
0x90, 0x90, 0x90, 0x90,
};
const u8 kUnpatchableCode7[] = {
0x33, 0xc0,
0x48, 0x85, 0xd2,
0x74, 0x10,
};
const u8 kUnpatchableCode8[] = {
0x48, 0x8b, 0xc1,
0x0f, 0xb7, 0x10,
0x48, 0x83, 0xc0, 0x02,
0x66, 0x85, 0xd2,
0x75, 0xf4,
};
const u8 kUnpatchableCode9[] = {
0x4c, 0x8b, 0xc1,
0x8a, 0x01,
0x48, 0xff, 0xc1,
0x84, 0xc0,
0x75, 0xf7,
};
const u8 kPatchableCode6[] = {
0x48, 0x89, 0x54, 0x24, 0xBB,
0x33, 0xC9,
0xC3,
};
const u8 kPatchableCode7[] = {
0x4c, 0x89, 0x4c, 0x24, 0xBB,
0x33, 0xC9,
0xC3,
};
const u8 kPatchableCode8[] = {
0x4c, 0x89, 0x44, 0x24, 0xBB,
0x33, 0xC9,
0xC3,
};
const u8 kPatchableCode9[] = {
0x8a, 0x01,
0x45, 0x33, 0xc0,
0x84, 0xc0,
};
const u8 kPatchableCode10[] = {
0x45, 0x33, 0xc0,
0x41, 0x8b, 0xc0,
0x48, 0x85, 0xd2,
};
const u8 kPatchableCode11[] = {
0x48, 0x83, 0xec, 0x38,
0x83, 0x64, 0x24, 0x28, 0x00,
};
const u8 kPatchableCode12[] = {
0x55,
0x53,
0x57,
0x56,
0x8b, 0x6c, 0x24, 0x18,
};
const u8 kPatchableCode13[] = {
0x55,
0x53,
0x57,
0x56,
0x8b, 0x5c, 0x24, 0x14,
};
const u8 kPatchableCode14[] = {
0x55,
0x89, 0xe5,
0x53,
0x57,
0x56,
};
const u8 kUnsupportedCode1[] = {
0x0f, 0x0b,
0x0f, 0x0b,
0x0f, 0x0b,
0x0f, 0x0b,
};
u8* ActiveCode;
const size_t ActiveCodeLength = 4096;
int InterceptorFunction(int x);
u8 *AllocateCode2GBAway(u8 *Base) {
size_t TwoGB = 0x80000000;
size_t AllocGranularity = 0x10000;
Base = (u8 *)((((uptr)Base + TwoGB + AllocGranularity)) & ~(AllocGranularity - 1));
MEMORY_BASIC_INFORMATION mbi = {};
while (sizeof(mbi) == VirtualQuery(Base, &mbi, sizeof(mbi))) {
if (mbi.State & MEM_FREE) break;
Base += mbi.RegionSize;
}
return (u8 *)::VirtualAlloc(Base, ActiveCodeLength, MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
}
template<class T>
static void LoadActiveCode(
const T &code,
uptr *entry_point,
FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
if (ActiveCode == nullptr) {
ActiveCode = AllocateCode2GBAway((u8*)&InterceptorFunction);
ASSERT_NE(ActiveCode, nullptr) << "failed to allocate RWX memory 2GB away";
}
size_t position = 0;
for (int i = 0; i < 16; ++i)
ActiveCode[position++] = 0xC3;
size_t padding = 0;
if (prefix_kind == FunctionPrefixPadding)
padding = 16;
else if (prefix_kind == FunctionPrefixDetour ||
prefix_kind == FunctionPrefixHotPatch)
padding = FIRST_32_SECOND_64(5, 6);
for (size_t i = 0; i < padding; ++i)
ActiveCode[position++] = 0x90;
*entry_point = (uptr)&ActiveCode[position];
if (prefix_kind == FunctionPrefixDetour) {
#if SANITIZER_WINDOWS64
ActiveCode[position++] = 0x66;
ActiveCode[position++] = 0x90;
#else
ActiveCode[position++] = 0x8B;
ActiveCode[position++] = 0xFF;
#endif
}
for (size_t i = 0; i < sizeof(T); ++i)
ActiveCode[position++] = code[i];
}
int InterceptorFunctionCalled;
IdentityFunction InterceptedRealFunction;
int InterceptorFunction(int x) {
++InterceptorFunctionCalled;
return InterceptedRealFunction(x);
}
}
TEST(Interception, InternalGetProcAddress) {
HMODULE ntdll_handle = ::GetModuleHandle("ntdll");
ASSERT_NE(nullptr, ntdll_handle);
uptr DbgPrint_expected = (uptr)::GetProcAddress(ntdll_handle, "DbgPrint");
uptr isdigit_expected = (uptr)::GetProcAddress(ntdll_handle, "isdigit");
uptr DbgPrint_adddress = InternalGetProcAddress(ntdll_handle, "DbgPrint");
uptr isdigit_address = InternalGetProcAddress(ntdll_handle, "isdigit");
EXPECT_EQ(DbgPrint_expected, DbgPrint_adddress);
EXPECT_EQ(isdigit_expected, isdigit_address);
EXPECT_NE(DbgPrint_adddress, isdigit_address);
}
template <class T>
static void TestIdentityFunctionPatching(
const T &code, TestOverrideFunction override,
FunctionPrefixKind prefix_kind = FunctionPrefixNone,
int function_start_offset = 0) {
uptr identity_address;
LoadActiveCode(code, &identity_address, prefix_kind);
identity_address += function_start_offset;
IdentityFunction identity = (IdentityFunction)identity_address;
InterceptorFunctionCalled = 0;
EXPECT_EQ(0, identity(0));
EXPECT_EQ(42, identity(42));
EXPECT_EQ(0, InterceptorFunctionCalled);
uptr real_identity_address = 0;
bool success = override(identity_address,
(uptr)&InterceptorFunction,
&real_identity_address);
EXPECT_TRUE(success);
EXPECT_NE(0U, real_identity_address);
IdentityFunction real_identity = (IdentityFunction)real_identity_address;
InterceptedRealFunction = real_identity;
if (!success || !real_identity_address)
return;
InterceptorFunctionCalled = 0;
EXPECT_EQ(0, identity(0));
EXPECT_EQ(42, identity(42));
EXPECT_EQ(2, InterceptorFunctionCalled);
InterceptorFunctionCalled = 0;
EXPECT_EQ(0, real_identity(0));
EXPECT_EQ(42, real_identity(42));
EXPECT_EQ(0, InterceptorFunctionCalled);
TestOnlyReleaseTrampolineRegions();
}
# if !SANITIZER_WINDOWS64
TEST(Interception, OverrideFunctionWithDetour) {
TestOverrideFunction override = OverrideFunctionWithDetour;
FunctionPrefixKind prefix = FunctionPrefixDetour;
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
}
#endif
TEST(Interception, OverrideFunctionWithRedirectJump) {
TestOverrideFunction override = OverrideFunctionWithRedirectJump;
TestIdentityFunctionPatching(kIdentityCodeWithJump, override);
TestIdentityFunctionPatching(kIdentityCodeWithJumpBackwards, override,
FunctionPrefixNone,
kIdentityCodeWithJumpBackwardsOffset);
}
TEST(Interception, OverrideFunctionWithHotPatch) {
TestOverrideFunction override = OverrideFunctionWithHotPatch;
FunctionPrefixKind prefix = FunctionPrefixHotPatch;
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
}
TEST(Interception, OverrideFunctionWithTrampoline) {
TestOverrideFunction override = OverrideFunctionWithTrampoline;
FunctionPrefixKind prefix = FunctionPrefixNone;
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
prefix = FunctionPrefixPadding;
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
}
TEST(Interception, OverrideFunction) {
TestOverrideFunction override = OverrideFunction;
FunctionPrefixKind prefix = FunctionPrefixNone;
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
prefix = FunctionPrefixPadding;
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
prefix = FunctionPrefixHotPatch;
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
prefix = FunctionPrefixDetour;
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
}
template<class T>
static void TestIdentityFunctionMultiplePatching(
const T &code,
TestOverrideFunction override,
FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
uptr identity_address;
LoadActiveCode(code, &identity_address, prefix_kind);
uptr real_identity_address = 0;
bool success = override(identity_address,
(uptr)&InterceptorFunction,
&real_identity_address);
EXPECT_TRUE(success);
EXPECT_NE(0U, real_identity_address);
success = override(identity_address,
(uptr)&InterceptorFunction,
&real_identity_address);
EXPECT_FALSE(success);
TestOnlyReleaseTrampolineRegions();
}
TEST(Interception, OverrideFunctionMultiplePatchingIsFailing) {
#if !SANITIZER_WINDOWS64
TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue,
OverrideFunctionWithDetour,
FunctionPrefixDetour);
#endif
TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov,
OverrideFunctionWithHotPatch,
FunctionPrefixHotPatch);
TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop,
OverrideFunctionWithTrampoline,
FunctionPrefixPadding);
}
TEST(Interception, OverrideFunctionTwice) {
uptr identity_address1;
LoadActiveCode(kIdentityTwice, &identity_address1);
uptr identity_address2 = identity_address1 + kIdentityTwiceOffset;
IdentityFunction identity1 = (IdentityFunction)identity_address1;
IdentityFunction identity2 = (IdentityFunction)identity_address2;
uptr real_identity_address = 0;
EXPECT_TRUE(OverrideFunction(identity_address1,
(uptr)&InterceptorFunction,
&real_identity_address));
EXPECT_TRUE(OverrideFunction(identity_address2,
(uptr)&InterceptorFunction,
&real_identity_address));
IdentityFunction real_identity = (IdentityFunction)real_identity_address;
InterceptedRealFunction = real_identity;
InterceptorFunctionCalled = 0;
EXPECT_EQ(42, identity1(42));
EXPECT_EQ(42, identity2(42));
EXPECT_EQ(2, InterceptorFunctionCalled);
TestOnlyReleaseTrampolineRegions();
}
template<class T>
static bool TestFunctionPatching(
const T &code,
TestOverrideFunction override,
FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
uptr address;
LoadActiveCode(code, &address, prefix_kind);
uptr unused_real_address = 0;
bool result = override(
address, (uptr)&InterceptorFunction, &unused_real_address);
TestOnlyReleaseTrampolineRegions();
return result;
}
TEST(Interception, PatchableFunction) {
TestOverrideFunction override = OverrideFunction;
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override));
#if SANITIZER_WINDOWS64
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
#else
EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override));
#endif
EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override));
#if SANITIZER_WINDOWS64
EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override));
#endif
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
}
#if !SANITIZER_WINDOWS64
TEST(Interception, PatchableFunctionWithDetour) {
TestOverrideFunction override = OverrideFunctionWithDetour;
EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
FunctionPrefixKind prefix = FunctionPrefixDetour;
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
}
#endif
TEST(Interception, PatchableFunctionWithRedirectJump) {
TestOverrideFunction override = OverrideFunctionWithRedirectJump;
EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
}
TEST(Interception, PatchableFunctionWithHotPatch) {
TestOverrideFunction override = OverrideFunctionWithHotPatch;
FunctionPrefixKind prefix = FunctionPrefixHotPatch;
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
#if SANITIZER_WINDOWS64
EXPECT_TRUE(TestFunctionPatching(kPatchableCode6, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode7, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode8, override, prefix));
#endif
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
}
TEST(Interception, PatchableFunctionWithTrampoline) {
TestOverrideFunction override = OverrideFunctionWithTrampoline;
FunctionPrefixKind prefix = FunctionPrefixPadding;
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
#if SANITIZER_WINDOWS64
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode9, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode10, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode11, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode7, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode8, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode9, override, prefix));
#else
EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode12, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode13, override, prefix));
#endif
EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode14, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
}
TEST(Interception, UnsupportedInstructionWithTrampoline) {
TestOverrideFunction override = OverrideFunctionWithTrampoline;
FunctionPrefixKind prefix = FunctionPrefixPadding;
static bool reportCalled;
reportCalled = false;
struct Local {
static void Report(const char *format, ...) {
if (reportCalled)
FAIL() << "Report called more times than expected";
reportCalled = true;
ASSERT_STREQ(
"interception_win: unhandled instruction at %p: %02x %02x %02x %02x "
"%02x %02x %02x %02x\n",
format);
va_list args;
va_start(args, format);
u8 *ptr = va_arg(args, u8 *);
for (int i = 0; i < 8; i++) EXPECT_EQ(kUnsupportedCode1[i], ptr[i]);
int bytes[8];
for (int i = 0; i < 8; i++) {
bytes[i] = va_arg(args, int);
EXPECT_EQ(kUnsupportedCode1[i], bytes[i]);
}
va_end(args);
}
};
SetErrorReportCallback(Local::Report);
EXPECT_FALSE(TestFunctionPatching(kUnsupportedCode1, override, prefix));
SetErrorReportCallback(nullptr);
if (!reportCalled)
ADD_FAILURE() << "Report not called";
}
TEST(Interception, PatchableFunctionPadding) {
TestOverrideFunction override = OverrideFunction;
FunctionPrefixKind prefix = FunctionPrefixPadding;
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
#if SANITIZER_WINDOWS64
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
#else
EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
#endif
EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
}
TEST(Interception, EmptyExportTable) {
uptr FunPtr = InternalGetProcAddress((void *)GetModuleHandleA(0), "example");
EXPECT_EQ(0U, FunPtr);
}
}
# endif
#endif
#endif