我可以使用 Assembly.TryGetRawMetadata 和 System.Reflection.Metadata 访问方法体(例如 IL 字节数组)吗?
Can I access method bodies (e.g. IL byte array) using Assembly.TryGetRawMetadata and System.Reflection.Metadata?
.NET Core 2 的 FCL 包含扩展方法 Assembly.TryGetRawMetadata
which one can use to inspect a loaded assembly's metadata using 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 的引用。
AFAIK,Assembly.TryGetRawMetadata
returns 只是一个从元数据根 (BSJB
) 开始并包括元数据流和堆的数据 blob,但方法体实际上存储在此之外数据。
当然,我可以从检查整个程序集文件开始(其路径在 thisAssembly.Location
中给出),但这需要将其重新加载到内存中。
难道 Assembly.TryGetRawMetadata
真的不允许我访问方法体,还是我忽略了什么?
我认为 TryGetRawMetadata
不可能完全按照您的意愿进行。正如规范所述,"Method bodies can be stored in any read-only section of a PE file",因此单靠元数据 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
的东西,其中 returns 指针和整个 PE 图像的长度。 PEReader
已经有接受这样的指针和长度的构造函数,据我所知已经提出了这样的模拟方法(TryGetRawImage
),但还没有实现。
也就是说,PEReader
不需要将整个程序集文件读入内存。它接受流,并向构造函数提供 PEStreamOptions
参数。这些选项包括 PrefetchImage
、PrefetchMetadata
(等等),这表明默认情况下它不会将整个内容读入内存。
作为一个选项 - 您可以使用 TryGetRawMetadata
获取 RVA,然后单独使用 PEReader
将其解析为方法体。有可能 PEReader
将读取解决该 RVA 所需的最小数量,然后将直接搜索 body 并只读取它,尽管我对此并不完全确定。
如果你足够勇敢 - 你甚至可以尝试自己从元数据根指针中找到 PE 映像的开始,然后将其输入 PEReader
构造函数,尽管我显然不会推荐这样做。
.NET Core 2 的 FCL 包含扩展方法 Assembly.TryGetRawMetadata
which one can use to inspect a loaded assembly's metadata using 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 的引用。
AFAIK,Assembly.TryGetRawMetadata
returns 只是一个从元数据根 (BSJB
) 开始并包括元数据流和堆的数据 blob,但方法体实际上存储在此之外数据。
当然,我可以从检查整个程序集文件开始(其路径在 thisAssembly.Location
中给出),但这需要将其重新加载到内存中。
难道 Assembly.TryGetRawMetadata
真的不允许我访问方法体,还是我忽略了什么?
我认为 TryGetRawMetadata
不可能完全按照您的意愿进行。正如规范所述,"Method bodies can be stored in any read-only section of a PE file",因此单靠元数据 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
的东西,其中 returns 指针和整个 PE 图像的长度。 PEReader
已经有接受这样的指针和长度的构造函数,据我所知已经提出了这样的模拟方法(TryGetRawImage
),但还没有实现。
也就是说,PEReader
不需要将整个程序集文件读入内存。它接受流,并向构造函数提供 PEStreamOptions
参数。这些选项包括 PrefetchImage
、PrefetchMetadata
(等等),这表明默认情况下它不会将整个内容读入内存。
作为一个选项 - 您可以使用 TryGetRawMetadata
获取 RVA,然后单独使用 PEReader
将其解析为方法体。有可能 PEReader
将读取解决该 RVA 所需的最小数量,然后将直接搜索 body 并只读取它,尽管我对此并不完全确定。
如果你足够勇敢 - 你甚至可以尝试自己从元数据根指针中找到 PE 映像的开始,然后将其输入 PEReader
构造函数,尽管我显然不会推荐这样做。