Ejemplos del programa de comandos del depurador
En las secciones siguientes se describen los programas de comandos del depurador.
Uso del token .foreach
En el ejemplo siguiente se usa el token .foreach para buscar valores de WORD de 5a4d. Para cada valor 5a4d que se encuentra, el depurador muestra 8 valores DWORD, empezando por la dirección de donde se encontró el DWORD 5a4d.
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place L8 }
En el ejemplo siguiente se usa el token .foreach para buscar valores de WORD de 5a4d. Para cada valor de 5a4d que se encuentra, el depurador muestra 8 valores DWORD, comenzando 4 bytes antes de la dirección donde se encontró el DWORD 5a4d.
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place -0x4 L8 }
En el ejemplo siguiente se muestran los mismos valores.
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc ( place -0x4 ) L8 }
Nota Si desea operar en el nombre de la variable en la parte OutCommands del comando, debe agregar un espacio después del nombre de la variable. Por ejemplo, en el ejemplo anterior, hay un espacio entre el lugar variable y el operador de resta.
La opción -[1] junto con el comando s (Memoria de búsqueda) hace que su salida incluya solo las direcciones que encuentra, no los valores que se encuentran en esas direcciones.
El siguiente comando muestra información detallada del módulo para todos los módulos que se encuentran en el intervalo de memoria de 0x77000000 a través de 0x7F000000.
0:000> .foreach (place { lm1m }) { .if ((${place} >= 0x77000000) & (${place} <= 0x7f000000)) { lmva place } }
La opción 1m junto con el comando lm (List Loaded Modules) hace que su salida incluya solo las direcciones de los módulos, no la descripción completa de los módulos.
En el ejemplo anterior se usa el token ${ } (intérprete de alias) para asegurarse de que los alias se reemplazan incluso si están junto a otro texto. Si el comando no incluye este token, el paréntesis de apertura que está junto a colocar impide el reemplazo de alias. Tenga en cuenta que el token ${} funciona en las variables que se usan en .foreach y en alias true.
Caminar la lista de procesos
En el ejemplo siguiente se recorre la lista de procesos en modo kernel y se muestra el nombre ejecutable de cada entrada de la lista.
Este ejemplo debe almacenarse como un archivo de texto y ejecutarse con el comando $$>< (Ejecutar archivo de script). Este comando carga todo el archivo, reemplaza todos los retornos de carro por punto y coma y ejecuta el bloque resultante. Este comando permite escribir programas legibles mediante varias líneas y sangría, en lugar de tener que comprimir todo el programa en una sola línea.
En este ejemplo se muestran las siguientes características:
Los pseudo-registros de $t 0, $t 1 y $t 2 se usan como variables en este programa. El programa también usa alias denominados Procc y $ImageName.
Este programa usa el evaluador de expresiones MASM. Sin embargo, el token de @@c++( ) aparece una vez. Este token hace que el programa use el evaluador de expresiones de C++ para analizar la expresión entre paréntesis. Este uso permite al programa usar directamente los tokens de estructura de C++.
La marca ? se usa con el comando r (Registers). Esta marca asigna valores con tipo al pseudo-register $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
}
Caminar por la lista de LDR_DATA_TABLE_ENTRY
En el ejemplo siguiente se recorre la lista de LDR_DATA_TABLE_ENTRY modo de usuario y se muestra la dirección base y la ruta de acceso completa de cada entrada de lista.
Al igual que en el ejemplo anterior, este programa debe guardarse en un archivo y ejecutarse con el comando $$>< (Ejecutar archivo de script).
En este ejemplo se muestran las siguientes características:
Este programa usa el evaluador de expresiones MASM. Sin embargo, en dos lugares, aparece el token @@c++( ). Este token hace que el programa use el evaluador de expresiones de C++ para analizar la expresión entre paréntesis. Este uso permite al programa usar directamente tokens de estructura de C++.
La marca ? se usa con el comando r (Registers). Esta marca asigna valores con tipo a los pseudo-registers $t 0 y $t 1. En el cuerpo del bucle, $t 1 tiene el tipo ntdll!_LDR_DATA_TABLE_ENTRY\*, por lo que el programa puede hacer referencias directas a miembros.
Los alias con nombre de usuario $Base y $Mod se usan en este programa. Los signos de dólar reducen la posibilidad de que estos alias se hayan usado anteriormente en la sesión actual del depurador. Los signos de dólar no son necesarios. El token ${/v: } interpreta el alias literalmente, lo que impide que se reemplace si se definió antes de que se ejecute el script. También puede usar este token junto con cualquier bloque para evitar que se usen definiciones de alias antes de que se use el bloque.
El token .block se usa para agregar un paso de reemplazo de alias adicional. El reemplazo de alias se produce una vez para todo el script cuando se carga y una vez cuando se escribe cada bloque. Sin el token .block y sus llaves, el comando .echo no recibe los valores de los $Mod y $Base alias asignados en las líneas anteriores.
$$ 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}
}