以降のセクションでは、デバッガー コマンド プログラムについて説明します。
.foreach トークンの使用
次の例では、.foreach トークンを使用して、5a4d の WORD 値を検索します。 見つかった 5a4d 値ごとに、5a4d DWORD が見つかったアドレスから始まる 8 つの DWORD 値がデバッガーに表示されます。
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place L8 }
次の例では、.foreach トークンを使用して、5a4d の WORD 値を検索します。 見つかった 5a4d 値ごとに、デバッガーは 8 つの DWORD 値を表示し、5a4d DWORD が見つかったアドレスの前の 4 バイトを開始します。
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place -0x4 L8 }
次の例では、同じ値が表示されます。
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc ( place -0x4 ) L8 }
注 コマンドの OutCommands 部分で変数名を操作する場合は、変数名の後にスペースを追加する必要があります。 たとえば、前置の例では、変数 place と減算演算子の間にスペースがあります。
-[1] オプションと (Search Memory) コマンドを指定すると、その出力には、それらのアドレスで見つかった値ではなく、検索したアドレスのみが含まれます。
次のコマンドは、0x77000000から0x7F000000までのメモリ範囲内にあるすべてのモジュールの詳細なモジュール情報を表示します。
0:000> .foreach (place { lm1m }) { .if ((${place} >= 0x77000000) & (${place} <= 0x7f000000)) { lmva place } }
1m オプションと lm (List Loaded Modules) コマンドを使用すると、モジュールの完全な説明ではなく、モジュールのアドレスのみが出力に含まれます。
前の例では、${ } (エイリアス インタープリター) トークンを使用して、エイリアスが他のテキストの横にある場合でも、エイリアスが置き換えられます。 コマンドにこのトークンが含まれていない場合、place の横にある左かっこによってエイリアスの置換が禁止されます。 ${} トークンは、.foreach で使用される変数と、真のエイリアスで動作します。
プロセス リストのウォーク
次の例では、カーネル モードプロセスの一覧について説明し、リスト内の各エントリの実行可能ファイル名を表示します。
この例はテキスト ファイルとして格納し、$$>< (スクリプト ファイルの実行) コマンドを使用して実行する必要があります。 このコマンドは、ファイル全体を読み込み、すべての復帰をセミコロンに置き換えて、結果のブロックを実行します。 このコマンドを使用すると、プログラム全体を 1 行に絞る代わりに、複数の行とインデントを使用して読み取り可能なプログラムを記述できます。
この例では、次の機能を示します。
このプログラムでは、$t 0、$t 1、および $t 2 擬似レジスタが変数として使用されます。 このプログラムでは、Procc と $ImageName という名前のエイリアスも使用されます。
このプログラムでは、MASM 式エバリュエーターを使用します。 ただし、@@c++( ) トークンは 1 回表示されます。 このトークンにより、プログラムは C++ 式エバリュエーターを使用してかっこ内の式を解析します。 この使用法により、プログラムは C++ 構造体トークンを直接使用できます。
? フラグは、r (Registers) コマンドで使用されます。 このフラグは、擬似レジスタ $t 2に型指定された値を割り当てます。
$$ 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
}
LDR_DATA_TABLE_ENTRYリストを歩く
次の例では、ユーザー モードのLDR_DATA_TABLE_ENTRYリストについて説明し、各リスト エントリのベース アドレスと完全なパスを表示します。
前の例と同様に、このプログラムはファイルに保存し、$$>< (スクリプト ファイルの実行) コマンドを使用して実行する必要があります。
この例では、次の機能を示します。
このプログラムでは、MASM 式エバリュエーターを使用します。 ただし、@@c++( ) トークンは 2 か所に表示されます。 このトークンにより、プログラムは C++ 式エバリュエーターを使用してかっこ内の式を解析します。 この使用法により、プログラムは C++ 構造体トークンを直接使用できます。
? フラグは、r (Registers) コマンドで使用されます。 このフラグは、擬似レジスタ $t 0 と $t 1に型指定された値を割り当てます。 ループの本体では、$t 1 は ntdll!_LDR_DATA_TABLE_ENTRY\* 型であるため、プログラムは直接メンバー参照を行うことができます。
このプログラムでは、ユーザー名のエイリアス $Base と $Mod が使用されます。 ドル記号は、これらのエイリアスが現在のデバッガー セッションで以前に使用されている可能性を減らします。 ドル記号は必要ありません。 ${/v: } トークンはエイリアスをリテラルで解釈するため、スクリプトを実行する前に定義した場合に置き換えられるのを防ぎます。 このトークンを任意のブロックと共に使用して、ブロックが使用される前にエイリアス定義を防ぐこともできます。
.block トークンを使用して、エイリアス置換手順を追加します。 エイリアスの置換は、スクリプト全体が読み込まれるときに 1 回、各ブロックが入力されたときに 1 回行われます。 .block トークンとその中かっこがないと、.echo コマンドは、前の行で割り当てられた $Mod と $Base エイリアスの値を受け取りません。
$$ 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}
}