Diese Veröffentlichung konzentriert sich auf synthetische Module und Symbole der Windows-Debugging-Engine (Debugger-Engine). Das heißt, über Entitäten, die dem Debugger künstlich hinzugefügt werden können, um Speicheradressen einzufärben.

Synthetische Module
Im Allgemeinen ist ein Modul im Rahmen einer Debugger-Engine ein bestimmter kontinuierlicher Bereich des virtuellen Speichers: die Basisadresse des Moduls (Adresse des ersten Bytes der projizierten Datei) und seine Größe. Für jede Art von Debugging (Live-Debugging / Dump-Analyse, Benutzermodus / Kernel-Modus usw.) verfügt der Debugger über einen eigenen Mechanismus zum Lesen und Aktualisieren der Liste der geladenen Module. Der einfachste Weg, die Aktualisierung der Liste der geladenen Module zu erzwingen, ist der Befehl .reload mit der Option / s .
Wenn wir zum Beispiel über das Live-Debugging des Benutzermodus sprechen, wird die Liste der geladenen Module anhand von drei Hauptlisten des Loaders erstellt: einer Liste der Modulladereihenfolge (InLoadOrderModuleList), einer Liste der Module im Speicher (InMemoryOrderModuleList) und einer Initialisierungsprioritätsliste (InInitializationOrderModuleL). Einerseits hindert uns ( fast ) nichts daran, beliebige Daten (z. B. aus einer PE- Datei auf der Festplatte) zu erfassen und zur Ausführung mit unseren eigenen Händen im Speicher zu markieren. Andererseits sind Techniken zum Entfernen von DLLs, die mit regulären Mitteln geladen wurden, aus den obigen drei Loader-Listen (Ausblenden des Moduls) seit langem bekannt.
In beiden Fällen ist es beim Debuggen dieser Situation hilfreich, den Bereich des ausgeblendeten Moduls zu markieren. Hierfür eignen sich synthetische Module. Als praktisches Experiment können Sie WinDbg einfach dazu bringen, das geladene Modul mit demselben Befehl .reload, jedoch mit der Option / u, aus seiner internen Liste zu löschen .
Außerdem werde ich in der Qualität der aufgelisteten Einträge das übliche Debugging des Benutzermodusprozesses (notepad.exe) verwenden. Merken Sie sich zunächst die Basisadresse des ntdll-Moduls (0x07ffa8a160000) und berechnen Sie dessen Größe (0x01e1000):
0:007> lm m ntdll Browse full module list start end module name 00007ffa`8a160000 00007ffa`8a341000 ntdll 0:007> ? 00007ffa`8a341000-00007ffa`8a160000 Evaluate expression: 1970176 = 00000000`001e1000
Betrachten Sie eine Liste der einfachen RtlFreeSid- Funktion aus dem ntdll-Modul, die die RtlFreeHeap-Funktion aus diesem Modul aufruft und gleichzeitig die Adressen der RtlFreeSid- und RtlFreeHeap-Zeichen (0x7ffa8a1cbc20 und 0x7ffa8a176df0) speichert:
0:007> uf ntdll!RtlFreeSid ntdll!RtlFreeSid: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll!RtlFreeHeap (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
Entsprechend der Auflistung ist es auch einfach, die Größe der Funktion ntdll! RtlFreeSid zu berechnen:
0:007> ? 00007ffa`8a1cbc51 - 0x07ffa8a1cbc20 Evaluate expression: 49 = 00000000`00000031
Die Größe der Funktion ntdll! RtlFreeHeap ist für unser Experiment nicht wichtig. Der Einfachheit halber können Sie sie auf ein Byte setzen.
Simulieren Sie nun das Ausblenden des ntdll-Moduls:
0:007> .reload /u ntdll Unloaded ntdll
Das Feld dieser Arbeit mit der Adresse der Funktion ntdll! RtlFreeSid im Debugger ist nicht so informativ (und Sie können bereits über die virtuelle Adresse auf den Beginn der Funktion zugreifen):
0:007> uf 00007ffa`8a1cbc20 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call 00007ffa`8a176df0 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
Um ein synthetisches Modul hinzuzufügen, müssen Sie die Programmschnittstelle IDebugSymbols3 :: AddSyntheticModule aufrufen . Es gibt einfach keine eingebauten Befehle, mit denen dieser Aufruf erfolgen könnte (soweit ich weiß). Mikhail I. Izmestev schlug vor, dass es einen ähnlichen Mechanismus gibt - das gleiche .reload , jedoch mit den Parametern Name, Adresse und Größe: "Modul = Adresse, Größe" (und möglicherweise auf synthetischen Modulen implementiert).
.reload ntdll = 00007ff8`470e1000,001e1000 0:007> .reload ntdll=00007ff8`470e1000,001e1000 *** WARNING: Unable to verify timestamp for ntdll *** ERROR: Module load completed but symbols could not be loaded for ntdll 0:007> uf 00007ff8`4714bc20 ntdll+0x6ac20: 00007ff8`4714bc20 4053 push rbx 00007ff8`4714bc22 4883ec20 sub rsp,20h 00007ff8`4714bc26 488bd9 mov rbx,rcx 00007ff8`4714bc29 33d2 xor edx,edx 00007ff8`4714bc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ff8`4714bc34 4c8bc3 mov r8,rbx 00007ff8`4714bc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ff8`4714bc3b e8b0b1faff call ntdll+0x15df0 (00007ff8`470f6df0) 00007ff8`4714bc40 33c9 xor ecx,ecx 00007ff8`4714bc42 85c0 test eax,eax 00007ff8`4714bc44 480f45d9 cmovne rbx,rcx 00007ff8`4714bc48 488bc3 mov rax,rbx 00007ff8`4714bc4b 4883c420 add rsp,20h 00007ff8`4714bc4f 5b pop rbx 00007ff8`4714bc50 c3 ret
Nun, wir werden die Debugger-Erweiterung verwenden, und hier wird pykd zur Rettung kommen
. In der neuesten Version (zum Zeitpunkt des Schreibens) 0.3.4.3 wurden Funktionen zum Verwalten synthetischer Module hinzugefügt: addSyntheticModule (...) (in unserem Fall erforderlich) und removeSyntheticModule (...).
Unter Verwendung der zuvor gespeicherten Basisadresse und Modulgröße fügen wir dem Debugger Informationen zum versteckten ntdll-Modul hinzu (im Fehlerfall wird eine Ausnahme ausgelöst, daher ist die stille Ausführung ein Zeichen für Erfolg, Druckwarnungen können ignoriert werden):
0:007> !py Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> addSyntheticModule(0x07ffa8a160000, 0x01e1000, 'ntdll') *** WARNING: Unable to verify timestamp for ntdll >>> exit()
Jetzt ist die Disassembler-Liste etwas informativer geworden:
0:007> uf 00007ffa`8a1cbc20 ntdll+0x6bc20: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll+0x16df0 (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
Genauer gesagt sehen wir, dass die Funktion innerhalb des ntdll-Moduls eine andere Funktion innerhalb desselben Moduls aufruft.
Synthetische Symbole
Das Auflisten ist nach dem Hinzufügen eines synthetischen Moduls informativer geworden, aber immer noch nicht so beredt wie das ursprüngliche. Es fehlen Zeichen (in unserem Fall die Namen der Funktionen RtlFreeSid und RtlFreeHeap). Um dies zu beheben, ist erneut ein Aufruf einer anderen Programmschnittstelle erforderlich - IDebugSymbols3 :: AddSyntheticSymbol . Wieder Pykd
bereit, uns dabei zu helfen:
0:007> !py Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> addSyntheticSymbol(0x07ffa8a1cbc20, 0x31, 'RtlFreeSid') <pykd.syntheticSymbol object at 0x0000014D47699518> >>> addSyntheticSymbol(0x07ffa8a176df0, 1, 'RtlFreeHeap') <pykd.syntheticSymbol object at 0x0000014D476994A8> >>> exit()
Das Ergebnis ist dem bei Verwendung der Symbole aus der ntdll-pdb-Datei sehr ähnlich:
0:007> uf 00007ffa`8a1cbc20 ntdll!RtlFreeSid: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll!RtlFreeHeap (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
Merkmale synthetischer Einheiten
Es ist erwähnenswert, dass die Erstellung synthetischer Symbole in allen vorhandenen Modulen und nicht nur in synthetischen Symbolen zulässig ist. Das heißt, Sie können Symbole sowohl zu Modulen mit zugänglichen PDF-Dateien als auch zu Modulen hinzufügen, für die wir keine Dateien mit Debugging-Informationen haben. Sie können jedoch keine Zeichen außerhalb der Module erstellen. Das heißt, um eine beliebige Speicheradresse außerhalb der Grenzen vorhandener Module zu markieren, müssen Sie zuerst ein umhüllendes synthetisches Modul erstellen und dann (falls erforderlich, da der Modulname zum Färben völlig ausreicht) ein synthetisches Symbol darin erstellen.
Erwähnenswert ist auch, dass synthetische Module und Symbole mit einer unachtsamen Handbewegung entfernt werden können:
- Durch erneutes Laden der Debug-Symbole des Moduls werden alle synthetischen Symbole dieses Moduls gelöscht.
- Durch erneutes Laden aller Module werden alle synthetischen Module entfernt.
Obwohl die Verwendung von pykd in den allermeisten Fällen praktisch ist (insbesondere in Anbetracht des Vorhandenseins eines Bootstarppers ), kann es manchmal vorkommen, dass Sie erhebliche Anstrengungen unternehmen müssen, um pykd zu verwenden. Zum Beispiel musste ich einmal von dem Host-Computer debuggen, auf dem Windows XP funktionierte. Wie sich herausstellte, unterstützt pykd XP seit einiger Zeit nicht mehr und ich brauchte synthetische Zeichen und Module. Es schien mir, dass es für diese Aufgabe einfacher ist, eine separate kleine Erweiterung zusammenzustellen, die einen engen Bereich notwendiger Aufgaben löst, als die vollständige XP-Unterstützung für pykd wiederherzustellen. Als Ergebnis wurde ein separates Projekt erstellt ! Synexts .
Dies ist eine einfache Erweiterung, für die dem Benutzer zwei Exporte zur Verfügung stehen:
- ! synexts.addsymbol - Erstellt ein synthetisches Symbol in einem vorhandenen Modul.
- ! synexts.addmodule - Erstellt ein synthetisches Modul in der internen Liste der Debugging-Engine.
Zur Demonstration simulieren wir das erneute Ausblenden des ntdll-Moduls:
0:007> .reload /u ntdll Unloaded ntdll 0:007> uf 00007ffa`8a1cbc20 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call 00007ffa`8a176df0 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
Auch hier stellen wir das Wissen über das Modul und die Symbole in Form von synthetischen Entitäten wieder her, verwenden jedoch bereits die Erweiterung! Synexts:
0:007> !synexts.addmodule ntdll C:\Windows\System32\ntdll.dll 00007ffa`8a160000 0x01e1000 *** WARNING: Unable to verify timestamp for C:\Windows\System32\ntdll.dll Synthetic module successfully added 0:007> !synexts.addsymbol RtlFreeSid 00007ffa`8a1cbc20 31 Synthetic symbol successfully added 0:007> !synexts.addsymbol RtlFreeHeap 00007ffa`8a176df0 1 Synthetic symbol successfully added
Es wird davon ausgegangen, dass Sie die kompilierte Bibliothek synexts.dll (entsprechend der von WinDbg verwendeten Bittiefe) bereits in das Debugger-Verzeichnis Winext kopiert haben:
0:007> .chain Extension DLL search Path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\WINXP;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\arcade;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\pri;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64;<…> Extension DLL chain: pykd.pyd: image 0.3.4.3, API 1.0.0, built Thu Jan 10 19:56:25 2019 [path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\pykd.pyd] synexts: API 1.0.0, built Fri Jan 18 17:38:17 2019 [path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\synexts.dll] <…>
Und wieder sehen wir das Ergebnis des Hinzufügens synthetischer Zeichen zum synthetischen Modul:
0:007> uf 00007ffa`8a1cbc20 ntdll!RtlFreeSid: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll!RtlFreeHeap (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret