デバッガコマンドプログラムの例
以降のセクションでは、デバッガコマンドプログラムについて説明します。
.foreachトークンの使用
次の例では、.foreach トークンを 使用して5a4dのWORD値を検索します。 見つかった5a4d値ごとに、5a4dDWORDが見つかったアドレスから始まる8つのDWORD値がデバッガーに表示されます。
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place L8 }
次の例では、.foreach トークンを 使用して5a4dのWORD値を検索します。 見つかった5a4d値ごとに、デバッガーは8つのDWORD値を表示し、5a4dDWORDが見つかったアドレスの前の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 部分で変数名を操作する場合は、変数名の後にスペースを追加する必要があります。 たとえば、前置の例では、変数 の場所 と減算演算子の間にスペースがあります。
-[1]オプションと一緒に (検索メモリ) オプションを指定すると、その出力には検索したアドレスのみが含まれますが、それらのアドレスで見つかった値は含まれません。
次のコマンドは、0x77000000から0x7F000000までのメモリ範囲内にあるすべてのモジュールの詳細なモジュール情報を表示します。
0:000> .foreach (place { lm1m }) { .if ((${place} >= 0x77000000) & (${place} <= 0x7f000000)) { lmva place } }
1mオプションと一緒に lm (ロードされたモジュールのリスト) オプションを指定すると、モジュールの完全な説明ではなく、モジュールのアドレスのみが出力に含まれます。
前の例では、${ } (エイリアスインタープリター) トークンを使用して、エイリアスが他のテキストの横にある場合でも、エイリアスが確実に置き換えられます。 コマンドにこのトークンが含まれていない場合、配置の横にある始めかっこによってエイリアスの置換が禁止されます。 ${} トークンは、.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}
}