1

谁能解释我如何从 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

4

2 回答 2

1

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

如果要加载 DLL,按名称查找函数并获取指向它的可调用指针,请使用LoadLibraryand GetProcAddress。这些功能旨在完成您正在尝试做的事情。

于 2013-01-01T18:04:07.797 回答
0

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

于 2013-02-10T02:45:19.550 回答