windows - Hvordan fungerer funktionen hooking faktisk? WinAPI, C ++

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg injicerer min DLL i en proces og hakker derefter en funktion som denne: (recv)


BOOL HookFunction(LPCWSTR moduleName, LPCSTR funcName, LPVOID funcProxy, 
unsigned char* lpBackup)
{
     BYTE jmp[6] = { 0xe9,0x00,0x00,0x00,0x00,0xc3 };
     DWORD funcAddr = (DWORD)GetProcAddress(GetModuleHandle(moduleName), funcName);

     DWORD prev;
     VirtualProtect((LPVOID)funcAddr, 6, PAGE\_EXECUTE\_READWRITE, &prev);

     ReadProcessMemory(GetCurrentProcess(), (LPVOID)funcAddr, lpBackup, 6, NULL);

     DWORD proxy = ((DWORD)funcProxy - funcAddr) - 5;
     memcpy(&jmp[1], &proxy, 4);
     memcpy((LPVOID)funcAddr, jmp, 6);

     VirtualProtect((LPVOID)funcAddr, 6, prev, &prev);
     FlushInstructionCache(GetCurrentProcess(), NULL, NULL);

     return funcAddr;
}

// Hook
HookFunction(L"ws2\_32.dll", "recv", (LPVOID*)nRecv, hookR);


Jeg vedhæfter en debugger da og her er resultatet:


Før tilslutning:
Indtast billedbeskrivelse her [9]


Efter tilslutning:
Indtast billedbeskrivelse her [10]


Der er et par ting, jeg ikke forstår, da jeg stadig forsøger at forstå og visualisere, hvordan fungerer stacken, bunken osv. Sammen i en debugger.


BYTE jmp[6] = { 0xe9,0x00,0x00,0x00,0x00,0xc3 };


Skifter jeg instruktioner her, for eksempel 'move, edi, edi' (recv) af den oprindelige funktion med 0xe9? Og så den næste instruktion med 0x00 ... eller hvordan virker det præcist?


Enhver detaljeret forklaring ville blive værdsat.

Bedste reference


BOOL HookFunction(LPCWSTR moduleName, LPCSTR funcName, LPVOID funcProxy, 
unsigned char* lpBackup)
{
     BYTE jmp[6] = 
     { 
        0xe9,0x00,0x00,0x00,0x00, /*JMP and 4 bytes of offset*/
        0xc3                      /*RET*/
     };

     /*
       JMP (e9) is relative, its 32-bit signed immediate operand encodes the 
       number of bytes to jump forward relative to the NEXT instruction.
     */

     /* Get the target address of the function to hook */
     DWORD funcAddr = (DWORD)GetProcAddress(GetModuleHandle(moduleName), funcName);

     /* Code is not necessarily mapped as writable, we remap it */
     DWORD prev;
     VirtualProtect((LPVOID)funcAddr, 6, PAGE\_EXECUTE\_READWRITE, &prev);

     /* Read the original 6 bytes we are going to overwrite */
     ReadProcessMemory(GetCurrentProcess(), (LPVOID)funcAddr, lpBackup, 6, NULL);

     /* 
        Compute the offset: target - source 
        target = funcProxy
        source = funcAddr + 5 (length of JMP)

        target - source = funcProxy - funcAddr - 5
     */
     DWORD proxy = ((DWORD)funcProxy - funcAddr) - 5;

     /*
        Create the JMP instruction: set the offset
     */
     memcpy(&jmp[1], &proxy, 4);

     /* Overwrite the first 6 bytes of the target function */
     memcpy((LPVOID)funcAddr, jmp, 6);

     /* Reset the memory protection to its original value*/
     VirtualProtect((LPVOID)funcAddr, 6, prev, &prev);

     /* Since we write to a code section with DS, flush the L1 I cache */
     FlushInstructionCache(GetCurrentProcess(), NULL, NULL);

     return funcAddr;
}


HookFunction opretter et lille stykke x86-kode i hukommelsen (en trampolin) af formularen [11]


jmp <0>     ;e9 00 00 00 00
ret         ;c3


hvor <0> overskrives successivt med det kodede mål (se kommentarer i koden) af jump-krogen funktionen.

Trampolinen bliver, når den er udformet


jmp funcProxy     ;e9 .. .. .. ..
ret               ;c3


Denne kode skrives derefter direkte i begyndelsen af ​​den hooked funktion, hvorved den oprindelige kode overskrives.


Koden er polyglot - den virker både for x86 og x86-64.





Den oprindelige kode for den hooked funktion kopieres til lpBackup.

Dette er nødvendigt for at ringe til den oprindelige funktion igen, krogfunktionen kan ikke kalde den uden først at genoprette den.


Da dette er dyrt og ikke genindtræder, er en renere tilgang til at ændre importadressen tabel - effektiviteten af ​​denne løsning afhænger dog af dine krav. [12]