Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Wow64Hook example
#include "stdafx.h"
#include <iostream>
LPVOID lpJmpRealloc = nullptr;
DWORD Backup_Eax, Handle, Address_1, New, Old, *DwSizee;
const DWORD_PTR __declspec(naked) GetGateAddress()
{
__asm
{
mov eax, dword ptr fs : [0xC0]
ret
}
}
void __declspec(naked) hk_NtProtectVirtualMemory()
{
__asm {
mov Backup_Eax, eax
mov eax, [esp + 0x8]
mov Handle, eax
mov eax, [esp + 0xC]
mov Address_1, eax
mov eax, [esp + 0x10]
mov DwSizee, eax
mov eax, [esp + 0x14]
mov New, eax
mov eax, [esp + 0x18]
mov Old, eax
mov eax, Backup_Eax
pushad
}
printf("NtPVM Handle: [%x] Address: [0x%x] Size: [%d] NewProtect: [0x%x]\n", Handle, Address_1, *DwSizee, New);
__asm popad
__asm jmp lpJmpRealloc
}
void __declspec(naked) hk_NtReadVirtualMemory()
{
__asm pushad
printf("Calling NtReadVirtualMemory.\n");
__asm popad
__asm jmp lpJmpRealloc
}
void __declspec(naked) hk_Wow64Trampoline()
{
__asm
{
cmp eax, 0x3f //64bit Syscall id of NtRVM
je hk_NtReadVirtualMemory
cmp eax, 0x50 //64bit Syscall id of NtPVM
je hk_NtProtectVirtualMemory
jmp lpJmpRealloc
}
}
const LPVOID CreateNewJump()
{
DWORD_PTR Gate = GetGateAddress();
lpJmpRealloc = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
memcpy(lpJmpRealloc, (void *)Gate, 9);
return lpJmpRealloc;
}
const void WriteJump(const DWORD_PTR dwWow64Address, const void *pBuffer, size_t ulSize)
{
DWORD dwOldProtect = 0;
VirtualProtect((LPVOID)dwWow64Address, 0x1000, PAGE_EXECUTE_READWRITE, &dwOldProtect);
(void)memcpy((void *)dwWow64Address, pBuffer, ulSize);
VirtualProtect((LPVOID)dwWow64Address, 0x1000, dwOldProtect, &dwOldProtect);
}
const void EnableWow64Redirect()
{
LPVOID Hook_Gate = &hk_Wow64Trampoline;
char trampolineBytes[] =
{
0x68, 0xDD, 0xCC, 0xBB, 0xAA, /*push 0xAABBCCDD*/
0xC3, /*ret*/
0xCC, 0xCC, 0xCC /*padding*/
};
memcpy(&trampolineBytes[1], &Hook_Gate, 4);
WriteJump(GetGateAddress(), trampolineBytes, sizeof(trampolineBytes));
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
FILE* fp;
freopen_s(&fp, "CONOUT$", "w", stdout);
printf("Gate: %p\n", GetGateAddress());
printf("Trampoline Gate: %p\n", CreateNewJump());
printf("Hook Gate: %p\n", hk_Wow64Trampoline);
EnableWow64Redirect();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
@hoangprod
Copy link
Author

hoangprod commented Jan 28, 2021

is this a 32 or 64 bit DLL may i ask?

Since this is a Wow64 hook, this should be compiled as a 32bit DLL injected into a 32bit process on a 64bit OS.

@nioe8956
Copy link

nioe8956 commented Feb 4, 2021

void __declspec(naked) hk_NtProtectVirtualMemory()
{
__asm {
mov Backup_Eax, eax
mov eax, [esp + 0x8]
mov Handle, eax
mov eax, [esp + 0xC]
mov Address_1, eax
mov eax, [esp + 0x10]
mov DwSizee, eax
mov eax, [esp + 0x14]
mov New, eax
mov eax, [esp + 0x18]
mov Old, eax
mov eax, Backup_Eax
pushad
}

How can I arguments of find that function?
i will want to find NtOpenProcess function stack [esp+0x00]

thank you

@zhao-lun
Copy link

zhao-lun commented Jul 27, 2021

const LPVOID CreateNewJump()
{
	DWORD_PTR Gate = GetGateAddress();
	lpJmpRealloc = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT,
		PAGE_EXECUTE_READWRITE);
	memcpy(lpJmpRealloc, (void *)Gate, 9);

	return lpJmpRealloc;
}

Why do we copy 9 bytes? I noticed Heaven's gate only has 7 useful bytes.
Thank you.

@hoangprod
Copy link
Author

hoangprod commented Jul 27, 2021

const LPVOID CreateNewJump()
{
	DWORD_PTR Gate = GetGateAddress();
	lpJmpRealloc = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT,
		PAGE_EXECUTE_READWRITE);
	memcpy(lpJmpRealloc, (void *)Gate, 9);

	return lpJmpRealloc;
}

Why do we copy 9 bytes? I noticed Heaven's gate only has 7 useful bytes.
Thank you.

I have not work with Wow64 in some time and by looking through the code, I don't see a good reason either. At the transition gate, it looks like there are 7 useful bytes and then 2x 00 bytes but those 2x 00 bytes should never be executed due to it being after an unconditional jump. Therefore, I think using just 7 bytes should be sufficed.

@zhao-lun
Copy link

zhao-lun commented Jul 27, 2021

Thank you so much. @hoangprod

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment