Я думаю, что это невозможно сделать так, как вы хотели бы с TryGetRawMetadata
. Как указано в спецификации, «тела метода могут храниться в любом доступном только для чтения разделе PE-файла», и поэтому одного блоба метаданных недостаточно для разрешения этого 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
для конструктора. Эти опции включают PrefetchImage
, PrefetchMetadata
(среди прочих), что предполагает, что по умолчанию он не считывает все это в память.
Как вариант - вы можете использовать TryGetRawMetadata
, чтобы получить RVA, а затем отдельно использовать PEReader
, чтобы преобразовать его в тело метода. Есть вероятность, что PEReader
будет тогда читать минимальное количество, необходимое для разрешения этого RVA, а затем будет искать непосредственно в теле и читать только это, хотя я не совсем уверен в этом.
Если вы достаточно смелы - вы можете даже попытаться найти начало PE-образа из корневого указателя метаданных, а затем передать его в конструктор PEReader
, хотя я, очевидно, не рекомендую этого.