2013-01-01 20 views
1

任何人都可以解释我如何从PE映像中正确获取函数地址,然后使用委托调用该函数? 我找到了一个好一块代码google搜索周围的负载从一个DLL库出口,但只得到函数名出来的......所以我修改,如下所示:用PE导出表解决函数地址

[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

回答

1

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

如果要加载DLL,请按名称查找函数,并获取指向它的可调用指针,则使用LoadLibraryGetProcAddress。这些功能旨在完成您正在尝试执行的操作。

+0

这就是问题所在......我不想使用GetProcAddress和LoadLibrary。我知道使用它很容易找到一个名称的函数地址......但这不是我正在寻找的。我看到很多C/C++程序正在这样做,但我无法在.NET中重现它...有其他选择吗?像mh ...从内存中读取DLL? –

+0

@Zarathos - 然后你必须重新编写Windows加载器加载DLL时所做的所有逻辑 - 祝你好运。我不知道为什么你不喜欢使用LoadLibrary/GetProcAddress(他们在.NET中工作正常 - 我自己使用它们)。如果这是一次学习经历,那么请自己解决;如果这是生产代码,则使用LoadLibrary/GetProcAddress。 – shf301

0

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