02. Buscando a senha correta
Neste tutorial, vamos aprender como encontrar um código válido para que a mensagem correta apareça. É bom lembrar que engenharia reversa é completamente legal, desde que não envolva softwares comerciais ou que não viole direitos autorais. Como, neste caso, estaremos utilizando um aplicativo criado exclusivamente para esse tipo de estudo, não há problema algum.
Antes de tudo, baixe o nosso alvo:
- Download: fwdv2.zip
Vamos lá. Antes de iniciar o Olly, execute o programa, digite um código qualquer e clique em 'Register'. Hum, apareceu a mensagem de "Wrong Code". Isso, por incrível que pareça, é bom, por alguns motivos — sendo dois deles:
1) A mensagem aparece em uma MessageBox (que é uma chamada de API). Podemos localizar a região onde é feito o cálculo do código correto colocando um breakpoint em todos os locais onde há chamada para a função MessageBoxA.
2) Através dessa mensagem de "Wrong Code", também podemos descobrir o local correto vendo onde ela é utilizada (provavelmente em conjunto com a MessageBox).
Vamos pelo segundo método. Inicie o Olly e abra o nosso alvo. O código é bem pequeno, com poucas linhas. Bom para nós. Clique com o botão direito sobre a janela principal, vá em 'Search for -> All Referenced Text Strings'. Uma nova janela será aberta mostrando todos os textos utilizados no programa. Logo de cara, você já encontra a tal mensagem "Sorry, wrong code". Mas veja logo abaixo: há uma mensagem "Success! Thanks for Playing". Ora, provavelmente essa mensagem é usada quando acertamos o código.
Dê um duplo clique sobre a "boa mensagem". Seremos levados ao local onde ela é utilizada. Você vai parar aqui:
00401068 6A 40 PUSH 40
0040106A 68 00304000 PUSH v2.00403000
0040106F 68 2A304000 PUSH v2.0040302A
00401074 FF75 08 PUSH DWORD PTR SS:[EBP+8]
00401077 E8 28000000 CALL <JMP.&user32.MessageBoxA>
Como você pode ver, ela é o segundo argumento da função MessageBoxA. Certo, mas quando essa função é chamada? Precisamos descobrir como podemos parar aqui. Para isso, selecione a primeira linha dessa sequência do MessageBox (00401068). Agora, logo abaixo da janela do código, apareceu o texto "Jump from 00401050".
Isso significa que, para essa mensagem aparecer, um salto no endereço 00401050 precisa ser executado. Vá até o endereço 00401050 (aperte CTRL+G e digite o endereço, ou simplesmente procure visualmente, já que o código é pequeno).
No endereço 00401050 temos:
00401050 74 16 JE SHORT v2.00401068
Se dois elementos comparados forem iguais, ele pula para 00401068 (o local onde a MessageBox com a mensagem de sucesso aparece). Quais elementos? Veja as linhas anteriores ao jump:
00401043 E8 56000000 CALL <JMP.&user32.GetDlgItemInt>
00401048 BB 9A030000 MOV EBX,39A
0040104D 4B DEC EBX
0040104E 3BC3 CMP EAX,EBX
00401050 74 16 JE SHORT v2.00401068
Em 00401043, ele chama uma função que pega o número digitado em uma caixa de texto (já imagina qual número é esse, né?). Essa função normalmente coloca o valor obtido no registrador EAX. Depois, o valor hexadecimal 39A (922 em decimal) é movido para o registrador EBX. Em seguida, EBX é decrementado (subtrai-se 1), passando a valer 921. No endereço 0040104E, ele compara EBX com EAX. EBX vale 921, e EAX contém o valor digitado. Se forem iguais, o salto da linha 00401050 é executado, levando à mensagem da senha correta; caso contrário, o salto não ocorre e a mensagem de erro é exibida.
Matamos a charada. Se o valor digitado for igual a EBX (921), ele exibe a mensagem de sucesso; caso contrário, recebemos a mensagem de erro. Experimente digitar 921 na caixa de texto do programa e clicar em 'Register'. Voilà! Descobrimos a senha de acesso :)
Existem outras maneiras de localizar onde está o algoritmo de verificação da senha. Uma delas é essa que usamos. Outra seria colocar breakpoints em chamadas de funções clássicas (caso o programa as utilize). Algumas delas:
- GetDlgItemText ou GetDlgItemText
- LStrCmp ou StrCmp
- GetWindowTextA ou GetWindowText
- MessageBoxA
- GetDlgItemInt
Os nomes das funções já dizem tudo: a primeira pega textos digitados em caixas de diálogo, a segunda compara strings, a terceira pega texto de janela, a quarta exibe MessageBox (como neste tutorial), e a última pega um número digitado (também usada aqui).
Outro método seria alterar o código para aceitar qualquer valor digitado. Para isso, você deve forçar o programa a realizar o salto, independentemente da comparação. Isso pode ser feito alterando o JE
(Jump if Equal) para JMP
(salto incondicional). Assim, ele sempre executa a mensagem de sucesso, mesmo com código errado. Leia meu tutorial anterior para saber como alterar o código e salvar o arquivo novamente.
F3rGO!