¿Cómo puedo encontrar la estructura de datos que representa la disposición de la mía Buscaminas en la memoria?

StackOverflow https://stackoverflow.com/questions/931257

Pregunta

Estoy tratando de aprender sobre ingeniería inversa, usando Buscaminas como una aplicación de ejemplo. He encontrado este artículo de MSDN en un simple comando de WinDbg que revela todas las minas pero es vieja, no se explica en detalle y realmente no es lo que estoy buscando.

IDA Pro desensamblador y la WinDbg depurador y me he cargado Winmine.exe en ambos. ¿Puede alguien dar algunos consejos prácticos para cualquiera de estos programas en términos de encontrar la ubicación de la estructura de datos que representa el campo de minas?

En WinDbg puedo establecer puntos de interrupción, pero es difícil para mí imaginar en qué momento para establecer un punto de interrupción y en qué posición de memoria. Del mismo modo, cuando veo el código estático en IDA Pro, no estoy seguro de por dónde empezar siquiera a encontrar la estructura o función de los datos que representa el campo de minas.

¿Hay alguna Ingenieros inversa en Stackoverflow que me puede apuntar en la dirección correcta?

¿Fue útil?

Solución

Parte 1 de 3


Si usted es serio en la ingeniería inversa - olvidarse de los formadores y de engañar a los motores.

Buena ingeniería inversa debe primero conocer OS, las funciones básicas de la API, la estructura general del programa (bucle de lo que se ejecute, las estructuras de las ventanas, las rutinas de manipulación de eventos), formato de archivo (PE). de Petzold clásicos "Windows de programación" puede ayudar (www.amazon.com/exec/obidos/ISBN=157231995X), así como en línea de MSDN.

En primer lugar usted debe pensar en la rutina de inicialización campo de minas puede ser llamado. Pensé en lo siguiente:

  • Al iniciar el juego
  • Al hacer clic cara feliz
  • Al hacer clic en Juego-> Nuevo o pulse F2
  • Cuando se cambia el nivel de dificultad

Me decidí a la salida de comando del acelerador F2.

Para encontrar el código de manejo del acelerador hay de encontrar mensaje de ventana procedimiento de manipulación (WndProc). Su origen se remonta por CreateWindowEx y registerClass llamadas.

Para leer:

Abre la AIF, ventana de importaciones, encontrar "CreateWindow *", salta a ella y utilizar "Saltar referencia externa al operando (X)" comando para ver donde se llama. No debe haber sólo una llamada.

Ahora mira más arriba para la función RegisterClass y es el parámetro WndClass.lpfnWndProc. Ya función llamada 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

Hit Intro en nombre de la función (use 'N' para cambiar su nombre a algo mejor)

Ahora echa un vistazo a

.text:01001BCF                 mov     edx, [ebp+Msg]

Este es el ID de mensaje, que en caso de botón F2 de prensa debe contener valor WM_COMMAND. Hay de encontrar donde se compara a 111h. Se puede hacer ya sea mediante el trazado de abajo edx en IDA o por ajuste de punto de interrupción condicional en WinDbg y pulsando 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 sobre 111h y el uso de "constante simbólica" -> "Usar constante simbólica estándar", el tipo WM_ y Enter. Ahora debe tener

.text:01001D5B                 sub     eax, WM_COMMAND
.text:01001D60                 jz      short loc_1001DBC

Es una manera fácil de averiguar los valores de ID de mensaje.

Para entender el manejo del acelerador echa un vistazo a:

Es un buen montón de texto para una sola respuesta. Si usted está interesado puedo escribir un par de mensajes. Larga historia corta campo de minas almacenadas como una matriz de bytes [24x36], 0x0F muestra que no se utiliza el byte (campo de juego más pequeño), 0x10 - campo vacío, 0x80 -. mía

Parte 2 de 3


Ok, vamos a seguir con el botón F2.

Según Usando aceleradores de teclado función wndProc cuando se pulsa el botón F2

  

... recibe una WM_COMMAND o WM_SYSCOMMAND   mensaje. La palabra de orden inferior de la   parámetro wParam contiene el   identificador del acelerador.

Ok, que ya encontramos donde se procesa WM_COMMAND, pero la forma de determinar el valor del parámetro wParam correspondiente? Aquí es donde Resource Hacker entra en juego. Alimentarlo con binario y se le muestra todo. Como mesa de aceleradores para mí.

texto alternativo http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg

Se puede ver aquí, ese botón F2 corresponde a 510 en WParam.

Ahora vamos a volver al código, que se encarga de WM_COMMAND. Se 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

Uso del menú contextual o combinación de teclas 'H' para mostrar los valores decimales y se puede ver nuestra 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

Esto lleva a trozo de código que llama a algunos proc y sale wndProc.

.text:01001EC8 loc_1001EC8:                            ; CODE XREF: mainWndProc+20Fj
.text:01001EC8                 call    sub_100367A     ; startNewGame ?
.text:01001EC8
.text:01001ECD                 jmp     callDefAndExit  ; default

es que la función que inicia nuevo juego? Encontrar que en la última parte! Manténgase en sintonía.

Parte 3 de 3

Vamos a echar 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 en comparación con los otros dos valores (dword_1005164, dword_1005338).

Tome un vistazo a los valores reales utilizando WinDBG ( 'pb 01003696'; en las vacaciones 'EAX p; p ECX') - parecían como las dimensiones del campo de minas para mí. Jugando con un tamaño de campo de minas a medida mostró que el primer par son nuevas dimensiones y segundo - dimensiones actuales. Vamos a establecer 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 nuevos valores sobreescriben actual y subrutina se llama

.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

Yo estaba completamente seguro de que he encontrado gama campo de minas. Causa de ciclo que INITs array bytes 360h longitud (dword_1005340) con 0xF.

¿Por qué 360h = 864? Hay algunas señales por debajo de la fila toma 32 bytes y 864 se puede dividir por 32, de modo matriz puede contener 27 * 32 células (aunque la interfaz de usuario permite max 24 * 30 campo, hay un relleno de byte alrededor de matriz para las fronteras).

siguiente código genera superior campo de minas y bordes inferiores (0x10 byte). Espero que se puede ver iteración del bucle en ese lío;) tuve que usar papel y lápiz

.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 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

Uso inteligente de WinDBG comandos que puede proporcionar volcado campo minado fresco (encargo 9x9 de tamaño). Echa un vistazo a 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  ................................

Hmm, parece que voy a necesitar otro post para cerrar el tema

Otros consejos

Parece como si estuviera tratando de desmontar la fuente, pero lo que hay que hacer es mirar el espacio de memoria del programa en ejecución. El editor hexadecimal HxD tiene una característica que le permite precisamente eso.

http://www.freeimagehosting.net/uploads/fcc1991162.png

Una vez que estás en el espacio de memoria, es una cuestión de tomar instantáneas de la memoria mientras que perder el tiempo con la junta. Aislar lo que cambia en comparación con lo que no. Cuando usted piensa que tiene un mango en donde la estructura de datos se encuentra en la memoria hexagonal, intentar editar mientras está en la memoria y ver si el tablero cambia como consecuencia de ello.

El proceso que se desea no es diferente a la construcción de un 'entrenador' para un videojuego. Los que se basan por lo general en la búsqueda donde los valores como la salud y munición real en la memoria y cambiar sobre la marcha. Usted puede ser capaz de encontrar algunos buenos tutoriales sobre cómo construir entrenadores del juego.

Confirmar este artículo del proyecto de código, que es un poco más en profundidad que el blog que usted ha mencionado.

http://www.codeproject.com/KB/trace/minememoryreader.aspx

Editar

Y este artículo, aunque no se trata de dragaminas directamente, le da una buena guía paso a paso a través de la caza de memoria utilizando WinDbg:

http://www.codingthewheel.com/archives/extracting- oculto de texto con windbg-

Editar 2

Una vez más, no se trata de dragaminas, pero definitivamente me ha dado algunos elementos de reflexión para mi depuración de memoria, hay una gran cantidad de tutoriales aquí:

http://memoryhacking.com/forums/index.php

Además, descarga CheatEngine (mencionado por Nick D.) y trabajar con el tutorial que viene con.

  

"En WinDbg puedo establecer puntos de interrupción, pero   es difícil para mí imaginar a   qué momento para establecer un punto de interrupción y al   lo que la posición de memoria. Del mismo modo, cuando   Veo el código estático en IDA Pro, estoy   no sabe dónde empezar siquiera a encontrar   la función o estructura de datos que   representa el campo de minas ".

Exactamente!
Bueno, se puede buscar rutinas como aleatorio () que serán llamados durante la construcción de la tabla de minas. Este libro me ayudó mucho cuando yo estaba experimentando con la ingeniería inversa. :)

En general, un buen lugar para establecer puntos de ruptura son llamadas a buzones de mensajes, las llamadas a reproducir un sonido, temporizadores y otras rutinas de la API Win32.
Por cierto, estoy escaneando dragaminas en este momento con OllyDbg .

Actualización: nemo me recordó una gran herramienta, de trucos motor de Eric "Dark Byte" Heijnen.
Cheat Engine (CE) es una gran herramienta para ver y modificar otros procesos de espacio de memoria. Más allá de eso básica instalación, CE tiene características más especiales como la visualización de la memoria desmontada de un proceso e inyectar código en otros procesos.
( real valor de ese proyecto es que se puede descargar el código fuente -Delphi- y ver cómo se implementaron los mecanismos - lo hice hace muchos años: o)

Un muy buen artículo sobre este mismo tema se puede encontrar en Uninformed . Cubre revertir Buscaminas (como una introducción a la ingeniería inversa aplicaciones Win32) en muy gran detalle y es todo un muy buen recurso.

Este sitio web podría ser más útil:

http://www.subversity.net/reversing/hacking-minesweeper

La forma más general, a ir haciendo esto es:

  1. De alguna manera obtener el código fuente.
  2. desmontar y espero símbolos sobrantes pueden ayudarle.
  3. adivinar el tipo de datos y tratar de manipular y utilizar un escáner de memoria para limitar las posibilidades.

En respuesta a Bounty

Bueno, en una segunda lectura, parece como si querías una guía sobre el uso de un depurador como WinDBG en lugar de la habitual pregunta de cómo realizar ingeniería inversa. Ya le he mostrado el sitio web que los valores que hay que buscar dice, así que la pregunta es, ¿cómo lo buscas?

Estoy utilizando el Bloc de notas en este ejemplo porque no tiene instalado Buscaminas. Pero la idea es la misma.

text alt

Se escribe

s <options> <memory start> <memory end> <pattern>

Presione "?" Y luego "s" para ver la ayuda.

Una vez que haya encontrado el patrón de memoria que desea, a continuación, puede pulsar Alt + 5 para abrir el visor de memoria para una visualización agradable.

text alt

WinDBG toma algún tiempo para acostumbrarse, pero es tan bueno como cualquier otro depurador por ahí.

Un buen punto para iniciar el rastreo de depuración sería el ratón hacia arriba. Así encontró el procedimiento de la ventana principal (creo herramientas como spyxx puede inspeccionar las propiedades de Windows y dirección de controlador de eventos es uno de ellos). Irrumpir en ella y encontrar donde maneja los eventos de ratón - habrá un interruptor, si se puede reconocer que en ensamblador (mirar valor de WM_XXX para ratón hacia arriba en windows.h)

.

Ponga un punto de ruptura y empezar a pisar. En algún lugar entre el momento de soltar el botón del ratón y la pantalla están actualizando la victum accederá a la estructura de datos que busca.

Sea paciente, tratar de identificar qué se está haciendo en un momento dado, pero no se molestan en mirar demasiado profundamente en código sospecha de ser poco interesantes para su objetivo actual. Podría tomar varias carreras en depurador para clavar abajo.

El conocimiento de flujo de trabajo normal de las aplicaciones Win32 también ayuda.

Las minas probablemente serán almacenados en una especie de matriz de dos dimensiones. Esto significa que o bien es una matriz de punteros o una única matriz de estilo C de booleanos.

Siempre que el formulario recibe un evento de ratón-up esta estructura de datos se referencia. El índice se calcula utilizando la coordenada de ratón, probablemente utilizando división de enteros. Eso significa que probablemente debería buscar un cmp o una instrucción similares, donde uno de los operandos se calcula utilizando un offset y x, donde x es el resultado de un cálculo que implica la división entera. El desplazamiento será entonces el puntero al comienzo de la estructura de datos.

Es bastante razonable suponer que la información acerca de las minas se organizada de forma contigua en la memoria al menos para las filas (es decir, que es un 2D-matriz, o una matriz-of-arrays). Por lo tanto, me gustaría probar la apertura de varias células adyacentes en la misma fila, haciendo volcados de memoria del proceso como voy, y luego diff ellos y buscar cualquier cambio que se repiten en la región misma memoria (es decir, 1 byte cambió el primer paso, el siguiente byte cambió a exactamente el mismo valor en el siguiente paso, etc).

También hay posibilidad de que se trata de una matriz de bits comprimido (3 bits por minas deberían ser suficientes para registrar todos los estados posibles - cerrado / abierto, el mío / no-mía, marcado / no estén designados), así que me gustaría mirar hacia fuera para eso también (los patrones también sería repetible, aunque más difícil de detectar). Pero no es una estructura conveniente de tratar, y no creo que el uso de memoria era un cuello de botella para el Buscaminas, por lo que es poco probable que este tipo de cosas sería utilizado.

Aunque no es estrictamente "herramienta de ingeniería inversa" a, y más de un juguete incluso un idiota como yo podría utilizar, echa un vistazo a Cheat Engine . Esto hace que sea algo fácil de realizar un seguimiento de qué partes de la memoria han cambiado, cuando, e incluso tiene disposiciones para el seguimiento de las partes de memoria modificados a través de punteros (aunque es probable que no necesita de eso). Se incluye un buen tutorial interactivo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top