logo
Contato | Sobre...        
rebarba rebarba

WinDbg: Debugger de gente grande (parte 1)

O que é o WinDbg

Considerando a forma como o WinDbg é construído, ele não é realmente um debugger. O que ele faz é prover uma interface Windows, bem mais intuitiva, para os debuggers com interface linha de comando que são encontrados no Platform SDK e no DDK : o kd (kernel mode) e o cdb (user mode). Ele usa a infra-estrutura desses debuggers para prover um ambiente mais parecido com o Visual Studio, com janelas de watch, breakpoints visuais em linhas de código e outras facilidades possíveis somente no mundo das janelinhas. Inclusive, a maioria das coisas que eu disser sobre o WinDbg também se aplicam aos dois debuggers, o kd e o cdb.

O WinDbg não é o único debugger de gente grande que existe. Além dele, você pode usar também o SoftIce da Compuware, que inclusive, permite que você faça debug em modo kernel NA MESMA MÁQUINA, sem precisar de uma máquina adicional (como é o caso do WinDbg e do kd). O grande problema do SoftIce é que ele custa mais do que uma máquina de testes...

Diferenças entre o WinDbg e o Visual Studio.NET

O Visual Studio.NET possui um debugger integrado diretamente no ambiente de desenvolvimento, o que permite que você desenvolva seu aplicativo e faça o debug dele usando o mesmo software. Isso facilita bastante as coisas, já que você não precisa operar diversos programas para desenvolver e fazer debug de um aplicativo.

(No Visual Studio 2005, além de todas as ferramentas que já temos hoje, teremos ferramentas para testes, Code Coverage tests, Unit Tests, diagramas de classes, entre outras. Tudo isso integrado com a IDE)

Segue agora uma lista com as principais diferenças entre os debugger do VS.NET e o WinDbg:

  • Debug remoto por meio de debug Proxy, para quando você não pode efetuar conexão direta (via TCP/IP ou serial). Com o WinDbg, você conecta em um WinDbg em outra máquina, que então conecta em outra máquina para debug, como no diagrama abaixo


  • É um debugger com linha de comando (parecido com o AutoCAD e com o Command Windows do VS.NET), o que dá mais flexibilidade;
  • Metacomandos, onde você pode fazer pequenos scripts para facilitar o debug de coisas repetitivas;
  • Facilidade em colocar breakpoints em funções da API ou de DLLs de terceiros. Isso facilita bastante estudar o funcionamento e fazer engenharia reversa de softwares;
  • Criar assembly inline e trocar código que está na memória;
  • Fazer debug de drivers e códigos que rodam em kernel mode. Para fazer esse tipo de debug, você deve colocar o código a ser depurado em uma segunda máquina, e conectá-la a sua máquina (com WinDbg) via cabo serial ou firewire;
  • O WinDbg não colore o código, como o Visual Studio;
  • O WinDbg só faz debug de managed code no Windows Longhorn (por enquanto, eu espero). Você consegue listar os métodos de um executável managed, mas não consegue colocar breakpoints. A documentação diz que é possível fazer isso com o framework 2.0 beta, mas eu não consegui. Se alguém conseguir, me conte como fez e eu coloco aqui :-)

Um item dessa lista fala sobre engenharia reversa. O conhecimento de engenharia reversa geralmente não é visto com bons olhos, pois está geralmente ligado ao crack de software. Mas ele é somente um dos usos da engenharia reversa. Você pode usá-la para descobrir porque um programa causa um GPF quando usa uma determinada API em uma determinada situação, entre outras utilidades. Esse conhecimento é muito útil no dia-a-dia, para resolver diversos problemas, principalmente os com programas cujo código fonte não está disponível (o Windows, por exemplo). Já tive problemas que só foram resolvidos depois que eu instalei a versão checked do Windows 2000 e fiz engenharia reversa de partes do WinLogon e da MSGINA.DLL, para ver como a autenticação do usuário funcionava.

Instalando

O WinDbg é gratuito e disponível para download na página da Microsoft. Ele faz parte do pacote "Debugging Tools for Windows", que além do WinDbg, contém os debuggers que eu já citei (kd e cdb), a documentação e os headers para fazer extensões para os debuggers. Caso o WinDbg não faça aquilo que você precisa, você pode fazer uma DLL de extensão, que tem acesso à todas as informações de debug que o WinDbg tem.

A instalação é bem no estilo "next-next-finish", sem maiores dificuldades.

Fazendo os acertos finais

No Visual Studio.NET, o ambiente de desenvolvimento já está integrado com o debugger, e 99,99% das vezes, você fará debug de um aplicativo através do projeto que está aberto. Isso faz com o que o Visual Studio já saiba onde encontrar todas as informações necessárias para debug. Entre elas, onde está o arquivo com as informações de debug e a localização dos fontes do programa.

No WinDbg, essa informação é completamente desconhecida, já que não existe integração entre o projeto do VS.NET e o debugger. Nos aplicativos compilados em versão DEBUG, usando o Visual Studio.NET, as informações de debug são embutidas dentro do executável. Além disso, a localização dos fontes está dentro das informações de debug, o que faz com que o WinDbg os ache automaticamente.

Em casos onde o aplicativo foi compilado em versão RELEASE (mas tem symbols) ou o caso de um aplicativo DEBUG sendo executado em outra máquina, precisamos informar ao WinDbg onde estão os symbols da aplicação (mais sobre isso depois) e onde estão os fontes. Para fazer isso, use os menus File >> Sources Path e File >> Symbols Path.

3, 2, 1: Launch!

Existem duas maneiras de fazer debug de um processo: iniciando o aplicativo diretamente no debugger, ou fazer um attach (anexar) em um processo que já esteja em execução.

Para iniciar um aplicativo direto no debug, usamos o menu File >> Open Executable (CTRL+E). O programa será iniciado pelo WinDbg, com um breakpoint diretamente no loader do Windows, ou seja, antes do método Main ser executado. Agora é só colocar breakpoints onde for necessário e mandar seguir. Por falar em mandar seguir, ele tem teclas de atalho bem parecidas com o Visual Studio (F5, F9, F10 e F11), o que torna a adaptação bem menos traumática.

Para essa nossa primeira experiência eu fiz um programinha simples em C++ que muda o fundo de tela para uma outra imagem (essa imagem vem junto com o Windows XP), usando o ActiveDesktop.

#define _WINVER      0x500
#define _WIN32_WINNT 0x500
#define _WIN32_IE    0x500
#define UNICODE
#define _UNICODE

#include <atlstr.h>
#include <atlbase.h>
#include <wininet.h>
#include <shlobj.h>

int wmain(int argc, WCHAR* argv[])
{
   HRESULT hr;
   CComPtr<IActiveDesktop> pActiveDesktop;
   ATL::CString strBuffer;

   CoInitialize(0);

   //
   // pega a pasta do Windows
   //
   hr = SHGetFolderPath(NULL,
                        CSIDL_WINDOWS,
                        NULL,
                        SHGFP_TYPE_CURRENT,
                        strBuffer.GetBuffer(MAX_PATH));
                        
   strBuffer.ReleaseBuffer();
   
   if(FAILED(hr))
      return hr;

   //
   // anexa o caminho do jpg
   //
   strBuffer += L"\\web\\wallpaper\\Crystal.jpg";
   

   //
   // cria o objeto COM do ActiveDesktop
   //
   hr = CoCreateInstance(CLSID_ActiveDesktop,
                         NULL,
                         CLSCTX_ALL,
                         IID_IActiveDesktop,
                         (void**)&pActiveDesktop);

   if(FAILED(hr))
      return hr;

   //
   // agora é só mudar o wallpaper
   //
   hr = pActiveDesktop->SetWallpaper(strBuffer,NULL);
   
   if(FAILED(hr))
      return hr;

   hr = pActiveDesktop->ApplyChanges(AD_APPLY_ALL);
   
   CoUninitialize();
   
   return hr;
}
	

Esse programa usa ATL e é compilado em UNICODE (note o L antes da string). Você pode criar um projeto console no Visual C++ e colocar esse código (movendo a parte dos includes para o stdafx.h) no CPP ou compilar em linha de comando usando "cl [nome do arquivo].cpp /Zi /link".

Caso você não tenha o Visual C++, você pode baixar o Visual C++ 2005 Express (com IDE e grátis) ou o Visual C++ Toolkit 2003 (compilador de linha de comando, grátis), e depois instalar via web o Microsoft Platform SDK (grátis também, instale só o [Core SDK >> Build Environment] e o [Internet Development SDK >> Build Environment]). Depois é só configurar o VC++ para procurar os includes em Microsoft SDK\include.

Com o programa compilado, vamos abri-lo no WinDbg. Sua tela de comando vai exibir um texto parecido com esse:

Microsoft (R) Windows Debugger Version 6.3.0011.2
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: C:\TEMP\code\ds1\ds1.exe

Executable search path is:

ModLoad: 00400000 00410000 ds1.exe

ModLoad: 77f50000 77ff7000 ntdll.dll
ModLoad: 77e60000 77f46000 C:\WINDOWS\system32\kernel32.dll
ModLoad: 77d40000 77dcc000 C:\WINDOWS\system32\USER32.dll
ModLoad: 7e090000 7e0d1000 C:\WINDOWS\system32\GDI32.dll
ModLoad: 77dd0000 77e5d000 C:\WINDOWS\system32\ADVAPI32.dll
ModLoad: 78000000 78087000 C:\WINDOWS\system32\RPCRT4.dll
ModLoad: 771b0000 772d4000 C:\WINDOWS\system32\ole32.dll
ModLoad: 773d0000 77bc9000 C:\WINDOWS\system32\SHELL32.dll
ModLoad: 77c10000 77c63000 C:\WINDOWS\system32\msvcrt.dll
ModLoad: 70a70000 70ad5000 C:\WINDOWS\system32\SHLWAPI.dll
(45c.a2c): Break instruction exception - code 80000003 (first chance)
eax=00241eb4 ebx=7ffdf000 ecx=00000002 edx=77f51304 esi=00241eb4 edi=00241f48
eip=77f75a58 esp=0012fb38 ebp=0012fc2c iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!DbgBreakPoint:
77f75a58 cc int 3
0:000>

Aqui temos listadas as DLLs que foram carregadas com o seu programa e a função que está na pilha (ntdll!DbgBreakPoint). Agora vamos começar a controlar o programa. Com o foco no prompt do WinDbg (a linha abaixo da saída que tem 0:000> no começo), digite "P" e aperte ENTER. Você verá que na saída foi adicionada mais um DUMP da situação dos registradores. O "P" é equivalente ao F10 do Visual Studio. Assim como o "G" é equivalente ao F5 e o "T" ao F11.

Seguindo passo a passo

Siga o código usando F11. Você notará que logo mais você entrará na função ntdll!LdrpInitializeProcess. Isso faz parte do Loader do Windows. Isso serve para notar que o breakpoint inicial do programa é feito ANTES do método wmain. Nós poderíamos seguir com F11 até chegar ao nosso wmain, mas isso levaria bastante tempo. O mais fácil é colocar um breakpoint no nosso método wmain. Para fazer isso, usamos o comando

bp ds1!wmain

Considerando que ds1 é o nome do nosso executável. Como existem várias funções no nosso executável e também nas DLLs que foram carregadas, é necessário informar em qual módulo reside a função onde queremos o breakpoint. O comando funciona sem qualificar o módulo da função, mas isso fará que o WinDbg procure a função em todos os módulos carregados, o que é bem mais demorado.

Agora que temos nosso breakpoint na função wmain, pressione F5 (comando "G") para seguirmos até o nosso programa, que é o que interessa. Se os arquivos fontes estão na mesma pasta onde a compilação foi feita, o WinDbg deve abrir automaticamente o fontes, como vemos a seguir:

O que tem nessa variável?

Temos duas formas principais para visualizar o conteúdo das nossas variáveis: usando a janela de watch ou o comando DT. Para usar a janela de watch, é só exibi-la usando o menu View >> Watch. Na janela de watch, basta digitar o nome da variável em algum campo em branco. Usando o comando DT, basta digitar DT [nome da variável], como no exemplo abaixo:

Esse não é o fim

Aqui vimos os comandos básicos do WinDbg, que nos permite efetuar o procedimentos mais comuns em uma sessão de debug. Vimos como controlar o programa e visualizar o conteúdo das variáveis. Nos próximos artigos veremos mais coisas sobre o WinDbg.

Veja também
WinDbg: Debugger de gente grande (parte 2)

  
 
 
Comentários
Emerson | e-mail | em 18/07/2005 | #
Rodrigo,
Gostaria de saber o que você tem alguma coisa que ajude no desenvolvimento de driver para modem. Estou começando a estudar este assunto e preciso desenvolver um driver para um modem que desenvolvi.

Grato pela atenção

Emerson da Fonseca Silvério
Rodrigo Strauss | website | em 18/07/2005 | #
Emerson, dê uma olhada em http://www.1bit.com.br/content.1bit/weblog/fazer_drivers_1 e http://www.1bit.com.br/content.1bit/weblog/como_fazer_driver...
Elan Duarte Fraga | e-mail | em 11/10/2005 | #
Eu tenho um grande problema com a dll, meu sistema é em delphi 7 , dbx e firebird 15.
erro:Access violation at address 7C9010F3 in module 'ntdll.dll'. Write of address 004347C4
Alguem pode me ajudar?
iata vanderson | em 15/06/2006 | #
fera, peço por favor q me indique alguns sites e livros pois estou começando em programação C++ e preciso de referencias
Rodrigo Strauss | website | em 15/06/2006 | #
http://www.1bit.com.br/content.1bit/weblog/faq_cpp_start
guilherme | em 14/11/2006 | #
Gostario de parabenizar, mas como sou iniciante não etendi muito bem, se possivel ponha exemplos completos para podermos estudar.
value, muito obrigado.
Guilherme | em 14/11/2006 | #
ai tocomeçando em c++, tem como dar umas indicações de tutorias completos p/ iiciantes
Rodrigo Strauss | website | em 14/11/2006 | #
http://www.1bit.com.br/content.1bit/weblog/faq_cpp_start
valdeci santana | e-mail | em 18/03/2007 | #
eu estou querendo aprender o oficio de programação mas não sei por onde começar.um amigo meu que é programador me aconselhou a começar a estudar logica de programação.
me disse que tenho que estudar bastante a estrutura de algoritimo.
Rodrigo Strauss | website | em 19/03/2007 | #
http://www.1bit.com.br/content.1bit/programador
moises | em 17/07/2007 | #
link de download off?
Rodrigo Strauss | website | em 17/07/2007 | #
Oops...
http://www.google.com/search?q=windbg%20download
Algo a dizer?
Nome:


Site:


E-mail:


Escreva o número vinte e seis:


 Não mostre meu e-mail no site, não serve pra nada mesmo...

Comentário





Os comentários devem ser sobre assuntos relativos ao post, eu provavelmente apagarei comentários totalmente offtopic. Se quiser me enviar uma mensagem, use o formulário de contato. E não esqueça: isso é um site pessoal e eu me reservo o direito de apagar qualquer comentário ofensivo ou inapropriado.
rebarba rebarba
  ::::