This source file includes following definitions.
- __declspec
- HookIncrementNumber
- __declspec
- TestDisassembler
- TestPatchWithLongJump
- TestPatchWithPreambleShortCondJump
- TestPatchWithPreambleNearRelativeCondJump
- TestPatchWithPreambleAbsoluteJump
- TestPatchWithPreambleNearRelativeCall
- TestPatchUsingDynamicStub
- PatchThenUnpatch
- AutoTestingHookTest
- AutoTestingHookInContainerTest
- TestPreambleAllocation
- UnitTests
- safe_vsnprintf
- _tmain
#include "config_for_unittests.h"
#include "preamble_patcher.h"
#include "mini_disassembler.h"
#pragma warning(push)
#pragma warning(disable:4553)
#include "auto_testing_hook.h"
#pragma warning(pop)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
#pragma optimize("", off)
#define UNPATCH(target_function, replacement_function, original_function_stub) \
sidestep::PreamblePatcher::Unpatch((void*)(target_function), \
(void*)(replacement_function), \
(void*)(original_function))
namespace {
int __declspec(noinline) IncrementNumber(int i) {
#ifdef _M_X64
__int64 i2 = i + 1;
return (int) i2;
#else
return i + 1;
#endif
}
extern "C" int TooShortFunction(int);
extern "C" int JumpShortCondFunction(int);
extern "C" int JumpNearCondFunction(int);
extern "C" int JumpAbsoluteFunction(int);
extern "C" int CallNearRelativeFunction(int);
typedef int (*IncrementingFunc)(int);
IncrementingFunc original_function = NULL;
int HookIncrementNumber(int i) {
SIDESTEP_ASSERT(original_function != NULL);
int incremented_once = original_function(i);
return incremented_once + 1;
}
int __declspec(noinline) AutoHookIncrementNumber(int i) {
return i + 10;
}
};
namespace sidestep {
bool TestDisassembler() {
unsigned int instruction_size = 0;
sidestep::MiniDisassembler disassembler;
void * target = reinterpret_cast<unsigned char *>(IncrementNumber);
void * new_target = PreamblePatcher::ResolveTarget(target);
if (target != new_target)
target = new_target;
while (1) {
sidestep::InstructionType instructionType = disassembler.Disassemble(
reinterpret_cast<unsigned char *>(target) + instruction_size,
instruction_size);
if (sidestep::IT_RETURN == instructionType) {
return true;
}
}
}
bool TestPatchWithLongJump() {
original_function = NULL;
void *p = ::VirtualAlloc(reinterpret_cast<void *>(0x0000020000000000), 4096,
MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
SIDESTEP_EXPECT_TRUE(p != NULL);
memset(p, 0xcc, 4096);
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
sidestep::PreamblePatcher::Patch(IncrementNumber,
(IncrementingFunc) p,
&original_function));
SIDESTEP_ASSERT((*original_function)(1) == 2);
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
UNPATCH(IncrementNumber,
(IncrementingFunc)p,
original_function));
::VirtualFree(p, 0, MEM_RELEASE);
return true;
}
bool TestPatchWithPreambleShortCondJump() {
original_function = NULL;
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
sidestep::PreamblePatcher::Patch(JumpShortCondFunction,
HookIncrementNumber,
&original_function));
(*original_function)(1);
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
UNPATCH(JumpShortCondFunction,
(void*)HookIncrementNumber,
original_function));
return true;
}
bool TestPatchWithPreambleNearRelativeCondJump() {
original_function = NULL;
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
sidestep::PreamblePatcher::Patch(JumpNearCondFunction,
HookIncrementNumber,
&original_function));
(*original_function)(0);
(*original_function)(1);
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
UNPATCH(JumpNearCondFunction,
HookIncrementNumber,
original_function));
return true;
}
bool TestPatchWithPreambleAbsoluteJump() {
original_function = NULL;
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
sidestep::PreamblePatcher::Patch(JumpAbsoluteFunction,
HookIncrementNumber,
&original_function));
(*original_function)(0);
(*original_function)(1);
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
UNPATCH(JumpAbsoluteFunction,
HookIncrementNumber,
original_function));
return true;
}
bool TestPatchWithPreambleNearRelativeCall() {
original_function = NULL;
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
sidestep::PreamblePatcher::Patch(
CallNearRelativeFunction,
HookIncrementNumber,
&original_function));
(*original_function)(0);
(*original_function)(1);
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
UNPATCH(CallNearRelativeFunction,
HookIncrementNumber,
original_function));
return true;
}
bool TestPatchUsingDynamicStub() {
original_function = NULL;
SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
sidestep::PreamblePatcher::Patch(IncrementNumber,
HookIncrementNumber,
&original_function));
SIDESTEP_EXPECT_TRUE(original_function);
SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 4);
SIDESTEP_EXPECT_TRUE(original_function(3) == 4);
sidestep::MiniDisassembler disassembler;
unsigned int instruction_size = 0;
SIDESTEP_EXPECT_TRUE(sidestep::IT_JUMP == disassembler.Disassemble(
reinterpret_cast<unsigned char*>(IncrementNumber),
instruction_size));
#if 0
IncrementingFunc dummy = NULL;
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_JUMP_INSTRUCTION ==
sidestep::PreamblePatcher::Patch(IncrementNumber,
HookIncrementNumber,
&dummy));
dummy = NULL;
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_FUNCTION_TOO_SMALL ==
sidestep::PreamblePatcher::Patch(TooShortFunction,
HookIncrementNumber,
&dummy));
#endif
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
UNPATCH(IncrementNumber,
HookIncrementNumber,
original_function));
return true;
}
bool PatchThenUnpatch() {
original_function = NULL;
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
sidestep::PreamblePatcher::Patch(IncrementNumber,
HookIncrementNumber,
&original_function));
SIDESTEP_EXPECT_TRUE(original_function);
SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 3);
SIDESTEP_EXPECT_TRUE(original_function(2) == 3);
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
UNPATCH(IncrementNumber,
HookIncrementNumber,
original_function));
original_function = NULL;
SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
return true;
}
bool AutoTestingHookTest() {
SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
{
AutoTestingHook hook = MakeTestingHook(IncrementNumber,
AutoHookIncrementNumber);
(void) hook;
SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
}
SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
return true;
}
bool AutoTestingHookInContainerTest() {
SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
{
AutoTestingHookHolder hook(MakeTestingHookHolder(IncrementNumber,
AutoHookIncrementNumber));
(void) hook;
SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
}
SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
return true;
}
bool TestPreambleAllocation() {
__int64 diff = 0;
void* p1 = reinterpret_cast<void*>(0x110000000);
void* p2 = reinterpret_cast<void*>(0x810000000);
unsigned char* b1 = PreamblePatcher::AllocPreambleBlockNear(p1);
SIDESTEP_EXPECT_TRUE(b1 != NULL);
diff = reinterpret_cast<__int64>(p1) - reinterpret_cast<__int64>(b1);
SIDESTEP_EXPECT_TRUE(diff <= INT_MAX && diff >= INT_MIN);
unsigned char* b2 = PreamblePatcher::AllocPreambleBlockNear(p2);
SIDESTEP_EXPECT_TRUE(b2 != NULL);
diff = reinterpret_cast<__int64>(p2) - reinterpret_cast<__int64>(b2);
SIDESTEP_EXPECT_TRUE(diff <= INT_MAX && diff >= INT_MIN);
unsigned char* b3 = b1;
unsigned char* b4 = b2;
PreamblePatcher::FreePreambleBlock(b1);
PreamblePatcher::FreePreambleBlock(b2);
b1 = PreamblePatcher::AllocPreambleBlockNear(p1);
SIDESTEP_EXPECT_TRUE(b1 == b3);
b2 = PreamblePatcher::AllocPreambleBlockNear(p2);
SIDESTEP_EXPECT_TRUE(b2 == b4);
PreamblePatcher::FreePreambleBlock(b1);
PreamblePatcher::FreePreambleBlock(b2);
return true;
}
bool UnitTests() {
return TestPatchWithPreambleNearRelativeCall() &&
TestPatchWithPreambleAbsoluteJump() &&
TestPatchWithPreambleNearRelativeCondJump() &&
TestPatchWithPreambleShortCondJump() &&
TestDisassembler() && TestPatchWithLongJump() &&
TestPatchUsingDynamicStub() && PatchThenUnpatch() &&
AutoTestingHookTest() && AutoTestingHookInContainerTest() &&
TestPreambleAllocation();
}
};
int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
if (size == 0)
return -1;
str[size-1] = '\0';
return _vsnprintf(str, size-1, format, ap);
}
int _tmain(int argc, _TCHAR* argv[])
{
bool ret = sidestep::UnitTests();
printf("%s\n", ret ? "PASS" : "FAIL");
return ret ? 0 : -1;
}
#pragma optimize("", on)