[Software Reverse] How to remotely inject dll under windows and perform virtual table hook

Tools required

  1. Microsoft Visual Studio development tools.
  2. IDA pro dynamic debugging tool.
  3. Process Hacker 2 process monitoring tool.
  4. Exe program that is remotely injected. (Take crackme.exe as an example)

Remotely inject dll for virtual table hook

1. Decompile IDA pro to find the logical address of the function

  1. Use IDA pro to open crackme.exe and enable dynamic debugging.
  2. Find the place where you need to hook, usually a function in the system library, take jmp cs:EnterCriticalSection as an example. (where EnterCriticalSection can be other system functions)
  3. Double-click the function name and find its real address 0x7ff6472bd0c8.
  4. The starting address of the found program is 0x7ff6472a0000.
  5. It can be calculated that the logical address of the EnterCriticalSection function relative to the program entry is 0x7ff6472bd0c8-0x7ff6472a0000=0x1d0c8.

2. VS writes virtual table hook dynamic link library

  1. Open Visual Studio and create a DLL project.
  2. Modify dllmain.cpp to the following code, in which 0x1d0c8 is modified to the logical address of the function in the first step, and write the code you want to execute in the Hooked_VtableFunc function.
// dllmain.cpp: Defines the entry point of the DLL application.
#include "pch.h"
#include <Windows.h>
#include <stdio.h>
#include <iostream>
typedef void(__fastcall* VtableFunc_t)();
VtableFunc_t VtableFunc = nullptr;

//Function to be executed
void __fastcall Hooked_VtableFunc() {<!-- -->
    printf("Correct\\
");
    system("pause");
    return VtableFunc();
}

void HookVtableTest() {<!-- -->
    uintptr_t VtableAddress = (uintptr_t)GetModuleHandleA(0) + 0x1d0c8; //0x1d0c8 is modified to the logical address of the function in the first step
    DWORD old_protect = 0;
    VirtualProtect((LPVOID)VtableAddress, 0x8, PAGE_EXECUTE_READWRITE, & amp;old_protect);
    *(uintptr_t*)(VtableAddress) = (uintptr_t)Hooked_VtableFunc;
    VirtualProtect((LPVOID)VtableAddress, 0x8, old_protect, & amp;old_protect);
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD ul_reason_for_call,
    LPVOID lpReserved
)
{<!-- -->
    switch (ul_reason_for_call)
    {<!-- -->
    case DLL_PROCESS_ATTACH:
        HookVtableTest(); break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
  1. After generating the solution, you can get the dll file of the virtual table hook. The dll file is generally in “project path/x64/Debug/”.

3. VS writes remote injection code

  1. Open Visual Studio and create a console application.
  2. Copy the following code to the cpp source file, in which the wStr variable in the first line of the main function is modified to the path of the dll generated in the second step (\ under the windows path needs to be translated with \), and the second line is modified to process name (you can open the task manager to view).
#include <iostream>
#include <vector>
#include <Windows.h>
#include <tlhelp32.h>
#include <fstream>
using namespace std;

bool Inject(DWORD dwId, WCHAR* szPath)//Parameter 1: Target process PID Parameter 2: DLL path
{<!-- -->
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwId);
    LPVOID pRemoteAddress = VirtualAllocEx(
        hProcess,
        NULL,
        wcslen(szPath) * 2,
        MEM_COMMIT,
        PAGE_READWRITE
    );
    DWORD dwWriteSize = 0;
    BOOL bRet = WriteProcessMemory(hProcess, pRemoteAddress, szPath, wcslen(szPath) * 2, NULL);
    HMODULE hModule = GetModuleHandle(L"kernel32.dll");
    if (!hModule)
    {<!-- -->
        printf("GetModuleHandle Error !\\
");
        GetLastError();
        CloseHandle(hProcess);
        return FALSE;
    }
    LPTHREAD_START_ROUTINE dwLoadAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryW");
    if (!dwLoadAddr)
    {<!-- -->
        printf("GetProcAddress Error !\\
");
        CloseHandle(hProcess);
        CloseHandle(hModule);
        return FALSE;
    }

    HANDLE hThread = CreateRemoteThread(
        hProcess,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)dwLoadAddr,
        pRemoteAddress,
        NULL,
        NULL
    );
    return 0;
}
DWORD GetPid(WCHAR* szName)
{<!-- -->
    HANDLE hprocessSnap = NULL;
    PROCESSENTRY32 pe32 = {<!-- --> 0 };
    hprocessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (Process32First(hprocessSnap, & amp;pe32))
    {<!-- -->
        do {<!-- -->
            if (!wcscmp(szName, pe32.szExeFile))
                return (int)pe32.th32ProcessID;
        } while (Process32Next(hprocessSnap, & amp;pe32));
    }
    else
        CloseHandle(hprocessSnap);
    return 0;
}

int main()
{<!-- -->
    wchar_t wStr[] = L"C:\Users\zhang\source\\repos\\crackme_dll\x64\\Release\\crackme_dll .dll";
    WCHAR S[] = L"crackme.exe";
    DWORD SS = GetPid(S);
    printf("The process PID of the target window is: %d\\
", SS);
    Inject(SS, wStr);
    return 0;
}
  1. After generating the solution, you can get the remotely injected exe file. The exe file is generally in “Project Path/x64/Debug/”.

4. Inject dll remotely and use Process Hack 2 to observe the injection results

  1. The administrator runs crackme.exe, and the administrator runs Process Hacker 2, searches for crackme, and looks at Modules. You can see that there is no dll we injected.
  2. The administrator runs the exe program in the third step and opens Process Hacker 2 again. You can see that crackme_dll.dll has been injected successfully.
  3. You can see that the Hooked_VtableFunc function in the second step of the code is successfully executed.

    If it helped you, please give it a like. If you don’t need it for the time being, you might as well save it below, it may be useful in the future. If there are any errors in the tutorial, please leave a message or private message to correct them, and try to correct them as soon as possible.