Adress- und Adressbereichssyntax
Es gibt mehrere Möglichkeiten, Adressen im Debugger anzugeben.
Adressen sind normalerweise virtuelle Adressen, es sei denn, die Dokumentation weist ausdrücklich auf eine andere Art von Adresse hin. Im Benutzermodus interpretiert der Debugger virtuelle Adressen entsprechend dem Seitenverzeichnis des aktuellen Prozesses. Im Kernelmodus interpretiert der Debugger virtuelle Adressen entsprechend dem Seitenverzeichnis des Prozesses, den der Prozesskontext angibt. Sie können den Adresskontext im Benutzermodus auch direkt festlegen. Weitere Informationen zum Adresskontext im Benutzermodus finden Sie unter .context (Festlegen User-Mode Adresskontext).
In MASM-Ausdrücken können Sie den poi-Operator verwenden, um einen beliebigen Zeiger zu dereferenzieren. Wenn beispielsweise der Zeiger auf die Adresse 0x0000008e'ed57b108 auf den Adressspeicherort 0x805287637256 verweist, sind die folgenden beiden Befehle gleichwertig.
0:000> dd 805287637256
0:000> dd poi(000000bb`7ee23108)
Beispiel für die Anzeigespeicheradresse
Um ein Beispiel für die Verwendung von poi anzuzeigen, bestimmen Sie den Offset für currentLocale des Threadumgebungsblocks (TEB). Verwenden Sie den Dx-Befehl, um @$teb anzuzeigen. Dies ist ein Beispiel für Pseudoregister, die allgemeine Adressen enthalten, z. B. den aktuellen Speicherort des Programmzählers.
0:000> dx @$teb
@$teb : 0x1483181000 [Type: _TEB *]
...
[+0x108] CurrentLocale : 0x409 [Type: unsigned long]
CurrentLocale ist vom Anfang des TEB +0x108. Ermitteln Sie als Nächstes die Speicheradresse dieses Speicherorts.
0:000> ? @$teb + 0x108
Evaluate expression: 613867303176 = 0000008e`ed57b108
Verwenden Sie poi, um diese Adresse zu dereferenzieren, um festzustellen, dass sie den CurrentLocale-Wert von 0x409 enthält.
0:000> ? poi(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409
In C++-Debuggerausdrücken verhalten sich Zeiger wie Zeiger in C++. Zahlen werden jedoch als ganze Zahlen interpretiert. Wenn Sie eine tatsächliche Zahl zurückstellen müssen, müssen Sie sie möglicherweise zuerst umwandeln, wie im folgenden Beispiel gezeigt.
Um dies zu versuchen, verwenden Sie .expr , um die Ausdrucksauswertung auf C++ festzulegen.
0:000> .expr /s C++
Current expression evaluator: C++ - C++ source expressions
Wenn der Ausdrucksauswerter auf C++ festgelegt ist, können wir die Umwandlung mit long durchführen.
0:000> d *((long*)0x00000014`83181108 )
00000000`00000409 ???????? ???????? ???????? ????????
Weitere Informationen zum Umwandeln numerischer Werte finden Sie unter C++-Zahlen und -Operatoren.
Wenn die Ausdrucksauswertung auf c++ festgelegt ist, können wir den Poi-Zeiger mit @@masm() umschließen, damit nur dieser Teil des Ausdrucks von der MASM-Ausdrucksauswertung ausgewertet wird.
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions
0:000> ? @@masm(poi(00000078`267d7108))
Evaluate expression: 1033 = 00000000`00000409
Weitere Informationen zu den beiden Ausdrucksauswertungen finden Sie unter Auswerten von Ausdrücken.
Sie können auch eine Adresse in einer Anwendung angeben, indem Sie den ursprünglichen Quelldateinamen und die Zeilennummer angeben. Weitere Informationen zum Angeben dieser Informationen finden Sie unter Quellzeilensyntax.
Adressbereiche
Sie können einen Adressbereich anhand eines Adresspaars oder einer Adress- und Objektanzahl angeben.
Um einen Bereich anhand eines Adresspaars anzugeben, geben Sie die Anfangsadresse und die Endadresse an. Das folgende Beispiel ist beispielsweise ein Bereich von 8 Bytes, beginnend bei der Adresse 0x00001000.
0x00001000 0x00001007
Um einen Adressbereich anhand einer Adress- und Objektanzahl anzugeben, geben Sie ein Adressargument, den Buchstaben L (Groß- oder Kleinbuchstaben) und ein Wertargument an. Die Adresse gibt die Startadresse an. Der -Wert gibt die Anzahl der Objekte an, die untersucht oder angezeigt werden sollen. Die Größe des Objekts hängt vom Befehl ab. Wenn die Objektgröße beispielsweise 1 Byte beträgt, ist das folgende Beispiel ein Bereich von 8 Byte, beginnend bei der Adresse 0x00001000.
0x00001000 L8
Wenn die Objektgröße jedoch ein doppeltes Wort (32 Bits oder 4 Bytes) ist, weisen die folgenden beiden Bereiche jeweils einen Bereich von 8 Byte auf.
0x00001000 0x00001007
0x00001000 L2
L-Größenbereichsspezifizierer
Es gibt zwei weitere Möglichkeiten, den Wert anzugeben (der L-Größenbereichsspezifizierer):
L?Größe (mit Fragezeichen) bedeutet dasselbe wie L-Größe, mit der Ausnahme, dass L?Die Größe entfernt den automatischen Bereichsgrenzwert des Debuggers. In der Regel gilt ein Bereichslimit von 256 MB, da größere Bereiche typografische Fehler sind. Wenn Sie einen Bereich angeben möchten, der größer als 256 MB ist, müssen Sie das L? Größensyntax.
L-Size (mit einem Bindestrich) gibt einen Längenbereich Größe an, der bei der angegebenen Adresse endet. Beispielsweise gibt 80000000 L20 den Bereich von 0x80000000 bis 0x8000001F an, und 800000000 L-20 gibt den Bereich von 0x7FFFFFE0 bis 0x7FFFFFFF an.
Einige Befehle, die nach Adressbereichen fragen, akzeptieren eine einzelne Adresse als Argument. In diesem Fall verwendet der Befehl eine Standardobjektanzahl, um die Größe des Bereichs zu berechnen. In der Regel lassen Befehle, für die der Adressbereich der endgültige Parameter ist, diese Syntax zu. Die genaue Syntax und die Standardbereichsgröße für jeden Befehl finden Sie in den Referenzthemen für jeden Befehl.
Beispiel für den Suchspeicherbereich
Zunächst ermitteln wir die Adresse des Zeigerregisters für die Rip-Anweisung mithilfe der MASM-Ausdrucksauswertung.
0:000> ? @rip
Evaluate expression: 140720561719153 = 00007ffc`0f180771
Dann suchen wir ab 00007ffc'0f180771 nach 100000, indem wir den Befehl s (Arbeitsspeicher durchsuchen) verwenden . Wir geben den zu durchsuchenden Bereich mithilfe von L100000 an.
0:000> s -a 00007ffc`0f180771 L100000 "ntdll"
00007ffc`0f1d48fa 6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00 ntdll\ldrinit.c.
00007ffc`0f1d49c2 6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00 ntdll\ldrmap.c..
00007ffc`0f1d4ab2 6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63 ntdll\ldrredirec
00007ffc`0f1d4ad2 6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00 ntdll\ldrsnap.c.
...
Wir können auch den gleichen Bereich wie diesen angeben, indem wir zwei Speicheradressen verwenden.
0:000> s -a 0x00007ffc`0f180771 0x00007ffc`0f280771 "ntdll"
00007ffc`0f1d48fa 6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00 ntdll\ldrinit.c.
00007ffc`0f1d49c2 6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00 ntdll\ldrmap.c..
00007ffc`0f1d4ab2 6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63 ntdll\ldrredirec
00007ffc`0f1d4ad2 6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00 ntdll\ldrsnap.c.
...
Schließlich können wir mithilfe des L-length-Parameters rückwärts im Speicherbereich suchen.
0:000> s -a 00007ffc`0f1d4ad2 L-100000 "ntdll"
00007ffc`0f1d48fa 6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00 ntdll\ldrinit.c.
00007ffc`0f1d49c2 6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00 ntdll\ldrmap.c..
00007ffc`0f1d4ab2 6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63 ntdll\ldrredirec
Beispiel für nichtassemierbaren Arbeitsspeicher
In diesem Beispiel werden der Befehl u (unassemble) und der L-Parameter verwendet, um drei Byte Code aufzuheben.
0:000> u 00007ffc`0f1d48fa L3
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e outs dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464 je ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c ins byte ptr [rdi],dx
Oder geben Sie einen Speicherbereich von drei Byte an, der wie folgt aufzuheben ist.
0:000> u 00007ffc`0f1d48fa 00007ffc`0f1d48fd
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e outs dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464 je ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c ins byte ptr [rdi],dx
Adressmodi und Segmentunterstützung
Auf x86-basierten Plattformen unterstützen CDB und KD die folgenden Adressierungsmodi. Diese Modi unterscheiden sich durch ihre Präfixe.
Präfix | Name | Adresstypen |
---|---|---|
% | Wohnung | 32-Bit-Adressen (auch 16-Bit-Selektoren, die auf 32-Bit-Segmente verweisen) und 64-Bit-Adressen auf 64-Bit-Systemen. |
& | virtual 86 | Adressen im realen Modus. Nur x86-basiert. |
# | plain | Adressen im realen Modus. Nur x86-basiert. |
Der Unterschied zwischen dem einfachen und dem virtuellen 86-Modus besteht darin, dass eine einfache 16-Bit-Adresse den Segmentwert als Selektor verwendet und den Segmentdeskriptor sucht. Eine virtuelle 86-Adresse verwendet jedoch keine Selektoren und wird stattdessen direkt den unteren 1 MB zugeordnet.
Wenn Sie über einen Adressierungsmodus auf arbeitsspeicher zugreifen, der nicht der aktuelle Standardmodus ist, können Sie die Adressmoduspräfixe verwenden, um den aktuellen Adressmodus außer Kraft zu setzen.
Adressargumente
Adressargumente geben den Speicherort von Variablen und Funktionen an. In der folgenden Tabelle werden die Syntax und die Bedeutung der verschiedenen Adressen erläutert, die Sie in CDB und KD verwenden können.
Syntax | Bedeutung |
---|---|
offset |
Die absolute Adresse im virtuellen Speicher mit einem Typ, der dem aktuellen Ausführungsmodus entspricht. Wenn der aktuelle Ausführungsmodus beispielsweise 16 Bit ist, beträgt der Offset 16 Bit. Wenn der Ausführungsmodus 32-Bit segmentiert ist, ist der Offset 32-Bit-segmentiert. |
&[[ segment:]] offset |
Die tatsächliche Adresse. x86-basiert und x64-basiert. |
%segment:[[ offset]] |
Eine segmentierte 32-Bit- oder 64-Bit-Adresse. x86-basiert und x64-basiert. |
%[[ Offset]] |
Eine absolute Adresse (32-Bit oder 64-Bit) im virtuellen Speicherbereich. x86-basiert und x64-basiert. |
name[[ +|− ]] offset |
Eine flache 32-Bit- oder 64-Bit-Adresse. name kann ein beliebiges Symbol sein. offset gibt den Offset an. Dieser Offset kann unabhängig vom Adressmodus sein, der vom Präfix angegeben wird. Kein Präfix gibt eine Standardmodusadresse an. Sie können den Offset als positiver (+) oder negativer (−) Wert angeben. |
Verwenden Sie den Befehl dg (Display Selector), um Segmentdeskriptorinformationen anzuzeigen.
Weitere Informationen
Verwenden Sie den Befehl !address , um Informationen zum Arbeitsspeicher anzuzeigen.
Verwenden Sie zum Durchsuchen des Arbeitsspeichers den Befehl s (Arbeitsspeicher durchsuchen).
Verwenden Sie zum Anzeigen des Speicherinhalts den Befehl d, da, db, dc, dd, dD, df, dp, dq, du, dw (Speicher anzeigen).
Informationen zum Anzeigen und Bearbeiten von Arbeitsspeicher mithilfe eines Speicherfensters finden Sie unter Verwenden eines Speicherfensters.
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für