02. Buscando a senha correta
Neste tutorial vamos aprender como encontrar um cógido válido para que a mensagem correta apareça. É bom lembrar que engenharia reversa é completametne legal desde que não envolva softwares comerciais ou que não viole direitos autorais. Como nesse caso nós estaremos utilizando um aplicativo que foi criado exclusivamente para esse tipde de estudo, não tem problema.
Antes de tudo baixe o nosso alvo:
-Download: fwdv2.zip
Vamos lá. Antes de iniciar o Olly, execute o programa, entre com um cógido qualquer e clique em 'Register'. Hum, apareceu a mensagem de Wrong Code. Isso, por incrível que pareça é bom, por alguns motivos, sendo 2 deles:
1) A mensagem aparece numa 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 é feita uma chamada para a funcao MessageBoxA
2) Através dessa mensagem de "Wrong Code", podemos também 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, 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 vai abrir mostrando todos os textos utilizados no programa. Logo de cara você já encontra a tal mensagem "Sorry, wrong code". Mas veja logo abaixo. Tem uma mensagem "Success! Thanks for Playing". Oras, provavelmente essa mesagem é usada quando acertamos o código.
Dê um duplo clique sobre a "boa mensagem". Nós vamos ser 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 que essa função é chamada? Precisamos descobrir como que nós podemos parar aqui. Para isso, selecione a primeira linha dessa sequencia do message box ( 0041068 ). Agora bem em baixo da janela do código, apareceu um texto "Jump from 00401050".
Isso significa que para essa mensagem aparecer, um salto no endereco 00401050 vai ter que ser efetuado. Vá até o endereco 00401050 ( aperte CTRL G e digite o endereço ou simplesmente procure no olho mesmo, já que o código é pequeno.
No endereço 00401050 temos:
00401050 74 16 JE SHORT v2.00401068
Se 2 elementos comparados forem iguais, ele pula para 00401068 ( que é o local onde a MessageBox contendo a mensagem de sucesso aparece ). Quais elementos? Os elementos da linha anterior. Dê uma olhada geral nas linhas anteriores à esse 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 um número digitado em uma caixa de texto ( já desconfia que número é esse que ele pega né? ). Normalmente essa função coloca o seu resultado ( o valor ), no registrador EAX ( lembre-se disso ). Depois ele move para o registrador EBX o valor hexadecimal 39A ( 922 em decimal ). Na linha seguinte ele decrementa o EBX ( subtrai 1 de EBX ). Como EBX tinha o valor 922, agora ele passa a ser 921. No endereço 0040104E ele compara EBX com EAX. EBX é 921, mas e o EAX, quanto é? Algumas linhas acima eu disse que o valor pego na caixa de texto é armazenado no registrador EAX, logo, ele vai comparar o EAX ( 921 ) com o texto digitado. Se os 2 forem iguais, ele vai executar o salto ( da linha 00401050 ) que nos leva até a mensagem da senha correta, caso contrário, ele continua sem fazer o pulo e exibe a mensagem de senha incorreta.
Matamos a charada. Se o valor digitado for igual a EBX ( 921 ), ele exibe a mensagem de senha válida, caso contrário, receberemos a mensagem de senha incorreta. Experimente digitar 921 na caixa de texto do programa e clicar em 'Register'. Voilá! Descobriu a senha de acesso :)
Tem algumas outras maneiras de localizar o local onde está o algoritmo que verifica a senha correta. Um deles é este que nós usamos. Outra maneira seria colocar breakpoints em chamadas de funções clássicas ( caso o programa use-as ). Abaixo algumas delas:
- GetDlgItemText ou GetDlgItemText
- LStrCmp ou StrCmp
- GetWindowTextA ou GetWindowText
- MessageBoxA
- GetDlgItemInt
O nome 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 foi o caso deste tutorial ), e a última pega um número digitado na caixa de texto ( também neste tutorial ).
Outro método que poderia ser utilizado é alterar o código para que ele aceite qualquer valor que você digite. Para fazer isso, você tem que obrigar o programa a realizar o salto, não somente quando a comparação for verdadeira. Você consegue isso alterando o JE ( Jump if Equal ) para simplesmente JMP ( Jump ). Ele vai sempre pular para a Msgbox correta, não interessando se o valor digitado está certo ou não. Leia meu tutorial anterior para saber como alterar o código e salvar o arquivo novamente.
F3rGO!