Skip to content

Commit

Permalink
Merge pull request #111 from EasyHook/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
justinstenning committed Jul 10, 2016
2 parents e995775 + 95e563c commit 002314e
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 32 deletions.
2 changes: 2 additions & 0 deletions DriverShared/DriverShared.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ void LhCriticalFinalize();

void* LhAllocateMemory(void* InEntryPoint);

void* LhAllocateMemoryEx(void* InEntryPoint, ULONG* OutPageSize);

void LhFreeMemory(PLOCAL_HOOK_INFO* RefHandle);

HOOK_ACL* LhBarrierGetAcl();
Expand Down
38 changes: 37 additions & 1 deletion DriverShared/LocalHook/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,38 @@ void* LhAllocateMemory(void* InEntryPoint)
NULL if no memory could be allocated, a valid pointer otherwise.
*/
ULONG pageSize;
return LhAllocateMemoryEx(InEntryPoint, &pageSize);
}

///////////////////////////////////////////////////////////////////////////////////
/////////////////////// LhAllocateMemoryEx
///////////////////////////////////////////////////////////////////////////////////
void* LhAllocateMemoryEx(void* InEntryPoint, ULONG* OutPageSize)
{
/*
Description:
Allocates one page of hook specific memory. The page size is returned in OutPageSize
Parameters:
- InEntryPoint
Ignored for 32-Bit versions and drivers. In 64-Bit user mode, the returned
pointer will always be in a 31-bit boundary around this parameter. This way
a relative jumper can still be placed instead of having to consume much more entry
point bytes for an absolute jump!
- OutPageSize
Will be updated to contain the page size.
Returns:
NULL if no memory could be allocated, a valid pointer otherwise.
*/

UCHAR* Res = NULL;
Expand All @@ -91,6 +123,7 @@ void* LhAllocateMemory(void* InEntryPoint)
GetSystemInfo(&SysInfo);

PAGE_SIZE = SysInfo.dwPageSize;
*OutPageSize = PAGE_SIZE;
#endif


Expand Down Expand Up @@ -134,7 +167,10 @@ void* LhAllocateMemory(void* InEntryPoint)
if(Res == NULL)
return NULL;
#else
// in 32-bit mode the trampoline will always be reachable

*OutPageSize = PAGE_SIZE;
// in 32-bit mode the trampoline will always be reachable
// In 64-bit driver mode we use an absolute address so the trampoline will always be reachable
if((Res = (UCHAR*)RtlAllocateMemory(TRUE, PAGE_SIZE)) == NULL)
return NULL;

Expand Down
80 changes: 59 additions & 21 deletions DriverShared/LocalHook/install.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,17 @@ EASYHOOK_BOOL_INTERNAL LhIsValidHandle(
}


// The maximum number of bytes that can be used for a trampoline jump
// Under most circumstance the max is 8 bytes, for X64_DRIVER this
// increases to 16 bytes to support jumping to absolute addresses
#define MAX_JMP_SIZE 16


#if X64_DRIVER
// The size of the instructions for a jump in/out of the trampoline within a 64-bit driver
#define X64_DRIVER_JMPSIZE 16
// The offset for where the address should be copied to within the jump
#define X64_DRIVER_JMPADDR_OFFSET 3
#endif

EASYHOOK_NT_INTERNAL LhAllocateHook(
void* InEntryPoint,
Expand Down Expand Up @@ -159,11 +168,21 @@ EASYHOOK_NT_INTERNAL LhAllocateHook(
LONGLONG RelAddr;
UCHAR* MemoryPtr;
LONG NtStatus = STATUS_INTERNAL_ERROR;
ULONG PageSize = 0;

#if X64_DRIVER
// This is the ASM that will perform a JMP back out of the trampoline
// Note that the address 0x0 will be replaced with appropriate address.
// 50 push rax
// 48 b8 00 00 00 00 00 00 00 00 mov rax, 0x0
// ff e0 jmp rax
UCHAR Jumper_x64[12] = {0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0};
// 48 87 04 24 xchg QWORD PTR[rsp], rax
// c3 ret
UCHAR Jumper_x64[X64_DRIVER_JMPSIZE] = {
0x50,
0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x87, 0x04, 0x24,
0xc3
};
#endif

#ifndef _M_X64
Expand All @@ -178,18 +197,19 @@ EASYHOOK_NT_INTERNAL LhAllocateHook(
if(!IsValidPointer(InHookProc, 1))
THROW(STATUS_INVALID_PARAMETER_2, L"Invalid hook procedure.");

// allocate memory for hook, for 64-bit this will be located within a 32-bit relative jump of entry point
if((*OutHook = (LOCAL_HOOK_INFO*)LhAllocateMemory(InEntryPoint)) == NULL)
// allocate memory for hook, for 64-bit non-driver this will be located within a 32-bit relative jump of entry point
if ((*OutHook = (LOCAL_HOOK_INFO*)LhAllocateMemoryEx(InEntryPoint, &PageSize)) == NULL)
THROW(STATUS_NO_MEMORY, L"Failed to allocate memory.");
Hook = *OutHook;

FORCE(RtlProtectMemory(Hook, 4096, PAGE_EXECUTE_READWRITE));
FORCE(RtlProtectMemory(Hook, PageSize, PAGE_EXECUTE_READWRITE));

MemoryPtr = (UCHAR*)(Hook + 1);
// Set MemoryPtr to end of LOCAL_HOOK_INFO structure where we will copy the trampoline and old proc
MemoryPtr = (UCHAR*)(Hook + 1);

// determine entry point size
#ifdef X64_DRIVER
FORCE(EntrySize = LhRoundToNextInstruction(InEntryPoint, 12));
FORCE(EntrySize = LhRoundToNextInstruction(InEntryPoint, X64_DRIVER_JMPSIZE));
#else
FORCE(EntrySize = LhRoundToNextInstruction(InEntryPoint, 5));
#endif
Expand Down Expand Up @@ -232,24 +252,30 @@ EASYHOOK_NT_INTERNAL LhAllocateHook(
Has to be written directly into the target buffer, because to
relocate RIP-relative addressing we need to know where the
instruction will go to...
The entry point code will be copied to the end of the trampoline
with any relative addresses adjusted (if possible). Hook->OldProc
points to this location.
*/
*RelocSize = 0;
Hook->OldProc = MemoryPtr;

FORCE(LhRelocateEntryPoint(Hook->TargetProc, EntrySize, Hook->OldProc, RelocSize));

MemoryPtr += *RelocSize + 12;
Hook->NativeSize += *RelocSize + 12;
// Reserve enough room to fit worst case
MemoryPtr += *RelocSize + MAX_JMP_SIZE;
Hook->NativeSize += *RelocSize + MAX_JMP_SIZE;

// add jumper to relocated entry point that will proceed execution in original method
// add jumper to end of relocated entry point that will continue execution at
// the next instruction within the original method.
#ifdef X64_DRIVER

// absolute jumper
RelAddr = (LONGLONG)(Hook->TargetProc + Hook->EntrySize);

RtlCopyMemory(Hook->OldProc + *RelocSize, Jumper_x64, 12);
RtlCopyMemory(Hook->OldProc + *RelocSize, Jumper_x64, X64_DRIVER_JMPSIZE);
// Set address to be copied into RAX
RtlCopyMemory(Hook->OldProc + *RelocSize + 2, &RelAddr, 8);
RtlCopyMemory(Hook->OldProc + *RelocSize + X64_DRIVER_JMPADDR_OFFSET, &RelAddr, 8);

#else

Expand All @@ -265,11 +291,12 @@ EASYHOOK_NT_INTERNAL LhAllocateHook(

#endif

// backup original entry point
// backup original entry point (8 bytes)
Hook->TargetBackup = *((ULONGLONG*)Hook->TargetProc);

#ifdef X64_DRIVER
Hook->TargetBackup_x64 = *((ULONGLONG*)(Hook->TargetProc + 8));
// 64-bit driver requires backup of additional 8 bytes supporting up to MAX_JMP_SIZE
Hook->TargetBackup_x64 = *((ULONGLONG*)(Hook->TargetProc + 8));
#endif

#ifndef _M_X64
Expand Down Expand Up @@ -376,15 +403,25 @@ EASYHOOK_NT_EXPORT LhInstallHook(
ULONG Index;
LONGLONG RelAddr;
ULONG RelocSize;
UCHAR Jumper[12] = {0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// This will contain the ASM that will perform a JMP into the trampoline
UCHAR Jumper[MAX_JMP_SIZE] = { 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ULONGLONG AtomicCache;
BOOL Exists;
LONG NtStatus = STATUS_INTERNAL_ERROR;

#if X64_DRIVER
// This is the ASM that will perform a jump INTO the trampoline for X64_DRIVER
// Note that the address 0x0 will be replaced with appropriate address.
// 50 push rax
// 48 b8 00 00 00 00 00 00 00 00 mov rax, 0x0
// ff e0 jmp rax
UCHAR Jumper_x64[12] = {0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0};
// 48 87 04 24 xchg QWORD PTR[rsp], rax
// c3 ret
UCHAR Jumper_x64[X64_DRIVER_JMPSIZE] = {
0x50,
0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x87, 0x04, 0x24,
0xc3
};
ULONGLONG AtomicCache_x64;
KIRQL CurrentIRQL = PASSIVE_LEVEL;
#endif
Expand All @@ -411,9 +448,9 @@ EASYHOOK_NT_EXPORT LhInstallHook(
// absolute jumper
RelAddr = (ULONGLONG)Hook->Trampoline;

RtlCopyMemory(Jumper, Jumper_x64, 12);
RtlCopyMemory(Jumper, Jumper_x64, X64_DRIVER_JMPSIZE);
// Set address to be copied into RAX
RtlCopyMemory(Jumper + 2, &RelAddr, 8);
RtlCopyMemory(Jumper + X64_DRIVER_JMPADDR_OFFSET, &RelAddr, 8);

#else

Expand Down Expand Up @@ -461,7 +498,8 @@ EASYHOOK_NT_EXPORT LhInstallHook(
AtomicCache = *((ULONGLONG*)(Hook->TargetProc + 8));
{
RtlCopyMemory(&AtomicCache_x64, Jumper, 8);
RtlCopyMemory(&AtomicCache, Jumper + 8, 4);
// Copy the second part of the Jumper
RtlCopyMemory(&AtomicCache, Jumper + 8, X64_DRIVER_JMPSIZE - 8);

// backup entry point for later comparison
Hook->HookCopy = AtomicCache_x64;
Expand Down
1 change: 1 addition & 0 deletions DriverShared/LocalHook/uninstall.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ EASYHOOK_NT_EXPORT LhWaitForPendingRemovals()
#endif
*((ULONGLONG*)Hook->TargetProc) = Hook->TargetBackup;
#ifdef X64_DRIVER
// we support a trampoline jump of up to 16 bytes in X64_DRIVER
*((ULONGLONG*)(Hook->TargetProc + 8)) = Hook->TargetBackup_x64;
RtlWPOn(CurrentIRQL);
#endif
Expand Down
6 changes: 5 additions & 1 deletion EasyHookDll/RemoteHook/stealth.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ EASYHOOK_NT_EXPORT RhCreateStealthRemoteThread(
STEALTH_CONTEXT* RemoteCtx = NULL;
CONTEXT Context;
HANDLE hHijackedThread = NULL;
DWORD hijackedThreadId = 0;
HANDLE hCompletionEvent = NULL;
HANDLE hSyncEvent = NULL;
SIZE_T BytesRead = 0;
Expand Down Expand Up @@ -204,6 +205,8 @@ EASYHOOK_NT_EXPORT RhCreateStealthRemoteThread(
// if thread was active, it is now suspended...
IsSuspended = TRUE;

hijackedThreadId = NativeEntry.th32ThreadID;

break;
}

Expand Down Expand Up @@ -312,7 +315,7 @@ EASYHOOK_NT_EXPORT RhCreateStealthRemoteThread(
if(!WriteProcessMemory(hProc, (UCHAR*)RemoteCtx + GetStealthStubSize(), &LocalCtx, sizeof(LocalCtx), &BytesRead))
THROW(STATUS_INTERNAL_ERROR, L"Unable to write remote context.");

if(!WriteProcessMemory(hProc, RemoteCtx, GetStealthStubPtr(), GetStealthStubSize(), &BytesRead))
if(!WriteProcessMemory(hProc, (UCHAR*)RemoteCtx, GetStealthStubPtr(), GetStealthStubSize(), &BytesRead))
THROW(STATUS_INTERNAL_ERROR, L"Unable to write remote stealth stub.");

// resume thread
Expand All @@ -325,6 +328,7 @@ EASYHOOK_NT_EXPORT RhCreateStealthRemoteThread(

// TODO:
//::PostThreadMessage(HijackedThreadId,
//PostThreadMessage(hijackedThreadId, WM_NULL, 0, 0);

/*
Wait for completion and process results...
Expand Down
22 changes: 13 additions & 9 deletions Examples/UnmanagedHook/UnmanagedHook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,23 @@ BOOL WINAPI MessageBeepHook(__in UINT uType)
return TRUE;
}

DWORD __stdcall TestThread(void* InParams)
DWORD __stdcall HijackEntry(void* InParams)
{
while(TRUE) Sleep(100);
if(InParams != (PVOID)0x12345678)
throw;

printf("\n" "Hello from stealth remote thread!\n");

return 0;
}

DWORD __stdcall HijackEntry(void* InParams)

DWORD __stdcall TestThread(void* InParams)
{
if(InParams != (PVOID)0x12345678)
throw;
HANDLE hRemoteThread;
RhCreateStealthRemoteThread(GetCurrentProcessId(), HijackEntry, (PVOID)0x12345678, &hRemoteThread);

printf("\n" "Hello from stealth remote thread!\n");
while (TRUE) Sleep(100);

return 0;
}
Expand All @@ -64,7 +68,7 @@ extern "C" int main(int argc, wchar_t* argv[])
HANDLE hRemoteThread;

// test driver...
printf("Installing support driver...\n");
/*printf("Installing support driver...\n");
FORCE(RhInstallSupportDriver());
Expand All @@ -74,13 +78,13 @@ extern "C" int main(int argc, wchar_t* argv[])
FORCE(RhInstallDriver(L"TestDriver64.sys", L"TestDriver64.sys"))
else
FORCE(RhInstallDriver(L"TestDriver32.sys", L"TestDriver32.sys"));

*/
// test stealth thread creation...
printf("Testing stealth thread creation...\n");

hRemoteThread = CreateThread(NULL, 0, TestThread, NULL, 0, NULL);

FORCE(RhCreateStealthRemoteThread(GetCurrentProcessId(), HijackEntry, (PVOID)0x12345678, &hRemoteThread));
//FORCE(RhCreateStealthRemoteThread(GetCurrentProcessId(), HijackEntry, (PVOID)0x12345678, &hRemoteThread));

Sleep(500);

Expand Down

0 comments on commit 002314e

Please sign in to comment.