Win32, How can i hook functions in compiled programs with C++?

前端 未结 1 1453
北海茫月
北海茫月 2020-12-10 23:23

Take for instance this function (viewed in Ollydbg debugger) \"enter

The first PUSH EB

相关标签:
1条回答
  • 2020-12-11 00:21

    First, you will want to inject a dll in the target process. To do so, you can use this code:

    Injector.h

    #ifndef INJECTOR_H_INCLUDED
    #define INJECTOR_H_INCLUDED
    
    #include <Windows.h>
    #include <string>
    
    class Injector
    {
    public:
        /**
         * Loads a DLL into the remote process
         * @Return true on sucess, false on failure
        */
        bool InjectDll(DWORD processId, std::string dllPath);
    private:
    };
    
    #endif // INJECTOR_H_INCLUDED
    

    Injector.cpp

    #include "Injector.h"
    
    bool Injector::InjectDll(DWORD processId, std::string dllPath)
    {
        HANDLE hThread, hProcess;
        void*  pLibRemote = 0;  // the address (in the remote process) where szLibPath will be copied to;
    
        HMODULE hKernel32 = GetModuleHandle("Kernel32");
        HINSTANCE hInst = GetModuleHandle(NULL);
    
        char DllFullPathName[_MAX_PATH];
        GetFullPathName(dllPath.c_str(), _MAX_PATH, DllFullPathName, NULL);
    
        // Get process handle
        hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
    
        // copy file path in szLibPath
        char szLibPath[_MAX_PATH];
        strcpy_s(szLibPath, DllFullPathName);
    
        // 1. Allocate memory in the remote process for szLibPath
        pLibRemote = VirtualAllocEx( hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE );
    
        if (pLibRemote == NULL)
        {
            // probably because you don't have administrator's right
            return false;
        }
    
        // 2. Write szLibPath to the allocated memory
        WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath, sizeof(szLibPath), NULL);
    
        // 3. Force remote process to load dll
        hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) GetProcAddress(hKernel32,"LoadLibraryA"), pLibRemote, 0, NULL);
    
        if (hThread == NULL)
        {
            return false;
        }
    
        return true;
    }
    

    main.cpp

    #include "Injector.h"
    int main()
    {
        Injector injector;
        DWORD processId = 1653; // change the process id here. 
    
        if (injector.InjectDll(processId, "injected.dll"))
        {
            printf("Good job, you injected the dll\n");
        }
        else
        {
            printf("Something wrong happened\n");
        }
    
        while (true);
    }
    

    Then you have to make your dll. This is where it gets a little more complicated. First some includes:

    injected.dll

    #include <Windows.h>
    #include <stdio.h>
    

    Then we need to make a function that will detour the right location:

    void DetourAddress(void* funcPtr, void* hook, BYTE* mem)
    {
        BYTE cmd[5] = { 0xE9, 0x00, 0x00, 0x00, 0x00 }; // jump place holder
        void* RVAaddr = (void*)((DWORD)funcPtr + (DWORD)GetModuleHandle(NULL)); // base + relative address
    
        // make memory readable/writable
        DWORD dwProtect;
        VirtualProtect(RVAaddr, 5, PAGE_EXECUTE_READWRITE, &dwProtect);
    
        // read memory
        ReadProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, &mem[2], 5, NULL);
    
        // write jmp in cmd
        DWORD offset = ((DWORD)hook - (DWORD)RVAaddr - 5);  // (dest address) - (source address) - (jmp size)
        memcpy(&cmd[1], &offset, 4); // write address into jmp
        WriteProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, cmd, 5, 0); // write jmp
    
        // write mem
        VirtualProtect(mem, 13, PAGE_EXECUTE_READWRITE, &dwProtect);
    
        void* returnAdress = (void*)((DWORD)RVAaddr + 5);
        memcpy(&mem[8], &returnAdress, 4); // write return address into mem
    
        // reprotect
        VirtualProtect(RVAaddr, 5, dwProtect, NULL);
    }
    

    If you need to remove your dll at some point, you will need to restore the code:

    void PatchAddress(void* funcPtr, BYTE* mem)
    {
        void* RVAaddr = (void*)((DWORD)funcPtr + (DWORD)GetModuleHandle(NULL)); // base + relative address
    
        // make memory readable/writable
        DWORD dwProtect;
        VirtualProtect(funcPtr, 5, PAGE_EXECUTE_READWRITE, &dwProtect);
    
        WriteProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, &mem[2], 5, NULL); // write jmp
    
        VirtualProtect(RVAaddr, 5, dwProtect, NULL);
    }
    

    Next, we need to make a function out of the detoured bytes in order for the program to execute them, so that it isn't affected by our detour. Add this in global space:

    // memory (0x5E = pop esi, 0x68 = push DWORD, 0xC3 = RETN)
    BYTE detourMem[13] = { 0x5E, 0x5E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x00, 0x00, 0x00, 0x00, 0xC3 };
    
    // Convert bytes array to function
    typedef void ( * pFunc)();
    pFunc funcMem = (pFunc) &detourMem;
    
    // I also added a variable as an example of what you can do with it.
    DWORD var = 0;
    

    After that, you need your detouring function:

    _declspec(naked) void DetourFunction()
    {
        // we need to push all flag and registers on the stack so we don't modify them by accident
        __asm
        {
            PUSHFD
            PUSHAD
    
            // You can do "whatever" you want here in assembly code
            // ex, put eax value into var:
            mov var, eax
        }
    
        printf("this code is executed everytime the detoured function is called\n");
        // Do whatever you want in c++ here
        if (var < 7)
        {
            // eax was smaller than 7
        }
    
        // We pop every flags and registers we first pushed so that the program continue as it was supposed to
        __asm
        {
            // we set everything back to normal
            POPAD
            POPFD
            push esi
    
            // we call our funcMem
            mov edx, funcMem;
            call edx
        }
    }
    

    Finaly, here is how your DLLMain would look like:

    BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved  )
    {
        DWORD detouredAddress = 0x689B; // add the RELATIVE ADDRESS of the location you want to detour
        FILE *stream;
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            // Only add this if you want a console to appears when you inject your dll (don't forget FreeConsole when you remove the dll)
            AllocConsole();
            freopen_s(&stream, "CONOUT$", "w", stdout);
    
            // If you need to know the base address of the process your injected:   
            printf("base address: 0x%X\n", (DWORD)GetModuleHandle(NULL));
    
            // Our detour function
            DetourAddress((void*)detouredAddress, (void*)&DetourFunction, detourMem);
            break;
        case DLL_PROCESS_DETACH:
            // We restore the process to have what it was before it was injected
            PatchAddress((void*)detouredAddress, detourMem);
    
            FreeConsole();
            break;
        }
    
        return true;
    }
    

    I understand this is a lot all at once, so if you have any questions don't hesitate!

    0 讨论(0)
提交回复
热议问题