You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

获取系统进程模块时遇访问拒绝问题求助

解决读取lsass.exe/csrss.exe模块时的访问拒绝问题

你遇到的这个问题很典型——lsass.exe和csrss.exe是Windows系统中受保护的核心进程,即使你以NT AUTHORITY\SYSTEM身份运行,默认权限也不足以读取它们的模块信息。而卡巴斯基的avp.exe能正常读取,是因为杀毒软件通常会被系统授予特殊权限(比如代码签名信任、额外的特权),或者使用了更底层的系统API绕过常规限制。

下面给你几个可行的解决方案:

1. 启用SeDebugPrivilege特权

Windows的SeDebugPrivilege特权允许进程调试和访问其他所有进程,包括受保护的系统进程。你需要在代码中手动启用这个特权,步骤如下:

首先,添加P/Invoke调用所需的Windows API:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

public static class PrivilegeHelper
{
    [StructLayout(LayoutKind.Sequential)]
    private struct LUID
    {
        public uint LowPart;
        public int HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct LUID_AND_ATTRIBUTES
    {
        public LUID Luid;
        public uint Attributes;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    private struct TOKEN_PRIVILEGES
    {
        public uint PrivilegeCount;
        public LUID_AND_ATTRIBUTES Privileges;
    }

    private const uint SE_PRIVILEGE_ENABLED = 0x00000002;
    private const string SE_DEBUG_NAME = "SeDebugPrivilege";

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, uint BufferLength, IntPtr PreviousState, IntPtr ReturnLength);

    public static bool EnableSeDebugPrivilege()
    {
        if (!OpenProcessToken(Process.GetCurrentProcess().Handle, 0x0020 /* TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY */, out var tokenHandle))
            return false;

        try
        {
            if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out var luid))
                return false;

            var privileges = new TOKEN_PRIVILEGES
            {
                PrivilegeCount = 1,
                Privileges = new LUID_AND_ATTRIBUTES
                {
                    Luid = luid,
                    Attributes = SE_PRIVILEGE_ENABLED
                }
            };

            return AdjustTokenPrivileges(tokenHandle, false, ref privileges, 0, IntPtr.Zero, IntPtr.Zero);
        }
        finally
        {
            if (tokenHandle != IntPtr.Zero)
                CloseHandle(tokenHandle);
        }
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);
}

然后在你的主代码中,先启用特权再尝试读取模块:

static void Main(string[] args)
{
    // 先启用SeDebugPrivilege
    if (!PrivilegeHelper.EnableSeDebugPrivilege())
    {
        Console.WriteLine("无法启用SeDebugPrivilege特权");
        Console.ReadKey();
        return;
    }

    try
    {
        int id = // 替换为lsass.exe或csrss.exe的进程ID
        ProcessModuleCollection pmc = Process.GetProcessById(id).Modules;
        foreach (ProcessModule pm in pmc)
        {
            Console.WriteLine(pm.FileName);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"错误: {ex.Message}");
    }
    Console.ReadKey();
}

2. 使用Native API直接枚举模块

如果.NET的Process.Modules仍然无法读取,你可以直接调用Windows Native API(比如EnumProcessModulesEx),确保打开进程时使用足够的权限:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

public static class ProcessModuleReader
{
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("psapi.dll", SetLastError = true)]
    private static extern bool EnumProcessModulesEx(IntPtr hProcess, IntPtr[] lphModule, uint cb, out uint lpcbNeeded, uint dwFilterFlag);

    [DllImport("psapi.dll", SetLastError = true)]
    private static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize);

    private const uint PROCESS_QUERY_INFORMATION = 0x0400;
    private const uint PROCESS_VM_READ = 0x0010;
    private const uint LIST_MODULES_ALL = 0x03;

    public static void ReadProcessModules(int processId)
    {
        var processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, processId);
        if (processHandle == IntPtr.Zero)
        {
            Console.WriteLine($"无法打开进程,错误码: {Marshal.GetLastWin32Error()}");
            return;
        }

        try
        {
            uint bufferSize = 1024;
            IntPtr[] modules = new IntPtr[bufferSize];
            if (!EnumProcessModulesEx(processHandle, modules, (uint)(IntPtr.Size * modules.Length), out uint bytesNeeded, LIST_MODULES_ALL))
            {
                Console.WriteLine($"枚举模块失败,错误码: {Marshal.GetLastWin32Error()}");
                return;
            }

            uint moduleCount = bytesNeeded / (uint)IntPtr.Size;
            StringBuilder sb = new StringBuilder(2048);
            for (int i = 0; i < moduleCount; i++)
            {
                if (GetModuleFileNameEx(processHandle, modules[i], sb, (uint)sb.Capacity) > 0)
                {
                    Console.WriteLine(sb.ToString());
                    sb.Clear();
                }
            }
        }
        finally
        {
            if (processHandle != IntPtr.Zero)
                CloseHandle(processHandle);
        }
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);
}

调用示例:

static void Main(string[] args)
{
    PrivilegeHelper.EnableSeDebugPrivilege(); // 先启用特权
    int lsassId = Process.GetProcessesByName("lsass")[0].Id;
    ProcessModuleReader.ReadProcessModules(lsassId);
    Console.ReadKey();
}

3. 注意进程位数匹配

如果你的程序是32位,在64位Windows系统上读取64位进程(比如lsass.exe、csrss.exe)的模块会失败。此时你需要:

  • 编译程序为x64平台(在Visual Studio的项目属性中设置)
  • 或者使用Wow64 API(比如Wow64EnableWow64FsRedirection)来处理跨位数访问,但这种方式复杂且容易出错,优先推荐位数匹配。

为什么avp.exe可以正常读取?

卡巴斯基的avp.exe作为系统级杀毒服务,通常具备以下优势:

  • 拥有微软的代码签名,被Windows信任为合法的系统组件
  • 被授予了额外的系统特权(比如SeSecurityPrivilege)
  • 使用了更底层的内核级API来访问进程信息,绕过了用户态的权限限制

注意事项

  • 启用SeDebugPrivilege需要程序以管理员身份运行,即使是SYSTEM身份也需要确保权限配置正确
  • Windows的安全功能(比如HVCI核心隔离、Defender应用控制)可能会阻止这种操作,需要在测试环境中临时关闭验证
  • 这种权限非常敏感,不要在生产环境中随意启用,避免安全风险

内容的提问来源于stack exchange,提问作者Oleg Lylok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:35:54