C# 找出一个进程是否是一个系统进程

C# 找出一个进程是否是一个系统进程,c#,process,C#,Process,我试图找出我的程序运行时用户正在运行的程序,并将它们输出到文件中。现在我面临的情况是,当使用Process.getprocesss()检索所有进程时,我会看到一个包含269个进程的列表,相当于Task Manager显示的所有进程,包括Windows进程,如77个svchost进程 现在我想过滤掉一些系统进程(至少是那些在任务管理器中显示为“Windows进程”的进程)。有什么方法可以做到这一点,或者我必须维护所有Windows进程的进程名(或文件目录)列表吗?一种方法是过滤掉路径以Window

我试图找出我的程序运行时用户正在运行的程序,并将它们输出到文件中。现在我面临的情况是,当使用
Process.getprocesss()
检索所有进程时,我会看到一个包含269个进程的列表,相当于Task Manager显示的所有进程,包括Windows进程,如77个svchost进程


现在我想过滤掉一些系统进程(至少是那些在任务管理器中显示为“Windows进程”的进程)。有什么方法可以做到这一点,或者我必须维护所有Windows进程的进程名(或文件目录)列表吗?

一种方法是过滤掉路径以Windows目录路径开头的所有进程

您可以通过调用 与此类似:

然后,您可以筛选出其映像位于该文件夹中某个位置的所有进程:

var processes = Process.GetProcesses();
foreach (var process in processes) {
  if (!process.MainModule.FileName.StartsWith(windowsPath)) {
    // Do something with process
  }
}

只需过滤结果:

Process.GetProcesses().Where(x => x.MainWindowHandle != IntPtr.Zero)

检查路径时,可能会被绕过

简短回答:

taskmanager中的解决方案是基于以下列表(取自Windows 10版本)硬编码的:



长答案:

我花了一些时间才找到那个清单——下面是通往启蒙的道路;-)



原始答案:

要回答您的问题,找出一个流程是否是一个系统流程并不像看上去那么容易。为了获得此信息,您必须获得进程的所有者,该进程在windows系统上通常与之关联

安全标识符(SID)是用于标识受信者的可变长度的唯一值。每个帐户都有一个由权威机构(如Windows域控制器)颁发并存储在安全数据库中的唯一SID。每次用户登录时,系统都会从数据库中检索该用户的SID,并将其放入该用户的访问令牌中。系统使用访问令牌中的SID在与Windows security的所有后续交互中标识用户。当SID被用作用户或组的唯一标识符时,就不能再使用它来标识另一个用户或组

你肯定会看到其中一个,它类似于S-1-5-18或S-1-5-21-2557247…-…-1001

有一个完整的列表,其中包括一组SID,你可能会把它们看作是系统过程相关的。 如果我的假设是正确的,那么您希望获得在本地系统帐户(即S-1-5-18)下运行的所有进程

别说了,我们来编码:

首先,我们(即您,我已经测试过;-)需要从advapi32.dll进行如下导入:

[DllImport("advapi32.dll", SetLastError = true)]
private static extern uint GetSecurityInfo(IntPtr handle,
                                           SE_OBJECT_TYPE objectType,
                                           SECURITY_INFORMATION securityInfo,
                                           out IntPtr sidOwner,
                                           out IntPtr sidGroup,
                                           out IntPtr dacl,
                                           out IntPtr sacl,
                                           out IntPtr securityDescriptor);
private enum SE_OBJECT_TYPE
{
    SE_UNKNOWN_OBJECT_TYPE,
    SE_FILE_OBJECT,
    SE_SERVICE,
    SE_PRINTER,
    SE_REGISTRY_KEY,
    SE_LMSHARE,
    SE_KERNEL_OBJECT,
    SE_WINDOW_OBJECT,
    SE_DS_OBJECT,
    SE_DS_OBJECT_ALL,
    SE_PROVIDER_DEFINED_OBJECT,
    SE_WMIGUID_OBJECT,
    SE_REGISTRY_WOW64_32KEY
}

private enum SECURITY_INFORMATION
{
    OWNER_SECURITY_INFORMATION = 1,
    GROUP_SECURITY_INFORMATION = 2,
    DACL_SECURITY_INFORMATION = 4,
    SACL_SECURITY_INFORMATION = 8,
}
SecurityIdentifier securityIdentifier = new SecurityIdentifier(ownerSid);

if (securityIdentifier.IsWellKnown(WellKnownSidType.LocalSystemSid))
{
    // The process is running unter the local system account.
}
bool criticalProcess = false;

if (!IsProcessCritical(process.Handle, ref criticalProcess))
{
    // Could not retrieve process information
}

if (criticalProcess)
{
    // This is a critical process, it should be listed
    // in the "Windows processes" section.
}
…需要两个枚举来定义和,如下所示:

[DllImport("advapi32.dll", SetLastError = true)]
private static extern uint GetSecurityInfo(IntPtr handle,
                                           SE_OBJECT_TYPE objectType,
                                           SECURITY_INFORMATION securityInfo,
                                           out IntPtr sidOwner,
                                           out IntPtr sidGroup,
                                           out IntPtr dacl,
                                           out IntPtr sacl,
                                           out IntPtr securityDescriptor);
private enum SE_OBJECT_TYPE
{
    SE_UNKNOWN_OBJECT_TYPE,
    SE_FILE_OBJECT,
    SE_SERVICE,
    SE_PRINTER,
    SE_REGISTRY_KEY,
    SE_LMSHARE,
    SE_KERNEL_OBJECT,
    SE_WINDOW_OBJECT,
    SE_DS_OBJECT,
    SE_DS_OBJECT_ALL,
    SE_PROVIDER_DEFINED_OBJECT,
    SE_WMIGUID_OBJECT,
    SE_REGISTRY_WOW64_32KEY
}

private enum SECURITY_INFORMATION
{
    OWNER_SECURITY_INFORMATION = 1,
    GROUP_SECURITY_INFORMATION = 2,
    DACL_SECURITY_INFORMATION = 4,
    SACL_SECURITY_INFORMATION = 8,
}
SecurityIdentifier securityIdentifier = new SecurityIdentifier(ownerSid);

if (securityIdentifier.IsWellKnown(WellKnownSidType.LocalSystemSid))
{
    // The process is running unter the local system account.
}
bool criticalProcess = false;

if (!IsProcessCritical(process.Handle, ref criticalProcess))
{
    // Could not retrieve process information
}

if (criticalProcess)
{
    // This is a critical process, it should be listed
    // in the "Windows processes" section.
}
现在我们就快到了。如果您以以下方式调用
GetSecurityInfo

uint returnValue = GetSecurityInfo(process.Handle,
                                   SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
                                   SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION,
                                   out IntPtr ownerSid,
                                   out IntPtr groupSid,
                                   out IntPtr dacl,
                                   out IntPtr sacl,
                                   out IntPtr securityDescriptor);
。。。并得到结果(即
0
),您可以使用该类的实例来检查检索到的SID是否为本地系统帐户,如下所示:

[DllImport("advapi32.dll", SetLastError = true)]
private static extern uint GetSecurityInfo(IntPtr handle,
                                           SE_OBJECT_TYPE objectType,
                                           SECURITY_INFORMATION securityInfo,
                                           out IntPtr sidOwner,
                                           out IntPtr sidGroup,
                                           out IntPtr dacl,
                                           out IntPtr sacl,
                                           out IntPtr securityDescriptor);
private enum SE_OBJECT_TYPE
{
    SE_UNKNOWN_OBJECT_TYPE,
    SE_FILE_OBJECT,
    SE_SERVICE,
    SE_PRINTER,
    SE_REGISTRY_KEY,
    SE_LMSHARE,
    SE_KERNEL_OBJECT,
    SE_WINDOW_OBJECT,
    SE_DS_OBJECT,
    SE_DS_OBJECT_ALL,
    SE_PROVIDER_DEFINED_OBJECT,
    SE_WMIGUID_OBJECT,
    SE_REGISTRY_WOW64_32KEY
}

private enum SECURITY_INFORMATION
{
    OWNER_SECURITY_INFORMATION = 1,
    GROUP_SECURITY_INFORMATION = 2,
    DACL_SECURITY_INFORMATION = 4,
    SACL_SECURITY_INFORMATION = 8,
}
SecurityIdentifier securityIdentifier = new SecurityIdentifier(ownerSid);

if (securityIdentifier.IsWellKnown(WellKnownSidType.LocalSystemSid))
{
    // The process is running unter the local system account.
}
bool criticalProcess = false;

if (!IsProcessCritical(process.Handle, ref criticalProcess))
{
    // Could not retrieve process information
}

if (criticalProcess)
{
    // This is a critical process, it should be listed
    // in the "Windows processes" section.
}
就这样。 要获得最终结果,您必须检查多个SID,如系统、本地服务、网络服务等

下面是一个小示例,它对本地计算机上的所有进程都执行此操作。 当然,您需要以正确的权限运行此程序,否则将出现拒绝访问错误

private static void Main(string[] args)
{
    const uint ERROR_SUCCESS = 0;
    Process[] processes = Process.GetProcesses();

    foreach (Process process in processes)
    {
        try
        {
            uint returnValue = GetSecurityInfo(process.Handle,
                                               SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
                                               SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION,
                                               out IntPtr ownerSid,
                                               out IntPtr groupSid,
                                               out IntPtr dacl,
                                               out IntPtr sacl,
                                               out IntPtr securityDescriptor);

            if (returnValue != ERROR_SUCCESS)
            {
                // If the function succeeds, the return value is ERROR_SUCCESS.
                // If the function fails, the return value is a nonzero error code defined in WinError.h.
                continue;
            }

            SecurityIdentifier securityIdentifier = new SecurityIdentifier(ownerSid);
            Console.WriteLine("Owner of process {0} is {1}", process.ProcessName, securityIdentifier);

            if (securityIdentifier.IsWellKnown(WellKnownSidType.LocalSystemSid))
            {
                Console.WriteLine("Running under System Account");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Unable to retrieve owner for process {0}: {1}", process.ProcessName, e.Message);
        }
    }




更新:

如果将结果(原始答案)与任务管理器中的流程列表进行比较,仍然存在差异。当我进一步研究这个问题时,我突然意识到,标记为关键的进程将显示在windows进程下

如果流程有一个可见窗口,则任务管理器将其称为“应用程序”

如果进程被标记为关键进程,则任务管理器将其称为“Windows进程”。

否则,任务管理器称之为“后台进程”

这可以通过简单地调用来评估。因此,需要一个
DllImport

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool IsProcessCritical(IntPtr hProcess, ref bool Critical);
…之后可以这样称呼:

[DllImport("advapi32.dll", SetLastError = true)]
private static extern uint GetSecurityInfo(IntPtr handle,
                                           SE_OBJECT_TYPE objectType,
                                           SECURITY_INFORMATION securityInfo,
                                           out IntPtr sidOwner,
                                           out IntPtr sidGroup,
                                           out IntPtr dacl,
                                           out IntPtr sacl,
                                           out IntPtr securityDescriptor);
private enum SE_OBJECT_TYPE
{
    SE_UNKNOWN_OBJECT_TYPE,
    SE_FILE_OBJECT,
    SE_SERVICE,
    SE_PRINTER,
    SE_REGISTRY_KEY,
    SE_LMSHARE,
    SE_KERNEL_OBJECT,
    SE_WINDOW_OBJECT,
    SE_DS_OBJECT,
    SE_DS_OBJECT_ALL,
    SE_PROVIDER_DEFINED_OBJECT,
    SE_WMIGUID_OBJECT,
    SE_REGISTRY_WOW64_32KEY
}

private enum SECURITY_INFORMATION
{
    OWNER_SECURITY_INFORMATION = 1,
    GROUP_SECURITY_INFORMATION = 2,
    DACL_SECURITY_INFORMATION = 4,
    SACL_SECURITY_INFORMATION = 8,
}
SecurityIdentifier securityIdentifier = new SecurityIdentifier(ownerSid);

if (securityIdentifier.IsWellKnown(WellKnownSidType.LocalSystemSid))
{
    // The process is running unter the local system account.
}
bool criticalProcess = false;

if (!IsProcessCritical(process.Handle, ref criticalProcess))
{
    // Could not retrieve process information
}

if (criticalProcess)
{
    // This is a critical process, it should be listed
    // in the "Windows processes" section.
}
虽然这听起来很有希望,但事实并非如此——它仍然会导致错误的结果。


因此,在安装(顺便说一句,这是一个令人难以置信的软件)并过滤和搜索了500多万个(已经预过滤的)api调用之后,我注意到Taskmgr.exe多次使用参数调用,这些参数在调用之前似乎没有被检索到


在进一步调查(和逻辑结论)后,我注意到Taskmgr.exe中嵌入了一个硬编码列表。只需使用以下命令即可找到:

  • 正在启动process explorer
  • 右键单击Taskmgr.exe
  • 导航到“字符串”选项卡
  • 向下滚动
  • 失望
  • 有以下条目:

    %windir%\explorer.exe
    %windir%\system32\ntoskrnl.exe
    %windir%\system32\WerFault.exe
    %windir%\system32\backgroundTaskHost.exe
    %windir%\system32\backgroundTransferHost.exe
    %windir%\system32\winlogon.exe
    %windir%\system32\wininit.exe
    %windir%\system32\csrss.exe
    %windir%\system32\lsass.exe
    %windir%\system32\smss.exe
    %windir%\system32\services.exe
    %windir%\system32\taskeng.exe
    %windir%\system32\taskhost.exe
    %windir%\system32\dwm.exe
    %windir%\system32\conhost.exe
    %windir%\system32\svchost.exe
    %windir%\system32\sihost.exe
    


    因此,我的结论是:
    taskmanager中的解决方案是基于上述列表(取自Windows 10版本)硬编码的。

    我确实考虑过这一点,可能最终会使用它,但有人不能将他们的东西放在Windows文件夹中并绕过它?(而且我从来没有想到过
    Environment.SpecialFolder.Windows
    ,所以非常感谢您让我的生活变得如此轻松)是的,以提升权限运行的进程(以管理员身份运行)可以修改和添加Windows目录中的文件。实际上,大多数司机都这样做。我目前没有时间写一个正确的答案,但是您也可以尝试读取可执行文件的代码签名证书。几乎所有Windows可执行文件都是使用Microsoft证书签名的。其他可执行文件不能伪造这样的证书。因为我没有更好的事情要做(如果是这样的话,事实是,我无法阻止investiga)