Ingeniería Inversa con cargadores : Volumen I

Escrito por David García Martín
Seguridad
3

El objetivo de este artículo es describir el presentar una forma rápida, ágil y sencilla de defenderse de los cargadores. Para ello, vamos a describir dos enfoques diferentes, de manera que el futuro programador sepa como y cuando defenderse de estas técnicas.
Esta lectura de papel requiere un poco de conocimiento del lenguaje C / C + +, todo el código que se muestre está escrito para una aplicación en consola; no se le ve sentido a escribir código con interfaz gráfica para ilustrar este artículo, debido a su complejidad y a que el 99% de cargadores funcionarán en consola y en ensamblador.

¿QUÉ ES UN CARGADOR?

El primer paso para entender este artículo es, obviamente, conocer qué es un cargador. Un cargador o Loader, es un programa con capacidad para cargar a otros en memoria y correr cualquier otro programa.  Cada vez que un usuario de Windows ejecuta un programa, el cargador de ventanas estándar que tiene Windows, ejecuta dicha tarea de forma transparente.

Existen multitud de cargadores diferentes por lo que no nos vamos a extender en ese punto.

CARGADOR EN MODO DEBUG

Un cargador en modo Debug es lo que cualquier cracker utilizaría para aproximarse al programa y piratearlo.

¿Qué debe hacer un cargador?.

Como mínimo, un cargador debe utilizar las siguientes funciones:

CreateProcess

OpenProcess

DebugActiveProcess

ReadProcessMemory

WriteProcessMemory

Por si la persona que lee este artículo no conoce demasiado sobre la arquitectura de Windows, explicaré brevemente estas funciones:

CreateProcess: habilita al depurador para poder cargar un proceso y depurarlo.

OpenProcess: permite al depurador obtener el PID de un proceso.

DebugActiveProcess: permite enlazar un proceso activo al depurador (función attach de algunos depuradores como ollydbg.)

Estas funciones están sacadas del API de Windows y son mundialmente conocidas.

OCULTANDO EL DEPURADOR

Esta función de ocultar el depurador es absolutamente necesaria para el atacante. ¿Qué quiere decir ocultar el depurador? Cualquier programa que intente ser mínimamente seguro ofreciendo una protección anti cracking, debe implementar una técnica que permita detectar depuradores, puesto que estos son una herramienta absolutamente indispensable para el atacante.

Esto conlleva que cualquier atacante intentará por todos los medios esconder el depurador que está usando del programa que está activo.

Las técnicas de ocultación de los depuradores son variadas; algunas de ellas un poco inocentes. En los albores de los tiempos del cracking en Windows, Windows 95-NT, SoftIce era el depurador por excelencia: su potencia le daba unas perspectivas de éxito bastante considerables.

La forma de detectar dicho depurador por algunas aplicaciones era buscar claves en el registro de Windows que indicaran su instalación. Como es obvio, la técnica dejó de funcionar en muy poco tiempo volviéndose completamente obsoleta.

Otra técnica que tuvo bastante mas éxito, era la detección de SoftIce mediante llamadas a VxDCall. Este método tiene la desventaja de que sólo se puede utilizar con Windows 95-Me y consiste en identificar al driver o por su nombre o por su identificador.

Esta técnica dejó de servir, obviamente, al saltar a Windows XP.

Existen otras técnicas pero no explicaremos todas, se escapa del alcance de este artículo.

El problema con los cargadores, objetivo del texto, es que el API debe ser cargado dentro del espacio de memoria del proceso; eso significa que tanto el proceso de detección como el de ocultado han de ser forzosamente distintos a los habituales para ocultar un depurador; y por consiguiente las técnicas de detección no servirán; nuestro programa quedará completamente desprotegido. Estos sistemas de ocultamiento se describirán con detalle con la segunda parte de este artículo, para no hacerlo demasiado denso e ilegible para los inexpertos.

PSAPI.DLL

Esta librería del API de Windows (sacada también del MSDN) provee una serie de importantes funciones muy útiles para el futuro atacante. Entre ellas se encuentra información de lo siguiente:

Información de los procesos que están corriendo en el sistema Windows

Información de los módulos (DLL y ejecutables asociados).

Información de los dispositivos

Información de la memoria que utilizan los procesos

Toda esta información se puede sacar utilizando la popular combinación de teclas Ctrl+Alt+Supr de cualquier entorno Windows.

Posiblemente, el lector se pregunte el por qué de la utilidad de esta información y la respuesta es la siguiente: gracias a esta información, podemos identificar el proceso víctima y sus asociados. Con “sus asociados” se pretende identificar a aquellas DLL y ejecutables, los módulos, que tengan relación con dicho proceso víctima.

La forma de realizar esto se describirá posteriormente en el segundo Volumen de este artículo, pero podemos avanzar que necesitaremos nuevas funciones sacadas del API de Windows:

EnumProcessModules

GetModuleFileName

GetModuleBaseName

GetModuleFileNameEx

GetModuleInformation

Cada una de estas funciones está documentada en el MSDN de Windows, pero para el lector inexperto explicaré brevemente lo que realiza cada una de ellas:

  • EnumProcessModules: Lista los módulos manejados por un proceso dado
  • GetModuleBaseName: Devuelve el nombre del módulo, como indica su nombre. (ModuloRedesZone.dll)
  • GetModuleFileNameEx: Devuelve la ruta y el módulo (C:|miModuloModuloRedesZone.dll)
  • GetModuleInformation: Devuelve la dirección del módulo en memoria, el tamaño del espacio de direcciones y un puntero a su punto de entrada

Con la información obtenida en los puntos precedentes, el atacante estaría en disponibilidad de iniciar el análisis para atacar el programa y tener éxito. Necesitamos, por consiguiente, conocer las técnicas de los atacantes para poder proteger nuestro programa de ellas. Un ejemplo de lo descrito en este artículo se proporcionará en el segundo volumen de este artículo.