Beruflich Dokumente
Kultur Dokumente
net/comunidade/utilizando-debugger/785195/
Usuário Lembrar?
Senha
Compre lindos relógios da Timex e Dumont com super descontos de revenda autorizada, toda
linha a pronta entrega!
Página 1 de 3 1 23
Sumário:
1. Introdução e conceitos
2. Um pouco de assembly
3. Interface do Olly Debugger
4. Formas de aproximação
5. Re-assembly
6. Plugins
INTRODUÇÃO
Seguindo a minha linha de tutoriais voltados a programação, vou tratar sobre um assunto que
me interessa muito e talvez seja interessante para os programadores em geral: disassembler e
1 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
debuggers.
Atualmente existem dezenas de debuggers e disassemblers por aí, dentre os quais os mais
famosos são: W32DASM, IDA, WinDbg, SoftICE e Ollydbg. Neste tutorial será utilizado o
OllyDbg, pois é um dos melhores e mais poderosos debuggers (incluindo um disassembler)
disponíveis no mercado. É também pequeno e gratuito
Engenharia reversa. O processo de engenharia reversa de software não poderia ser feito
de forma eficiente sem a utilização de um debugger/disassembler. Muitas pessoas tendem
a confundir cracking com engenharia reversa, sendo que são conceitos diferentes. A
engenharia reversa por si só é uma atividade completamente legal, pois muito do que
vemos hoje só foi possível devido à engenharia reversa. A criação de drivers para Linux
de periféricos que antes só funcionavam com o Windows (WinModems) é um bom
exemplo de como a engenharia reversa traz coisas boas para nós.
CONCEITOS NECESSÁRIOS
Para entender o funcionamento de um debugger é preciso saber um pouco sobre alguns
conceitos ligados a informática, como o funcionamento da memória, processador, pilhas e
endereços. O conhecimento básico de assembly também é necessário, já que essa é a
linguagem que teremos de analisar. Caso não tenha experiência em assembly, fique tranqüilo,
pois nos capítulos seguintes darei uma visão geral sobre ela, o suficiente para entender o nosso
mini-aplicativo de estudo. Abaixo segue uma breve lista de conceitos:
2 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
Abraços,
Fergo
23-09-2007 por Fergo
Continuação...
UM POUCO DE ASSEMBLY
Para fazer o debug de binários compilados é necessário ter um conhecimento (ao menos básico)
da linguagem assembly, já que é para ela que a linguagem de máquina é traduzida.
Assembly (ou asm, com é abreviada) é uma linguagem de baixo nível que basicamente
interpreta os códigos operacionais (opcodes, veja abaixo) e os transcreve para seus
mnemônicos. É literalmente uma tradução da linguagem de máquina. O uso da linguagem
assembly pode ser bem variado, podendo fazer de tudo um pouco, mas é amplamente utilizada
na programação básica de Kernels e em algoritmos que precisam ser altamente otimizados,
onde asm é a linguagem ideal, já que é puramente linguagem de máquina traduzida.
Não pretendo agora explicar todo o funcionamento, estrutura e comandos da linguagem. Vou
dar apenas um apanhado geral sobre alguns termos e uma breve descrição sobre os comandos
mais básicos e corriqueiros que se encontra. Precisamos primeiramente definir o que são
mnemônicos e o que são os opcodes.
Código:
MOV EAX,1
3 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
Esse comando em assembly apenas move o valor 1 para o registrador EAX (veremos isso logo
adiante na explicação dos comandos). Na hora de transformar isso em linguagem de máquina
(por um asssembler), esse comando é traduzido para um conjunto de números que possa ser
interpretado pelo processador:
Código:
B801000000
Para o assembly, a localização dos valores e variáveis é sempre baseada nos endereços que
elas ocupam na memória. O nome que você define para uma variável durante a programação é
substituído pelo endereço de memória que ela ocupa. Cada instrução também possui um
endereço, que é utilizado para controlar o fluxo e a estrutura do código. Sempre que você faz
um salto, é necessário indicar o endereço que o código deve ser direcionado, semelhante ao
que ocorria nas numerações de linhas dos BASICs mais antigos. Veja um exemplo abaixo de
como ficaria um código em C e o seu resultado compilado para assembly, utilizando apenas
registradores comuns:
Código:
void main() {
int a = 4;
int b = 6;
int c;
O código acima quando compilado pode se transformar em algo semelhante a isso (boa parte do
código acima é inútil, estou utilizando somente para exemplificar):
Código:
00000000 MOV EAX,4h ;move o valor 4 para EAX
00000005 MOV EBX,6h ;move o valor 6 para EBX
0000000A CMP EAX,4h ;compara EAX com 4, se for verdadeiro: ZF = 1
0000000D JNE 00000019h ;se ZF != 1, pule para endereço 00000019h
0000000F CMP EBX,6h ;compara EBX com 6, se for verdadeiro: ZF = 1
00000012 JNE 00000019h ;se ZF != 1, pule para endereço 00000019h
00000014 MOV ECX,5h ;move o valor 5 para ECX
00000019 RETN ;finaliza execução e retorna
Pra entender o código acima é necessário entender sobre aquilo que compõe a linguagem
4 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
Os registradores foram explicados no capítulo anterior, mas vamos agora saber quem são eles.
Os processadores da arquitetura Intel de 32 bits possuem basicamente nove registradores de
32 bits comuns: EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI e EIP. Teoricamente cada um desses
registradores possui uma determinada “função padrão”, mas devido a sua escassez, muitas
vezes eles são utilizados como registradores para qualquer propósito. Você pode criar um
código usando livremente os oito primeiros registradores que não haverá muitos problemas
(desde que saiba o que está fazendo/modificando). O último registrador, EIP, é quase sempre
mantido intacto, pois ele é o responsável por contar as instruções e informar o endereço da
próxima instrução. Alterar o seu valor pode desviar completamente o fluxo do aplicativo e
provavelmente vai gerar uma falha de segmentação ou uma operação ilegal.
Esses registradores apresentados são todos de 32 bits. No entanto também é possível utilizar
apenas 8 ou 16 bits, como mostra a tabela abaixo utilizando o EAX como exemplo (a teoria
vale para os outros registradores também):
Para o caso da porção de 8 bits, o registrador terminado em L são os 8 bits menos significantes
de AX e o terminado em H são os 8 bits mais significantes de AX. Para a porção de 16 bits, são
utilizados os 16 bits menos significantes da porção de 32 bits.
Além dos registradores, também existem as Flags, que são bits utilizados como resultado de
operações (verdadeiro ou falso, por exemplo). Elas são usadas principalmente para análise
condicional em instruções como CMP e TEST. Dentre as diversas flags, as mais corriqueiras são:
ZF (Zero Flag), CF (Carry Flag) e SF (Signal Flag). A ZF é setada sempre que uma operação
resulta em zero (uma comparação entre dois números através do comando CMP subtrai seus
operandos sem alterar valores e seta a ZF caso o resultado da subtração seja zero, indicando
valores iguais). A flag CF é setada quando o resultado de uma operação estoura o valor
máximo comportado pelo registrador/local sem considerar o sinal (overflow). Por último,
tempos a SF, que é ativada sempre que o bit mais significativo de um operando for 1, indicando
um valor negativo (pesquise sobre complemento de dois).
Código:
00401000 MOV BYTE PTR DS:[00403000], 09h
Por último temos as instruções, que nada mais são do que os opcodes traduzidos em um
mnemônico, como demonstrado e exemplificado alguns parágrafos acima.
Abaixo eu vou por uma pequena lista mostrando algumas das instruções mais utilizadas, pois
seria inviável colocar todas elas (são aproximadamente 130 instruções bases para a arquitetura
Intel).
5 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
por isso ela pode aparecer de diversas formas diferentes (pode-se trabalhar com
constantes, memória, pilha, etc). Alguns exemplos:
JMP endereço
Faz um salto incondicional e obrigatório para o endereço indicado.
JMP 00401008h
JZ endereço / JE endereço
Faz um salto condicional. Caso o valor da zero flag seja 1, ele realiza o salto.
Normalmente utilizado junto com um CMP para realizar um desvio caso a comparação
seja verdadeira.
JE 0040101Ah
JNZ 0040102Ch
PUSH valor
Coloca o valor no topo da pilha (Stack). O comando PUSH é amplamente utilizado nas
chamadas de funções (CALL), pois é através da pilha que a função busca seus
argumentos.
PUSH 08h
POP destino
Remove o valor do topo da pilha e o armazena no destino.
POP EAX
CALL local
Faz chamada a uma função. É possível passar o local de diversas formas para o comando
CALL, desde uma constante, registrador ou até mesmo uma função externa dentro de
uma DLL. O comando CALL usa a pilha para indicar o endereço para o qual a função deve
retornar depois de finalizada a sua execução.
6 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
CALL User32!GetDlgItemTextA
CALL 0040115Fh
Essas são as instruções mais comuns dentro de um binário compilado. Claro que existe mais de
uma centena delas, mas eu procurei colocar aqui apenas aquelas que serão utilizadas no
aplicativo de aprendizado. Para uma lista completa com uma explicação mais profunda dos
opcodes, recomendo ver a lista apresentada neste endereço:
http://www.numaboa.com.br/informatic...ncias/opcodes/
Comentários/críticas/sugestões são bem vindas, claro (não me importo que as partes não
fiquem em sequência).
Abraços!
Fergo
23-09-2007 por philix
Ô cara!! Para que vc faz um tutorial tão bom?! Vou ter que parar meu serviço para ler agora!
24-09-2007 por Etinin
Nota 10 como praticamente todos seus tutos anteriores, Fergo!
25-09-2007 por Fergo
Valeu pelo suporte pessoal! Aí vai mais um pedaço
Para o nosso estudo, eu criei um simples aplicativo que iremos depurar mais a frente. Ele é
necessário neste já neste capítulo (não para depuração, mas para a apresentação dos itens do
Olly). Você pode baixar o arquivo executável juntamente com o seu código fonte (programado
em assembly na sintaxe MASM32 utilizando o WinAsm Studio como IDE) no link abaixo:
http://www.fergonez.net/files/adivinhe.rar
7 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
A interface do aplicativo é composta por poucos botões. O segredo do Olly é o botão direito do
mouse. A maioria das funções existentes no aplicativo pode ser acessada através do botão
direito do mouse, sendo que os itens exibido no menu de popup variam de acordo com o local
onde foi dado o clique (dependendo da coluna e da região).
Região 1
Coluna 1 – Address. Ela nos mostra o endereço virtual das instruções (para saber mais
sobre esse endereçamento, veja meu artigo sobre o funcionamento dos executáveis).
Você pode reparar que os endereços não são em intervalos iguais para cada instrução.
Isso ocorre devido ao fato de que o tamanho das instruções ser variável, como podemos
observar na segunda coluna.
Coluna 2 – Hex Dump. Aqui temos o código da instrução no seu formato hexadecimal (a
cada 2 caracteres, temos 1 byte). São esses valores que ficam armazenados dentro do
arquivo executável e que são passados para o processador. Como mencionado no
parágrafo anterior, as instruções variam de tamanho, sendo que o endereço da próxima
instrução é dado pelo endereço da instrução atual mais a soma dos bytes da instrução.
Veja o exemplo do nosso aplicativo de exemplo. Ele começa no endereço 00401000
(padrão do Windows) e a sua primeira instrução é composta por 2 bytes (6A 00). O
endereço da próxima instrução (na linha de baixo) vai ser o endereço atual somado com
o tamanho da instrução (00401000+2) = 00401002.
8 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
para assembly das instruções presentes na segunda coluna. A análise do aplicativo é feita
quase que inteiramente nela.
Coluna 4 – Comments. Essa coluna não influencia no aplicativo, ela é utilizada apenas
para comentários e informações. O Olly a utiliza para identificar as chamadas de função
juntamente com os seus argumentos (você pode ver que ele identifica as chamadas da
API do Windows em vermelho e lhe mostra os argumentos, facilitando e muito a
interpretação).
Região 2
Essa área mostra todos os registradores e flags que nós vimos anteriormente (juntamente com
diversos outros valores). A cada instrução essa tela é atualizada, mostrando o estado atual de
cada um dos itens. Caso algum desses itens tenha sido modificado de uma instrução para outra,
o Olly as colore com outra cor (nesse caso é o vermelho). As flags são mostradas logo abaixo
dos registradores, abreviadas com a letra C (Carry Flag), Z (Zero Flag) e S (Signal Flag)
Região 3
Essa região nos mostra a memória física (RAM) destinada ao aplicativo. É possível observar o
valor de cada byte de memória dentro do espaço reservado ao aplicativo. É composta por três
colunas:
Coluna 2 – Hex Dump. Este espaço contém o valor de cada byte da memória. Por padrão
o Olly coloca 8 bytes por linha e por essa razão a coluna de endereços cresce de 8 em 8
bytes.
Coluna 3 – ASCII. Essa coluna pode ser utilizada para exibir de formas diferentes os
valores contidos na memória. Por padrão o Olly opta por exibir a representação ASCII
desses valores. O modo de representação pode ser alterado utilizando o botão direito do
mouse.
Região 4
Mostra o estado atual da pilha (stack). Como visto anteriormente, a pilha é amplamente
utilizada durante as chamadas de função. O VisualBasic é uma linguagem que faz um uso
muito grande da pilha, principalmente pela quantidade de funções que são utilizadas pelo
aplicativo. Também é dividida em 3 colunas :
Coluna 1 – Address. Cumpre o mesmo papel das outras colunas de endereço. Nota-se
que o endereço cresce de quatro em quatro bytes, pois cada posição da pilha é ocupada
por um tipo DWORD (4 bytes)
9 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
Play – Inicia a execução e depuração do aplicativo. Caso nenhum breakpoint tenha sido
posicionado (veremos adiante), o programa será executado normalmente.
Pause – Pausa o aplicativo em andamento
Step Into – Caso um breakpoint tenha sido colocado em uma chamada de função, esse
botão lhe permite fazer a depuração do conteúdo dessa função.
Step Over – O contrário do item anterior. Ele simplesmente não “entra” dentro da
chamada (mas ainda assim a executa), continuando a depuração na próxima instrução.
Trace Into – Utilizado apenas quando está se faz backtracing. Ele registra as ações e
endereços em um log, registrando também o conteúdo das funções chamadas.
Trace Over – Semelhante ao item acima, mas não faz o registro do conteúdo das
chamadas.
L – Show Log Window: exibe um log, no qual o Olly registra algumas ações como
carregamento de plugins, etc.
E – Show Modules Window: exibe todos os módulos e funções externas utilizados pelo
programa (DLLs). Com o menu direito é possível acessar uma gama de opções dentro
dessa janela (o mesmo vale para todas as outras janelas que forem mencionadas). Essa
janela de módulos é muito importante para configurar breakpoints nas APIs do Windows,
facilitando a aproximação em determinada região do código.
M – Show Memory Window: mostra o estado da memória que está sendo utilizado pelo
aplicativo, incluindo as seções do executável e tabelas de importação/exportação. Para
um detalhamento byte a byte da memória, deve se utilizar a região de memória física
mostrada na janela principal do aplicativo.
T – Show Threads: exibe o estado de cada thread contida no aplicativo. Em aplicações
multi-threading é possível, através dessa janela, ter um controle sobre cada uma das
threads.
W – Show Windows: mostra a estrutura e configuração das janelas carregadas pelo
aplicativo (definida pelo WinProc). Os dados só são mostrados com o programa em
execução e precisa ser atualizada manualmente pelo usuário (através do botão direito do
mouse).
H – Show Handles: exibe uma informação detalhada sobre os handles (referência a um
objeto) que estão sendo utilizados pelo aplicativo. Quando o aplicativo abre um arquivo,
é retornado um handle, que é utilizado para fazer a leitura e escrita, por exemplo.
C – Show CPU: janela padrão do aplicativo, que é aberta automaticamente na hora de
carregar o alvo. O seu conteúdo já foi explicado nos itens anteriores (onde as regiões
foram numeradas de 1 a 4).
/ - Show Patches: as modificações feitas no executável ficam registradas nessa janela,
facilitando a modificação ou o retorno à instrução original.
K – Show Call Stack: mostra uma pilha de todas as chamadas de função até então
feitas pelo aplicativo.
B – Show Breakpoints Window: exibe todos os breakpoints setados no programa alvo.
R – Show references: exibe todas as referências encontradas durante uma busca (seja
ela uma constante, instrução, string). Veremos mais sobre elas adiante.
... – Run Trace: nessa janela é mostrado o resultado da operação de tracing
(mencionada quando falamos de Trace Into/Over). Tracing é um processo um pouco
complicado, por isso a sua explicação detalhada será apresentada mais a frente (é
possível encontrar uma boa explicação na própria ajuda do Olly).
S – Show Source: quando o aplicativo alvo é compilado com as informações de debug,
normalmente o código assembly resultante também é armazenado. Nesse caso essa
janela exibe esse código e mostra em tempo real o local no código fonte original que está
sendo executado no momento. Muito útil para comparar o código assembly escrito e o
compilado.
10 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
Estas foram as opções contidas na barra de ferramentas. O Olly também conta com um menu
tradicional, que contém basicamente as mesmas funções da barra de ferramentas. Um dos itens
do menu que vale a pena mencionar é o de plugins. O Olly suporta a criação de plugins, sendo
alguns deles muito úteis. Por padrão ele vêm apenas com dois plugins, um de bookmarks e
outro de comandos, que adiciona uma caixa de texto no rodapé do programa onde você pode
entrar com ações e comandos de forma semelhante ao SoftICE.
No rodapé do Olly fica uma pequena barra de status, que além de mostrar o estado atual do
alvo (finalizado, pausado ou em execução), serve como um informativo.
Abraços,
Fergo
26-09-2007 por luishoc
Fergo parabéns por criar um tutorial tão exepcional como esse.
Tópico bem explicativo.
Falou!
[]'s
luishoc
26-09-2007 por rhfpt
voce tem algum site para que possamos baixar esse tutorial?
26-09-2007 por philix
Citação:
voce tem algum site para que possamos baixar esse tutorial?
Abraços!
Fergo
27-09-2007 por rhfpt
ops... nao havia percebido..
Abraços,
Fergo
27-09-2007 por intruso
Muito bom o tópico, parabéns. :-)
28-09-2007 por Fergo
Valeu galera!
11 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
Quarta parte saindo do forninho. Desta vez fala de como encontrar aquilo que você quer no
meio de tanta instrução.
FORMAS DE APROXIMAÇÃO
Uma das maiores dificuldades em debugging de baixo nível (em assembly) é identificar o local
onde se encontra aquele trecho de código de deseja analisar. Existem diversas manhas para
convergir ao local correto, sendo que vou citar duas das mais utilizadas.
A primeira delas consiste em buscar em buscar por strings. Na maioria dos casos todo o texto
presente em um aplicativo fica armazenado em uma string table (tabela de strings), cada uma
com seu número identificador. Normalmente quem decide o que vai para a tabela de strings ou
o que é referenciado diretamente no código é o compilador, por isso esse método nem sempre
é totalmente funcional, mas costuma ter bons resultados.
Certo, mas que strings devemos procurar? Nós queremos é encontrar o local onde é feita a
comparação do número digitado com o número correto. Se o número não for aquele que você
digitou, ele vai exibir uma mensagem, que contém um título e um texto. Isso é bastante
interessante, pois a provável lógica do programa é verificar pelo número digitado e caso ele
seja incorreto, nos mostrar a MessageBox. Se nós encontrarmos o local onde o texto é utilizado
pela MsgBox, sabemos que estamos pertos e um pouco adiante de onde foi feita a verificação.
Há uma maneira bem direta de descobrir o local onde está a chamada para a MsgBox, mas vou
focar mais no sistema de busca por string. Vamos lá. Entre com um valor qualquer (maior que
0 e menor que 21) e mande verificar. Provavelmente você recebeu uma mensagem semelhante
a essa:
Repare que ela é composta por um título e um texto. Que tal verificar se é possível buscar
esses textos dentro do OllyDbg. Para tal, na janela principal, sobre o disassembly do código,
clique com o botão direito e vá em “Search For -> All referenced text strings”. Isso fará
com que o Olly mostre uma janela contendo todas as strings que são referenciadas por algum
comando dentro do código. Note que no conteúdo da janela apareceram três itens:
Podemos observar que temos três referências ao texto mensagem, ocorrendo em diferentes
endereços. “Curiosamente” a string “Mensagem.” é o título da mensagem de texto que
recebemos ao entrar com um valor errado. Isso significa que encontramos 3 possíveis locais
onde a caixa de texto é exibida. Uma maneira fácil de descobrir qual das três é a verdadeira
(mais pra frente veremos que na realidade nenhuma delas é “falsa”, são apenas mensagens de
texto diferentes) é setando um breakpoint sempre a mensagem de texto for referenciada. Para
tal, clique com o botão direito em qualquer uma das linhas e selecione “Set Breakpoint on
every command”. Sempre que a mensagem for utilizada, o Olly vai pausar a execução e lhe
mostrar onde a execução foi congelada.
Com o breakpoint configurado, apenas digite novamente o número no aplicativo de teste (sem
fechar ou reiniciar o Olly). Assim que você clicar no botão, ao invés de exibir a mensagem de
número incorreto, o Olly vai pausar a execução e lhe mostrar o local onde a referência de texto
foi utilizada. Você deve ter parado aqui (linha marcada em cinza):
12 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
Foi bem como queríamos. Paramos bem no local onde o endereço da mensagem é colocado na
pilha para ser utilizada pela função MessageBoxA:
Por curiosidade, note que temos 3 chamadas para a função MessageBox. Pelo texto de cada
uma é possível identificar que a primeira é referente ao texto de quando você acerta o número,
a segunda (que nós estamos) é de quando você erra e a última é para quando você entra com
um valor fora do intervalo especificado. Isso explica também o fato de termos três referências a
string “Mensagem.”, pois ela é utilizada pelas três chamadas.
Como mencionado anteriormente, esse método nos faz convergir para um local além de onde
foi feita a comparação (pois a mensagem de texto é exibida somente depois que o valor é
verificado). Para encontrar a comparação a partir do local atual podem-se utilizar diversos
métodos. Alguns preferem simplesmente ir analisado o código acima da MsgBox “na mão” ou
fazer um backtrace, que consiste em analisar o código asm inversamente. Como esse aplicativo
é bem pequeno, fica fácil achar o local na marra, mas vou dar uma visão sobre o backtracing. O
Olly felizmente possui várias funções que ajudam na interpretação do código, sendo que vamos
utilizar as referências de salto para essa situação. Para chegar até a mensagem de texto, muito
provavelmente foi feito um salto, já que a provável lógica seria:
Sabendo onde foi realizado o salto nos deixa mais próximo ainda do local da comparação. Como
o pulo foi realizado para mostrar a mensagem de texto, destino mais provável para o salto é
quando os dados da mensagem de texto começam a ser empilhados. Selecione a linha logo
acima da atual, onde tem o comando PUSH 0 (primeiro valor colocado na pilha). Note que o
Olly identifica esse local como sendo o alvo de um salto (veja na parte de baixo da região do
disassembly):
13 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
Basicamente ele está te dizendo que para chegar ao local atual, foi feito um salto no endereço
00401061. Podemos ir até esse local e verificar se esse salto realmente existe. Clique com o
botão direito sobre essa linha (no endereço 00401079) e vá em “GoTo -> JNZ from
00401061”. Isso nos levará diretamente para o local do salto:
Fomos levados até o endereço 00401061 onde realmente existe um salto (JNZ SHORT
adivinhe.00401079) e provavelmente estamos bem próximo do local da comparação.
Realmente estamos. Analise as linhas que antecedem o salto. Temos uma chamada a função
GetDlgItemInt (busca um inteiro contido dentro de um item da janela, que nesse caso é uma
caixa de texto) e o armazena em EAX (isso é padrão, todo retorno de função é em EAX). Em
sequida temos:
Creio que você já tenha sacado o que está ocorrendo. Ele está primeiramente verificando se o
número digitado está dentro do intervalo (20 >= X >= 1). Se eles estão no intervalo, nenhum
salto foi realizado, logo ele continua a execução. Logo após o valor digitado é comparado com o
número 4, e se eles forem diferentes, o programa pula para aquela mensagem de texto que
estávamos anteriormente. Que tal experimentar colocar o número 4 na caixa de texto do
programinha de estudo e ver o resultado? Bingo, encontramos o local da comparação e por
conseqüência, o número com o qual ele compara o valor digitado.
Esse código asm seria gerado basicamente por uma estrutura semelhante a esta, em um
pseudocódigo:
Código:
Declara variável inteira X;
X = Número contido na caixa de texto;
Se X < 1 ou X > 20 Então
Exibe mensagem de texto “Número Inválido”
Fim Se
Se X = 4 Então
Exibe mensagem de texto “Parabéns”
Caso Contrário
Exibe mensagem de texto “Você Errou”
Fim Se
Essa é uma das maneiras para localizar trechos de código em um debugger. É usado por muita
gente, sendo que esse exemplo que apresentei é um “clássico”. Outra forma, muito mais direta,
mas que exige um conhecimento da API do Windows é buscar pelas chamadas das funções das
APIs do Windows.
Supondo que o usuário tenha certa experiência em programação (seja em asm ou em C), ele
provavelmente conhece algumas funções do Windows, já que elas são necessárias para
qualquer aplicativo visual. Como a lógica desse programa se baseia em buscar e comparar um
dado digitado em uma caixa de texto, um usuário que já conheça um pouco da API sabe que é
necessário usar uma função do Windows para realizar esse processo. As duas funções mais
famosas que pegam dados de controles são: GetDlgItemText e GetDlgItemInt.
O Olly possui uma janela que mostra todas as funções utilizadas pelo programa, então podemos
14 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
verificar se existe uma dessas duas funções no aplicativo alvo. Para isso, clique no botão E (ou
use o atalho ALT+E) para abrir a janela de módulos. Vai ter uma breve lista, contendo na
primeira linha o próprio programa e nas outras as DLLs dependentes. Clique sobre a linha que
contém o nosso aplicativo (adivinhe) e vá em “View Names”. Isso exibirá uma lista com todas
as funções utilizadas pelo aplicativo.
Note que a função GetDlgItemInt foi utilizada, como buscávamos. Para descobrir o local onde
ela é usada pode-se utilizar o mesmo método de antes, clicando com o botão direito e
selecionando “Set breakpoint on every referecence”. Daí basta continuar a execução do
programa, digitar um número e clicar no botão. Quando o alvo for chamar a função, o Olly
congela e exibe o local onde será feita a chamada, que é logo acima de onde é feita a
verificação, como vimos anteriormente.
Eu particularmente prefiro este método sobre o das referências, por algumas razões:
Ele normalmente nos leva para uma região bem mais próxima da verificação e antes
dela. Utilizando as referências, você pode ser levado para um local muito além,
necessitando de muito backtracing.
Algumas referências de texto não aparecem na lista da string table, o que torna esse
método mais prático.
Não depende de mensagem de texto ou MessageBox, que nem sempre estão presentes
em todos os aplicativos.
Em breve a continuação!
Abraços,
Fergo
03-10-2007 por emtudo
cara nao posso deixar de te agradecer por este tutorial, eu queria ate viajar para aprender isso,
mas nunca sobrou "$"
esta de parabens!
05-10-2007 por junior Fire
Primeiramente quero dar parabéns pelo tutorial.
15 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
Estou acompanhando ele dês do inicio e quero sabe se você ira com ele até o fim.
T+
05-10-2007 por Fergo
Valeu pessoal!
Pretendo ir postando sim (até não sei se vai ter um final, posso ir sempre postando dicas sobre
o Olly e tudo mais). Tive 2 semanas corridas de prova na faculdade e não sobrou tempo para
muita coisa.
Fergo
05-10-2007 por emtudo
Citação:
Fergo
Se for falta de agradecer e dizer que o tutorial esta muito bom, vai ter um fim sim, pq vamos
sempre agradecer por este excelente trabalho
Mais uma vez o trabalho esta excelente, estamos aguardando com paciencia vc ter um tempo
para postar mais, mas nao tenha presa, aguardandos assim vc pode postar com paciencia e o
trabalho vai ficar excelente como ja esta ficando...
20-10-2007 por Fergo
Valeu pelo apoio pessoal.
Finalmente arranjei um tempo livre e dei continuidade do estudo
RE-ASSEMBLY
O Olly além de ser um ótimo debugger, é um ótimo assembler. Com ele também é possível
editar o código em tempo real e observar as mudanças de comportamento. Todas as mudanças
que você realiza no código ficam salvas já janela de “Show Patches” (/). Vamos agora ver
como podemos modificar o código e re-salvar o nosso executável (muito útil para correção de
bugs).
Reabra o nosso arquivo no Olly, caso ele esteja fechado. Nos capítulos anteriores discutimos
um pouco sobre o funcionamento do nosso aplicativo de teste, então vamos agora fazer uma
pequena modificação no mesmo para que ele sempre exiba a mensagem de “Você acertou”.
Nós tínhamos uma seqüência de comparações seguidas pelos seus respectivos saltos. A
primeira verificava se o número era menor que 1, a segunda se ele era maior que 20 e a
terceira se ele era em si o número escondido (4). Existem diversas formas de fazer com que o
número seja sempre o correto. Vou listar algumas:
Alterar o código forçando que o valor 4 seja movido para EAX antes da comparação.
Anular o último salto (após o CMP EAX, 4), fazendo com que o fluxo do aplicativo siga
direto para a mensagem correta.
Desviando e forçando um salto para a mensagem correta logo na primeira comparação
realizada.
Existem outras formas ainda, mas vamos ficar com essas três, pois são as mais óbvias. Eu vou
utilizar o último método neste tutorial para exemplificar o processo.
16 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
O que basicamente nós vamos fazer é forçar um salto logo após a função GetDlgItemInt
diretamente para a região que chama a nossa mensagem de texto “Você acertou...”, como
mostra a imagem abaixo:
Para modificar o disassembly, basta clicar sobre a linha que deseja alterar e apertar a tecla
“Espaço”. Isso fará com que uma janela se abra com um local onde você possa indicar a
instrução que deseja colocar no local.
O nosso objetivo aqui é substituir o CMP EAX, 1 por um salto não-condicional até o local onde
os argumentos da nossa mensagem de texto começam a ser selecionados (no PUSH 0,
localizado no endereço 00401063).
Clique sobre a linha que contém o CMP EAX, 1 (no endereço 00401054) e pressione “Espaço”.
A seguinte janela se abrirá:
Na caixa de texto é onde você entra com a instrução em assembly que deseja substituir. Caso a
instrução que nós inserirmos seja menor (em bytes) que a instrução anterior, o Olly substitui
esses bytes restantes pela instrução NOP, que não realiza nenhuma operação, evitando assim
que fiquem resquícios e “lixos” do comando anterior (caso a caixa de seleção “Fill with NOP’s”
esteja selecionada, claro).
Em seguida, basta clicar em Assemble para confirmar a modificação. Você deve ter notado que
o Olly coloriu com vermelho aquilo que foi modificado. Note também que ele inseriu um
comando NOP após o salto, indicando que o nosso opcode do salto era 1 byte menor que o
comando anterior.
Você pode rodar o nosso aplicativo dentro do Olly e observar a modificação. Agora, com
17 de 18 19/08/2010 18:31
Utilizando um debugger - OllyDbg http://www.guiadohardware.net/comunidade/utilizando-debugger/785195/
qualquer valor que você entre (mesmo aqueles fora do intervalo), o programa vai exibir a
mensagem que desejávamos.
Para salvar o novo executável é bem simples. Na janela de dissassembly, clique com o botão
direito e vá para “Copy to Executable -> All modifications”. Uma pequena janela se abrirá
perguntando se você deseja copiar o código modificado. Selecione “Copy All”. Uma nova
janela, contendo todo o código modificado, será exibida. Clique com o botão direito sobre ela e
selecione “Save File”. Basta escolher o local e você terá um novo executável, contendo a
modificação realizada.
Citação:
RE-ASSEMBLY
Valeu, esta cada vez melhor, nao posso deixar de sempre agradecer
22-10-2007 por Fergo
Valeu emtudo!
Já foi liberada a versão 2.0 pré-alpha do Ollydbg, pode ser conferida no link:
http://www.ollydbg.de/
Ainda não é boa para ser utilizada em debugging, pois quase todas as funcionalidades ainda
estão desativadas, mas já da para perceber uma certa melhoria na análise do código.
Fergo
18 de 18 19/08/2010 18:31