Resolve Function Address with PE Export Table

2019-07-30 10:19发布

问题:

Can anyone explain me how to properly obtain a function address from a PE image and then call that function with a delegate? I found a good piece code googling around that loads exports from a DLL library, but it only get function names out of it... so I modified it as follows:

[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;
}

I'm sure I'm quote close to the solution... but I always get AccessViolationException (when I use wrong pointers) or InvalidFunctionPointerInDelegate and PInvokeStackImbalance (when I try to cast the pointer to a delegate using Marshal.GetDelegateForFunctionPointer and then execute it). I tried everything but I can't make it work (I already pulled out the correct address of the function I'm looking for using LoadLibrary and GetProcAddress... so I can compare the results, but I don't want to use those functions).

[EDIT] I found another example, but I'm not sure it can do what I'm looking for: http://www.rohitab.com/discuss/topic/39366-c-loadlibary-from-byte/page_k_bb2fe024f8a71424996db6d9af08c1fc_settingNewSkin_19

回答1:

You can't do that. The MapAndLoad and function from the ImageHlp library only loads a PE file into memory as a data file so it can be examined. It does not run through all of the logic of the Windows loader does when it loads a DLL to make it executable (RVA fixups, etc.).

If you want to load a DLL, find a function by name, and get an callable pointer to it, you use LoadLibrary and GetProcAddress. Those functions where designed to do exactly what you are looking trying to do.



回答2:

As has been said previously, the MapAndLoad function is just loading the file as data - the memory page it's loaded into will non-executable, and so trying to jump to a location within this memory will almost certainly not work. You're going to need a significantly more complex method if you want to get around using LoadLibrary - but the first step will be ensuring that the executable sections of the PE file are loaded into executable memory (followed by implementing all of the other functionality of the Windows Loader!) I've never attempted this, but from what I can see on a brief search there are numerous issues associated with getting around issues such as Windows DEP (data execution prevention).