Exempel på felsökningskommandoprogram
I följande avsnitt beskrivs kommandoprogram för felsökning.
Använda .foreach-token
I följande exempel används .foreach token för att söka efter WORD-värden på 5a4d. För varje 5a4d-värde som hittas visar felsökningsprogrammet 8 DWORD-värden, med början på adressen där 5a4d DWORD hittades.
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place L8 }
I följande exempel används .foreach token för att söka efter WORD-värden på 5a4d. För varje 5a4d-värde som hittas visar felsökningsprogrammet 8 DWORD-värden, med start 4 byte före adressen där 5a4d DWORD hittades.
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place -0x4 L8 }
I följande exempel visas samma värden.
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc ( place -0x4 ) L8 }
Observera Om du vill använda variabelnamnet i OutCommands del av kommandot måste du lägga till ett blanksteg efter variabelnamnet. I före-exemplet finns det till exempel ett utrymme mellan variabeln plats och subtraktionsoperatorn.
Alternativet -[1] tillsammans med kommandot s (Sökminne) gör att dess utdata endast innehåller de adresser som hittas, inte de värden som finns på dessa adresser.
Följande kommando visar utförlig modulinformation för alla moduler som finns i minnesintervallet från 0x77000000 till 0x7F000000.
0:000> .foreach (place { lm1m }) { .if ((${place} >= 0x77000000) & (${place} <= 0x7f000000)) { lmva place } }
Alternativet 1 m tillsammans med kommandot lm (List Loaded Modules) gör att dess utdata endast inkluderar modulernas adresser, inte den fullständiga beskrivningen av modulerna.
I föregående exempel används ${ } (aliastolkare) token för att se till att alias ersätts även om de finns bredvid annan text. Om kommandot inte innehåller den här token förhindrar den inledande parentesen som ligger bredvid plats aliasbyte. Observera att token ${} fungerar på variablerna som används i .foreach och på sanna alias.
Gå till processlistan
I följande exempel går vi igenom processlistan för kernelläge och visar det körbara namnet för varje post i listan.
Det här exemplet ska lagras som en textfil och köras med kommandot $$>< (Kör skriptfil). Det här kommandot läser in hela filen, ersätter alla vagnreturer med semikolon och kör det resulterande blocket. Med det här kommandot kan du skriva läsbara program med hjälp av flera rader och indrag, i stället för att behöva pressa hela programmet på en enda rad.
Det här exemplet illustrerar följande funktioner:
$t 0, $t 1och $t 2 pseudoregister används som variabler i det här programmet. Programmet använder även alias med namnet Procc och $ImageName.
Det här programmet använder MASM-uttrycksut utvärderaren. Men @@c++( )-token visas en gång. Den här token gör att programmet använder C++-uttrycksutvärderingen för att parsa uttrycket inom parenteserna. Med den här användningen kan programmet använda C++-strukturtoken direkt.
Den ?-flaggan används med kommandot r (register). Den här flaggan tilldelar inskrivna värden till pseudoregistret $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
}
Gå på LDR_DATA_TABLE_ENTRY-listan
I följande exempel går vi igenom användarläget LDR_DATA_TABLE_ENTRY listan och visar basadressen och den fullständiga sökvägen för varje listpost.
Precis som i föregående exempel bör det här programmet sparas i en fil och köras med kommandot $$>< (Kör skriptfil).
Det här exemplet illustrerar följande funktioner:
Det här programmet använder MASM-uttrycksut utvärderaren. På två ställen visas dock @@c++( ) token. Den här token gör att programmet använder C++-uttrycksutvärderingen för att parsa uttrycket inom parenteserna. Med den här användningen kan programmet använda C++-strukturtoken direkt.
Den ?-flaggan används med kommandot r (register). Den här flaggan tilldelar typvärden till pseudoregister $t 0 och $t 1. I loopens brödtext har $t 1 typen ntdll!_LDR_DATA_TABLE_ENTRY\*, så att programmet kan göra direkta medlemsreferenser.
De användarnamnsalias som $Base och $Mod används i det här programmet. Dollar-tecknen minskar risken för att dessa alias har använts tidigare i den aktuella felsökningssessionen. Dollarskyltarna är inte nödvändiga. Den ${/v: } token tolkar aliaset bokstavligen, vilket förhindrar att det ersätts om det definierades innan skriptet körs. Du kan också använda den här token tillsammans med alla block för att förhindra att aliasdefinitioner innan blocket används.
Den .block--token används för att lägga till ett extra aliasbytessteg. Aliasbyte sker en gång för hela skriptet när det läses in och en gång när varje block anges. Utan .block token och dess klammerparenteser tar kommandot .echo inte emot värdena för de $Mod och $Base alias som har tilldelats i föregående rader.
$$ 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}
}