Sdílet prostřednictvím


Příklady příkazů ladicího programu

Následující části popisují programy příkazů ladicího programu.

Použití tokenu .foreach

Následující příklad používá token .foreach k vyhledání hodnot WORDu 5a4d. Pro každou nalezenou hodnotu 5a4d ladicí program zobrazí 8 hodnot DWORD počínaje adresou, kde byl nalezen 5a4d DWORD.

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

Následující příklad používá token .foreach k vyhledání hodnot WORDu 5a4d. Pro každou nalezenou hodnotu 5a4d ladicí program zobrazí 8 hodnot DWORD počínaje 4 bajty před adresou, kde byl nalezen 5a4d DWORD.

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

Následující příklad zobrazuje stejné hodnoty.

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

Poznámka Pokud chcete pracovat s názvem proměnné v části příkazu OutCommands části příkazu, musíte za název proměnné přidat mezeru. Například v přednabídce existuje mezera mezi proměnnou umístění a operátorem odčítání.

Možnost -[1] společně s příkazem s (Prohledávat paměť) způsobí, že jeho výstup bude obsahovat pouze adresy, které najde, ne hodnoty nalezené na těchto adresách.

Následující příkaz zobrazí podrobné informace o modulu pro všechny moduly umístěné v rozsahu paměti od 0x77000000 až po 0x7F000000.

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

Možnost 1m společně s příkazem lm (List Loaded Modules) způsobí, že jeho výstup bude obsahovat pouze adresy modulů, nikoli úplný popis modulů.

Předchozí příklad používá ${ } (interpret aliasu) token, aby se zajistilo, že aliasy budou nahrazeny, i když jsou vedle jiného textu. Pokud příkaz nezahrnul tento token, levá závorka vedle místo zabrání nahrazení aliasu. Všimněte si, že token ${} funguje na proměnných, které se používají v .foreach a na skutečných aliasech.

Procházení seznamu procesů

Následující příklad vás provede seznamem procesů v režimu jádra a zobrazí název spustitelného souboru pro každou položku v seznamu.

Tento příklad by se měl uložit jako textový soubor a spustitpříkazem$$>< (Spustit soubor skriptu). Tento příkaz načte celý soubor, nahradí všechny návraty na začátek řádku středníky a spustí výsledný blok. Tento příkaz umožňuje psát čitelné programy pomocí více řádků a odsazení, aniž byste museli stisknout celý program na jeden řádek.

Tento příklad ukazuje následující funkce:

  • $t 0, $t 1a $t 2 pseudoregistry se v tomto programu používají jako proměnné. Program také používá aliasy s názvem Procc a $ImageName.

  • Tento program používá vyhodnocovače výrazů MASM. Token @@c++( ) se však zobrazí jednou. Tento token způsobí, že program použije vyhodnocovače výrazů jazyka C++ k parsování výrazu v závorkách. Toto použití umožňuje programu používat tokeny struktury C++přímo.

  • ? příznak se používá s příkazemr (Registers). Tento příznak přiřadí typové hodnoty pseudoregistru $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
}

Procházení seznamu LDR_DATA_TABLE_ENTRY

Následující příklad vás provede seznamem LDR_DATA_TABLE_ENTRY v uživatelském režimu a zobrazí základní adresu a úplnou cestu každé položky seznamu.

Podobně jako v předchozím příkladu by se tento program měl uložit do souboru a spustit se příkazem $$>< (Spustit soubor skriptu).

Tento příklad ukazuje následující funkce:

  • Tento program používá vyhodnocovače výrazů MASM. Na dvou místech se však zobrazí token @@c++(). Tento token způsobí, že program použije vyhodnocovače výrazů jazyka C++ k parsování výrazu v závorkách. Toto použití umožňuje programu používat tokeny struktury jazyka C++přímo.

  • ? příznak se používá s příkazemr (Registers). Tento příznak přiřadí zadané hodnoty pseudoregistrům $t 0 a $t 1. V těle smyčky $t 1 má typ ntdll!_LDR_DATA_TABLE_ENTRY\*, aby program mohl vytvářet přímé členské odkazy.

  • Aliasy pojmenované uživatelem $Base a $Mod se používají v tomto programu. Známky dolaru snižují možnost, že tyto aliasy byly použity dříve v aktuální relaci ladicího programu. Znak dolaru není nutný. ${/v: } token interpretuje alias doslova a brání jeho nahrazení, pokud byl definován před spuštěním skriptu. Tento token můžete také použít společně s libovolným blokem, abyste zabránili definicím aliasů před použitím bloku.

  • Token .block slouží k přidání dalšího kroku nahrazení aliasu. Nahrazení aliasu nastane jednou pro celý skript při jeho načtení a jednou při každém zadání bloku. Bez tokenu .block a jeho složených závorek .echo neobdrží hodnoty $Mod a $Base aliasů, které jsou přiřazeny v předchozích řádcích.

$$ 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}
}