2009-10-14 57 views
1

我已經從另一個進程加載到內存中的非託管模塊成功讀取PE標頭。我現在想要做的是讀取模塊導出的名稱。基本上,這是我迄今爲止(我省略了大部分的PE解析代碼的,因爲我已經知道了它的工作原理):如何從PE模塊的導出表中讀取名稱?

擴展

public static IntPtr Increment(this IntPtr ptr, int amount) 
{ 
    return new IntPtr(ptr.ToInt64() + amount); 
} 

public static T ToStruct<T>(this byte[] data) 
{ 
    GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); 
    T result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 
    handle.Free(); 
    return result; 
} 

public static byte[] ReadBytes(this Process process, IntPtr baseAddress, int size) 
{ 
    int bytesRead; 
    byte[] bytes = new byte[size]; 
    Native.ReadProcessMemory(process.Handle, baseAddress, bytes, size, out bytesRead); 
    return bytes; 
} 

public static T ReadStruct<T>(this Process process, IntPtr baseAddress) 
{ 
    byte[] bytes = ReadBytes(process, baseAddress, Marshal.SizeOf(typeof(T))); 
    return bytes.ToStruct<T>(); 
} 

public static string ReadString(this Process process, IntPtr baseAddress, int size) 
{ 
    byte[] bytes = ReadBytes(process, baseAddress, size); 
    return Encoding.ASCII.GetString(bytes); 
} 

GetExports()

Native.IMAGE_DATA_DIRECTORY dataDirectory = 
    NtHeaders.OptionalHeader.DataDirectory[Native.IMAGE_DIRECTORY_ENTRY_EXPORT]; 

if (dataDirectory.VirtualAddress > 0 && dataDirectory.Size > 0) 
{ 
    Native.IMAGE_EXPORT_DIRECTORY exportDirectory = 
     _process.ReadStruct<Native.IMAGE_EXPORT_DIRECTORY>(
      _baseAddress.Increment((int)dataDirectory.VirtualAddress)); 

    IntPtr namesAddress = _baseAddress.Increment((int)exportDirectory.AddressOfNames); 
    IntPtr nameOrdinalsAddress = _baseAddress.Increment((int)exportDirectory.AddressOfNameOrdinals); 
    IntPtr functionsAddress = _baseAddress.Increment((int)exportDirectory.AddressOfFunctions); 

    for (int i = 0; i < exportDirectory.NumberOfFunctions; i++) 
    { 
     Console.WriteLine(_process.ReadString(namesAddress.Increment(i * 4), 64)); 
    } 
} 

當我運行這個,我得到的是一個雙重問號模式,然後完全隨機的字符。我知道標題被正確讀取,因爲簽名是正確的。問題的關鍵在於我正在迭代函數列表。

回答

1

this link的代碼似乎表明名稱和序數形成一對匹配的數組,計數到NumberOfNames,並且這些函數是分開的。所以你的循環可能會迭代錯誤次數,但這並不能解釋爲什麼你從一開始就看到壞字符串。

對於只是打印名稱,我成功了一個如下所示的循環。我認爲ImageRvaToVa的呼叫可能是你需要得到正確的字符串?但是我不知道這個函數是否可以工作,除非你已經通過調用MapAndLoad實際加載了圖像 - 這就是文檔要求的內容,而且這個映射在我用LoadLibrary代替的一些快速實驗中似乎不起作用。

這裏的PInvoke的聲明:

[DllImport("DbgHelp.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity] 
    public static extern IntPtr ImageRvaToVa(
     IntPtr NtHeaders, 
     IntPtr Base, 
     uint Rva, 
     IntPtr LastRvaSection); 

,這裏是我的主循環:

   LOADED_IMAGE loadedImage = ...; // populated with MapAndLoad 
       IMAGE_EXPORT_DIRECTORY* pIID = ...; // populated with ImageDirectoryEntryToData 

       uint* pFuncNames = (uint*) 
        ImageRvaToVa(
         loadedImage.FileHeader, 
         loadedImage.MappedAddress, 
         pIID->AddressOfNames, 
         IntPtr.Zero); 

       for (uint i = 0; i < pIID->NumberOfNames; i++) 
       { 
        uint funcNameRVA = pFuncNames[i]; 
        if (funcNameRVA != 0) 
        { 
         char* funcName = 
           (char*) (ImageRvaToVa(loadedImage.FileHeader, 
            loadedImage.MappedAddress, 
            funcNameRVA, 
            IntPtr.Zero)); 
         var name = Marshal.PtrToStringAnsi((IntPtr) funcName); 
         Console.WriteLine(" funcName: {0}", name); 
        } 
       } 
相關問題