@@ -0,0 +1,31 @@ | |||
Introduction | |||
============ | |||
This project aims to give a simple overview on how good various x64 hooking | |||
engines (on windows) are. I'll try to write various functions, that are hard to | |||
patch and then see how each hooking engine does. | |||
I'll test: | |||
* [EasyHook]() | |||
* [PolyHook]() | |||
(I'd like to test detours, but I'm not willing to pay for it. So that isn't | |||
tested :( ) | |||
There are multiple things that make hooking difficult. Maybe you want to patch | |||
while the application is running -- in that case you might get race conditions, | |||
as the application is executing your half finished hook. Maybe the software has | |||
some self protection features (or other software on the system provides that, | |||
e.g. Trustee Rapport) | |||
Evaluating how the hooking engines stack up against that is not the goal here. | |||
This is just about the challenges the function to be hooked itself poses. | |||
Namely: | |||
* Are jumps relocated? | |||
* What about RIP adressing? | |||
* If it's a tail recurisve function, does the hooking engine handle it? | |||
* How good is the dissassembler, how many instructions does it know? | |||
Test cases | |||
========== |
@@ -146,6 +146,18 @@ | |||
</Link> | |||
</ItemDefinitionGroup> | |||
<ItemGroup> | |||
<ClInclude Include="catch.hpp" /> | |||
<ClInclude Include="simple_tests.h" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ClCompile Include="main.cpp" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="README.md" /> | |||
<None Include="simple_tests.asm" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Object Include="simple_tests.obj" /> | |||
</ItemGroup> | |||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | |||
<ImportGroup Label="ExtensionTargets"> |
@@ -14,4 +14,26 @@ | |||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> | |||
</Filter> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ClInclude Include="catch.hpp"> | |||
<Filter>Header Files</Filter> | |||
</ClInclude> | |||
<ClInclude Include="simple_tests.h"> | |||
<Filter>Header Files</Filter> | |||
</ClInclude> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ClCompile Include="main.cpp"> | |||
<Filter>Source Files</Filter> | |||
</ClCompile> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="simple_tests.asm"> | |||
<Filter>Source Files</Filter> | |||
</None> | |||
<None Include="README.md" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Object Include="simple_tests.obj" /> | |||
</ItemGroup> | |||
</Project> |
@@ -0,0 +1,17 @@ | |||
#include <stdint.h> | |||
#include <iostream> | |||
#define CATCH_CONFIG_MAIN | |||
#include "catch.hpp" | |||
#include "simple_tests.h" | |||
TEST_CASE("Functions work as expected, unhooked") { | |||
REQUIRE(_small() == 0); | |||
REQUIRE(_branch(1) == 0); | |||
REQUIRE(_branch(0) == 0); | |||
for (int i = 0; i < 1000; i++) { | |||
REQUIRE(_rip_relative() == rand()); | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
format ms64 coff | |||
section '.text' code readable writeable executable | |||
use64 | |||
public _small | |||
_small: | |||
xor eax, eax | |||
ret | |||
public _rip_relative | |||
_rip_relative: | |||
mov eax, [seed] | |||
mov ecx, 214013 | |||
mul ecx | |||
add eax, 2531011 | |||
mov [seed], eax | |||
shr eax, 16 | |||
and eax, 0x7FFF | |||
ret | |||
seed dd 1 | |||
public _branch | |||
_branch: | |||
and rax, 1 | |||
jz @branch_ret | |||
xor rax, rax | |||
nop ; Just some padding, so the function can't be copied entirely into the | |||
nop ; trampoline | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
nop | |||
@branch_ret: | |||
ret | |||
@@ -0,0 +1,31 @@ | |||
#pragma once | |||
extern "C" { | |||
/** | |||
* A small function, that always returns 0 | |||
*/ | |||
uint64_t _small(void); | |||
/** | |||
* This function checks if the parameter is even or odd, and then | |||
* always returns 0. | |||
* | |||
* The check is done with a branch, so the hooking engine has to take that | |||
* into account. | |||
* | |||
* @param Number to be checked | |||
*/ | |||
uint64_t _branch(uint64_t); | |||
/** | |||
* Replicates the MSVCRT rand(). | |||
* | |||
* This function is used to check whether the hooking engine correctly fixes | |||
* rip relative addressing. | |||
* | |||
* @internal: | |||
* static seed = 1; | |||
* return( ((seed = seed * 214013L | |||
* + 2531011L) >> 16) & 0x7fff ); | |||
*/ | |||
uint64_t _rip_relative(void); | |||
}; |