Skip to content

Instantly share code, notes, and snippets.

@thomasxm
Forked from odzhan/BaseThreadInitThunk.cpp
Created June 29, 2024 20:02
Show Gist options
  • Select an option

  • Save thomasxm/7ad905259f429a35f9f8d706aeaf81f2 to your computer and use it in GitHub Desktop.

Select an option

Save thomasxm/7ad905259f429a35f9f8d706aeaf81f2 to your computer and use it in GitHub Desktop.

Revisions

  1. @odzhan odzhan revised this gist May 17, 2023. No changes.
  2. @odzhan odzhan revised this gist Apr 3, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion BaseThreadInitThunk.cpp
    Original file line number Diff line number Diff line change
    @@ -45,7 +45,7 @@ main(void) {
    }
    }

    printf("Searching for kernel32!BaseThreadInitThunk (%p) in ntdll.dll\n", (PVOID)fn, m);
    printf("Searching for kernel32!BaseThreadInitThunk (%p) in ntdll.dll\n", (PVOID)fn);

    for (DWORD i=0; i<cnt; i++) {
    if (ds[i] == fn) {
  3. @odzhan odzhan revised this gist Apr 3, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion BaseThreadInitThunk.cpp
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,7 @@ main(void) {
    }

    //
    // Save pointer and overwrite with our function.
    // Overwrite with our function.
    //
    _InterlockedCompareExchangePointer((PVOID*)Kernel32ThreadInitThunkFunction, (PVOID)BaseThreadInitThunk, (PVOID)fn);

  4. @odzhan odzhan created this gist Apr 3, 2023.
    78 changes: 78 additions & 0 deletions BaseThreadInitThunk.cpp
    Original file line number Diff line number Diff line change
    @@ -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;
    }