Partilhar via


Exemplos de programas de comando do depurador

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

Usando o token .foreach

O exemplo a seguir usa o token de.foreachpara procurar 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 de.foreachpara procurar valores WORD de 5a4d. Para cada valor 5a4d encontrado, o depurador exibe 8 valores DWORD, iniciando 4 bytes antes do endereço onde 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 } 

Observação 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 anterior, há um espaço entre a variável lugar e o operador de subtração.

A opção -[1] juntamente com o comando s (Search Memory) 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 a 0x7F000000.

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

A opção 1m juntamente com o comandolm (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${ } (Alias Interpreter) 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 local impede a substituição do alias. Observe que o token ${} funciona nas variáveis que são usadas em .foreach e em aliases verdadeiros.

Caminhando na 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 $$>< (Run Script File). Este comando carrega o arquivo inteiro, substitui todos os retornos de carro por ponto-e-vírgula e executa o bloco resultante. Este comando permite que você escreva programas legíveis usando várias linhas e recuo, em vez de ter que espremer todo o programa em uma única linha.

Este exemplo ilustra os seguintes recursos:

  • Os pseudo-registros $t 0, $t 1e $t 2 são usados como variáveis neste programa. O programa também usa pseudônimos 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 entre parênteses. Esse uso permite que o programa use os tokens de estrutura C++ diretamente.

  • O ? sinalizador é usado com o comandor (Registers). Esse sinalizador atribui valores digitados 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 pela lista de LDR_DATA_TABLE_ENTRY

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

Como o exemplo anterior, este programa deve ser salvo em um arquivo e executado com o comando$$>< (Run Script File).

Este exemplo ilustra os seguintes recursos:

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

  • O ? sinalizador é usado com o comandor (Registers). Esse sinalizador atribui valores digitados 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 de membros.

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

  • O token .block é usado para adicionar uma etapa extra de substituição de alias. 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 de .block e suas chaves, o comando .echo não recebe os valores dos $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}
}