Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
ExportHider — ExportHider: Generierung der Exporttabelle zur Laufzeit, um die exportierten Funktionen aus der DLL-Datei zu verbergen. | Kitploit
Tools/GitHubGitHub/frkngksl/exporthider
Dynamische Code-Analyse (DAST)ExploitationReverse EngineeringMalware-AnalyseBinäranalyseRed TeamingPayload-Entwicklung
GitHubfrkngksl/exporthider

ExportHider

ExportHider: Generierung der Exporttabelle zur Laufzeit, um die exportierten Funktionen aus der DLL-Datei zu verbergen.

Repository anzeigen
332vor 4 MonatenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

ExportHider

ExportHider generiert eine C++ DLL-Vorlage, die einen Code-Stub enthält, mit dem Sie exportierte Funktionen aus dem Exportverzeichnis der DLL im Dateisystem ausblenden können. Nach dem Einfügen der Funktionsdefinitionen und dem Kompilieren der Datei werden die versteckten Exportfunktionen in PE-Datei-Viewern wie CFF Explorer nicht mehr angezeigt. Da der Code-Stub in der Vorlage das Exportverzeichnis jedoch zur Laufzeit neu erstellt, werden legitime GetProcAddress-Aufrufe erfolgreich ausgeführt. Diese Methode funktioniert nur bei dynamischem DLL-Laden oder benutzerdefinierten DLL-Ladefällen.

Funktionsweise

Normalerweise definiert man eine exportierte Funktion in DLL-Dateien (in C oder C++), indem man einfach das Schlüsselwort __declspec(dllexport) vor den Funktionsnamen setzt oder eine .def-Datei erstellt. Nach der Kompilierung erstellt der Compiler eine spezielle Tabelle namens Exportverzeichnis, die die Informationen zu den exportierten Funktionen enthält. Die Struktur des Exportverzeichnisses ist unten dargestellt:

Wenn ein Prozess eine Funktion aus einer DLL-Datei verwenden möchte, parst der Windows-Loader einfach diese Struktur und importiert die angeforderten Funktionen mithilfe der Arrays AddressOfFunctions, AddressOfNames, AddressOfNameOrdinals.

Die genaue Routine zum Importieren einer Funktion wird im Blogbeitrag von ferreirasc ausführlich erklärt, aber kurz gesagt: Bei einem namentlichen Import iteriert der Loader durch das AddressOfNames-Array (die Werte dieses Arrays sind nur RVA-Werte) und sucht nach dem angegebenen Namen. Sobald der Loader eine Übereinstimmung an der Position „i“ findet, greift er auf den i-ten Index des AddressOfNameOrdinals-Arrays zu und erhält die dieser Funktion zugeordnete Ordinalzahl. Mit der Ordinalzahl greift der Loader auf die Position des Ordinalwertes im AddressOfFunctions-Array zu, um schließlich die RVA der importierten Funktion zu erhalten.

Der entscheidende Punkt hier ist, dass alle diese Such- und Zugriffsoperationen des Windows-Loaders beim Aufruf von LoadLibrary durchgeführt werden, nachdem die DLL in den Prozessadressraum gemappt wurde. Während des DLL-Mappings wird die gesamte DLL-Datei, einschließlich ihrer PE-Header, in den Speicher geschrieben, und der Loader parst die Header im Speicher, um zum Exportverzeichnis zu gelangen. Das bedeutet, dass der Loader, wenn die DLL selbst in der Lage ist, ihre PE-Header im Speicher zu überschreiben, um die Exportverzeichnisadresse (einfach den 0. Index des DataDirectory) nach dem Anhängen an den Prozess zu ändern, nach Funktionen in einem beliebigen Exportverzeichnis suchen kann, anstatt in dem vom Compiler hinzugefügten Exportverzeichnis.

Befehlszeilenparameter

root@kitploit:~

   __                       _          _     _
  /__\_  ___ __   ___  _ __| |_  /\  /(_) __| | ___ _ __
 /_\ \ \/ / '_ \ / _ \| '__| __|/ /_/ / |/ _` |/ _ \ '__|
//__  >  <| |_) | (_) | |  | |_/ __  /| | (_| |  __/ |
\__/ /_/\_\ .__/ \___/|_|   \__\/ /_/ |_|\__,_|\___|_|
          |_|
                     by @R0h1rr1m

Usage of C:\Users\Public\DLLDemo\ExportHider.exe:

    -h | --help                                 Show the help message.
    -i | --input <Input Path>                   Input path for the list of function names to be hidden. (Mandatory)
    -o | --output <Output Path>                 Output path for the DLL template. (Mandatory)
    -n | --name <DLL Name>                      Name of the DLL for the Export Directory. (Mandatory)
    -c | --count <Number of Other Functions>    Number of other exported functions that won't be hidden.

Bezüglich des Parameters -i | --input <Input Path> müssen Sie einen Pfad für die Eingabedatei angeben, die die auszublendenden Funktionsnamen zeilenweise speichert. Der Inhalt einer Beispiel-Eingabedatei wäre:

root@kitploit:~
TestFunction1
TestFunction2
TestFunction3

Bezüglich des Parameters -c | --count: Wenn Sie nicht alle Ihre exportierten Funktionen ausblenden möchten (d.h., es gibt einige Funktionen, die mit __declspec(dllexport) oder einer .def-Datei exportiert werden und im Exportverzeichnis der DLL-Datei im Dateisystem über PE-Datei-Viewer sichtbar sind), geben Sie einfach deren Anzahl mit diesem Parameter an, da das Tool diese Informationen für Speicherberechnungen benötigt.

Schnelles Demovideo

Problemumgehungen

Wenn Sie mit der Technik experimentieren möchten, gibt es zwei interessante Punkte, die mir während der Entwicklung des Projekts begegnet sind. Sie sollten diese kennen, bevor Sie das Projekt ändern:

  • Der Windows-Loader verwendet einen binären Suchalgorithmus, um die exportierte Funktion zu finden, wenn Sie GetProcAddress mit einem Namen aufrufen. Aus diesem Grund müssen die Namen aller exportierten Funktionen, einschließlich der versteckten, im AddressOfNames-Array sortiert sein. Andernfalls gibt GetProcAddress NULL zurück. Daher habe ich den Bubble-Sort-Algorithmus verwendet, um die Mitglieder dieses Arrays zu sortieren.
  • Wie bereits erwähnt, erfordern das AddressOfNames-Array, das AddressOfFunctions-Array, das DataDirectory-Array und einige andere Felder Werte in relativen virtuellen Adressen (RVAs). Darüber hinaus werden diese RVA-Werte in Feldern der Größe DWORD gespeichert. Wenn Sie einen Speicherbereich für ein neues beliebiges Exportverzeichnis mit dynamischen Speicherzuweisungsfunktionen wie VirtualAlloc oder HeapAlloc zuweisen, liegen die angegebenen Adressen weit entfernt vom gemappten DLL-Bereich, und die RVA-Werte passen nicht in die DWORD-großen Felder, was zu einem Integer-Überlauf führt. Deshalb habe ich globale Variablen vom Typ Byte-Array in der DLL-Vorlage für die Speicheranforderungen verwendet.

Statisch importierte DLL (auch bekannt als DLL Sideloading) Fall

Mein erstes Ziel bei der Erstellung dieses Projekts war es, eine DLL zu generieren, die fehlende Exporte (oder ein vollständiges Fehlen einer Exporttabelle) aufweist, aber dennoch erfolgreich vom neu erstellten Prozess geladen wird. Ich dachte, dieses Verhalten könnte ein neues Spielfeld für DLL-Sideloading-Payloads bieten. Allerdings konnte ich keine Funktion oder Möglichkeit finden, bei der der Exportverzeichnis-Reparatur-Stub ausgeführt wird, bevor der Windows-Loader die exportierten DLL-Funktionen überprüft.

dll_timing_problem (1)

Technischer gesehen habe ich den folgenden Ablauf und Funktionsaufruf für jede DLL in den Codeabschnitten des Windows-Loaders in NTDLL festgestellt (aus alten Notizen; es könnte einige Fehler geben, da ich kein Experte in Reverse Engineering bin):

root@kitploit:~
1. LdrpMapDll - This is where the DLL is mapped to the Process Address Space. All DLLs that satisfy the DLL name condition 
                are directly put into the memory, no precheck control for the filesystem version.
2. LdrpSnapModule - This is where the Windows Loader starts to resolve imports. For each import descriptor, it parses the PE 
                    structure, checks the export table, binary searching for the imported function, calculating RVA of that,
                    and writes its address to the corresponding caller's process' Import Address Table entry during this function.
3. LdrpDoPostSnapWork - If step 2 succeeds for each imported function, memory protections, TLS initialization, CFG enablement
                        are done in this function.
4. LdrpInitializeNode - If step 3 succeeds, there are module linking functions in this step.
5. LdrpCallTlsInitializers - This is where the TLS callbacks are called before the DllMain function.
6. LdrpCallInitRoutine - This is where the DLLMain itself is called for the first time for the imported DLL. In the original 
                         solution, this function is too late to fix the export table.

Wenn Sie eine ausführbare Datei ausführen, die eine DLL importiert, und der Windows-Loader den erforderlichen Funktionsnamen in der Exporttabelle der DLL nicht finden kann, stoppt er die Ausführung und führt keine Funktionen aus, die nach LdrpSnapModule ausgeführt werden.

Für den Fall des DLL-Sideloadings können wir den aufrufenden Prozess nicht ändern; daher besteht die einzige Chance, die Exporttabelle dynamisch zu reparieren, darin, eine Codeausführungsmöglichkeit zwischen den Funktionen LdrpMapDll und LdrpSnapModule zu finden, da der Loader während der Überprüfungen der Funktion LdrpSnapModule sofort anhält. Ich habe TLS-Callbacks, zweite DLL-Ladungen, weitergeleitete Exporte und einige andere Workarounds ausprobiert, aber keine davon hat mir geholfen, einen solchen Ort zu finden, daher funktioniert diese Methode leider nicht direkt für DLL-Sideloading oder statisch importierte DLLs. Wenn Sie eine Lösung oder einen gangbaren Workaround für dieses Problem entdecken, würde ich mich sehr freuen, dies weiter zu untersuchen – sei es, die Idee zu diskutieren, den Ansatz gemeinsam durchzudenken oder ihn zu implementieren. Jeder Beitrag in diese Richtung wäre sehr willkommen.

Eine mögliche Möglichkeit, diese Methode für DLL-Sideloading-Fälle zu nutzen, besteht darin, die gesamte Arbeit auf zwei DLLs aufzuteilen, nämlich die Proxy-DLL und die Payload-DLL. Die Proxy-DLL trägt den Namen, den die EXE erwartet, und hat sichtbare Exporte, die die statische Importprüfung des Loaders erfüllen, während die Payload-DLL die eigentliche versteckte Funktionalität enthält, fehlende Exporte aufweist und ihre Exporttabelle in DllMain rekonstruiert. Ich halte dies nicht für einen guten Workaround für dieses Problem, daher habe ich es nicht implementiert.

Referenzen

  • DLL-Export mit PE-bear analysieren
  • PE-Export-Adresstabelle

Haftungsausschluss

Nur für autorisierte Sicherheitstests. Missbrauch dieses Tools gegen Systeme ohne ausdrückliche Genehmigung ist illegal.

Tool herunterladen