如何使用来自 System.Reflection 的 PEReader 从 DLLImport 属性获取 DLL name/path?

How do I get the DLL name/path from the DLLImport attribute using PEReader from System.Reflection?

我正在编写一个实用程序来反汇编用 c# 编写的 dll/exe 文件,然后扫描此文件中的所有类型以查找是否存在从非托管 DLL 导入的方法。我需要获取每个导入方法的信息,包括从中导入该方法的 DLL 的 name/path,即 DllImport 属性的第一个参数的值。假设在dll/exe文件中有这样一个函数声明:

[DllImport("C:\TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void HelloWorld();

我是反射的新手,我正在尝试使用 PEReader 查看所有类型并搜索从 DLL 导入的函数。我从 System.Reflection.Metadata.MethodDefinition 调用 GetImport() 以确定当前 MethodDefinition 是否是导入方法。通过GetImport().Attributes我希望得到所有的DllImport参数,包括这个DLL的路径,但是这样并没有给出想要的结果:

using (var fileStream = new FileStream(pathToBinary, FileMode.Open, FileAccess.Read))
{
    using (var peReader = new PEReader(fileStream))
    {
        var mdReader = peReader.GetMetadataReader();

        foreach (var typeHandler in mdReader.TypeDefinitions)
        {
            var typeDef = mdReader.GetTypeDefinition(typeHandler);

            foreach (var methodHandler in typeDef.GetMethods())
            {
                var methodDef = mdReader.GetMethodDefinition(methodHandler);
                var import = methodDef.GetImport();
                if(import.Module.IsNil)
                {
                    continue;
                }

                //Returns "CallingConventionCdecl" but not ""C:\TestDll.dll," CallingConventionCdecl":
                var dllImportParameters = import.Attributes.ToString();
            }
        }
    }
}

也就是说,GetMethod().Attributes returns 除了从中导入方法的库 name/path 之外的所有 DLLImport 参数。

如何从 DllImport 的第一个参数获取 DLL 路径?

我找到了解决问题的办法。所以 import 有一个 Module 属性,returns 是 System.Reflection.Metadata.ModuleReferenceHandle 的一个实例。用MetaDataReader.GetModuleReference(moduleReferenceHandle)可以转换成System.Reflection.Metadata.ModuleReference。反过来,ModuleReference 的实例有一个 Name 属性 即 returns StringHandle 并且也可以使用 MetaDataReader.GetString(stringHandle) 转换为字符串。这是DLL的name/path。

问题的完整解决方案:

string dllPath = mdReader.GetString(mdReader.GetModuleReference(import.Module).Name);