API copying is an old yet effective technique which renders user-mode hooks useless, this is because most user-mode hooks rely on physically hooking the API through either a detour (inline on API or IAT) so by copying the API you render the hook useless. So here's quite an easy example of API copying & also a small trampoline:
Code: |
.386 .model flat, stdcall option casemap : none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib .data strUser32 db "user32.dll", 0 strSendInput db "SendInput", 0 strMouse_Event db "mouse_event", 0 strKeybd_Event db "keybd_event", 0 lpflOldProtect dd 0 .code xSendInput proc ;; SendInput copy, this will have enough room for the copy. (you could allocate & copy more if it changes) dd 090909090h dd 090909090h dd 090909090h db 090h, 090h, 090h ;db 15d dup(?) ; I could have done this but it doesn't look nice when debugging :< db 090h ; Gap for debugger cleanliness :P xSendInput endp CalcJump proc Source:DWORD, Destination:DWORD ;; Jump calculation function. dest - source - 5 = offset mov ecx, dword ptr ds:[Destination] sub ecx, dword ptr ds:[Source] sub ecx, 5 pop ebp retn 8 db 090h ; Gap for debugger cleanliness :P CalcJump endp WinMain proc invoke LoadLibrary, addr strUser32 ; Load user32.dll push eax ; Save the handle invoke GetProcAddress, eax, addr strSendInput ; Get the address for user32.SendInput mov ecx, 15d ; Move 15d into ECX (15 bytes to copy) for the rep prefix mov esi, eax ; Specify source as EAX (user32.SendInput) mov edi, offset xSendInput ; Specify destination as our empty SendInput buffer rep movsb ; Copy 15 bytes from SendInput to empty xSendInput function mov eax, dword ptr ds:[esp] ; Get the kernel32 handle from stack (saved earlier) invoke GetProcAddress, eax, addr strMouse_Event ; Get user32.mouse_event's address add eax, 36h ; Offset of SendInput call push eax ; Store mouse_event address inc eax ; Go to call offset location invoke VirtualProtect, eax, 4, PAGE_EXECUTE_READWRITE, addr lpflOldProtect ; Allow us to write to it. pop eax ; Restore mouse_event address invoke CalcJump, eax, addr xSendInput ; Calculate jump offset inc eax ; Point to offset address mov dword ptr ds:[eax], ecx ; Move xSendInput offset to replace user32.SendInput's offset mov eax, dword ptr ds:[esp] ; Get the kernel32 handle from stack (saved earlier) invoke GetProcAddress, eax, addr strKeybd_Event ; Get user32.keybd_event's address add eax, 37h ; Offset of SendInput call push eax ; Store keybd_event address inc eax ; Go to call offset location invoke VirtualProtect, eax, 4, PAGE_EXECUTE_READWRITE, addr lpflOldProtect ; Allow us to write to it. pop eax ; Restore mouse_event address invoke CalcJump, eax, addr xSendInput ; Calculate call offset inc eax ; Point to offset address mov dword ptr ds:[eax], ecx ; Move xSendInput offset to replace user32.SendInput's offset ;; ;; ;; YOUR OWN CODE HERE. ;; ;; invoke Sleep, INFINITE WinMain endp end WinMain |
Now let's get onto trampolines, they're effectively jumping over the hook, so I won't get too in-detail about this but let's just say npggnt.des has a 5 byte inline hook on user32.PostMessage, we can either call our own function which calls the first 5 bytes that npggnt.des overwrites with it's hook then we can jump over npggnt.des' hook. So putting it simply...
Code: |
TrampolinePostMessage proc mov edi, edi ;; push ebp ;; user32.PostMessage's first 5 bytes mov ebp, esp ;; jmp user32.PostMessage+5 ; Jump past the detour hook set by npggnt.des TrampolinepostMessage endp |
In most APIs (excluding services that directly hit the service dispatcher) the first 5 bytes will be as shown:
Code: |
mov edi, edi ; Windows hotfix leeway push ebp ; Save EBP (since it's used for parameters & local variables) mov ebp, esp ; Prepare EBP for variable usage. |
So we can just use those bytes then jump to GetProcAddress(handle, "whatever"); + 5.
Anyway, I'm lazy so I'll just abruptly end here.
P.S. The memory which you copy the API to must be writable.
Just another side-note: You could also just hook the IAT to point to your copied functions so you could integrate it with ACTools, etc.
0 comentarios:
Publicar un comentario