有人能解释我如何从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
答案 0 :(得分:1)
你做不到。来自MapAndLoad
库的ImageHlp
和函数仅将PE文件作为数据文件加载到内存中,以便对其进行检查。当Windows加载器加载DLL以使其可执行时(RVA fixups等),它不会运行Windows加载程序的所有逻辑。
如果要加载DLL,按名称查找函数,并获取指向它的可调用指针,则使用LoadLibrary
和GetProcAddress
。这些功能旨在完全按照您的目标进行操作。
答案 1 :(得分:0)
如前所述,MapAndLoad
函数只是将文件作为数据加载 - 它加载到的内存页面将是不可执行的,因此尝试跳转到此内存中的某个位置几乎肯定不会工作。如果你想使用LoadLibrary
,你将需要一个更复杂的方法 - 但第一步是确保将PE文件的可执行部分加载到可执行内存中(然后实现所有Windows Loader的其他功能!)我从来没有尝试过这个,但是从简短的搜索中我可以看到,存在许多与解决诸如Windows DEP(数据执行预防)等问题相关的问题。