Parent Process ID Spoofing
In this blog post, we're going to learn how to create a process under a legitimate one.
Normally, we don't expect that some processes run as a parent process. As an example, when you open the notepad.exe, it's going to be a child of explorer.exe. If we encounter notepad.exe as a parent process, we may assume that something is happening. But I'm not saying that it is a malicious application.
Steps to Spoof Parent Process ID
Take a snapshot of all running processes.
Find the ID of explorer.exe.
Open the process of explorer.exe with maximum privileges.
Allocate heap memory space in the current process with the size of thread attribute list.
Set parent process information of thread attribute list.
Create a notepad.exe process with thread attributes.
Step #1, 2 - Find The Process ID
I'm not going to talk about the details of a finding process. You can check out the Shellcode Injection blog post.
Step #3 - Open The Process
In order to open a process, we're going to use OpenProcess. The function takes 3 parameters.
[in] DWORD dwDesiredAccess
Level of access to the process.
[in] BOOL bInheritHandle
If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle.
[in] DWORD dwProcessId
The ID of the process.
#include <windows.h>
#include <TlHelp32.h>
// wchat_t* is used for UTF-16 character space.
int getProcessId(HANDLE snapshot, wchar_t* processName) {
PROCESSENTRY32 processEntry;
// The size of the structure, in bytes.
processEntry.dwSize = sizeof(PROCESSENTRY32);
BOOL success = Process32First(snapshot, &processEntry);
// Could not find a process.
if (!success)
return -2;
while (success) {
// wcscmp is used to compare UTF-16 strings.
if (wcscmp(processEntry.szExeFile, processName) == 0)
return processEntry.th32ProcessID;
success = Process32Next(snapshot, &processEntry);
}
return -1;
}
int main(int argc, char** argv) {
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
HANDLE parrentProcessHandle = OpenProcess(MAXIMUM_ALLOWED, FALSE, getProcessId(snapshot, TEXT("explorer.exe")));
CloseHandle(snapshot);
CloseHandle(parrentProcessHandle);
return 0;
}
Step #4 - Allocate Heap Memory Space
In order to allocate heap memory space, we need the size of attribute list.
InitializeProcThreadAttributeList takes 4 parameters.
[out, optional] lpAttributeList
The attribute list. This parameter can be NULL to determine the buffer size required to support the specified number of attributes.
[in] dwAttributeCount
The count of attributes to be added to the list.
[in] dwFlags
This parameter is reserved and must be zero.
[in, out] lpSize
If lpAttributeList is NULL, this parameter receives the required buffer size in bytes.
HeapAlloc take 3 parameters.
[in] hHeap
A handle to the heap from which the memory will be allocated. We're going to allocate heap memory space in the current process.
[in] dwFlags
The heap allocation options.
[in] dwBytes
The number of bytes to be allocated.
// -- snippet --
int main(int argc, char** argv) {
// -- snippet --
STARTUPINFOEXA si;
ZeroMemory(&si, sizeof(STARTUPINFOEXA));
SIZE_T attrSize = 0;
InitializeProcThreadAttributeList(NULL, 1, 0, &attrSize);
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attrSize);
InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attrSize);
CloseHandle(parrentProcessHandle);
return 0;
}
Step #5
To set the parent process of the attribute list, we need to update the list. In order to do that, we're going to use UpdateProcThreadAttribute. The function takes 7 parameters.
[in, out] lpAttributeList
A pointer to an attribute list.
[in] dwFlags
This parameter is reserved and must be zero.
[in] Attribute
The attribute key to update in the attribute list.
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
The lpValue parameter is a pointer to a handle to a process to use instead of the calling process as the parent for the process being created.
[in] lpValue
A pointer to the attribute value.
[in] cbSize
The size of the attribute value.
[out, optional] lpPreviousValue & [out, optional] lpReturnSize
These parameters are reserved and must be NULL.
// -- snippet --
int main(int argc, char** argv) {
// -- snippet --
UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parrentProcessHandle, sizeof(HANDLE), NULL, NULL);
CloseHandle(parrentProcessHandle);
return 0;
}
Step #6 - Create a Process
In order to create a process with the specified attribute list, we're going to use CreateProcessA. The function takes 10 parameters.
[in, optional] lpApplicationName
This can be full path of the application.
[in, out, optional] lpCommandLine
The command line to be executed.
[in, optional] lpProcessAttributes
A pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle to the new process object can be inherited by child processes. If lpProcessAttributes is NULL, the handle cannot be inherited.
[in, optional] lpThreadAttributes
A pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle to the new thread object can be inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited.
[in] bInheritHandles
If the parameter is FALSE, the handles are not inherited.
[in] dwCreationFlags
The flags that control the priority class and the creation of the process.
[in, optional] lpEnvironment
A pointer to the environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.
[in, optional] lpCurrentDirectory
If this parameter is NULL, the new process will have the same current drive and directory as the calling process.
[in] lpStartupInfo
A pointer to a STARTUPINFO or STARTUPINFOEX structure.
// -- snippet --
int main(int argc, char** argv) {
// -- snippet ---
PROCESS_INFORMATION pi;
CreateProcessA("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &si.StartupInfo, &pi);
CloseHandle(parrentProcessHandle);
return 0;
}
Links
Last updated
Was this helpful?