Beispiele für Debuggerbefehlsprogramme

In den folgenden Abschnitten werden Debuggerbefehlsprogramme beschrieben.

Verwenden des FOREACH-Tokens

Im folgenden Beispiel wird das Foreach-Token verwendet, um nach WORD-Werten von 5a4d zu suchen. Für jeden gefundenen 5a4d-Wert zeigt der Debugger 8 DWORD-Werte an, beginnend bei der Adresse, an der die 5a4d-DWORD gefunden wurde.

0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place L8 } 

Im folgenden Beispiel wird das Foreach-Token verwendet, um nach WORD-Werten von 5a4d zu suchen. Für jeden gefundenen 5a4d-Wert zeigt der Debugger 8 DWORD-Werte an, beginnend 4 Bytes vor der Adresse, an der das 5a4d-DWORD gefunden wurde.

0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place -0x4 L8 } 

Im folgenden Beispiel werden die gleichen Werte angezeigt.

0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc ( place -0x4 ) L8 } 

Hinweis Wenn Sie den Variablennamen im OutCommands-Teil des Befehls verwenden möchten, müssen Sie nach dem Variablennamen ein Leerzeichen hinzufügen. Im vorangestellten Beispiel gibt es beispielsweise ein Leerzeichen zwischen dem Variablenplatz und dem Subtraktionsoperator.

Die Option -[1] zusammen mit dem Befehl s (Arbeitsspeicher durchsuchen) bewirkt, dass die Ausgabe nur die Adressen enthält, die sie findet, nicht die Werte, die an diesen Adressen gefunden werden.

Der folgende Befehl zeigt ausführliche Modulinformationen für alle Module an, die sich im Speicherbereich von 0x77000000 bis 0x7F000000 befinden.

0:000> .foreach (place { lm1m }) { .if ((${place} >= 0x77000000) & (${place} <= 0x7f000000)) { lmva place } } 

Die Option 1m zusammen mit dem Befehl lm (List Loaded Modules) bewirkt, dass die Ausgabe nur die Adressen der Module enthält, nicht die vollständige Beschreibung der Module.

Im vorherigen Beispiel wird das Token ${ } (AliasInterpreter) verwendet, um sicherzustellen, dass Aliase ersetzt werden, auch wenn sie sich neben einem anderen Text befinden. Wenn der Befehl dieses Token nicht enthalten hat, verhindert die öffnende Klammer, die sich neben der Position befindet , den Austausch von Aliasen. Beachten Sie, dass das ${} -Token für die Variablen funktioniert, die in .foreach und für true-Aliase verwendet werden.

Durchlaufen der Prozessliste

Im folgenden Beispiel wird die Prozessliste des Kernelmodus durchlaufen und der name der ausführbaren Datei für jeden Eintrag in der Liste angezeigt.

Dieses Beispiel sollte als Textdatei gespeichert und mit dem Befehl $$>< (Skriptdatei ausführen) ausgeführt werden. Dieser Befehl lädt die gesamte Datei, ersetzt alle Wagenrückläufe durch Semikolons und führt den resultierenden Block aus. Mit diesem Befehl können Sie lesbare Programme schreiben, indem Sie mehrere Zeilen und einen Einzug verwenden, anstatt das gesamte Programm auf eine einzelne Zeile zu drücken.

In diesem Beispiel werden die folgenden Features veranschaulicht:

  • Die Pseudoregister $t 0, $t 1 und $t 2 werden in diesem Programm als Variablen verwendet. Das Programm verwendet auch Aliase namens Procc und $ImageName.

  • Dieses Programm verwendet den MASM-Ausdrucksauswerter. Das Token @@c++( ) wird jedoch einmal angezeigt. Dieses Token bewirkt, dass das Programm den C++-Ausdrucksauswerter verwendet, um den Ausdruck in den Klammern zu analysieren. Diese Verwendung ermöglicht es dem Programm, die C++-Strukturtoken direkt zu verwenden.

  • Das Flag ? wird mit dem Befehl r (Registers) verwendet. Dieses Flag weist dem Pseudoregister $t 2 typisierte Werte zu.

$$  Get process list LIST_ENTRY in $t0.
r $t0 = nt!PsActiveProcessHead

$$  Iterate over all processes in list.
.for (r $t1 = poi(@$t0);
      (@$t1 != 0) & (@$t1 != @$t0);
      r $t1 = poi(@$t1))
{
    r? $t2 = #CONTAINING_RECORD(@$t1, nt!_EPROCESS, ActiveProcessLinks);
    as /x Procc @$t2

 $$  Get image name into $ImageName.
 as /ma $ImageName @@c++(&@$t2->ImageFileName[0])

 .block
    {
        .echo ${$ImageName} at ${Procc}
    }

    ad $ImageName
    ad Procc
}

Gehen auf der LDR_DATA_TABLE_ENTRY Liste

Im folgenden Beispiel wird der Benutzermodus LDR_DATA_TABLE_ENTRY Liste beschrieben und die Basisadresse und der vollständige Pfad der einzelnen Listeneinträge angezeigt.

Wie im vorherigen Beispiel sollte dieses Programm in einer Datei gespeichert und mit dem Befehl $$>< (Skriptdatei ausführen) ausgeführt werden.

In diesem Beispiel werden die folgenden Features veranschaulicht:

  • Dieses Programm verwendet den MASM-Ausdrucksauswerter. Das Token @@c++( ) wird jedoch an zwei Stellen angezeigt. Dieses Token bewirkt, dass das Programm den C++-Ausdrucksauswerter verwendet, um den Ausdruck in den Klammern zu analysieren. Diese Verwendung ermöglicht es dem Programm, C++-Strukturtoken direkt zu verwenden.

  • Das Flag ? wird mit dem Befehl r (Registers) verwendet. Dieses Flag weist den Pseudoregistern $t 0 und $t 1 typisierte Werte zu. Im Textkörper der Schleife weist $t 1 den Typ ntdll!_LDR_DATA_TABLE_ENTRY\*auf, sodass das Programm direkte Memberverweise erstellen kann.

  • Die benutzerdefinierten Aliase $Base und $Mod werden in diesem Programm verwendet. Die Dollarzeichen verringern die Möglichkeit, dass diese Aliase zuvor in der aktuellen Debuggersitzung verwendet wurden. Die Dollarzeichen sind nicht erforderlich. Das Token ${/v: } interpretiert den Alias wörtlich und verhindert, dass er ersetzt wird, wenn er vor der Ausführung des Skripts definiert wurde. Sie können dieses Token auch zusammen mit einem beliebigen Block verwenden, um zu verhindern, dass Aliasdefinitionen vor dem Block verwendet werden.

  • Das Blocktoken wird verwendet, um einen zusätzlichen Aliasersatzschritt hinzuzufügen. Die Aliasersetzung erfolgt einmal für das gesamte Skript, wenn es geladen wird, und einmal, wenn jeder Block eingegeben wird. Ohne das Blocktoken und seine Klammern empfängt der Echo-Befehl nicht die Werte der $Mod und $Base Aliase, die in den vorherigen Zeilen zugewiesen sind.

$$ Get module list LIST_ENTRY in $t0.
r? $t0 = &@$peb->Ldr->InLoadOrderModuleList
 
$$ Iterate over all modules in list.
.for (r? $t1 = *(ntdll!_LDR_DATA_TABLE_ENTRY**)@$t0;
 (@$t1 != 0) & (@$t1 != @$t0);
      r? $t1 = (ntdll!_LDR_DATA_TABLE_ENTRY*)@$t1->InLoadOrderLinks.Flink)
{
    $$ Get base address in $Base.
 as /x ${/v:$Base} @@c++(@$t1->DllBase)
 
 $$ Get full name into $Mod.
 as /msu ${/v:$Mod} @@c++(&@$t1->FullDllName)
 
 .block
    {
        .echo ${$Mod} at ${$Base}
    }
 
    ad ${/v:$Base}
    ad ${/v:$Mod}
}