Példa hibakereső parancsprogramra

A következő szakaszok a hibakereső parancsprogramokat ismertetik.

A .foreach token használata

Az alábbi példa a .foreach tokent használja az 5a4d WORD-értékek kereséséhez. Minden talált 5a4d értéknél a hibakereső 8 DWORD értéket jelenít meg, attól a címtől kezdve, ahol az 5a4d DWORD található.

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

Az alábbi példa a .foreach tokent használja az 5a4d WORD-értékek kereséséhez. Minden talált 5a4d értéknél a hibakereső 8 DWORD-értéket jelenít meg, amely 4 bájtot jelent az 5a4d DWORD-t tartalmazó cím előtt.

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

Az alábbi példa ugyanazokat az értékeket jeleníti meg.

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

Megjegyzés Ha a parancs OutCommands részében lévő változónéven szeretne működni, a változó neve után szóközt kell hozzáadnia. Az előszűrési példában például szóköz van a változó hely és a kivonási operátor között.

A -[1] beállítás a s (Keresési memória) paranccsal együtt azt eredményezi, hogy a kimenet csak az általa talált címeket tartalmazza, nem pedig az ezeken a címeken található értékeket.

Az alábbi parancs részletes modulinformációkat jelenít meg a memóriatartományban található összes modulról 0x77000000 és 0x7F000000 között.

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

Az 1 m lehetőség és a lm (List Loaded Modules) parancs hatására a kimenet csak a modulok címét tartalmazza, nem pedig a modulok teljes leírását.

Az előző példa az ${ } (Alias értelmező) jogkivonatot használja annak biztosításához, hogy az aliasok akkor is lecserélődjenek, ha más szöveg mellett vannak. Ha a parancs nem tartalmazza ezt a jogkivonatot, a mellett található nyitó zárójel megakadályozza az alias cseréjét. Vegye figyelembe, hogy a ${} token az .foreach és a valódi aliasokban használt változókon működik.

A folyamatlista végigjárása

Az alábbi példa végigvezeti a kernel módú folyamatlistán, és megjeleníti a lista egyes bejegyzéseinek végrehajtható nevét.

Ezt a példát szövegfájlként kell tárolni, és a $$>< (Szkriptfájl futtatása) paranccsal kell végrehajtani. Ez a parancs betölti a teljes fájlt, az összes visszaadott kocsit pontosvesszőkre cseréli, és végrehajtja az eredményül kapott blokkot. Ez a parancs lehetővé teszi, hogy több sor és behúzás használatával írható programokat írjon, ahelyett, hogy az egész programot egyetlen sorba kellene szorítani.

Ez a példa a következő funkciókat mutatja be:

  • Ebben a programban a $t 0, $t 1és $t 2 pszeudoregisztráltak használhatók változóként. A program Procc és $ImageNamenevű aliasokat is használ.

  • Ez a program a MASM-kifejezés kiértékelőt használja. A @@c++( ) jogkivonat azonban egyszer jelenik meg. Ez a jogkivonat azt eredményezi, hogy a program a C++ kifejezésértékelő használatával elemzi a kifejezést a zárójeleken belül. Ez a használat lehetővé teszi, hogy a program közvetlenül használja a C++ struktúra jogkivonatait.

  • A ? jelölőt az r (Regisztrálás) parancs használja. Ez a jelző gépelt értékeket rendel a pszeudoregisztrálási $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
}

A LDR_DATA_TABLE_ENTRY listája

Az alábbi példa végigvezeti a felhasználói módú LDR_DATA_TABLE_ENTRY listát, és megjeleníti az egyes listabejegyzések alapcímét és teljes elérési útját.

Az előző példához hasonlóan ezt a programot egy fájlba kell menteni, és a $$>< (szkriptfájl futtatása) paranccsal kell végrehajtani.

Ez a példa a következő funkciókat mutatja be:

  • Ez a program a MASM-kifejezés kiértékelőt használja. Két helyen azonban megjelenik a @@c++( ) jogkivonat. Ez a jogkivonat azt eredményezi, hogy a program a C++ kifejezésértékelő használatával elemzi a kifejezést a zárójeleken belül. Ez a használat lehetővé teszi, hogy a program közvetlenül C++ struktúra jogkivonatokat használjon.

  • A ? jelölőt az r (Regisztrálás) parancs használja. Ez a jelző gépelt értékeket rendel a pszeudoregisztrálásokhoz $t 0 és $t 1. A hurok törzsében $t 1ntdll!_LDR_DATA_TABLE_ENTRY\*típussal rendelkezik, így a program közvetlen taghivatkozásokat tud készíteni.

  • A program a felhasználó által elnevezett aliasokat $Base és $Mod használja. A dollárjelek csökkentik annak lehetőségét, hogy ezeket az aliasokat korábban használták az aktuális hibakereső munkamenetben. A dollárjelek nem szükségesek. Az ${/v: } jogkivonat szó szerint értelmezi az aliast, megakadályozva a lecserélését, ha a szkript futtatása előtt lett definiálva. Ezt a jogkivonatot a blokkokkal együtt is használhatja, hogy megakadályozza az aliasdefiníciókat a blokk használata előtt.

  • A .block token további alias-cserelépés hozzáadására szolgál. Az alias cseréje a teljes szkript esetében egyszer történik, amikor betöltődik, és egy alkalommal, amikor minden blokk be van írva. A .block jogkivonat és zárójelei nélkül a .echo parancs nem kapja meg az előző sorokban hozzárendelt $Mod és $Base aliasok értékeit.

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