When a process launches a child process, it becomes the parent of the child process. That is the default behaviour. In Vista however, a process can launch a process as a child of yet another process. This facility is used by User Account Control (UAC) when elevated processes are launched by AppInfo service to look like being launched from non-elevated process that would have been the parent, had there been no elevation.
The win32 call CreateProcess launches processes, and in Vista onwards one can pass a new flag in dwCreationFlags parameter called EXTENDED_STARTUPINFO_PRESENT that enables the caller to pass a STARTUPINFOEX structure pointer (instead of STARTUPINFO structure) in the lpStartupInfo parameter.1
The STARTUPINFOEX structure is declared in winbase.h like thus
Note the new member lpAttributeList, a pointer to _PROC_THREAD_ATTRIBUTE_LIST structure. That structure is where the parent process handle gets passed to CreateProcess.2
First lpAttributeList must point to an allocation of sufficient size so we can store some attributes in there. We are interested in setting just one attribute which is the parent process attribute
InitializeProcThreadAttributeList initializes lpAttributeList and is the first call that needs to be made on the _PROC_THREAD_ATTRIBUTE_LIST structure. InitializeProcThreadAttributeList also indicates space needed for the attributes that need to go in there. Here is how the initialization code may look like
Now that lpAttributeList is allocated and initialized for one attribute, UpdateProcThreadAttribute can be called to put in the PROC_THREAD_ATTRIBUTE_PARENT_PROCESS attribute, with the attribute value set to a handle to the parent process. The code would look something like this -
The launched process will appear to be child of the process passed rather than the process from which it was launched.
I am not sure how this can be put to good use in software3 but I hope next time you look at parent child relationships in Process Explorer (or call PsGetProcessInheritedFromUniqueProcessId to get the parent process id in a driver) you do not believe everything you see.
1To keep the compiler happy STARTUPINFOEX pointer would need to be type cast to LPSTARTUPINFO
2What is tricky is that the STARTUPINFOEX.StartupInfo.cb must be set to sizeof(STARTUPINFOEX) not sizeof(STARTUPINFO) even though StartupInfo is of type STARTUPINFO. It is as if StartupInfo member was an unnamed member of STARTUPINFOEX.
3The only one thing I can think of is a malware writer trying to cover tracks to make things difficult for threat analyst to figure out the anatomy of a threat.