Rastreamento de eventos de aprendizagem para Windows: teoria e prática

Boa tarde. Recentemente, eu precisava lidar com o serviço de rastreamento do Windows. Esse serviço apareceu no Windows 2000, mas havia muito poucos artigos sobre esse serviço na Internet. Portanto, surgiu a idéia de escrever este artigo. Então, vamos começar!

Hoje vou tentar falar sobre:

  1. Teoria do Serviço de Rastreio do Windows
  2. Criando sua sessão ETW
  3. Usando a API de rastreamento de eventos para trabalhar com ETW
  4. Usando tracerpt e xperf para trabalhar com ETW

Teoria do Serviço de Rastreio do Windows


O Rastreamento de Eventos para Windows (ETW) é um serviço que permite receber eventos de um ou mais provedores de eventos em tempo real ou de um arquivo * .etl por um determinado período de tempo. Não está claro? Agora vamos descobrir!

Para entender como o ETW funciona, você precisa entender a estrutura desse serviço.A

imagem

arquitetura do ETW inclui 4 elementos

  1. fornecedores de eventos
  2. consumidores de eventos
  3. Controladores ETW
  4. Sessões ETW (sessões de rastreamento de eventos)

O princípio de operação é o seguinte.

Vários provedores de eventos estão registrados no sistema, ou seja, aplicativos que podem compartilhar suas experiências com sessões ETW. Também neste sistema, há um certo número de sessões ETW ativas que podem consumir eventos de um ou mais provedores e fornecê-las ao usuário em tempo real ou gravar todos os eventos dos fornecedores em um arquivo de log (* .etl). E os controladores controlam todo esse movimento.

E agora consideraremos cada elemento da arquitetura considerado acima em mais detalhes para finalmente entender o princípio do trabalho!

Provedores de Eventos


Provedores de eventos são aplicativos que contêm ferramentas de rastreamento de eventos. Após o provedor se registrar, o controlador pode ativar ou desativar o rastreamento de eventos no provedor. O provedor determina sua interpretação de ativado ou desativado. Normalmente, um provedor habilitado gera eventos, mas um provedor desabilitado não. Isso permite que você adicione o rastreamento de eventos ao nosso aplicativo sem exigir que ele gere eventos o tempo todo.

Um fornecedor pode compartilhar seus eventos com várias sessões ETW de uma só vez.

Cada evento consiste em dois elementos: um cabeçalho e dados! O cabeçalho do evento inclui informações sobre o evento: identificador do provedor, identificador de evento, registro de data e hora, etc. O restante dos dados é determinado por um provedor específico: o ETW recebe todos os dados e os grava no buffer, e sua interpretação é atribuída aos consumidores de informações.
Existem quatro tipos principais de provedores: provedores de

MOF (clássicos)
provedores de WPP
baseados no
TraceLogging dos provedores manifestos .

Os provedores de eventos diferem nos tipos de campos que eles armazenam nas cargas úteis do evento.

Os provedores de eventos parecem estar resolvidos. Ir em frente!

Controladores


Um controlador é um aplicativo responsável pela operação de uma ou mais sessões ETW. É o controlador que determina o tamanho e o local do arquivo de log, inicia e interrompe as sessões de rastreamento de eventos (sessões ETW) e permite que os provedores registrem eventos na sessão. Como mencionado anteriormente, é o controlador que permite que o provedor compartilhe seus eventos!

Consumidores


Consumidores são aplicativos que recebem e processam eventos de uma ou mais sessões de rastreamento ao mesmo tempo. Os consumidores podem receber eventos armazenados em arquivos de log ou de sessões que entregam eventos em tempo real. Como já sabemos, uma sessão da ETW pode ter vários fornecedores. Surge a pergunta: haverá confusão? Como os eventos das várias sessões da ETW se relacionam? Os eventos são classificados pela hora em que ocorrem, ou seja, o sistema entrega eventos em ordem cronológica!

Sessões ETW


As sessões de rastreamento de eventos (sessões ETW) registram eventos de um ou mais provedores permitidos pelo controlador. A sessão também é responsável por gerenciar e liberar buffers.

O Rastreio de Eventos suporta até 64 sessões de rastreio de eventos em execução simultaneamente. Dessas sessões, há duas sessões para fins especiais. As sessões restantes estão disponíveis para uso geral. Duas sessões para fins especiais:

  • Sessão do registrador global
  • Sessão do registrador de kernel do NT

Uma sessão de rastreamento de eventos do Global Logger registra os eventos que ocorrem no início do processo de inicialização do sistema operacional, como os gerados pelos drivers de dispositivo.
Um Registrador de Kernel da Sessão de Rastreamento de Eventos do NT registra eventos predefinidos do sistema gerados pelo sistema operacional, como eventos de E / S do disco ou falhas de página.

Então, agora vamos praticar !!!

Criando sua sessão ETW


Antes de iniciar o trabalho, precisamos conhecer vários utilitários, a saber: uma

lista de provedores disponíveis em um SO específico

logman query providers

obter informações completas sobre o provedor

wevtutil gp < > /ge /gm

lista de todas as sessões ativas de ETW

xperf -loggers

Além disso, para visualizar arquivos, é aconselhável ter o Notepad ++.

Depois de examinar a lista de fornecedores no seu computador (e existem mais de 1000 no Windows 10), escolheremos um deles para a nossa sessão:

imagem

Escolhi o Microsoft-Windows-WinINet (este serviço registra todas as nossas ações ao trabalhar no navegador Microsoft Edge).

1. Win + R -> compmgmt.msc
2. "Desempenho"
3. "Conjuntos de coletores de dados"
4. "Sessões de rastreamento de eventos"
5. “Novo”
6. “Conjunto de coletores de dados”
7. Especifique o nome do coletor de dados
8. “Criar manualmente (Avançado)” (“Criar manualmente (para experientes)")

imagem
9. Adicione interessantes nós fornecedores por sessão
10. Especifique as palavras-chave de seu interesse no campo “Palavras-chave (Qualquer)” - 0xFFFFFFFFFFFFFFFFFF
11. Especifique o nível de log 0xFF
= imagem

12. Selecione o caminho em que o arquivo de log da sessão será salvo
13. Selecione a opção “ Inicie este conjunto de coletores de dados agora ”(“ Executar o grupo de coletores de dados agora ”)

Agora a sessão que criamos funciona. O Microsoft Edge precisa de algum trabalho para que a sessão colete informações sobre nós!

Depois de algum tempo, vamos para o local onde salvamos o arquivo de log. Executamos o seguinte comando lá.

tracerpt "   .etl" -o -report -summary -lr

Após executar este comando, 4 arquivos serão gerados.

imagem

No momento, estamos interessados ​​em dumpfile.xml. Você pode abrir este arquivo através do bloco de notas ++, também pode fazer isso no Excel.

Tendo estudado cuidadosamente esse arquivo, você pode ver que esta sessão coletou quase todas as informações sobre nosso movimento na Internet !!! Você pode ler mais sobre isso aqui.Estudamos ETW e extraímos lucros .

Bem, e seguimos em frente. Acabamos de criar uma sessão com um único provedor de eventos. Dados da sessão recebidos do arquivo de log. É hora de codificar!

Usando a API de rastreamento de eventos para trabalhar com ETW


No habr, há um artigo interessante, a pior API já criada .

Neste artigo, você encontrará respostas para muitas perguntas que provavelmente terá ao escrever aplicativos!

Vamos codificar em C ++.

Vamos começar com o mais simples.

Configurar e iniciar uma sessão de rastreamento de eventos


Primeiro, considere a idéia geral.

Para iniciar uma sessão de rastreamento:

1) Defina a estrutura EVENT_TRACE_PROPERTIES

2) Inicie a sessão usando o StartTrace
Next, ative os provedores de eventos

3) Ligue os provedores usando EnableTrace | EnableTraceEx | EnableTraceEx2
Para interromper a sessão de rastreamento, você deve:

4) Antes de parar a sessão de rastreamento, você deve desativar os provedores usando EnableTrace | EnableTraceEx | EnableTraceEx2, passando EVENT_CONTROL_CODE_DISABLE_PROVIDER

5) Chame a função ControlTrace e passe EVENT_TRACE_CONTROL_STOP

No exemplo abaixo, estou criando uma sessão chamada MyEventTraceSession. O arquivo de log no diretório atual é chamado WriteThePuth.etl.O

provedor de eventos é Microsoft-Windows-Kernel-Process. Você pode descobrir o GUID dele usando

wevtutil gp Microsoft-Windows-Kernel-Process /ge /gm

Código diretamente:

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#include <iostream>
#define LOGFILE_PATH L"WriteThePuth.etl"
#define LOGSESSION_NAME L"MyEventTraceSession"


// GUID,     .
//      GUID .

// {AE44CB98-BD11-4069-8093-770EC9258A12}
static const GUID SessionGuid =
{ 0xae44cb98, 0xbd11, 0x4069, { 0x80, 0x93, 0x77, 0xe, 0xc9, 0x25, 0x8a, 0x12 } };


// GUID,   ,   
//    .

//{22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716} Microsoft-Windows-Kernel-Process
static const GUID ProviderGuid =
{ 0xd22FB2CD6, 0x0E7B, 0x422B, {0xA0, 0xC7, 0x2F, 0xAD, 0x1F, 0xD0, 0xE7, 0x16 } };

void wmain(void)
{
    setlocale(LC_ALL, "ru");
    ULONG status = ERROR_SUCCESS;
    TRACEHANDLE SessionHandle = 0;
    EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
    ULONG BufferSize = 0;
    BOOL TraceOn = TRUE;

    
    BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(LOGSESSION_NAME);
    pSessionProperties = (EVENT_TRACE_PROPERTIES*)malloc(BufferSize);
    if (NULL == pSessionProperties)
    {
        wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
        goto cleanup;
    }

    ZeroMemory(pSessionProperties, BufferSize);
    pSessionProperties->Wnode.BufferSize = BufferSize;
    pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
    pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
    pSessionProperties->Wnode.Guid = SessionGuid;
    pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
    pSessionProperties->MaximumFileSize = 1024;  // 1024 MB
    pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
    pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME);
    StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);
    

    status = StartTrace((PTRACEHANDLE)&SessionHandle, LOGSESSION_NAME, pSessionProperties);
    if (ERROR_SUCCESS != status)
    {
        wprintf(L"StartTrace() failed with %lu\n", status);
        goto cleanup;
    }

    //  ,   ,      .

    status = EnableTraceEx2(
        SessionHandle,
        (LPCGUID)&ProviderGuid,
        EVENT_CONTROL_CODE_ENABLE_PROVIDER,
        TRACE_LEVEL_INFORMATION,
        0,
        0,
        0,
        NULL
        );

    if (ERROR_SUCCESS != status)
    {
        wprintf(L"EnableTrace() failed with %lu\n", status);
        TraceOn = FALSE;
        goto cleanup;
    }

    //   .    ,   
    wprintf(L"Run the provider application. Then hit any key to stop the session.\n");
    _getch();
   

cleanup:
    if (SessionHandle)
    {
        if (TraceOn)
        {
            status = EnableTraceEx2(
                SessionHandle,
                (LPCGUID)&ProviderGuid,
                EVENT_CONTROL_CODE_DISABLE_PROVIDER,
                TRACE_LEVEL_INFORMATION,
                0,
                0,
                0,
                NULL
                );
        }

        status = ControlTrace(SessionHandle, LOGSESSION_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);

        if (ERROR_SUCCESS != status)
        {
            wprintf(L"ControlTrace(stop) failed with %lu\n", status);
        }
    }

    if (pSessionProperties)
    {
        free(pSessionProperties);
        pSessionProperties = NULL;
    }
}

Analisaremos o programa acima com mais detalhes.

1) Defina a estrutura EVENT_TRACE_PROPERTIES

Para configurar uma sessão de rastreamento de eventos, você deve usar a estrutura EVENT_TRACE_PROPERTIES para especificar propriedades da sessão. A memória que você aloca para a estrutura EVENT_TRACE_PROPERTIES deve ser grande o suficiente para conter também os nomes da sessão e os arquivos de log que seguem a estrutura na memória.

2) Inicie a sessão usando o StartTrace

Depois de especificar as propriedades da sessão, chame a função StartTrace para iniciar a sessão. Se a função for bem-sucedida, o parâmetro SessionHandle conterá o descritor da sessão e a propriedade LoggerNameOffset conterá o deslocamento do nome da sessão.

3) Ative os provedores usando o EnableTrace | EnableTraceEx | EnableTraceEx2

Para habilitar os provedores que você deseja permitir a gravação de eventos em sua sessão, chame a função EnableTrace para habilitar provedores clássicos e a função EnableTraceEx para habilitar provedores baseados em manifesto. Em outros casos - EnableTraceEx2.

4) Antes de parar a sessão de rastreamento, você deve desativar os provedores usando o EnableTrace | EnableTraceEx | EnableTraceEx2 passando EVENT_CONTROL_CODE_DISABLE_PROVIDER

Para parar a sessão de rastreamento após a coleta de eventos, chame a função ControlTrace e passe EVENT_TRACE_CONTROL_STOP como o código de controle. Para especificar uma sessão para parar, você pode passar o descritor da sessão de rastreamento de eventos obtido de uma chamada anterior para a função StartTrace ou o nome de uma sessão iniciada anteriormente. Desconecte todos os provedores antes de interromper a sessão. Se você parar a sessão antes de desligar o provedor pela primeira vez, o ETW desconectará o provedor e tentará chamar a função de controle de retorno de chamada do provedor. Se o aplicativo que iniciou a sessão terminar sem desconectar o provedor ou chamar a função ControlTrace, o provedor permanecerá ativado.

5) Para parar a sessão de rastreamento, chame a função ControlTrace e passe-a para EVENT_TRACE_CONTROL_STOP

Como vimos no exemplo acima, o uso da API de rastreamento de eventos não é o mais fácil. Dependendo do que você faz, você pode continuar escrevendo fornecedores de eventos ou consumidores de eventos. No entanto, essas duas tarefas são bastante volumosas e não serão consideradas neste artigo! Complexidade adicional é criada por 4 tipos de provedores de eventos e, consequentemente, 4 opções para gravar eventos e 4 opções para seu consumo. O trabalho com a API de rastreamento de eventos é descrito em detalhes e bem no site oficial da Microsoft. Usando o rastreamento de eventos

Depois de trabalhar por algum tempo com a API de rastreamento de eventos, tive uma pergunta: existem utilitários que simplificam minha vida?

Usando tracerpt e xperf para trabalhar com ETW


Neste capítulo, não considerarei esses utilitários do ponto de vista teórico.

Você pode usar o comando Tracerpt para analisar logs de rastreamento de eventos, arquivos de log gerados pelo monitor de desempenho e provedores de rastreamento de eventos em tempo real. Ele cria arquivos de despejo, arquivos de relatório e esquemas de relatório. Este utilitário possui um grande número de parâmetros, mas o seguinte "mínimo" é adequado para iniciar o trabalho

tracerpt " 1- .etl" ... " n- .etl" -o <   > -report <    > -summary<    > 

O utilitário xperf.exe é um controlador completo. Ele suporta argumentos de linha de comando para gerenciar provedores e sessões ETW. Os controladores podem solicitar o status das sessões ativas no momento e receber listas de todos os provedores registrados no sistema. Por exemplo, para obter todas as sessões ativas, use o seguinte comando:

C:\>xperf -loggers

e para obter uma lista de todos os provedores registrados no sistema, use o comando:

C:\>xperf -providers

Os controladores têm mais alguns recursos importantes. Eles podem atualizar sessões e liberar buffers para o disco.

É tudo por agora!

Infelizmente, neste artigo, não abordei uma série de questões interessantes (por exemplo, o consumo de eventos em tempo real ou o trabalho com sessões de finalidade específica).

Você pode ler sobre isso nos seguintes sites:

Rastreamento de eventos - documentação oficial da Microsoft
Estudamos o ETW e extraímos os benefícios do
Rastreamento de eventos para Windows no lado ruim. Mas essa não é exatamente a
pior API já criada

All Articles