2012-04-05 126 views
1

我的項目需要檢查.c和.dll文件。它將這些信息結合起來以確定它應該調用的內容,然後調用它。編程讀取可調用DLL函數

我需要檢查dll以查找哪個dll具有哪個函數。我已經得到了這樣的dll映射到內存,而不是初始化它。現在我需要將頭部映射到某個東西,以便我可以讀出其中包含可調用名稱的部分。

我該怎麼辦呢?這是迄今爲止代碼:

[DllImport("kernel32.dll")] 
    static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags); 

    public static string[] GetFKTNames(string dll) 
    { 
     IntPtr lib = LoadLibraryEx(dll, IntPtr.Zero, LoadLibraryFlags.DONT_RESOLVE_DLL_REFERENCES); 

     //INDICATES WHAT I WANT TO DO, BUT DOES NOT WORk 
     //Header header = GetHeader(lib); 
     //Unload(lib); 
     //return header.Names; 
} 

編輯#2:

我做了一點點進步,並退出它今天...有4天自由這裏即將在德國...

我不完全確定那個編組是否正確 - 我無法測試它。我很想閱讀關於該主題的一本書 - 所以請評論一下,如果你知道一本好書,解釋這個headertuff是如何工作的,以及那裏有哪些不同的頭文件。

private static List<string> ListDLLFunctions(string sADllName) 
    { 
     List<string> names = new List<string>(); 
     IntPtr LoadedImage = LoadLibraryEx(sADllName, IntPtr.Zero, LoadLibraryFlags.DONT_RESOLVE_DLL_REFERENCES); 

     IMAGE_NT_HEADERS header = (IMAGE_NT_HEADERS) Marshal.PtrToStructure(libPtr, typeof(IMAGE_NT_HEADERS)); 

     // ImageExportDirectory = (_IMAGE_EXPORT_DIRECTORY*) 
     //  ImageDirectoryEntryToData(LoadedImage.MappedAddress, 
     //  false, IMAGE_DIRECTORY_ENTRY_EXPORT, &cDirSize); 
     // if (ImageExportDirectory != NULL) 
     // { 
     //  dNameRVAs = (DWORD *)ImageRvaToVa(LoadedImage.FileHeader, 
     //   LoadedImage.MappedAddress, 
     //  ImageExportDirectory->AddressOfNames, NULL); 
     //  for(size_t i = 0; i < ImageExportDirectory->NumberOfNames; i++) 
     //  { 
     //   sName = (char *)ImageRvaToVa(LoadedImage.FileHeader, 
     //     LoadedImage.MappedAddress, 
     //     dNameRVAs[i], NULL); 
     //   slListOfDllFunctions.push_back(sName); 
     //  } 
     // } 
     FreeLibrary(LoadedImage); 
     return names; 
    } 

    static void Main(string[] args) 
    { 
     List<string> names = ListDLLFunctions("KERNEL32.DLL"); 
    } 

回答

0

我解決了我的用例的問題:

我加載lib放到momory,將它複製到一個字節組,然後用PE的信息進行調查。

有一對夫婦對這個話題很有ressources,幫助我很多:

在retrospec我得到我可以如何使用其他方法來獲取我的信息。我寫的Class對學習PE和探索一些dll很有幫助,如果你想掌握PE的工作方式,我建議你重寫它。

這裏是類:

public class DLLHelper 
{ 
    private byte[] dllInMemory; 
    private UInt32 PESizeOfImage; 
    private UInt32 VA_PE; 

    [DllImport("kernel32.dll")] 
    static public extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags); 

    [DllImport("kernel32.dll")] 
    static public extern bool FreeLibrary(IntPtr hModule); 

    public enum LoadLibraryFlags : uint 
    { 
     DONT_RESOLVE_DLL_REFERENCES = 0x00000001, 
     LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, 
     LOAD_LIBRARY_AS_DATAFILE = 0x00000002, 
     LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, 
     LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, 
     LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 
    } 


    public DLLHelper(string dllpath) 
    { 
     PESizeOfImage = GetDllSizeInMemory(dllpath); 
     dllInMemory = GetDLLCopy(dllpath, PESizeOfImage); 
     UInt32 VA_p_PE = 0x3C; 
     VA_PE = Get4ByteFromLocation(VA_p_PE, dllInMemory); 
    } 

    private byte[] GetDLLCopy(string dllpath, uint PESizeOfImage) 
    { 
     IntPtr libPtr = LoadLibraryEx(dllpath, IntPtr.Zero, LoadLibraryFlags.DONT_RESOLVE_DLL_REFERENCES); 
     byte[] dllInMemory = new byte[PESizeOfImage]; 
     Marshal.Copy(libPtr, dllInMemory, 0, (int)PESizeOfImage); 
     FreeLibrary(libPtr); 
     return dllInMemory; 
    } 

    private UInt32 GetDllSizeInMemory(string dllpath) 
    { 
     byte[] dllpreload = File.ReadAllBytes(dllpath); 
     UInt32 pp_PE = 0x3C; 
     UInt32 p_PE = Get4ByteFromLocation(pp_PE, dllpreload); 
     UInt32 p_PEOPTIONALHEADER = p_PE + 0x18; 
     UInt32 p_PESizeOfImage = p_PEOPTIONALHEADER + 0x38; 
     return Get4ByteFromLocation(p_PESizeOfImage, dllpreload); 
    } 

    public void DumpToFile(String filename) 
    { 
     File.WriteAllBytes(filename, dllInMemory); 
    } 

    public string GetDLLName() 
    { 
     UInt32 VAExport = GetVAExport(VA_PE, dllInMemory); 
     UInt32 VAName = GetVAName(VAExport, dllInMemory); 
     String Name = GetString(VAName, dllInMemory); 
     return Name; 
    } 

    public List<String> GetFunctionNames() 
    { 
     List<String> fkts = new List<String>(); 
     UInt32 VAExport = GetVAExport(VA_PE, dllInMemory); 
     UInt32 VA_p_firstFKT = GetVA_p_firstFKT(VAExport, dllInMemory); 
     UInt32 VA_p_lastFKT = GetVA_p_lastFKT(VAExport, dllInMemory); 
     for (UInt32 VA_p_fkt = VA_p_firstFKT; VA_p_fkt <= VA_p_lastFKT; VA_p_fkt += sizeof(UInt32)) 
     { 
      UInt32 VA_fkt = Get4ByteFromLocation(VA_p_fkt, dllInMemory); 
      fkts.Add(GetString(VA_fkt, dllInMemory)); 
     } 
     return fkts; 
    } 

    private UInt32 GetVA_p_lastFKT(UInt32 VAExport, byte[] dllInMemory) 
    { 
     UInt32 first = GetVA_p_firstFKT(VAExport, dllInMemory); 
     UInt32 count = GetfktCount(VAExport, dllInMemory); 
     UInt32 last = first + (count - 1) * sizeof(UInt32); 
     return last; 
    } 

    private UInt32 GetfktCount(UInt32 VAExport, byte[] dllInMemory) 
    { 
     UInt32 RVA_Count = 0x14; 
     UInt32 VA_Count = VAExport + RVA_Count; 
     return Get4ByteFromLocation(VA_Count, dllInMemory); 
    } 

    private UInt32 GetVA_p_firstFKT(UInt32 VAExport, byte[] dllInMemory) 
    { 
     UInt32 RVA_p_FIRST = 0x20; 
     UInt32 VA_p_FIRST = VAExport + RVA_p_FIRST; 
     return Get4ByteFromLocation(VA_p_FIRST, dllInMemory); 
    } 

    private UInt32 GetVAName(UInt32 VAExport, byte[] dllInMemory) 
    { 
     UInt32 RVA_p_NAME = 0x0C; 
     UInt32 VA_p_NAME = VAExport + RVA_p_NAME; 
     return Get4ByteFromLocation(VA_p_NAME, dllInMemory); 
    } 

    private UInt32 GetVAExport(UInt32 VAPE, byte[] dllInMemory) 
    { 
     UInt32 RVA_p_EXPORT = 0x78; 
     UInt32 VA_p_EXPORT = VAPE + RVA_p_EXPORT; 
     return Get4ByteFromLocation(VA_p_EXPORT, dllInMemory); 
    } 

    string GetString(UInt32 location, byte[] dll) 
    { 
     int length = 0; 
     while (dll[location + length] != 0x00) 
     { 
      length++; 
     } 
     if (location > int.MaxValue) throw new Exception("uncastable"); 
     return Encoding.UTF8.GetString(dll, (int)location, length); 
    } 

    private UInt32 Get4ByteFromLocation(UInt32 location, byte[] dll) 
    { 
     if (!(BitConverter.IsLittleEndian)) 
     { 
      byte[] partial = GetByteSubset(4, location, dll); 
      Array.Reverse(partial); 
      return BitConverter.ToUInt32(partial, 0); 
     } 
     return BitConverter.ToUInt32(dll, (int)location); 
    } 

    private byte[] GetByteSubset(int size, UInt32 location, byte[] dll) 
    { 
     byte[] val = new byte[size]; 
     for (int i = 0; i < size; i++) 
     { 
      val[i] = dll[location + i]; 
     } 
     return val; 
    } 
} 
+0

將這個函數用於幾個小項目之後,我遇到了這樣的問題,即並非所有的DLL都可能被這種方式感染。我使用兩種不同的編譯器遇到了問題...所以需要做很多工作......但我會改變我的方法來解決核心問題。 – Johannes 2012-04-28 08:35:00

0

從代碼非,但是從控制檯我通常使用

DumpBin工具查看DLL的出口。

我想你可以使用該工具與Process.Start(..)並解析其輸出,以獲得您需要的信息。

希望這會有所幫助。

+0

它可能在某些情況下有所幫助,但我不想應付來自我的程序調用其他可執行文件。我將不得不確保它安裝在所有目標機器上以及它的依賴關係......在我的機器上它說它缺少smoe dll並且根本不會啓動。 – Johannes 2012-04-05 13:37:46

+0

@Johannes:直到現在我沒有遇到一臺機器。您可以嘗試使其成爲程序設置的一部分。 – Tigran 2012-04-05 13:40:39

+0

我有一個它的副本:C:\ Program Files \ Microsoft Visual Studio 10.0 \ VC \ bin,它不會啓動,因爲某些DLL。我在一個相當大的公司 - 安裝任何東西都不是一個真正的選擇。 – Johannes 2012-04-05 14:09:59

1

沒有「一個呼叫」功能可以爲你做。 您必須加載dll並在導出表中查找名稱。

There is a post with some code to do it in c++ - 也許你可以嘗試將它移植到C#

+0

我不認爲我有我需要的所有技能來移植這個,但我會給它一個鏡頭。 – Johannes 2012-04-05 13:38:30