Compartilhar via


Exemplos de programa de comando do depurador

As seções a seguir descrevem programas de comando do depurador.

Usando o token .foreach

O exemplo a seguir usa o token .foreach para pesquisar valores word de 5a4d. Para cada valor 5a4d encontrado, o depurador exibe 8 valores DWORD, começando no endereço de onde o DWORD 5a4d foi encontrado.

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

O exemplo a seguir usa o token .foreach para pesquisar valores word de 5a4d. Para cada valor 5a4d encontrado, o depurador exibe 8 valores DWORD, iniciando 4 bytes antes do endereço em que o DWORD 5a4d foi encontrado.

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

O exemplo a seguir exibe os mesmos valores.

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

Nota Se você quiser operar no nome da variável na parte OutCommands do comando, deverá adicionar um espaço após o nome da variável. Por exemplo, no exemplo preceeding, há um espaço entre o local da variável e o operador de subtração.

A opção -[1] junto com o comando s (Memória de Pesquisa) faz com que sua saída inclua apenas os endereços encontrados, não os valores encontrados nesses endereços.

O comando a seguir exibe informações detalhadas do módulo para todos os módulos localizados no intervalo de memória de 0x77000000 até 0x7F000000.

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

A opção 1m junto com o comando lm (List Loaded Modules) faz com que sua saída inclua apenas os endereços dos módulos, não a descrição completa dos módulos.

O exemplo anterior usa o token ${ } (Interpretador de Alias) para garantir que os aliases sejam substituídos mesmo que estejam ao lado de outro texto. Se o comando não incluir esse token, o parêntese de abertura que está ao lado do local impedirá a substituição de alias. Observe que o token ${} funciona nas variáveis usadas em .foreach e em aliases verdadeiros.

Percorrendo a lista de processos

O exemplo a seguir percorre a lista de processos do modo kernel e exibe o nome executável para cada entrada na lista.

Este exemplo deve ser armazenado como um arquivo de texto e executado com o comando $$>< (Executar Arquivo de Script). Esse comando carrega todo o arquivo, substitui todos os retornos de carro por ponto e vírgula e executa o bloco resultante. Esse comando permite que você escreva programas legíveis usando várias linhas e recuos, em vez de precisar espremer todo o programa em uma única linha.

Este exemplo ilustra os seguintes recursos:

  • Os pseudo-registros $t 0, $t 1 e $t 2 são usados como variáveis neste programa. O programa também usa aliases chamados Procc e $ImageName.

  • Este programa usa o avaliador de expressão MASM. No entanto, o token @@c++( ) aparece uma vez. Esse token faz com que o programa use o avaliador de expressão C++ para analisar a expressão dentro dos parênteses. Esse uso permite que o programa use os tokens de estrutura C++ diretamente.

  • O sinalizador ? é usado com o comando r (Registros). Esse sinalizador atribui valores tipados ao pseudo-registro $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
}

Caminhando na lista de LDR_DATA_TABLE_ENTRY

O exemplo a seguir percorre a lista de LDR_DATA_TABLE_ENTRY do modo de usuário e exibe o endereço base e o caminho completo de cada entrada de lista.

Como no exemplo anterior, esse programa deve ser salvo em um arquivo e executado com o comando $$>< (Executar Arquivo de Script).

Este exemplo ilustra os seguintes recursos:

  • Este programa usa o avaliador de expressão MASM. No entanto, em dois lugares, o token @@c++( ) é exibido. Esse token faz com que o programa use o avaliador de expressão C++ para analisar a expressão dentro dos parênteses. Esse uso permite que o programa use tokens de estrutura C++ diretamente.

  • O sinalizador ? é usado com o comando r (Registros). Esse sinalizador atribui valores tipados aos pseudo-registros $t 0 e $t 1. No corpo do loop, $t 1 tem o tipo ntdll!_LDR_DATA_TABLE_ENTRY\*, para que o programa possa fazer referências diretas a membros.

  • Os aliases nomeados pelo usuário $Base e $Mod são usados neste programa. Os sinais de dólar reduzem a possibilidade de que esses aliases tenham sido usados anteriormente na sessão atual do depurador. Os sinais de dólar não são necessários. O token ${/v: } interpreta o alias literalmente, impedindo que ele seja substituído se ele tiver sido definido antes da execução do script. Você também pode usar esse token junto com qualquer bloco para impedir que definições de alias antes do bloco ser usado.

  • O token .block é usado para adicionar uma etapa de substituição de alias extra. A substituição de alias ocorre uma vez para todo o script quando ele é carregado e uma vez quando cada bloco é inserido. Sem o token .block e suas chaves, o comando .echo não recebe os valores do $Mod e $Base aliases atribuídos nas linhas 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}
}