Parte 1 de 3
Se você é sério em engenharia reversa - esqueça os treinadores e os mecanismos de trapaça.
Uma boa engenharia reversa deve primeiro conhecer o sistema operacional, as funções básicas da API, a estrutura geral do programa (o que é loop de execução, estruturas do Windows, rotinas de tratamento de eventos), formato de arquivo (PE). Os clássicos "Janelas de programação" da Petzold podem ajudar (www.amazon.com/exec/obidos/ISBN=157231995X), bem como MSDN online.
Primeiro você deve pensar sobre onde a rotina de inicialização do campo minado pode ser chamada. Pensei em seguir:
- Quando você inicia o jogo
- Quando você clica em cara feliz
- Quando você clica em Jogo-> Novo ou pressiona F2
- Quando você muda o nível de dificuldade
Decidi verificar o comando do acelerador F2.
Para localizar o código de manipulação do acelerador, você deve encontrar o procedimento de manipulação de mensagens da janela (WndProc). Ele pode ser rastreado por chamadas CreateWindowEx e RegisterClass.
Ler:
Abra a janela IDA, Importações, encontre "CreateWindow *", vá até ela e use o comando "Jump xref to operand (X)" para ver onde ela é chamada. Deve haver apenas uma chamada.
Agora procure a função RegisterClass e seu parâmetro WndClass.lpfnWndProc acima. Já chamei a função mainWndProc no meu caso.
.text:0100225D mov [ebp+WndClass.lpfnWndProc], offset mainWndProc
.text:01002264 mov [ebp+WndClass.cbClsExtra], edi
.text:01002267 mov [ebp+WndClass.cbWndExtra], edi
.text:0100226A mov [ebp+WndClass.hInstance], ecx
.text:0100226D mov [ebp+WndClass.hIcon], eax
.text:01002292 call ds:RegisterClassW
Pressione Enter no nome da função (use 'N' para renomeá-la para algo melhor)
Agora dê uma olhada em
.text:01001BCF mov edx, [ebp+Msg]
Este é o id da mensagem, que no caso de pressionar o botão F2 deve conter o valor WM_COMMAND. Você deve descobrir onde está em comparação com 111h. Isso pode ser feito rastreando edx no IDA ou definindo um ponto de interrupção condicional no WinDbg e pressionando F2 no jogo.
Qualquer uma das formas leva a algo como
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
Clique com o botão direito em 111h e use "Constante simbólica" -> "Usar constante simbólica padrão", digite WM_ e pressione Enter. Agora você deve ter
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
É uma maneira fácil de descobrir os valores de id da mensagem.
Para entender o manuseio do acelerador, verifique:
É muito texto para uma única resposta. Se você estiver interessado, posso escrever mais alguns posts. Longa história curta campo minado armazenado como uma matriz de bytes [24x36], 0x0F mostra que o byte não é usado (jogando campo menor), 0x10 - campo vazio, 0x80 - meu.
Parte 2 de 3
Ok, vamos continuar com o botão F2.
De acordo com o uso de aceleradores de teclado quando o botão F2 é pressionado função wndProc
... recebe uma mensagem WM_COMMAND ou WM_SYSCOMMAND. A palavra de ordem inferior do parâmetro wParam contém o identificador do acelerador.
Ok, já encontramos onde WM_COMMAND é processado, mas como determinar o valor do parâmetro wParam correspondente? É aqui que entra em jogo o Resource hacker . Alimente-o com binários e ele mostra tudo. Como mesa de aceleradores para mim.
texto alternativo http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
Você pode ver aqui que o botão F2 corresponde a 510 em wParam.
Agora vamos voltar ao código, que manipula WM_COMMAND. Ele compara wParam com diferentes constantes.
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 210h
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 1FEh
.text:01001DD8 jz loc_1001EC8
Use o menu de contexto ou o atalho de teclado 'H' para exibir os valores decimais e você pode ver nosso salto
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 528
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 510
.text:01001DD8 jz loc_1001EC8 ; here is our jump
Isso leva a um pedaço de código que chama algum proc e sai de wndProc.
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
É essa função que inicia um novo jogo? Descubra isso na última parte! Fique ligado.
Parte 3 de 3
Vamos dar uma olhada na primeira parte dessa função
.text:0100367A sub_100367A proc near ; CODE XREF: sub_100140C+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, dword_10056AC
.text:0100367F mov ecx, uValue
.text:01003685 push ebx
.text:01003686 push esi
.text:01003687 push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, dword_1005334
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, dword_1005338
.text:0100369E jnz short loc_10036A4
Existem dois valores (dword_10056AC, uValue) lidos nos registros eax e ecx e comparados a outros dois valores (dword_1005164, dword_1005338).
Dê uma olhada nos valores reais usando WinDBG ('bp 01003696'; no intervalo 'p eax; p ecx') - eles pareciam dimensões de campo minado para mim. Jogar com o tamanho do campo minado personalizado mostrou que o primeiro par são novas dimensões e o segundo - dimensões atuais. Vamos definir novos nomes.
.text:0100367A startNewGame proc near ; CODE XREF: handleButtonPress+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, newMineFieldWidth
.text:0100367F mov ecx, newMineFieldHeight
.text:01003685 push ebx
.text:01003686 push esi
.text:01003687 push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, currentMineFieldWidth
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, currentMineFieldHeight
.text:0100369E jnz short loc_10036A4
Um pouco mais tarde, os novos valores sobrescrevem a corrente e a sub-rotina é chamada
.text:010036A7 mov currentMineFieldWidth, eax
.text:010036AC mov currentMineFieldHeight, ecx
.text:010036B2 call sub_1002ED5
E quando eu vi isso
.text:01002ED5 sub_1002ED5 proc near ; CODE XREF: sub_1002B14:loc_1002B1Ep
.text:01002ED5 ; sub_100367A+38p
.text:01002ED5 mov eax, 360h
.text:01002ED5
.text:01002EDA
.text:01002EDA loc_1002EDA: ; CODE XREF: sub_1002ED5+Dj
.text:01002EDA dec eax
.text:01002EDB mov byte ptr dword_1005340[eax], 0Fh
.text:01002EE2 jnz short loc_1002EDA
Eu tinha certeza de que havia encontrado um campo minado Causa do ciclo que inicia a matriz de comprimento de bytes de 360h (dword_1005340) com 0xF.
Por que 360h = 864? Existem algumas dicas abaixo de que a linha ocupa 32 bytes e 864 podem ser divididos por 32, então a matriz pode conter 27 * 32 células (embora a IU permita no máximo 24 * 30 campos, há um preenchimento de byte ao redor da matriz para as bordas).
O código a seguir gera as bordas superior e inferior do campo minado (byte 0x10). Espero que você possa ver a iteração do loop nessa bagunça;) Eu tive que usar papel e caneta
.text:01002EE4 mov ecx, currentMineFieldWidth
.text:01002EEA mov edx, currentMineFieldHeight
.text:01002EF0 lea eax, [ecx+2]
.text:01002EF3 test eax, eax
.text:01002EF5 push esi
.text:01002EF6 jz short loc_1002F11 ;
.text:01002EF6
.text:01002EF8 mov esi, edx
.text:01002EFA shl esi, 5
.text:01002EFD lea esi, dword_1005360[esi]
.text:01002EFD
.text:01002F03 draws top and bottom borders
.text:01002F03
.text:01002F03 loc_1002F03: ; CODE XREF: sub_1002ED5+3Aj
.text:01002F03 dec eax
.text:01002F04 mov byte ptr MineField?[eax], 10h ; top border
.text:01002F0B mov byte ptr [esi+eax], 10h ; bottom border
.text:01002F0F jnz short loc_1002F03
.text:01002F0F
.text:01002F11
.text:01002F11 loc_1002F11: ; CODE XREF: sub_1002ED5+21j
.text:01002F11 lea esi, [edx+2]
.text:01002F14 test esi, esi
.text:01002F16 jz short loc_1002F39
E o resto da sub-rotina desenha as bordas esquerda e direita
.text:01002F18 mov eax, esi
.text:01002F1A shl eax, 5
.text:01002F1D lea edx, MineField?[eax]
.text:01002F23 lea eax, (MineField?+1)[eax+ecx]
.text:01002F23
.text:01002F2A
.text:01002F2A loc_1002F2A: ; CODE XREF: sub_1002ED5+62j
.text:01002F2A sub edx, 20h
.text:01002F2D sub eax, 20h
.text:01002F30 dec esi
.text:01002F31 mov byte ptr [edx], 10h
.text:01002F34 mov byte ptr [eax], 10h
.text:01002F37 jnz short loc_1002F2A
.text:01002F37
.text:01002F39
.text:01002F39 loc_1002F39: ; CODE XREF: sub_1002ED5+41j
.text:01002F39 pop esi
.text:01002F3A retn
O uso inteligente de comandos WinDBG pode fornecer a você um excelente despejo de campo minado (tamanho personalizado 9x9). Verifique as fronteiras!
0:000> db /c 20 01005340 L360
01005340 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005360 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005380 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053a0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053c0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053e0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005400 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005420 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005440 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005460 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005480 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054a0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054c0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054e0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
Hmm, parece que vou precisar de outro post para fechar o tópico