Skip to content

Instantly share code, notes, and snippets.

@RistBS
Forked from odzhan/wow64.cpp
Created April 19, 2023 22:54
Show Gist options
  • Save RistBS/e91e63790dbe2ae54d77b74fee098be5 to your computer and use it in GitHub Desktop.
Save RistBS/e91e63790dbe2ae54d77b74fee098be5 to your computer and use it in GitHub Desktop.
WOW64 Callbacks
//
// How to locate the WOW64 Callback Table in ntdll.dll
//
// @modexpblog
//
#define PHNT_VERSION PHNT_VISTA
#include <phnt_windows.h>
#include <phnt.h>
#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <cstring>
typedef union _W64_T {
LPVOID p;
BYTE b[8];
DWORD w[2];
DWORD64 q;
LPVOID *pp;
} W64_T;
typedef struct _WOW64_CALLBACK {
STRING Name;
W64_T Function;
} WOW64_CALLBACK, *PWOW64_CALLBACK;
//
// Structure based on 64-bit version of NTDLL
//
typedef struct _WOW64_CALLBACK_TABLE {
WOW64_CALLBACK Wow64LdrpInitialize;
WOW64_CALLBACK Wow64PrepareForException;
WOW64_CALLBACK Wow64ApcRoutine;
WOW64_CALLBACK Wow64PrepareForDebuggerAttach;
WOW64_CALLBACK Wow64SuspendLocalThread;
WOW64_CALLBACK Wow64SuspendLocalProcess;
} WOW64_CALLBACK_TABLE, *PWOW64_CALLBACK_TABLE;
BOOL
IsReadOnlyPtr(LPVOID ptr) {
MEMORY_BASIC_INFORMATION mbi;
if (!ptr) return FALSE;
// query the pointer
DWORD res = VirtualQuery(ptr, &mbi, sizeof(mbi));
if (res != sizeof(mbi)) return FALSE;
return ((mbi.State == MEM_COMMIT ) &&
(mbi.Type == MEM_IMAGE ) &&
(mbi.Protect == PAGE_READONLY));
}
//
//
//
BOOL
GetWow64FunctionPointer(PWOW64_CALLBACK Callback) {
auto m = (PBYTE)GetModuleHandleW(L"ntdll");
auto nt = (PIMAGE_NT_HEADERS)(m + ((PIMAGE_DOS_HEADER)m)->e_lfanew);
auto sh = IMAGE_FIRST_SECTION(nt);
for (DWORD i=0; i<nt->FileHeader.NumberOfSections; i++) {
if (*(PDWORD)sh[i].Name == *(PDWORD)".rdata") {
auto rva = sh[i].VirtualAddress;
auto cnt = (sh[i].Misc.VirtualSize - sizeof(STRING)) / sizeof(ULONG_PTR);
auto ptr = (PULONG_PTR)(m + rva);
for (DWORD j=0; j<cnt; j++) {
if (!IsReadOnlyPtr((LPVOID)ptr[j])) continue;
auto api = (PSTRING)ptr[j];
if (api->Length == Callback->Name.Length && api->MaximumLength == Callback->Name.MaximumLength) {
if (!strncmp(api->Buffer, Callback->Name.Buffer, Callback->Name.Length)) {
Callback->Function.p = (PVOID)ptr[j + 1];
return TRUE;
}
}
}
break;
}
}
return FALSE;
}
void
GetWow64CallbackTable(PWOW64_CALLBACK_TABLE Table) {
GetWow64FunctionPointer(&Table->Wow64LdrpInitialize);
GetWow64FunctionPointer(&Table->Wow64PrepareForException);
GetWow64FunctionPointer(&Table->Wow64ApcRoutine);
GetWow64FunctionPointer(&Table->Wow64PrepareForDebuggerAttach);
GetWow64FunctionPointer(&Table->Wow64SuspendLocalThread);
GetWow64FunctionPointer(&Table->Wow64SuspendLocalProcess);
GetWow64FunctionPointer(&Table->Wow64LdrpInitialize);
}
WOW64_CALLBACK_TABLE Wow64Table = {
{RTL_CONSTANT_STRING("Wow64LdrpInitialize"), NULL},
{RTL_CONSTANT_STRING("Wow64PrepareForException"), NULL},
{RTL_CONSTANT_STRING("Wow64ApcRoutine"), NULL},
{RTL_CONSTANT_STRING("Wow64PrepareForDebuggerAttach"), NULL},
{RTL_CONSTANT_STRING("Wow64SuspendLocalThread"), NULL},
{RTL_CONSTANT_STRING("Wow64SuspendLocalProcess"), NULL}
};
int
main(void) {
GetWow64CallbackTable(&Wow64Table);
printf("Wow64LdrpInitialize : %p\n", Wow64Table.Wow64LdrpInitialize.Function.p);
printf("Wow64PrepareForException : %p\n", Wow64Table.Wow64PrepareForException.Function.p);
printf("Wow64ApcRoutine : %p\n", Wow64Table.Wow64ApcRoutine.Function.p);
printf("Wow64PrepareForDebuggerAttach : %p\n", Wow64Table.Wow64PrepareForDebuggerAttach.Function.p);
printf("Wow64SuspendLocalThread : %p\n", Wow64Table.Wow64SuspendLocalThread.Function.p);
printf("Wow64SuspendLocalProcess : %p\n", Wow64Table.Wow64SuspendLocalProcess.Function.p);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment