EasyHook for srand is installed but seems to be ignored

73 views Asked by At

I want to hook a Windows process and replace CRT's srand with my own function that will use a static seed (42). For this I decided to spawn a new process in a suspended state, install the hook and then resume the target's thread, so the target application when it is actutually gets executed has no way but use my own srand. I created this code following the EasyHook tutorials:

// hook.cpp

#include "easyhook.h"
#include <string>
#include <iostream>
#include <Windows.h>

extern "C" void __declspec(dllexport) __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo);

static void StaticSrand(int seed) {
    std::cout << "[HOOK] called StaticSrand(" << seed << ")" << std::endl;
    const int staticSeed = 42;
    srand(staticSeed);
}

static void OverwriteFunc(REMOTE_ENTRY_INFO *inRemoteInfo, const char *dll, const char *funcName, void *func) {
        auto address = GetProcAddress(GetModuleHandle(TEXT(dll)), funcName);
        
        HOOK_TRACE_INFO hHook = { NULL };
        NTSTATUS result = LhInstallHook(address, func, NULL, &hHook);
        
        if (FAILED(result)) {
            std::wstring s(RtlGetLastErrorString());
            std::wcout << "[HOOK] failed to install hook: " << s << std::endl;
        } else {
            std::cout << "[HOOK] successfully installed hook by " << inRemoteInfo->HostPID << ", function '" << funcName << "' at " << address << std::endl;
        }
        
        ULONG ACLEntries[1] = { 0 };
        LhSetExclusiveACL(ACLEntries, 1, &hHook);
}

void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo) {
    OverwriteFunc(inRemoteInfo, "ucrtbase", "srand", StaticSrand);
}

// injector.cpp

#include <iostream>
#include "easyhook.h"
#include <Windows.h>

static LPCWSTR TARGET_EXE = L"target.exe";
static LPWSTR DLL_PATH_W = L"hook.dll";

int main() {
    // Create suspended process so the srand() hook is installed before the
    // target EXE can call it, on its startup for example. When the hook is
    // successfully installed we resume the target process, therefore it has no
    // other way but use or own srand() instead of the CRT's one.
    STARTUPINFOW si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    BOOL result = CreateProcessW(TARGET_EXE, NULL, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
    
    if (!result) {
        std::cout << "[INJECTOR] failed to create process" << std::endl;
        return EXIT_FAILURE;
    }
    
    NTSTATUS err = RhInjectLibrary(
        pi.dwProcessId,
        0, // Wake Up TID
        EASYHOOK_INJECT_DEFAULT, // Default options
        NULL, // 32-bit DLL
        DLL_PATH_W, // 64-bit DLL
        NULL, 0 // No passthrough data
    );
    
    if (err != 0) {
        std::cout << "[INJECTOR] failed to inject DLL" << std::endl;
        return EXIT_FAILURE;
    }
    
    std::cout << "[INJECTOR] successfully inject DLL into the process, resuming the thread" << std::endl;
    ResumeThread(pi.hThread);
    
    WaitForSingleObject(pi.hProcess, INFINITE);
    
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}
// target.cpp

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <Windows.h>

int main(void) {
    while (true) {
        const int seed = time(NULL);
        srand(seed);

        const int r0 = rand();
        const int r1 = rand();
        const int r2 = rand();

        std::cout << "Seed is " << seed << ": " << r0 << " " << r1 << " " << r2 << std::endl;
        Sleep(1000);
    }
}

I compile the files using MSVC 19.38.33130 x64:

cl /LD hook.cpp EasyHook64.lib /EHsc
cl injector.cpp EasyHook64.lib /EHsc
cl target.cpp /EHsc

Everything compiles without any warnings. But when I run injector.exe I got the following output:

C:\Users\User\Desktop\Hook>injector.exe
[INJECTOR] successfully inject DLL into the process, resuming the thread
[HOOJ] successfully installed hook by 9304, function 'srand' at 00007Seed is FFEAC5120D10
700850449: 20391 11210 1132
Seed is 1700850450: 20394 21959 18996
Seed is 1700850451: 20397 32707 4092
Seed is 1700850452: 20401 10687 21957
Seed is 1700850453: 20404 21436 7053
Seed is 1700850454: 20407 32184 24917
Seed is 1700850455: 20410 10165 10013
Seed is 1700850456: 20414 20913 27877
Seed is 1700850457: 20417 31661 12973
Seed is 1700850458: 20420 9642 30838
^C

So you can see although it seems that the hook is successfully installed, the srand call is not proxied by the hook and still uses current time as the seed. I have no prior experience with Windows API and EasyHook, what I am missing here?

0

There are 0 answers