Windows 中使用 CreateProcess 创建进程时,默认情况下子进程继承了当前进程作为父进程。实际上,我们可以指定其他进程作为我们要创建子进程的父进程。
原理
CreateProcess 函数的第六个参数 dwCreationFlags 有一个可选值为 EXTENDED_STARTUPINFO_PRESENT,我们可以在创建进程时,利用此值将子进程属性分配到指定进程作为其父级,这样创建进程的父进程即为我们指定的进程。
流程
- 获取指定进程的PID
- 提升本进程调试特权
- 更新属性列表中的指定属性
- 用更新后的属性参数创建新进程
代码
#include <stdio.h>
#include <windows.h>
void EnableDebugPriv();
void main(int argc, const char *argv[])
{
/* 制定父进程PID */
DWORD dwPid = 620;
// 提升权限
EnableDebugPriv();
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
/* 创建启动信息结构体 */
STARTUPINFOEXA si;
/* 初始化结构体 */
ZeroMemory(&si, sizeof(si));
/* 设置结构体成员 */
si.StartupInfo.cb = sizeof(si);
SIZE_T lpsize = 0;
/* 用微软规定的特定的函数初始化结构体 */
InitializeProcThreadAttributeList(NULL, 1, 0, &lpsize);
/* 转换指针到正确类型 */
char * pszTemp = new char[lpsize];
LPPROC_THREAD_ATTRIBUTE_LIST AttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)pszTemp;
/* 真正为结构体初始化属性参数 */
InitializeProcThreadAttributeList(AttributeList, 1, 0, &lpsize);
/* 用已构造的属性结构体更新属性表 */
if (!UpdateProcThreadAttribute(AttributeList, 0,
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &handle, sizeof(HANDLE), NULL, NULL))
{
printf("UpdateProcThreadAttribute() error\n!");
return;
}
/* 移交指针,此时已更换了父进程的属性 */
si.lpAttributeList = AttributeList;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
/*
if(CreateProcessA(
"C:\\Windows\\system32\\cmd.exe",
NULL,
NULL,
NULL,
true,
EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE,
NULL,
NULL,
(LPSTARTUPINFOA)&si,
&pi
))
*/
if (CreateProcessAsUserA(
NULL,
NULL,
"C:\\Windows\\system32\\cmd.exe",
NULL,
NULL,
NULL,
EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE,
NULL,
NULL,
(LPSTARTUPINFOA)&si,
&pi))
{
printf("创建子进程成功!");
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
/* 收尾处理 */
DeleteProcThreadAttributeList(AttributeList);
delete pszTemp;
}
void EnableDebugPriv()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
return ;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
{
return ;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
{
return ;
}
}
说明
- 创建进程时使用 CreateProcess 或者 CreateProcessAsUser 都可以达到同样效果。
- 只能选择同级权限或下级权限进程作为父进程,比如 local user 权限的进程只能选择 local user 进程作为父进程,不能选择 Administrator。而 Administrator 权限的进程可以选择 local user 权限的进程作为父进程。
- Administrator 权限进程可以选择 SYSTEM 权限进程作为父进程。
源码下载
参考链接