偵錯工具命令程式範例
下列各節說明偵錯工具命令程式。
使用 .foreach 權杖
下列範例會使用 .foreach 權杖來搜尋 5a4d 的 WORD 值。 針對找到的每個 5a4d 值,偵錯工具會顯示 8 個 DWORD 值,從找到 5a4d 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 部分中操作變數名稱,則必須在變數名稱後面加上空格。 例如,在前置範例中,變數 位置 與減法運算子之間有一個空格。
-[1]選項連同s (Search Memory) 命令會導致其輸出只包含其找到的位址,而不是在這些位址找到的值。
下列命令會顯示所有位於記憶體範圍中之模組的詳細資訊模組資訊,從0x77000000到0x7F000000。
0:000> .foreach (place { lm1m }) { .if ((${place} >= 0x77000000) & (${place} <= 0x7f000000)) { lmva place } }
1m選項與lm (List Loaded Modules) 命令會導致其輸出只包含模組的位址,而不是模組的完整描述。
上述範例會使用 ${ } (別名解譯器) 權杖,以確保即使別名位於其他文字旁邊也一樣。 如果命令未包含此權杖,則旁的左 括弧會防止 別名取代。 請注意, $ {} token 適用于.foreach和 true 別名中使用的變數。
逐步執行程式清單
下列範例會逐步解說核心模式進程清單,並顯示清單中每個專案的可執行檔名稱。
此範例應該儲存為文字檔,並使用 $$ >< (執行腳本檔案) 命令來執行。 此命令會載入整個檔案、以分號取代所有歸位字元,並執行產生的區塊。 此命令可讓您使用多行和縮排來撰寫可讀取的程式,而不需要將整個程式壓縮成單行。
此範例說明下列功能:
$t 0、$t 1和$t 2虛擬暫存器會作為此程式中的變數使用。 此程式也會使用名為 Procc 和 $ImageName 的別名。
此程式使用 MASM 運算式評估工具。 不過, @@c++ ( ) 權杖會出現一次。 此權杖會使程式使用 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++ ( ) 權杖隨即出現。 此權杖會使程式使用 C++ 運算式評估工具剖析括弧內的運算式。 此用法可讓程式直接使用 C++ 結構權杖。
?旗標會與r (Registers) 命令搭配使用。 此旗標會將具類型的值指派給虛擬暫存器 $t 0 和 $t 1。 在迴圈本文中, $t 1 具有 ntdll!_LDR_DATA_TABLE_ENTRY\*類型,因此程式可以進行直接成員參考。
此程式中會使用使用者命名別名 $Base 和 $Mod 。 貨幣符號可減少先前在目前偵錯工具會話中使用這些別名的可能性。 不需要貨幣符號。 ${/v: } Token 會常解譯別名,避免在腳本執行之前定義別名時加以取代。 您也可以將此權杖與任何區塊一起使用,以防止在區塊使用之前使用別名定義。
.block Token 可用來新增額外的別名取代步驟。 載入別名時,會針對整個腳本進行一次別名取代,並在輸入每個區塊時發生一次。 如果沒有 .block Token 及其大括弧, .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}
}