PssCreateSnapshot - 访问被拒绝的奇怪情况

时间:2017-05-19 10:40:12

标签: c# c++ powershell winapi pinvoke

我创建了一些使用PssCaptureSnapshot执行进程克隆的代码,然后执行克隆的小型转储。

但是,在某些进程中,我在运行PssCaptureSnapshot时运行被拒绝(以提升方式运行)。这根本不是问题,实际上我无法执行克隆的过程也无法使用ProcDump(来自SysInternals的工具)进行克隆。

然而,奇怪的是,如果我打开PowerShell PSSession到localhost并从那里运行我的应用程序......创建克隆没有问题!

现在突然出现的是......特权。所以我检查了PSSession内部的权限,以及那些外面的... Bingo! PSSession实际上具有人类已知的所有权限,而在PSSession之外我只有少数权限。

没什么大不了的,我想......我只是开始分配自己的权限,一次一个,在两者之间调用PssCaptureSnapshot。当我停止拒绝访问时,我知道我需要哪种权限!

这个计划万无一失。那是......直到我没有分配的权限,我仍然被拒绝访问...

所以现在我真的抓着吸管:为什么它在PSSession内部工作但不在外部,当所有特权(理论上)相同时?如何进一步排除故障?

任何帮助都将不胜感激。

PS:如果您认为它有用,我会很乐意发布代码。但请记住,我得到一个访问被拒绝的事实,它在PSSession内部工作,但不在之外的事实,ProcDump也不能为这些进程创建克隆...我不认为代码是相关的。

修改

whoami / all

的结果

本地会议:

USER INFORMATION
----------------

User Name          SID
================== ===========================================
xxxxxxxxxxxxxxxxxx S-1-5-21-1509752874-53682476-648048294-1107


GROUP INFORMATION
-----------------
(listing only groups that appear in this session, but don't appear in the other)
NT AUTHORITY\REMOTE INTERACTIVE LOGON       Well-known group S-1-5-14                                       Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\INTERACTIVE                    Well-known group S-1-5-4                                        Mandatory group, Enabled by default, Enabled group
LOCAL                                       Well-known group S-1-2-0


PRIVILEGES INFORMATION
----------------------

Privilege Name                  Description                               State
=============================== ========================================= ========
SeIncreaseQuotaPrivilege        Adjust memory quotas for a process        Disabled
SeSecurityPrivilege             Manage auditing and security log          Disabled
SeTakeOwnershipPrivilege        Take ownership of files or other objects  Disabled
SeLoadDriverPrivilege           Load and unload device drivers            Disabled
SeSystemProfilePrivilege        Profile system performance                Disabled
SeSystemtimePrivilege           Change the system time                    Disabled
SeProfileSingleProcessPrivilege Profile single process                    Disabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority              Disabled
SeCreatePagefilePrivilege       Create a pagefile                         Disabled
SeBackupPrivilege               Back up files and directories             Disabled
SeRestorePrivilege              Restore files and directories             Disabled
SeShutdownPrivilege             Shut down the system                      Disabled
SeDebugPrivilege                Debug programs                            Enabled
SeSystemEnvironmentPrivilege    Modify firmware environment values        Disabled
SeChangeNotifyPrivilege         Bypass traverse checking                  Enabled
SeRemoteShutdownPrivilege       Force shutdown from a remote system       Disabled
SeUndockPrivilege               Remove computer from docking station      Disabled
SeManageVolumePrivilege         Perform volume maintenance tasks          Disabled
SeImpersonatePrivilege          Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege         Create global objects                     Enabled
SeIncreaseWorkingSetPrivilege   Increase a process working set            Disabled
SeTimeZonePrivilege             Change the time zone                      Disabled
SeCreateSymbolicLinkPrivilege   Create symbolic links                     Disabled

USER CLAIMS INFORMATION
-----------------------

User claims unknown.

Kerberos support for Dynamic Access Control on this device has been disabled.

在PSSession中:

USER INFORMATION
----------------

User Name          SID
================== ===========================================
xxxxxxxxxxxxxxxxxx S-1-5-21-1509752874-53682476-648048294-1107


GROUP INFORMATION
-----------------
(listing only groups that appear in this session, but don't appear in the other)
NT AUTHORITY\NETWORK                        Well-known group S-1-5-2



PRIVILEGES INFORMATION
----------------------

Privilege Name                  Description                               State
=============================== ========================================= =======
SeIncreaseQuotaPrivilege        Adjust memory quotas for a process        Enabled
SeSecurityPrivilege             Manage auditing and security log          Enabled
SeTakeOwnershipPrivilege        Take ownership of files or other objects  Enabled
SeLoadDriverPrivilege           Load and unload device drivers            Enabled
SeSystemProfilePrivilege        Profile system performance                Enabled
SeSystemtimePrivilege           Change the system time                    Enabled
SeProfileSingleProcessPrivilege Profile single process                    Enabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority              Enabled
SeCreatePagefilePrivilege       Create a pagefile                         Enabled
SeBackupPrivilege               Back up files and directories             Enabled
SeRestorePrivilege              Restore files and directories             Enabled
SeShutdownPrivilege             Shut down the system                      Enabled
SeDebugPrivilege                Debug programs                            Enabled
SeSystemEnvironmentPrivilege    Modify firmware environment values        Enabled
SeChangeNotifyPrivilege         Bypass traverse checking                  Enabled
SeRemoteShutdownPrivilege       Force shutdown from a remote system       Enabled
SeUndockPrivilege               Remove computer from docking station      Enabled
SeManageVolumePrivilege         Perform volume maintenance tasks          Enabled
SeImpersonatePrivilege          Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege         Create global objects                     Enabled
SeIncreaseWorkingSetPrivilege   Increase a process working set            Enabled
SeTimeZonePrivilege             Change the time zone                      Enabled
SeCreateSymbolicLinkPrivilege   Create symbolic links                     Enabled

USER CLAIMS INFORMATION
-----------------------

User claims unknown.

Kerberos support for Dynamic Access Control on this device has been disabled.

1 个答案:

答案 0 :(得分:3)

经过对cogumel0的长期研究后,我们找到了问题的确切根源。

首先,我们发现PssCaptureSnapshot只有在使用PSS_CAPTURE_VA_CLONE标志调用时才会失败 - 因此捕获过程中所有可复制页面的快照。

尽管我们有进程句柄以及对进程的所有必需访问权(比如PROCESS_ALL_ACCESS) - 对于某些进程PssCaptureSnapshot返回错误。为什么?

我注意到只有当某个作业中的进程正在运行时,错误。 (为了确定这一点,我们可以使用IsProcessInJob )和PssCaptureSnapshot在这种情况下可以返回2个不同的错误:

  • ERROR_NOT_ENOUGH_QUOTA - 我在win8.1和win10中查看它 - 它 返回说某些chrome.exe进程(并非所有进程)
  • ERROR_ACCESS_DENIED - 此错误仅在我们处理的过程中发生 想要快照 - 在另一个会话中运行(比较我们的流程)和这个 仅在win8.1中 - 在win10中没有此错误,即使进入 工作和另一场会议。

了解为什么会发生这种情况 - 需要了解PssCaptureSnapshot内部实现PSS_CAPTURE_VA_CLONE语义的方式。它通过fork目标进程(是的,在Windows下的fork)来实现。对于此任务,使用了未记录的ZwCreateProcessEx api。当 SectionHandle == 0 时(win32 CreateProcess总是在这里传递创建在exe文件上的部分(如果现在说完全为真CreateProcess使用另一个api,这是早期的))ZwCreateProcessEx克隆(fork)进程( ParentProcess )而不是基于 SectionHandle (基于某些exe文件)创建新的

但如果 ParentProcess 在作业中 - 子(我们的分叉)进程也将被放置在此作业中。这可能是问题。

第一份工作可以限制工作中的工艺数量。如果说工作有这个限制 - 工作中不超过1个进程 - ZwCreateProcessEx并且失败并显示错误STATUS_QUOTA_EXCEEDED - 结果PssCaptureSnapshot返回给我们ERROR_NOT_ENOUGH_QUOTA。这是chrome.exe案例 - 出于安全原因,某些chrome进程在作业中运行(在1个进程中有限制)(此进程也有 Untrusted Mandatory Level 但这与问题无关)

但即使在win8.1中作业对活动进程数没有限制(或者我们没有超过此限制) - 作业属于另一个会话 - 使用STATUS_ACCESS_DENIED进行调用失败。为什么这个 ?这个已经内部的实现细节,现在(在Windows 10中)它发生了变化 - 不再是这个错误 - 我们可以派生进程,即使它在作业和另一个会话中。一些提示为什么我们可以进入AssignProcessToJobObject页面:

  

作业中的所有进程必须在与...相同的会话中运行   工作

所以这里有一些与作业对象和交叉会话相关的窗口限制。

如果有趣的话,如何在Windows 8.1上重现/测试此错误?对于我看起来最简单的方法 - 在会话0中运行一些Windows服务 - 这个服务必须对系统不起作用(容易启动/停止它)并拥有自己的exe。为了我的外观" msdtc.exe"完美的受害者。所以打开它,首先尝试快照,而不是放在工作中,然后再尝试快照。并查看不同的内容:

NTSTATUS status;
BOOLEAN b;
if (0 <= (status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b)))
{
    // GetProcessIdByName custom function not shown here 
    if (ULONG dwProcessId = GetProcessIdByName(L"msdtc.exe"))
    {
        DbgPrint("found dwProcessId=%x\n", dwProcessId);

        if (HANDLE hProcess = OpenProcess(PROCESS_CREATE_PROCESS|PROCESS_QUERY_LIMITED_INFORMATION |
            PROCESS_SET_QUOTA|PROCESS_TERMINATE , FALSE, dwProcessId))
        {
            BOOL bInJob;

            if (IsProcessInJob(hProcess, 0, &bInJob))
            {
                if (!bInJob)
                {
                    HPSS SnapshotHandle;
                    ULONG err;
                    if (!(err = PssCaptureSnapshot(hProcess, PSS_CAPTURE_VA_CLONE, 0,&SnapshotHandle)))
                    {
                        PssFreeSnapshot(NtCurrentProcess(), SnapshotHandle);
                    }

                    DbgPrint("PssCaptureSnapshot=%u\n", err);

                    if (HANDLE hJob = CreateJobObject(0, 0))
                    {
                        bInJob = AssignProcessToJobObject(hJob, hProcess);
                        CloseHandle(hJob);

                        if (bInJob)
                        {
                            if (IsProcessInJob(hProcess, 0, &bInJob) && bInJob)
                            {
                                DbgPrint("process in job now!\n");

                                if (!(err = PssCaptureSnapshot(hProcess, PSS_CAPTURE_VA_CLONE, 0,&SnapshotHandle)))
                                {
                                    PssFreeSnapshot(NtCurrentProcess(), SnapshotHandle);
                                }

                                DbgPrint("PssCaptureSnapshot=%u\n", err);
                            }
                            else
                            {
                                DbgPrint("process not in job !?\n");
                            }
                        }
                        else
                        {
                            DbgPrint("AssignProcessToJobObject error=%u\n", GetLastError());
                        }
                    }
                    else
                    {
                        DbgPrint("CreateJobObject error=%u\n", GetLastError());
                    }
                }
                else
                {
                    DbgPrint("process already in job\n");
                }
            }
            else
            {
                DbgPrint("IsProcessInJob error=%u\n", GetLastError());
            }

            CloseHandle(hProcess);
        }
        else
        {
            DbgPrint("OpenProcess error=%u\n", GetLastError());
        }
    }
}
else
{
    DbgPrint("RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE)=%x\n", status);
}
在Windows 8.1中我得到了下一个dbgprint:

found dwProcessId=950
PssCaptureSnapshot=0
process in job now!
PssCaptureSnapshot=5

但在Windows 10中另一张图片:

found dwProcessId=4d0
PssCaptureSnapshot=0
process in job now!
PssCaptureSnapshot=0

这是windows bug还是功能 - 很难说