具有适当PEB和ACL的服务中的CreateProcessAsUser

时间:2014-04-14 16:53:36

标签: windows winapi

我已经在这个问题上阅读了大量的SO问题,但我没有找到一个真正明确的指导方针,以正确的方式做到这一点。

我的目标是枚举[断开连接和活动]用户控制台会话,并在每个会话中启动一个进程。每个用户会话进程在其DACL中至少需要这些权限:

Token access rights :

Process access rights :

但是你可以阅读here(在底部):"Windows Vista introduces protected processes to enhance support for Digital Rights Management. The system restricts access to protected processes and the threads of protected processes."
所以我想也许只有PROCESS_QUERY_LIMITED_INFORMATION我才能获得有关其他进程的一些信息。我尝试QueryFullProcessImageName()从Vista开始提升流程(请参阅Giori's answer),但doesn't work anymore as it seems。 使用Windows服务的重复令牌解决方案:CreateProcessAs_ LOCAL_SYSTEM
问题:生成的进程应该将相应的已登录用户的环境变量设置为能够定位网络打印机和映射驱动器等。但是如果我使用服务的令牌,我继承了它的PEB,我甚至无法将映射的驱动器转换为它们的UNC路径。

所以我开始寻找方法来提升"过程并绕过UAC提示,我试过了:

我跟随的步骤是:

  1. 使用WTSEnumerateSessions()
  2. 枚举会话
  3. 获取令牌(两个选项):
  4. 使用DuplicateTokenEx()
  5. 复制令牌
  6. LookUpPrivilegeValue() / AdjustTokenPrivileges()(没用?)
  7. CreateEnvironmentBlock()
  8. CreateProccessAsUser(),flags:NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,启动信息桌面:"WinSta0\Default"
  9. 更改流程DACL(参见上面的链接,没用?)
  10. Dispose / Clean:销毁PEB创建,关闭打开的句柄和释放内存。
  11. 我的问题:如何在LOCAL_SYSTEM帐户下运行的Windows服务授予使用CreateProccessAsUser()创建的进程足够的权限/权限以获取有关其他进程的信息(来自其他进程)会话;其他用户和不同的完整性级别),而不会丢失用户的环境变量?

2 个答案:

答案 0 :(得分:2)

你对很多事情感到困惑。

  

每个用户会话进程在其DACL中至少需要这些权限

进程DACL控制对该进程的访问,但它不确定该进程具有哪些访问权限。该进程的安全令牌确定访问权限。

  

Windows Vista引入了受保护的进程,以增强对数字版权管理的支持。

很明显,你还没有足够的担心受保护的进程。首先让它适用于普通流程!

  

生成的进程应该将各自登录用户的环境变量设置为能够定位网络打印机和映射驱动器等。

网络打印机和映射驱动器与环境变量无关。我认为你要做的是将新进程放入用户的登录会话中,这就是控制网络驱动器映射等的方法。

  

如何授予使用CreateProccessAsUser()[...]创建的进程足够的权限/权限来获取其他进程(来自其他会话;其他用户和不同的完整性级别)的信息,而不会丢失用户的环境变量?

别。这会违反安全模型的完整性。

相反,枚举和查询系统服务中的进程,并使用共享内存(在MSDN中查找“文件映射对象”)或其他合适的IPC机制,仅传递用户会话进程所需的任何信息。

答案 1 :(得分:1)

我知道这个问题已经被问过了。因为我碰巧做了同样的事情,所以下面是工作伪代码。

首先,如何在服务的用户会话中运行流程:

//IMPORTANT: All error checks are omitted for brevity!
//           Each of the lines of code below MUST be 
//           checked for possible errors!!!

//INFO: The following pseudo-code is intended to run 
//      from the Windows local service.

DWORD dwSessionID;  //Session ID to run your user process in

//Get token for the session ID
HANDLE hToken;
WTSQueryUserToken(dwSessionID, &hToken);

//Duplicate this token
HANDLE hToken2;
DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2);

PSID gpSidMIL_High = NULL;

if(you_want_to_change_integrity_level_for_user_process)
{
    if(!Windows_XP)
    {
        //For example, create "high" mandaroty integrity level SID
        ::ConvertStringSidToSid(L"S-1-16-12288", &gpSidMIL_High);

        TOKEN_MANDATORY_LABEL tml = {0};
        tml.Label.Attributes = SE_GROUP_INTEGRITY;
        tml.Label.Sid = gpSidMIL_High;

        SetTokenInformation(hToken2, TokenIntegrityLevel, &tml, 
            sizeof(TOKEN_MANDATORY_LABEL) + ::GetSidLengthRequired(1));
    }
}

//Copy environment strings
LPVOID pEnvBlock = NULL;
CreateEnvironmentBlock(&pEnvBlock, hToken2, FALSE);

//Initialize the STARTUPINFO structure.
// Specify that the process runs in the interactive desktop.
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = _T("winsta0\\default");

PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));

//Create non-const buffer
TCHAR pBuffCmdLine[MAX_PATH];
pBuffCmdLine[0] = 0;

//Copy process path & parameters to the non-constant buffer
StringCchCopy(pBuffCmdLine, MAX_PATH, L"\"C:\\Program Files (x86)\\Company\\Brand\\process.exe\" -parameter");

//Impersonate the user
ImpersonateLoggedOnUser(hToken2);

//Launch the process in the user session.
bResult = CreateProcessAsUser(
    hToken2,            // client's access token
    L"C:\\Program Files (x86)\\Company\\Brand\\process.exe",              // file to execute
    pBuffCmdLine[0] != 0 ? pBuffCmdLine : NULL,     // command line
    NULL,              // pointer to process SECURITY_ATTRIBUTES
    NULL,              // pointer to thread SECURITY_ATTRIBUTES
    FALSE,             // handles are not inheritable
    NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,   // creation flags
    pEnvBlock,         // pointer to new environment block 
    NULL,              // name of current directory 
    &si,               // pointer to STARTUPINFO structure
    &pi                // receives information about new process
);

//Get last error
nOSError = GetLastError();

//Revert to self
RevertToSelf();

//At this point you may want to wait for the user process to start, etc.
//using its handle in `pi.hProcess`
...

//Otherwise, close handles
if(pi.hProcess)
    CloseHandle(pi.hProcess);
if(pi.hThread)
    CloseHandle(pi.hThread);

//Clean-up
if(pEnvBlock)
    DestroyEnvironmentBlock(pEnvBlock);

CloseHandle(hToken2);
CloseHandle(hToken);

if(gpSidMIL_High)
    ::LocalFree(gpSidMIL_High);

如果您需要在已登录的交互式用户的所有会话中运行您的流程,您可以运行我上面给出的方法,以获取您可以从以下枚举中获得的会话:

//Enumerate all sessions
WTS_SESSION_INFO* pWSI = NULL;
DWORD nCntWSI = 0;
if(WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, NULL, 1, &pWSI, &nCntWSI))
{
    //Go through all sessions
    for(DWORD i = 0; i < nCntWSI; i++)
    {
        //To select logged in interactive user session,
        //try to get its name. If you get something, then
        //this session has a user logged in to...
        LPTSTR pUserName = NULL;
        DWORD dwcbSzUserName = 0;
        if(WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
            pWSI[i].SessionId, 
            WTSUserName, &pUserName, &dwcbSzUserName) &&
            pUserName &&
            dwcbSzUserName >= sizeof(TCHAR) &&
            pUserName[0] != 0)
        {
            //Use my method above to run your user process
            // in this session.
            DWORD dwSessionID = pWSI[i].SessionId;

        }

        //Free mem                          
        if(pUserName)
            WTSFreeMemory(pUserName);
    }

    //Free mem
    WTSFreeMemory(pWSI);
}