調試程式命令程式範例
下列各節說明調試程式命令程式。
使用 .foreach 令牌
下列範例會使用 .foreach Token 來搜尋 5a4d 的 WORD 值。 針對找到的每個 5a4d 值,調試程式會顯示 8 個 DWORD 值,從找到 5a4d DWORD 的地址開始。
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place L8 }
下列範例會使用 .foreach Token 來搜尋 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) 命令會導致其輸出只包含模組的位址,而不是模組的完整描述。
上述範例會使用 ${ } (別名解釋器) 令牌,以確保即使別名位於其他文字旁邊也已取代。 如果命令未包含此令牌,則位於 位置旁的左括弧 會防止別名取代。 請注意,${} 令牌適用於 .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: } 令牌會以常值方式解譯別名,以避免在腳本執行之前定義別名。 您也可以將此令牌與任何區塊一起使用,以防止在區塊使用之前使用別名定義。
.block 令牌可用來新增額外的別名取代步驟。 載入別名時,會針對整個腳本進行一次別名取代,並在輸入每個區塊時發生一次。 如果沒有 .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}
}