debugging assembly x86 reverse-engineering

debugging - ¿Cuál es tu truco favorito contra la depuración?



assembly x86 (10)

¡Referencia memoria no inicializada! (Y otra magia negra / vodoo ...)

Esta es una lectura muy buena: http://spareclockcycles.org/2012/02/14/stack-necromancy-defeating-debuggers-by-raising-the-dead/

En mi anterior empleador utilizamos un componente de terceros que básicamente era solo un archivo DLL y un archivo de encabezado. Ese módulo en particular manejó la impresión en Win32. Sin embargo, la compañía que hizo el componente fue bankcrupt, así que no pude reportar un error que encontré.

Así que decidí corregir el error y lancé el depurador. Me sorprendió encontrar código anti-depuración casi en todas partes, el IsDebuggerPresent habitual, pero lo que más me llamó la atención fue este:

; some twiddling with xor ; and data, result in eax jmp eax mov eax, 0x310fac09 ; rest of code here

A primera vista, pasé por encima de la rutina que se llamó dos veces, luego las cosas se volvieron bananas. Después de un tiempo, me di cuenta de que el resultado de los giros cortos siempre era el mismo, es decir, el jmp eax siempre saltaba directamente al mov eax, 0x310fac09 instrucción mov eax, 0x310fac09 . Analicé los bytes y allí estaba, 0f31 , la instrucción rdtsc que se usó para medir el tiempo transcurrido entre algunas llamadas en la DLL.

Así que mi pregunta a SO es: ¿Cuál es tu truco favorito contra la depuración?


El método de ofuscación más moderno parece ser la máquina virtual.

Básicamente, toma parte de su código de objeto y conviértalo a su propio formato de bytecode. Luego, agrega una pequeña máquina virtual para ejecutar este código. La única manera de depurar correctamente este código será codificar un emulador o desensamblador para el formato de instrucción de su máquina virtual. Por supuesto, también debes pensar en el rendimiento. Demasiado bytecode hará que tu programa se ejecute más lento que el código nativo.

La mayoría de los viejos trucos son inútiles ahora:

  • Isdebuggerpresent: muy cojo y fácil de parchar
  • Otras detecciones de depurador / punto de interrupción
  • Cosas de Ring0: a los usuarios no les gusta instalar controladores, es posible que se rompa algo en su sistema, etc.
  • Otras cosas triviales que todos conocen, o que hacen que tu software sea inestable. recuerda que incluso si un crack hace que tu programa sea inestable pero aún funciona, esta inestabilidad será culpable de ti.

Si realmente desea codificar la solución de VM usted mismo (hay buenos programas para la venta), no use solo un formato de instrucción. Haz que sea polimórfico, para que puedas tener diferentes partes del código que tengan un formato diferente. De esta forma, no se puede romper todo el código escribiendo solo un emulador / desensamblador. Por ejemplo, la solución MIPS que algunas personas ofrecen parece que se puede romper fácilmente porque el formato de instrucción MIPS está bien documentado y las herramientas de análisis como IDA ya pueden desensamblar el código.

Lista de formatos de instrucción admitidos por IDA pro disassembler


En segundo lugar la sugerencia de la máquina virtual. Implementé un simulador MIPS I que (ahora) puede ejecutar binarios generados con mipsel-elf-gcc. Agregue a ese código / capacidades de cifrado de datos (AES o con cualquier otro algoritmo de su elección), la capacidad de auto-simulación (para que pueda tener simuladores anidados) y tiene un buen ofuscador de código.

La buena característica de elegir MIPS I es que 1) es fácil de implementar, 2) Puedo escribir código en C, depurarlo en mi escritorio y simplemente compilarlo para MIPS cuando esté listo. No es necesario depurar códigos de operación personalizados o escribir código manualmente para una máquina virtual personalizada.


Gira un proceso secundario que se conecta al padre como un depurador y modifica las variables clave. Puntos de bonificación para mantener al proceso hijo residente y utilizar las operaciones de memoria del depurador como una especie de IPC para ciertas operaciones clave.

En mi sistema, no puede adjuntar dos depuradores al mismo proceso.

Lo bueno de esto es que a menos que traten de alterar las cosas, nada se rompe.


He sido miembro de muchas comunidades de RCE y he compartido bastante piratería y crackeadores. Desde mi época, me he dado cuenta de que esos trucos endebles suelen ser volátiles y bastante inútiles. La mayoría de los trucos genéricos contra la depuración son específicos del sistema operativo y no son ''portátiles'' en absoluto.

En el ejemplo mencionado anteriormente, presumiblemente está usando ensamblado en línea y una función naked __declspec , ambas que no son compatibles con MSVC al compilar en la arquitectura x64. Por supuesto, todavía hay formas de implementar el truco antes mencionado, pero cualquiera que haya estado retrocediendo el tiempo suficiente podrá detectar y vencer ese truco en cuestión de minutos.

Por lo tanto, en general, sugeriría no utilizar trucos contra la depuración fuera de la utilización de la API IsDebuggerPresent para la detección. En cambio, sugiero que codifique un apéndice y / o una máquina virtual. Codifiqué mi propia máquina virtual y la he estado mejorando durante muchos años y honestamente puedo decir que ha sido la mejor decisión que he tomado con respecto a la protección de mi código hasta ahora.


Los saltos calculados en medio de una apariencia legítima pero que realmente ocultan las instrucciones reales de instrucción son mis favoritos. De todos modos, son bastante fáciles de detectar para los humanos, pero las herramientas automatizadas a menudo lo estropean.

Además, reemplazar una dirección de devolución en la pila hace que sea una buena pérdida de tiempo.


Mi favorito personal estaba en Amiga, donde hay un coprocesador (el Blitter ) que hace grandes transferencias de datos independientes del procesador; este chip sería instruido para borrar toda la memoria y reiniciar desde un IRQ de temporizador.

Cuando conectaste un cartucho de Action Replay, detener la CPU significaría que el Blitter continuaría borrando la memoria.


Mi truco favorito es escribir un simple emulador de instrucciones para un microprocesador oscuro.

La protección contra copia y parte de la funcionalidad principal se compilará para el microprocesador (GCC es una gran ayuda aquí) y se vinculará al programa como un blob binario.

La idea detrás de esto es que la protección contra copia no existe en el código x86 ordinario y, como tal, no se puede desmontar. Tampoco puedes eliminar todo el emulador porque esto eliminaría la funcionalidad principal del programa.

La única posibilidad de piratear el programa es realizar una ingeniería inversa de lo que hace el emulador de microprocesador.

He usado MIPS32 para la emulación porque era muy fácil de emular (tomó solo 500 líneas de código C simple). Para hacer las cosas aún más oscuras, no usé los códigos de operación MIPS32 en bruto. En cambio, cada código de operación fue desviado con su propia dirección.

El binario de la protección contra copia parecía basura.

¡Muy recomendable! Pasó más de 6 meses antes de que saliera una grieta (era para un proyecto de juego).


Preferiría que la gente escriba software sólido, confiable y que haga lo que se anuncia que debe hacer. Que también lo venden a un precio razonable con una licencia razonable.

Sé que he perdido demasiado tiempo tratando con proveedores que tienen esquemas de licencias complicados que solo causan problemas para los clientes y los proveedores. Siempre es mi recomendación evitar a esos vendedores. Trabajando en una planta de energía nuclear, nos vemos obligados a utilizar ciertos productos de vendedores y, por lo tanto, nos vemos obligados a tener que lidiar con sus esquemas de licencia. Ojalá hubiera una manera de recuperar el tiempo que personalmente he perdido tratando con sus intentos fallidos de darnos un producto licenciado que funcione. Parece una pregunta pequeña, pero parece ser algo difícil para las personas que se vuelven demasiado astutas para su propio bien.


Usar nop para eliminar el ensamblaje a través del depurador es un truco útil. ¡Por supuesto, devolver el código es mucho más difícil!