gpt4 book ai didi

c# - 我可以使用 Assembly.TryGetRawMetadata 和 System.Reflection.Metadata 访问方法主体(例如 IL 字节数组)吗?

转载 作者:行者123 更新时间:2023-11-30 23:02:45 25 4
gpt4 key购买 nike

.NET Core 2 的 FCL 包含一个扩展方法 Assembly.TryGetRawMetadata哪个可以使用 System.Reflection.Metadata 检查加载程序集的元数据.

我想使用这些工具来检查方法体(就像我使用常规反射的 MethodBody 一样),但这似乎不可能。

using System.Reflection;
using System.Reflection.Metadata;

class Program
{
unsafe static void Main()
{
var thisAssembly = Assembly.GetExecutingAssembly();
if (thisAssembly.TryGetRawMetadata(out byte* rawMetadata, out int rawMetadataLength) == false)
{
return;
}

var metadata = new MetadataReader(rawMetadata, rawMetadataLength);

foreach (var methodDefinitionHandle in metadata.MethodDefinitions)
{
var methodDefinition = metadata.GetMethodDefinition(methodDefinitionHandle);
var methodRVA = methodDefinition.RelativeVirtualAddress;
… // Question: Is there any way to get to the method body from `methodRVA`?
}
}
}

我可以获取方法的 RVA,但由于我无法找出 rawMetadata 指针对应的 RVA,因此我似乎无法取消对这些 RVA 的引用。

据我所知,Assembly.TryGetRawMetadata仅返回一个从元数据根 (BSJB) 开始并包括元数据流和堆的数据 blob,但方法体实际上存储在该数据之外。

当然,我可以从检查整个程序集文件开始(其路径在 thisAssembly.Location 中给出),但这需要再次将其重新加载到内存中。

是否Assembly.TryGetRawMetadata真的不允许我访问方法体,还是我忽略了什么?


最佳答案

我认为使用 TryGetRawMetadata 不可能完全按照您的意愿执行此操作。正如规范所述,“方法体可以存储在 PE 文件的任何只读部分”,因此仅靠元数据 blob 不足以解析 RVA。您必须像这样使用 PEReader:

static void Main() {
var thisAssembly = Assembly.GetExecutingAssembly();
using (var asmFile = File.OpenRead(thisAssembly.Location)) {
var reader = new PEReader(asmFile);
var metadata = reader.GetMetadataReader();

foreach (var methodDefinitionHandle in metadata.MethodDefinitions) {
var methodDefinition = metadata.GetMethodDefinition(methodDefinitionHandle);
var methodRVA = methodDefinition.RelativeVirtualAddress;
// now with PEReader you can resolve your RVA
var body = reader.GetMethodBody(methodRVA);
var ilReader = body.GetILReader();
// ...
}
}
}

要让它按照您的意愿工作 - 应该有一些类似于 TryGetRawMetadata 的东西,它返回整个 PE 图像的指针和长度。 PEReader 已经有接受这样的指针和长度的构造函数,据我所知,已经提出了这样的模拟方法(TryGetRawImage),但尚未实现。

也就是说,PEReader 不需要将整个程序集文件读入内存。它接受流,并为构造函数提供 PEStreamOptions 参数。这些选项包括 PrefetchImagePrefetchMetadata(以及其他选项),这表明默认情况下它不会将整个内容读入内存。

作为一个选项 - 您可以使用 TryGetRawMetadata 获取 RVA,然后单独使用 PEReader 将其解析为方法体。 PEReader 有可能会读取解析该 RVA 所需的最少数量,然后直接查找正文并只读取它,尽管我对此并不完全确定。

如果您足够勇敢 - 您甚至可以尝试自己从元数据根指针中找到 PE 图像的开始,然后将其提供给 PEReader 构造函数,尽管我显然不建议这样做。

关于c# - 我可以使用 Assembly.TryGetRawMetadata 和 System.Reflection.Metadata 访问方法主体(例如 IL 字节数组)吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50308931/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com