Parte 1 de 3
Si te tomas en serio la ingeniería inversa, olvídate de los entrenadores y los motores de trampa.
Un buen ingeniero inverso primero debe conocer el sistema operativo, las funciones básicas de la API, la estructura general del programa (qué es el ciclo de ejecución, las estructuras de Windows, las rutinas de manejo de eventos), el formato de archivo (PE). Los clásicos de Petzold "Programming Windows" pueden ayudar (www.amazon.com/exec/obidos/ISBN=157231995X) así como MSDN en línea.
Primero debe pensar en dónde se puede llamar a la rutina de inicialización del campo minado. Pensé en seguir:
- Cuando inicias el juego
- Cuando haces clic en la cara feliz
- Cuando haces clic en Juego-> Nuevo o presionas F2
- Cuando cambia el nivel de dificultad
Decidí verificar el comando del acelerador F2.
Para encontrar el código de manejo del acelerador, debe buscar el procedimiento de manejo de mensajes de ventana (WndProc). Se puede rastrear mediante llamadas CreateWindowEx y RegisterClass.
Leer:
Abra la ventana IDA, Imports, busque "CreateWindow *", salte a ella y use el comando "Jump xref to operand (X)" para ver dónde se llama. Debería haber una sola llamada.
Ahora mire arriba para la función RegisterClass y su parámetro WndClass.lpfnWndProc. Ya nombré la función mainWndProc en mi 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
Presione Enter en el nombre de la función (use 'N' para cambiarle el nombre a algo mejor)
Ahora echa un vistazo a
.text:01001BCF mov edx, [ebp+Msg]
Este es el ID del mensaje, que en caso de presionar el botón F2 debe contener el valor WM_COMMAND. Debe encontrar dónde se compara con 111h. Se puede hacer rastreando edx en IDA o estableciendo un punto de interrupción condicional en WinDbg y presionando F2 en el juego.
De cualquier manera conduce a algo como
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
Haga clic derecho en 111h y use "Constante simbólica" -> "Usar constante simbólica estándar", escriba WM_ y Enter. Ahora deberías tener
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
Es una forma sencilla de averiguar los valores de identificación de mensajes.
Para comprender el manejo del acelerador, consulte:
Es bastante texto para una sola respuesta. Si estás interesado puedo escribir otro par de publicaciones. Campo minado corto de la historia larga almacenado como una matriz de bytes [24x36], 0x0F muestra que el byte no se usa (jugando un campo más pequeño), 0x10 - campo vacío, 0x80 - mío.
Parte 2 de 3
Ok, continuemos con el botón F2.
De acuerdo con el uso de aceleradores de teclado cuando se presiona el botón F2 función wndProc
... recibe un mensaje WM_COMMAND o WM_SYSCOMMAND. La palabra de orden inferior del parámetro wParam contiene el identificador del acelerador.
Bien, ya encontramos dónde se procesa WM_COMMAND, pero ¿cómo determinar el valor del parámetro wParam correspondiente? Aquí es donde entra en juego el hacker de recursos . Aliméntelo con binario y le mostrará todo. Como mesa de aceleradores para mí.
texto alternativo http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
Puede ver aquí que el botón F2 corresponde a 510 en wParam.
Ahora volvamos al código, que maneja WM_COMMAND. Compara wParam con 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 el menú contextual o el atajo de teclado 'H' para mostrar valores decimales y podrá ver nuestro 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
Conduce a un fragmento de código que llama a algún proceso y sale de wndProc.
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
¿Es esa la función que inicia un nuevo juego? ¡Descúbrelo en la última parte! Manténganse al tanto.
Parte 3 de 3
Echemos un vistazo a la primera parte de esa función.
.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
Hay dos valores (dword_10056AC, uValue) leídos en los registros eax y ecx y comparados con otros dos valores (dword_1005164, dword_1005338).
Eche un vistazo a los valores reales usando WinDBG ('bp 01003696'; en el descanso 'p eax; p ecx'); me parecieron dimensiones de campo minado. Jugar con el tamaño personalizado del campo minado mostró que el primer par son nuevas dimensiones y las segundas dimensiones actuales. Establezcamos nuevos nombres.
.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
Un poco más tarde, los nuevos valores sobrescriben la corriente y se llama a la subrutina
.text:010036A7 mov currentMineFieldWidth, eax
.text:010036AC mov currentMineFieldHeight, ecx
.text:010036B2 call sub_1002ED5
Y cuando lo vi
.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
Estaba completamente seguro de que encontré una matriz de campo minado. Causa del ciclo que inicia su matriz de longitud de bytes de 360 h (dword_1005340) con 0xF.
¿Por qué 360h = 864? Hay algunas señales debajo de que la fila toma 32 bytes y 864 se puede dividir por 32, por lo que la matriz puede contener 27 * 32 celdas (aunque la interfaz de usuario permite un campo máximo de 24 * 30, hay un relleno de un byte alrededor de la matriz para los bordes).
El siguiente código genera los bordes superior e inferior del campo minado (0x10 bytes). Espero que puedas ver la iteración del bucle en ese lío;) Tuve que usar papel y bolígrafo
.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
Y el resto de la subrutina dibuja los bordes izquierdo y derecho
.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
El uso inteligente de los comandos WinDBG puede proporcionarle un volcado de campo minado genial (tamaño personalizado 9x9). ¡Mira las fronteras!
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 ................................
Mmm, parece que necesitaré otra publicación para cerrar el tema.