我需要获取我的appdomain中已加载程序集的内存地址。 将程序集加载到.Net应用程序后,它们将完全加载到主应用程序内存中。
如果我们在内存中搜索此字节模式:
byte[] pe_pattern = {
0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0xFF, 0xFF
};
我们找到它们在内存中放置的位置和地址。 但是由于性能,我需要在没有内存扫描的情况下执行此操作。
我尝试通过AppDomain.CurrentDomain.GetAssemblies()
获取已加载的程序集,并通过Garbage Collector将其地址作为对象获取,可以在这里找到其他一些方法:Memory address of an object in C#
但是我得到的地址不是正确的地址,我没有错误。
在c ++中,有一种方法可以通过loadlibrary获取已加载的dll,但在C#中我什么都找不到。
如何获取C#应用程序中已加载程序集的内存地址?
答案 0 :(得分:3)
我不确定您要查找的是(1)映射程序集文件的虚拟地址,还是(2)加载程序集后放置JITed代码的虚拟地址。
接下来,我将考虑主机进程加载一些程序集的简单情况。可以在here中找到该代码。让我们集中讨论 x64_Assembly.dll 加载时发生的情况。
如果我们要寻找的是上面定义的(1)(进程地址空间内映射文件的虚拟地址),则这意味着下面突出显示的行,如VMMap的输出所示。操作系统在其中加载包含程序集的文件。我不知道如何从自己的应用程序中以编程方式获得这一功能。
对于(2),这是找到程序集的JITed代码的虚拟地址,如果您使用调试器进入代码,则实际上可以看到相应的地址:
正如this thread所指出的那样,JITed程序集被放置在一个堆中,您可以通过再次使用VMMap轻松地进行验证。就我而言,可以通过VMMap看到调试器中显示的地址位于堆块内部:
那么您实际定位的是哪个地址?
最新更新:
您可以使用CLR MD来获取非常有趣的数据。看一下下面的简单代码(摘自Ben Watson的“编写高性能.NET代码”),它得到(1)和可能(2)。您可以在VMMap中看到已加载程序集的映像地址与module.ImageBase
的值匹配,因此您肯定会得到(1)。但是,对于(2),module.Address
的值与在我的原始答案中的调试器中看到的m_assembly
变量不同-因此其中一个正在显示其他内容。但是,如果您考虑一下,并非所有代码都会同时进行JIT处理-CLR会将JIT编译方法(如被调用)进行JIT编译。因此,我相信2个变量包含的虚拟地址指向表示程序集的某种通用结构。
由于您提到您确实有权检查内存内容,因此您可以很快地找出(2)感兴趣的2个变量中的哪个。
您如何在实践中做到这一点?我正在考虑构建CLR MD项目,该项目仅输出您要获取的信息(在一个简单文件中((1)和(2))),然后由您的主代码调用此EXE,以便它分析您的过程并它加载并写入数据的程序集。当CLR MD进程终止时,您的实际代码可以检索写在文件中的信息,并在它检索的那些虚拟地址上进行操作。在上面的示例中,PID只是简单地硬编码(我正在使用Process Explorer查看分配的PID),但是您可以将其作为参数传递给CLR MD项目。
您可以在Visual Studio中使用管理解决方案的NuGet软件包选项来安装CLR MD,并为您的特定项目进行配置,然后只需添加using Microsoft.Diagnostics.Runtime
。
需要牢记的两件事:
AttachFlag.Passive
方法中使用AttachToProcess
,否则原始代码将无限期地暂停。在拍完上面的屏幕截图并成功获得module.ImageBase
和module.Address
值之后,我也测试了此选项,并且初始代码继续运行良好。