|
|
@@ -0,0 +1,78 @@ |
|
|
// |
|
|
// Every new thread starts with ntdll!RtlUserThreadStart and it typically calls kernel32!BaseThreadInitThunk |
|
|
// |
|
|
// Some applications like Mozilla Firefox and Microsoft Edge will replace this with their own function for hooking purposes. |
|
|
// The following code shows how to find it without using debugging symbols. |
|
|
// |
|
|
// @modexpblog |
|
|
// |
|
|
|
|
|
#define PHNT_VERSION PHNT_VISTA |
|
|
#include <phnt_windows.h> |
|
|
#include <phnt.h> |
|
|
|
|
|
#include <cstdio> |
|
|
|
|
|
#pragma comment(lib, "ntdll") |
|
|
|
|
|
VOID |
|
|
WINAPI |
|
|
BaseThreadInitThunk( |
|
|
IN DWORD LdrReserved, |
|
|
IN LPTHREAD_START_ROUTINE lpStartAddress, |
|
|
IN LPVOID lpParameter) |
|
|
{ |
|
|
printf("New Thread created...\n"); |
|
|
RtlExitUserThread(0); |
|
|
} |
|
|
|
|
|
int |
|
|
main(void) { |
|
|
auto fn = (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32"), "BaseThreadInitThunk"); |
|
|
|
|
|
auto m = (PBYTE)GetModuleHandleA("ntdll"); |
|
|
auto nt = (PIMAGE_NT_HEADERS)(m + ((PIMAGE_DOS_HEADER)m)->e_lfanew); |
|
|
auto sh = IMAGE_FIRST_SECTION(nt); |
|
|
|
|
|
ULONG_PTR *ds = NULL, Kernel32ThreadInitThunkFunction = NULL; |
|
|
ULONG cnt = 0; |
|
|
|
|
|
for (DWORD i=0; i<nt->FileHeader.NumberOfSections; i++) { |
|
|
if(*(PDWORD)sh[i].Name == *(PDWORD)".data") { |
|
|
ds = (PULONG_PTR)(m + sh[i].VirtualAddress); |
|
|
cnt = sh[i].Misc.VirtualSize / sizeof(ULONG_PTR); |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
printf("Searching for kernel32!BaseThreadInitThunk (%p) in ntdll.dll\n", (PVOID)fn, m); |
|
|
|
|
|
for (DWORD i=0; i<cnt; i++) { |
|
|
if (ds[i] == fn) { |
|
|
printf("Found ntdll!Kernel32ThreadInitThunkFunction @ %p\n", (PVOID)&ds[i]); |
|
|
Kernel32ThreadInitThunkFunction = (ULONG_PTR)&ds[i]; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
// |
|
|
// Save pointer and overwrite with our function. |
|
|
// |
|
|
_InterlockedCompareExchangePointer((PVOID*)Kernel32ThreadInitThunkFunction, (PVOID)BaseThreadInitThunk, (PVOID)fn); |
|
|
|
|
|
// |
|
|
// Create new thread that executes our function indirectly. |
|
|
// |
|
|
CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ExitThread, NULL, 0, NULL)); |
|
|
|
|
|
printf("Press any key to continue...\n"); |
|
|
getchar(); |
|
|
|
|
|
// |
|
|
// Restore original pointer, removing our function. |
|
|
// |
|
|
_InterlockedCompareExchangePointer((PVOID*)Kernel32ThreadInitThunkFunction, (PVOID)fn, (PVOID)BaseThreadInitThunk); |
|
|
|
|
|
printf("Done.\n"); |
|
|
return 0; |
|
|
} |