Mike
Mike

Reputation: 11

Why does injecting code caves with thread injection crash my target win32 EXE?

I am currently trying to inject a code cave with thread injection to a remote win32 EXE running on my win7 (x64) system. To achieve this, I am using Microsoft VB6, through which I do the following:

For the sake of testing a successful code injection, I am trying to inject a shellcode that does nothing. I don't know much about shellcoding and asm, but I just started learning.

I've tried injecting different codes, like: - only NOPs (crashes but I'm assuming it's normal): \x90\x90\x90.. - only NULLs (same as above): \x00\x00\x00.. However what I don't understand is that NOPs followed by RETN crashes my target EXE aswell \x90\x90\x90\xCB. Every byte sequence I have tried injecting was followed by a NULL byte.

Why does my target process crash ? What byte sequence do I have to inject in order to perform a succesful injection that doesn't crash my target EXE (yet that doesn't do anything, just for the sake of testing the injection scheme) ?

What I want to end up doing is injecting a PUSH x, CALL targetfunction to a game. But if my dummy shellcode crashes my target process I'm assuming the latter byte sequence would too. Thanks for your time.

EDIT: The exception I get is 0xC0000005 [Access violation when writing]

VB6 Code: Just call the sub with the target Exe's pid as argument

Private Const PAGE_READWRITE As Long = &H4
Private Const PAGE_EXECUTE As Long = &H10

Private Const MEM_RELEASE As Long = &H8000
Private Const MEM_COMMIT As Long = &H1000
Private Const INFINITE As Long = &HFFFFFF

Public Const PROCESS_ALL_ACCESS As Long = &H1F0FFF

Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Public Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Declare Function CreateRemoteThread Lib "kernel32" (ByVal hProcess As Long, lpThreadAttributes As Long, ByVal dwStackSize As Long, lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long

'Function that performs the shellcode injection to a remote process. Takes the target's PID as argument
Public Sub injectCode(ByVal lngPid As Long)
    Dim RemThread As Long, LngModule As Long, LngProcess As Long
    Dim i As Long

    'The byte sequence we'll inject in the remote process (
    Dim shellcode(4) As Byte
    shellcode(0) = &H90 'NOP : just to pretend that it's actual code
    shellcode(1) = &H90 'NOP : same
    shellcode(2) = &HC2 'Near return to calling procedure and pop 4 bytes from stack.
    shellcode(3) = &H4
    shellcode(4) = 0    'NULL terminator

    'OpenProcess, to get a handle to the remote process
    LngProcess = OpenProcess(PROCESS_ALL_ACCESS, False, lngPid)
    'to allocate some space inside of process (with PAGE_EXECUTE protection and MEM_COMMIT as parameter.
    'lpAddress set to NULL so that the function determines where to allocate the region)
    LngModule = VirtualAllocEx(LngProcess, 0, UBound(shellcode), MEM_COMMIT, PAGE_EXECUTE)

    Debug.Print "VirtualAllocEx: " & Hex(LngModule) 'debug info

    'writing our shellcode to the target's memory
    For i = 0 To UBound(shellcode)
        Call WriteProcessMemory(LngProcess, LngModule + i, shellcode(i), 1, 0&)
    Next i
    'thread injection to execute my code cave
    RemThread = CreateRemoteThread(LngProcess, 0&, 0&, ByVal LngModule, 0&, 0&, ByVal 0&)

    Debug.Print "CreateRemoteThread: " & Hex(RemThread) 'debug info

    'wait for the thread to run
    Call WaitForSingleObject(RemThread, INFINITE)
    CloseHandle (RemThread)
    Call VirtualFreeEx(LngProcess, LngModule, UBound(shellcode), MEM_RELEASE)

    Debug.Print "DONE" 'debug info
End Sub

Something weird happens though. When I put a MsgBox (that pauses the execution) for debug purposes BEFORE calling CreateRemoteThread, the function returns a non-NULL handle (but the target EXE crashes). And if I don't put a Msgbox before calling CreateRemoteThread, a NULL handle is returned.

Upvotes: 1

Views: 1004

Answers (1)

Alex Guteniev
Alex Guteniev

Reputation: 13719

ThreadProc callback passed to CreateRemoteThread takes one LPVOID parameter and ThreadProc is __stdcall.

LPVOID parameter for ThreadProc is forwarded from CreateRemoteThread's LPVOID lpParameter.

On x86 it means that you need to put RET instruction such that frees four bytes from stack.

(Also ThreadProc returns DWORD, this means you should but return value to EAX before returning, but if you don't care about return value, you may skip it)

Additionally, CB is far return, you need to use near return.

Look for RETN imm opcode, looks like you need C2 04 00

Upvotes: 3

Related Questions