¿Cómo puedo encontrar la estructura de datos que representa la disposición de la mía Buscaminas en la memoria?
-
06-09-2019 - |
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?
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:
- http://msdn.microsoft.com /en-us/library/ms632680%28VS.85%29.aspx
- http://msdn.microsoft.com /en-us/library/ms633586%28VS.85%29.aspx
- Petzold del Capítulo 3 "de Windows y mensajes"
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:
- El uso de aceleradores de teclado
- Resource Hacker ( http://angusj.com/resourcehacker/ )
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.
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:
- De alguna manera obtener el código fuente.
- desmontar y espero símbolos sobrantes pueden ayudarle.
- 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.
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.
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.