2012-04-05 10 views
1

Mein Projekt muss .c- und .dll-Dateien überprüfen. es kombiniert diese Informationen, um zu bestimmen, was es anrufen soll und ruft es dann an.Programmgesteuertes Aufrufen aufrufbarer DLL-Funktionen

Ich muss die DLLs überprüfen, welche DLL welche Funktion hat. Ich bin so weit gegangen, die DLL in den Speicher zu mappen, ohne sie zu initialisieren. Jetzt muss ich den Header etwas zuordnen, damit ich den Abschnitt lesen kann, der die aufrufbaren Namen enthält.

Wie kann ich das tun? so weit dies ist der Code:

[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:

i ein wenig Fortschritte gemacht, und beenden Sie es für heute ... gibt es 4 freie Tage hier in Deutschland kommen ...

Ich bin mir nicht ganz sicher, ob das Marshalling korrekt ist - ich hatte keine Möglichkeit es zu testen. Ich würde gerne ein Buch zu diesem Thema lesen - also kommentiere bitte, wenn du ein gutes Buch kennst, das erklärt, wie dieser Headerstuff funktioniert und welche verschiedenen Header es gibt.

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"); 
    } 

Antwort

0

ich das Problem für meine usecase gelöst:

ich die lib in momory laden, kopieren Sie sie in eine bytearray und dann untersuchen sie PE Informationen mit .

Es gibt ein paar nützliche Ressourcen für dieses Thema, das mir sehr geholfen:

Im Rückblick bekomme ich, wie ich die anderen Ansätze verwendet haben könnte, um meine Informationen zu erhalten. Die Klasse, die ich geschrieben habe, ist großartig, PE zu lernen und einige dlls zu erforschen, ich empfehle es neu zu schreiben, wenn Sie den Griff bekommen wollen, wie das PE funktioniert.Hier

ist die Klasse:

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

Nachdem ich diese Funktion für ein paar kleine Projekte benutzt habe, bin ich auf das Problem gestoßen, dass nicht alle DLLs auf diese Weise entfernt werden können. Ich hatte Probleme, indem ich nur zwei verschiedene Compiler verwendete. Es gibt also viel zu tun ... aber ich werde meine Herangehensweise an das Kernproblem ändern. – Johannes

0

Nicht aus dem Code, sondern von der Konsole in der Regel verwende ich

DumpBin Dienstprogramm Dll Exporte zu sehen.

Ich denke, dass Sie dieses Werkzeug mit Process.Start(..) verwenden und seinen Ausgang analysieren können, um eine Information zu erhalten, die Sie benötigen.

Hoffe, das hilft.

+0

es in einigen Fällen helfen könnte, aber ich nicht mit Aufrufen anderen ausführbaren Dateien von meinem Programm beschäftigen möchten. Ich würde sicherstellen müssen, dass es auf allen Zielmaschinen mit seinen Abhängigkeiten installiert ist ... auf meinem Rechner sagt es, dass es smoe dll fehlt und überhaupt nicht starten wird. – Johannes

+0

@Johannes: Bis jetzt habe ich keine Maschine getroffen, wo es nicht ist. Sie können versuchen, es zu einem Teil Ihrer Programmeinrichtung zu machen. – Tigran

+0

Ich habe eine Kopie davon hier: C: \ Programme \ Microsoft Visual Studio 10.0 \ VC \ bin und es wird wegen einiger DLL nicht starten. Ich bin in einer ziemlich großen Firma - alles zu installieren ist nicht wirklich eine Option. – Johannes

1

Es gibt keine "einen Anruf" -Funktion, die es für Sie tun kann. Sie müssen die DLL laden und suchen Sie die Namen in der Export-Tabelle.

There is a post with some code to do it in c++ - vielleicht können Sie in den Hafen versuchen, es zu C#

+0

ich glaube nicht, dass ich alle Fähigkeiten habe, die ich brauche, um das zu portieren, aber ich werde es versuchen. – Johannes