【问题标题】:Getting a list of DLLs currently loaded in a process C#获取当前在进程 C# 中加载的 DLL 列表
【发布时间】:2016-07-25 16:20:30
【问题描述】:

在进程资源管理器中,我可以查看所选进程加载的所有 dll(和 dll 详细信息)。如何以编程方式做到这一点?

我可以像这样得到一个特定的过程细节。但不确定从这里去哪里?

Process[] processlist = Process.GetProcesses();

foreach(Process theprocess in processlist){
Console.WriteLine(“Process: {0} ID: {1}”, theprocess.ProcessName, theprocess.Id);
}

【问题讨论】:

    标签: c# dll


    【解决方案1】:

    存在Process.Modules 属性,您可以枚举进程加载的所有模块(exe 和.dll)。

    foreach (var module in proc.Modules)
    {
       Console.WriteLine(string.Format("Module: {0}", module.FileName));
    }
    

    根据ProcessModule 类,它为您提供特定模块的属性。

    【讨论】:

    • 我无法将module 扣除为ProcessModule 对象,因此我需要指定它而不是使用var
    【解决方案2】:

    这取决于你想要什么。

    获取加载到特定应用程序域的 .NET 程序集列表很容易 (AppDomain.GetAssemblies)。

    但是在进程中列出应用程序域并不容易,但可以是done

    但是,如果您想要一个 dll 列表(本机和 .NET)作为 Tony the Lion 的答案,则只需 Process.Modules

    【讨论】:

      【解决方案3】:

      Process.Modules 解决方案在运行 64 位程序并尝试从 32 位进程收集所有模块时是不够的。默认情况下,64位程序只能在64位进程上运行,32位程序只能在32位进程上运行。

      有关适用于“AnyCPU”、“x86”和“x64”的解决方案,请参见下文。只需使用目标进程调用CollectModules 函数。注意:32 位程序无法从 64 位进程中收集模块。

      public List<Module> CollectModules(Process process)
      {
              List<Module> collectedModules = new List<Module>();
      
              IntPtr[] modulePointers = new IntPtr[0];
              int bytesNeeded = 0;
      
              // Determine number of modules
              if (!Native.EnumProcessModulesEx(process.Handle, modulePointers, 0, out bytesNeeded, (uint)Native.ModuleFilter.ListModulesAll))
              {
                  return collectedModules;
              }
      
              int totalNumberofModules = bytesNeeded / IntPtr.Size;
              modulePointers = new IntPtr[totalNumberofModules];
      
              // Collect modules from the process
              if (Native.EnumProcessModulesEx(process.Handle, modulePointers, bytesNeeded, out bytesNeeded, (uint)Native.ModuleFilter.ListModulesAll))
              {
                  for (int index = 0; index < totalNumberofModules; index++)
                  {
                      StringBuilder moduleFilePath = new StringBuilder(1024);
                      Native.GetModuleFileNameEx(process.Handle, modulePointers[index], moduleFilePath, (uint)(moduleFilePath.Capacity));
      
                      string moduleName = Path.GetFileName(moduleFilePath.ToString());
                      Native.ModuleInformation moduleInformation = new Native.ModuleInformation();
                      Native.GetModuleInformation(process.Handle, modulePointers[index], out moduleInformation, (uint)(IntPtr.Size * (modulePointers.Length)));
      
                      // Convert to a normalized module and add it to our list
                      Module module = new Module(moduleName, moduleInformation.lpBaseOfDll, moduleInformation.SizeOfImage);
                      collectedModules.Add(module);
                  }
              }
      
              return collectedModules;
          }
      }
      
      public class Native
      {
          [StructLayout(LayoutKind.Sequential)]
          public struct ModuleInformation
          {
              public IntPtr lpBaseOfDll;
              public uint SizeOfImage;
              public IntPtr EntryPoint;
          }
      
          internal enum ModuleFilter
          {
              ListModulesDefault = 0x0,
              ListModules32Bit = 0x01,
              ListModules64Bit = 0x02,
              ListModulesAll = 0x03,
          }
      
          [DllImport("psapi.dll")]
          public static extern bool EnumProcessModulesEx(IntPtr hProcess, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)] [In][Out] IntPtr[] lphModule, int cb, [MarshalAs(UnmanagedType.U4)] out int lpcbNeeded, uint dwFilterFlag);
      
          [DllImport("psapi.dll")]
          public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, [In] [MarshalAs(UnmanagedType.U4)] uint nSize);
      
          [DllImport("psapi.dll", SetLastError = true)]
          public static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, out ModuleInformation lpmodinfo, uint cb);
      }
      
      public class Module
      {
          public Module(string moduleName, IntPtr baseAddress, uint size)
          {
              this.ModuleName = moduleName;
              this.BaseAddress = baseAddress;
              this.Size = size;
          }
      
          public string ModuleName { get; set; }
          public IntPtr BaseAddress { get; set; }
          public uint Size { get; set; }
      }
      

      【讨论】:

      • 这个答案只是部分正确。您的代码仅列出已由 LoadLibrary() 加载的本机 DLL。但是像 System.Windows.Forms.dll 这样的 .NET 框架 DLL 没有在 Framework 4.7 中列出,因为框架不使用 LoadLibrary() 来加载它们。见blogs.microsoft.co.il/sasha/2011/01/16/…
      • 有解决方案吗?有哪些方法可以查找在 LoadLibrary 之外加载的 DLL
      • 我认为没有解决方案,因为您可以调用 Assembly.Load(Byte[]) 将程序集从 Byte[] 数组加载到进程中。这意味着 .NET 应用程序甚至可以将程序集从 Internet 直接加载到进程中,并且您永远不会在 DLL 列表中看到该程序集。
      • 嗯。我想如果绝对需要找到以这种方式加载的 DLL,可以在内存中搜索 PE 标头,或者可能是设置了 Execute 标志的页面(尽管这本身并不是很好)
      • 但是即使你在内存中找到PE头文件你仍然不知道哪个是原始文件路径。您必须挂钩 CreateFile() API。但这太复杂了。
      【解决方案4】:

      在 CLR v4 之后,接受的答案将仅显示非托管程序集。 如果要获取外部进程的托管程序集,可以参考: Microsoft.Diagnostics.Runtime

      使用以下代码,您可以迭代外部进程的应用程序域并获取加载的程序集:

      using var dt = DataTarget.AttachToProcess(clientProcess.Id, false);
      assemblies = dt
            .ClrVersions
            .Select(dtClrVersion => dtClrVersion.CreateRuntime())
            .SelectMany(runtime => runtime.AppDomains.SelectMany(runtimeAppDomain => runtimeAppDomain.Modules))
            .Select(clrModule => clrModule.AssemblyName)
            .Distinct()
            .ToList();
      

      请参阅他们的github 了解更多详情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-11-12
        • 1970-01-01
        • 2013-06-24
        • 2010-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多