2012-04-05 13 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; 
} 

EDIT#2:

私は進歩の少しを作ったし、今日のためにそれを辞め...ドイツでここまで来て4ない日があります...

マーシャリングが正しいかどうかは完全にはわかりません。テストする方法はありませんでした。私はその話題の本を読んでみたいと思っています。そのヘッダーがどのように機能し、どのようなヘッダーがあるのか​​を説明する良い本を知っていればコメントしてください。コードから

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

にポートにそれを試すことができます。

私は、momoryにlibがロードされたByteArrayにそれをコピーし、PEの情報を使用して、それを調査。

私をたくさん助けたこのトピックのための便利なressourcesのカップルがあります:

retrospecでは、自分の情報を取得するために他の方法を使用する方法を知ることができます。私が書いたクラスは、PEを学び、いくつかのDLLを探索するのに最適です.PHの仕組みを把握したい場合は、書き直してください。ここで

はクラスです:

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がそうした方法で識別できるわけではないという問題に遭遇しました。私は2つの異なるコンパイラを使用するだけで問題を抱えていました。そのためには多くの作業が必要です...しかし、私は中心的な問題への私のアプローチを変えます。 – Johannes

0

ないが、コンソールから、私は通常、DLLの輸出を見て

DumpBinユーティリティを使用します。

私はこのツールをProcess.Start(..)と一緒に使用して、必要な情報を得るためにその出力を解析できると思います。

これが役に立ちます。

+0

それはいくつかのケースで役立つかもしれないが、私は私のプログラムから他の実行可能ファイルを呼び出すことに対処したくありません。私は、すべてのターゲットマシンとその依存関係にインストールされていることを確認する必要があります...私のマシンではsmoe dllがなくなっていて、まったく起動しないと言われています。 – Johannes

+0

@Johannes:今まで私はそれがないところのマシンには会えなかった。あなたはそれをあなたのプログラム設定の一部にしようとすることができます。 – Tigran

+0

私はここにそれのコピーを持っています:C:\ ProgramFiles \ MicrosoftVisual Studio 10.0 \ VC \ binそしていくつかのDLLのために起動しません。私はかなり大きな会社に入っています。何かをインストールすることは本当にオプションではありません。 – Johannes

1

「ワンコール」機能はありません。 dllをロードし、エクスポートテーブルで名前を探す必要があります。

There is a post with some code to do it in c++ - 多分あなたは私が私のユースケースのための問題を解決し、C#

+0

私はこれを移植する必要があるすべてのスキルを持っているとは思わないが、私はそれを撃つだろう。 – Johannes

関連する問題