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中嵌入了一个硬编码列表。只需使用以下命令即可找到:
%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)