Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
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
LdrShuffle — Codeausführungs-/Injektionstechnik durch Manipulation der DLL-PEB-Modulstruktur | Kitploit
Tools/GitHubGitHub/rwxstoned/ldrshuffle
Code-AnalyseExploitationLaterale BewegungShellcodePost-ExploitationPenetrationstestsRed TeamingPayload-EntwicklungBinary-Exploitation
GitHubrwxstoned/ldrshuffle

LdrShuffle

Codeausführungs-/Injektionstechnik durch Manipulation der DLL-PEB-Modulstruktur

2894410vor 1 JahrVon 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
Repository anzeigen

LdrShuffle

Verdeckte Codeausführung durch Modifikation des EntryPoint geladener Module zur Laufzeit.

Zusammenfassung

Windows-Prozesse haben zur Laufzeit verschiedene Module geladen. Jedes dieser Module definiert eine DllMain()-Funktion, die bei der Erstellung bzw. Zerstörung von Prozessen oder Threads aufgerufen wird (vier mögliche Szenarien).

Um diese Funktionen während der Lebensdauer des Prozesses ordnungsgemäß aufzurufen, beziehen sich die Windows-Loader-Funktionen (ntdll!Ldrp*) auf eine Liste von Einträgen, die für jedes Modul wichtige Parameter (einschließlich des EntryPoint-Felds) enthalten.

Indem wir diesen EntryPoint einer DLL überschreiben, stellen wir sicher, dass die Codeausführung an eine von uns gewählte Stelle umgeleitet wird.

Anwendungsfälle

Dies kann sowohl als Codeausführungs-Primitive als auch für API-Proxying verwendet werden, also um bestimmte APIs mit einem unverdächtigen Callstack auszuführen, da sie von legitimen Windows-Funktionen aufgerufen werden.

Dies kann auch verwendet werden, um die Ausführung in einem entfernten Prozess auszulösen, sofern der Angreifer in der Lage ist, Speicher in diesem Zielprozess zu lesen und zu schreiben. Ähnlich wie bei der Threadless Injection ermöglicht dies die Ausführung von Code in einem Prozess, ohne klassische APIs zur Ausführung aufzurufen (CreateRemoteThread, QueueUserAPC).

Herausforderungen

Das Laden/Entladen von Modulen innerhalb eines Windows-Prozesses ist ein komplexes Thema, das viele Herausforderungen mit sich bringt: potenzielle Instabilität, Race Conditions und Abstürze. Eine bekannte Hürde bei der Ausführung von Code innerhalb einer DllMain()-Funktion liegt beispielsweise darin, dass eine Loader Lock aktiv ist und wir in einem Thread laufen, der nicht vollständig eingerichtet wurde oder sich gerade im Prozess der Beendigung befindet.

Deshalb habe ich versucht, ordentlich zu dokumentieren, was möglich ist und was nicht. Während beispielsweise die meisten üblichen API-Aufrufe ausgeführt werden können, bringt der Betrieb eines vollwertigen Beacons bestimmte Anforderungen mit sich, die einen separaten Prozess erfordern, um Deadlocks durch die in wininet.dll oder winhttp.dll verwendeten Funktionen zu vermeiden.

Implementierung

Grundlagen des DLL-Ladens in Windows

Jeder Prozess verwaltet zur Laufzeit eine Liste von _LDR_DATA_TABLE_ENTRY-Strukturen. Diese Strukturen enthalten viele Details, die für die DLL relevant sind, wie etwa ihren EntryPoint (den wir überschreiben werden), ihren Namen, bestimmte Hashes, Zeitstempel, verschiedene Flags usw. Einige dieser Strukturen sind dokumentiert, andere nicht.

Diese können mit dem folgenden WinDbg-Befehl visualisiert werden:

dt nt!_LDR_DATA_TABLE_ENTRY 0xdeadbeef

0:006> dt nt!_LDR_DATA_TABLE_ENTRY 0x18d1c4838c0
ntdll!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x0000018d`1c485de0 - 0x0000018d`1c4832b0 ]
   +0x010 InMemoryOrderLinks : _LIST_ENTRY [ 0x0000018d`1c485df0 - 0x0000018d`1c4832c0 ]
   +0x020 InInitializationOrderLinks : _LIST_ENTRY [ 0x0000018d`1c4832d0 - 0x0000018d`1c482c80 ]
   +0x030 DllBase          : 0x00007ffe`e87e0000 Void
   +0x038 EntryPoint       : 0x00007ffe`e8838d00 Void
   +0x040 SizeOfImage      : 0x2fe000
   +0x048 FullDllName      : _UNICODE_STRING "C:\WINDOWS\System32\KERNELBASE.dll"
   +0x058 BaseDllName      : _UNICODE_STRING "KERNELBASE.dll"
   +0x068 FlagGroup        : [4]  "???"
   +0x068 Flags            : 0x8a2cc
   +0x068 PackagedBinary   : 0y0
   +0x068 MarkedForRemoval : 0y0
   +0x068 ImageDll         : 0y1
(...)
   +0x0e0 MappingInfoIndexNode : _RTL_BALANCED_NODE
   +0x0f8 OriginalBase     : 0x00007ffe`e87e0000
   +0x100 LoadTime         : _LARGE_INTEGER 0x01db5f86`2fa735fc
   +0x108 BaseNameHashValue : 0x235bec4
   +0x10c LoadReason       : 0 ( LoadReasonStaticDependency )
   +0x110 ImplicitPathOptions : 0x4000
   +0x114 ReferenceCount   : 1
   +0x118 DependentLoadFlags : 0x800
   +0x11c SigningLevel     : 0 ''

Die Adresse der Struktur kann ermittelt werden, indem man eine doppelt verknüpfte Struktur durchläuft, auf die in der Prozess-PEB innerhalb einer PEB_LDR_DATA-Struktur verwiesen wird.

dt nt!_PEB_LDR_DATA 0xb4b4c3c3

Beachten Sie das DontCallForThreads-Flag. Wie der Name schon sagt, wird das Betriebssystem bei gesetztem Flag die DllMain() dieses Moduls für Thread-Ereignisse (d.h. DLL_THREAD_ATTACH oder DLL_THREAD_DETACH) NICHT aufrufen.

Beim Erstellen einer DLL muss die folgende Vorlage befolgt werden, um mit den OS-Loader-Funktionen zusammenzuarbeiten:

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpvReserved )  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason ) 
    { 
        case DLL_PROCESS_ATTACH:
         // Initialize once for each new process.
         // Return FALSE to fail DLL load.
            break;

        case DLL_THREAD_ATTACH:
         // Do thread-specific initialization.
            break;

        case DLL_THREAD_DETACH:
         // Do thread-specific cleanup.
            break;

        case DLL_PROCESS_DETACH:
        
            if (lpvReserved != nullptr)
            {
                break; // do not do cleanup if process termination scenario
            }
            
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

Technische Details zur Implementierung

Einrichten eines API-Aufrufs

Wie oben beschrieben, überschreibt die Technik vorübergehend den EntryPoint einer DLL, um die Ausführung umzuleiten. Da wir keine Kontrolle über mehr als die Umleitung der Ausführung haben, müssen auf der Seite einige Vorkehrungen getroffen werden, um zu handhaben, was wir ausführen möchten, mit welchen Argumenten und wie wir den Rückgabewert zurückerhalten.

Dies geschieht durch das Definieren einer DATA_T-Struktur auf dem Heap, so dass sie während der verschiedenen Schritte zugänglich bleibt.

Diese Struktur ist wie folgt definiert:

typedef struct _DATA_T {
    // LDR structures manipulation
    ULONG_PTR   runner;             // malicious entry point to execute
    ULONG_PTR   bakOriginalBase;    // backup of overwritten OriginalBase
    ULONG_PTR   bakEntryPoint;      // backup of overwritten EntryPoint
    HANDLE      event;              // event signalling that the Runner has executed
    // function call
    ULONG_PTR   ret;                // return value
    DWORD       createThread;       // run this API call in a new thread (required for wininet/winhttp)
    ULONG_PTR   function;           // Windows API to call
    DWORD       dwArgs;             // number of args
    ULONG_PTR   args[MAX_ARGS];     // array of args
} DATA_T, * PDATA_T;

Um eine API-Ausführung einzurichten, müssen diese Felder vorbereitet werden. Der ret-Wert ist derjenige, der nach der Ausführung den Rückgabewert aufnimmt. Das event wird zur Synchronisation verwendet, um zu signalisieren, dass die Ausführung abgeschlossen wurde. Alle anderen Felder sind Eingaben, die festlegen, welche API aufgerufen werden soll (function), mit welchen Argumenten (dwArgs und args[]), die Adresse der Runner()-Funktion, auf die die Ausführung umgeleitet wird, sowie Sicherungen der überschriebenen ursprünglichen DLL-Einträge (bakOriginalBase und bakEntryPoint).

Das Feld createThread muss für diejenigen komplexen API-Funktionen auf 1 gesetzt werden, die in einer DllMain()-Umgebung nicht gut laufen (dazu gehören viele wininet- und winhttp-Bibliotheken).

Hier ist ein Beispiel für die Einrichtung eines Aufrufs von MessageBoxA(), wie im PoC sichtbar:

Tool herunterladen