【问题标题】:Resolve Function Address with PE Export Table使用 PE 导出表解析函数地址
【发布时间】:2012-12-15 23:29:53
【问题描述】:

谁能解释我如何从 PE 图像中正确获取函数地址,然后使用委托调用该函数? 我发现了一段很好的谷歌搜索代码,它可以从 DLL 库中加载导出,但它只能从中获取函数名......所以我对其进行了如下修改:

[DllImport("ImageHlp", CallingConvention = CallingConvention.Winapi), SuppressUnmanagedCodeSecurity]
public static extern bool MapAndLoad(string imageName, string dllPath, out LOADED_IMAGE loadedImage, bool dotDll, bool readOnly);

public static IntPtr CustomGetProcAddress(string modulePath, string moduleProc)
{
    LOADED_IMAGE loadedImage;

    if (MapAndLoad(modulePath, null, out loadedImage, true, true))
        return GetAddr(loadedImage, moduleProc);
    else
        return IntPtr.Zero;
}

private static IntPtr GetAddr(LOADED_IMAGE loadedImage, string moduleProc)
{
    var hMod = (void*)loadedImage.MappedAddress;

    if (hMod != null)
    {
        uint size;
        var pExportDir = (IMAGE_EXPORT_DIRECTORY*)ImageDirectoryEntryToData(
            (void*)loadedImage.MappedAddress,
            false,
            IMAGE_DIRECTORY_ENTRY_EXPORT,
            out size);

        uint* pFuncNames = (uint*)RvaToVa(loadedImage, pExportDir->AddressOfNames);
        ushort* pFuncOrdinals = (ushort*)RvaToVa(loadedImage, pExportDir->AddressOfNameOrdinals);
        uint* pFuncAddr = (uint*)RvaToVa(loadedImage, pExportDir->AddressOfFunctions);

        for (uint i = 0; i < pExportDir->NumberOfNames; i++)
        {
            uint funcNameRva = pFuncNames[i];

            if (funcNameRva != 0)
            {
                char* funcName = (char*)RvaToVa(loadedImage, funcNameRva);
                string name = Marshal.PtrToStringAnsi((IntPtr)funcName);
                _exports.Add(name);

                if (name == wantedFunction)
                    return addr = new IntPtr(*(uint*)(pFuncAddr + (*pFuncOrdinals * 4)));
            }
        }
    }

    return IntPtr.Zero;
}

我确定我的引用接近解决方案...但我总是得到 AccessViolationException(当我使用错误的指针时)或 InvalidFunctionPointerInDelegate 和 PInvokeStackImbalance(当我尝试使用 Marshal.GetDelegateForFunctionPointer 和然后执行它)。 我尝试了所有方法,但无法使其工作(我已经使用 LoadLibrary 和 GetProcAddress 提取了我正在寻找的函数的正确地址......所以我可以比较结果,但我不想使用那些函数)。

[编辑] 我找到了另一个例子,但我不确定它是否能满足我的要求: http://www.rohitab.com/discuss/topic/39366-c-loadlibary-from-byte/page_k_bb2fe024f8a71424996db6d9af08c1fc_settingNewSkin_19

【问题讨论】:

    标签: .net dll mapping dllexport portable-executable


    【解决方案1】:

    你不能那样做。 MapAndLoadImageHlp 库中的函数仅将 PE 文件作为数据文件加载到内存中,以便对其进行检查。它不会运行 Windows 加载程序在加载 DLL 以使其可执行(RVA 修复等)时执行的所有逻辑。

    如果要加载 DLL,按名称查找函数并获取指向它的可调用指针,请使用 LoadLibraryGetProcAddress。这些功能旨在完全按照您的要求去做。

    【讨论】:

    • 这就是问题所在...我不想使用 GetProcAddress 和 LoadLibrary。我知道使用它很容易通过名称找到函数地址......但这不是我要找的。我看到很多 C/C++ 程序都在这样做,但我无法在 .NET 中重现它……还有其他选择吗?像 mh... 从内存中读取 DLL?
    • @Zarathos - 然后你必须重写 Windows 加载器在加载 DLL 时执行的所有逻辑 - 祝你好运。我不知道您为什么不愿意使用 LoadLibrary/GetProcAddress(它们在 .NET 中运行良好——我自己也使用过)。如果这是一次学习经历,那就把自己打晕;如果这是生产代码,则使用 LoadLibrary/GetProcAddress。
    【解决方案2】:

    如前所述,MapAndLoad 函数只是将文件作为数据加载 - 它加载到的内存页面将不可执行,因此尝试跳转到此内存中的某个位置几乎肯定不会起作用。如果您想使用LoadLibrary,您将需要一个更复杂的方法 - 但第一步是确保将 PE 文件的可执行部分加载到可执行内存中(然后实现所有其他Windows Loader 的功能!)我从未尝试过此操作,但从简短的搜索中可以看出,有许多与解决 Windows DEP(数据执行保护)等问题相关的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-13
      • 2014-07-09
      • 1970-01-01
      • 2023-03-25
      • 2014-10-11
      相关资源
      最近更新 更多