2013-01-01 51 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(數據執行預防)等問題有關。