Delphi 5.0 Enterprise Trial / RainBow Sentinel LM v2.0 por ViPER


A continuación teneis un tutorial escrito por ViPER sobre la protección Rainbow Sentinel LM v2.0, lo he editado un poco y adaptado más o menos a la plantilla de mi página con permiso del autor. En mi opinión es un buen tutorial de obligada lectura para los que deban enfrentarse a este nuevo intento de protección ;), el cual a sido reducido a misería, pero, que se podia esperar de los señores de Sentinel. De nuevo se demuestra que el único obstáculo para crackear algo es el tiempo que se le dedique a su investigación.

Víctima:
Protecciones Sentinel LM (Delphi 5 Enterprise Trial)
URL:
http://www.borland.com/
Descripción:
Entorno de programación para Windows (RAD)
Tamaño del ejecutable:
950 KB´s
Tipo de Protección:
Trial, mediante encriptación y autoverificaciones varias
Método de ataque:
Desensamblar, Depurar, Monitorizar, Re-Codificar y Programar
Objetivo:
Conocer los mecanismos de protección de Rainbow Sentinel
Cracker:
ViPER
Dificultad:
Newbie - Aficionado - Avanzado - Experto - Élite
Herramientas: 
SoftIce 3+, IDA Pro, IID King, RegMon, FileMon, Hacker´s View, Algún compilador para Windows.
Fecha:
6 - Octubre - 2000

He configurado este documento partiendo de una serie de notas que he ido acumulando mientras me empleaba a fondo con la Trial de Delphi 5, que precisamente estaba protegida con este sistema. Este documento no es más que una explicación del sistema usado por Rainbow Sentinel para evitar el uso ilegal del Software, incluyendo un ejemplo práctico sobre como atacar las deficiencias de Sentinel. Este documento es aplicable a Rainbow Sentinel LM (License Manager) v2.0. No estoy muy seguro de que sea aplicable a otras variantes de este producto. Sin más preámbulos demos paso al primer apartado de este Manual.

Que és y cómo funciona Rainbow Sentinel

RainBow Sentinel LM es una pequeña "herramienta" que añade a nuestros programas un completo sistema de protección basado en archivos de licencias, periodos de evaluación y otros mecanismos para evitar un uso indeseado del software a la hora de distribuirlo (como el uso durante largos periodos de tiempo).

Este "tutorial" es un conjunto de técnicas para crackear programas con este sistema, doy por sentado que todo aquel que lee esto tiene unos conocimientos medios sobre ingeniería inversa, por lo que advierto que no voy a detenerme a explicar como se pone un breackpoint o que es la encriptación.

Las siglas LM quieren decir License Manager, que traducido significa Administrador de Licencias. Las licencias no son otra cosa que un archivo o clave que contiene información cifrada; esta información es procesada por un programa o librería encargada de descifrar e interpretar los datos, para determinar si el programa debe o no ejecutarse y con qué privilegios.

El proceso anteriormente citado no es ejecutado por un solo programa, Sentinel implica muchísimos archivos en el proceso de ejecución del programa protegido, a continuación vamos a ver una tabla con cada uno de ellos y la función que cumple, para desglosar mas adelante su funcionamiento.

Programa.exe  Es el programa en cuestión, que durante su inicialización llama a una función dentro Caitf32.dll que pone en marcha la protección. Según el producto protegido cambia de nombre (el caso que estudiamos es Delphi32.exe).
Caitf32.dll  Librería que exporta la función ClientActivatorA (entre otras) que recopila información sobre el sistema y lanza la Nag mediante el programa Activator.exe (este programa se llama siempre igual).
Activator.exe Recopila información del Archivo .rac (bitmaps, iconos, etc...) y muesta la nag.
Archivos de licencias Se localizan en directorios de sistema o en el propio directorio del programa. En ocasiones son modificados, creados o eliminados para indicar cierta información sobre el periodo de evaluación.
Archivos temporales Se crean de forma esporádica y en mi modesta opinión solo sirven para distraer la atención del cracker.
Entradas del registro También guardan valiosa información sobre el estado del periodo de evaluación y suelen usar nombre poco comunes para hacer dudar al cracker.

Estos son, a grandes rasgos, los diversos módulos de la protección Sentinel LM. Paso a describir como interactuan estos archivos entre sí y con que finalidad.

 

Flujo de ejecución

Empezamos ejecutando el programa y recibimos una bonita nag, frente a la que muchos crackers (me incluyo yo entre ellos) no dudan ni un segundo en atacar con métodos como breakpoints en ShowWindow y CreateWindowA. Lo cierto es que este método carece de efectividad dado que Sentinel LM usa un compleja maraña de programas y librerías para mostrar la simple ventana que vemos, empezemos a desglosar un poco esto...

Si desensamblamos delphi32.exe con IDA (atencion adeptos del W32Dasm, esta sencilla herramienta no nos dará toda la información necesaria, así que olvidaos de W32Dasm y comenzad a practicar con IDA Pro), no encontramos ninguna información referente a este diálogo que aparece, y las importaciones no muestran nada fuera de lo normal (ninguna dll distinta a las típicas: user32, kernel32, etc...) Algo es evidente, el código referente al diálogo inicial (llamémoslo nag a partir de ahora) está ubicado fuera del ejecutable delphi32.dll, pero la(s) funcion(es) a las que llaman no están referenciadas en su tabla de importaciones, lo que denota que se cargan en tiempo de ejecución mediante la API de windows.

Tenemos un primer punto de ataque, la importación LoadLibraryA. IDA nos muestra que está referenciada desde seis puntos del código y tras examianarlos minuciosamente encontramos alrededor de uno de ellos una cadena más que curiosa:

"ClientActivatorA"

... bien, esto parece estar basado en una API que el programador debe invocar desde su programa para asegurarse el sueldo. Y para conocer una API no hay nada mejor que ver su Kit de desarrollo. Tras descargar el Kit de Evaluación de Rainbow Sentinel LM obtenemos la siguiente información:

typedef struct _CA_ACTIVATOR_INFOA { 
   DWORD size; 
   DWORD wndHandle; 
   LONG spawnAndWait; 
   LONG enableTryButton; 
   LONG daysLeft; 
   LONG executionsLeft; 
   LONG minutesLeft; 
   LONG disableLicInstall; 
   char configFile[MAX_PATH_LEN]; 
} CA_ACTIVATOR_INFOA, FAR *PCA_ACTIVATOR_INFOA; 

Los apartados que nos interesan de esta estructura son:

enableTryButton: Activa o desactiva el botón "Try"
daysLeft: Dias restantes del periodo de evaluación
configFile: Archivo de configuración que contiene las imágenes y datos referentes a la nag.

La primera conclusión que podemos sacar es que todos los parámetros sobre la nag se almacenan en un archivo de configuración de extensión .rac (d5.rac, en nuestro caso). Y también podemos sacar en conclusión que el número de días de evaluación lo decide Delphi y no algún archivo de licencias encriptado que tardaríamos años en descifrar. Un prueba de esto es la siguiente:

Vuelve al lugar donde encontraste la llamada a LoadLibraryA que llama a ClientActivatorA

Ve a la dirección desde la que es llamado este trozo de código.

Observa que se le pasa un solo valor en eax, que es la dirección de memoria en la que se encuentra la estructura ya completada con los datos pertinentes y lista para usar.

Depura ese código con SoftIce y observa detenidamente la información contenida en la dirección que contiene eax, si te fijas bien, verás el número de dias que le quedan a tu evaluación (en hexadecimal, claro) algunos bytes mas atras del archivo de configuración.

En mi caso este valor es 3C (60 en decimal, nº de días que le restan a mi periodo de evaluación), pues cámbialo por 80 y deja correr el programa... ...felicidades, puede evaluar este programa durante 128 días! si conseguimos que siempre que Delphi carge la información contenida en la estructura sea la correcta nuestra bonita nag nos obsequiará siempre con muchos días de evaluación.

Pero tenemos otro escollo, si pulsamos "Try" Delphi32.exe continua su ejecución y hace mas comprobaciones sobre el estado de las licencias y periodos de evaluación (joder, con lo facil que estaba siendo todo!). Aquí llega la parte realmente problemática de la protección: el programa se enfrasca en un enorme bucle en el que se hacen comprobaciones matemáticas sobre un determinado valor y se van configurando variables de forma que el programa llega a la diversas conclusiones sobre la perversidad de su usuario ;)

Tras mucho estudiar este bucle, he llegado a la conclusión de que el programa original se va cargando en memoria en sucesivas partes de este bucle, y asignándole así un punto de entrada en tiempo de ejecución. Modificar este bucle es posible, pero demasiado costoso en mi opinión, teniendo en cuenta que hay otros trucos que casi pueden denominarse como "genéricos".

Modificaciones de Rainbow Sentinel en el sistema

Rainbow Sentinel guarda en múltiples localizaciones de nuestro sistema importantes datos sobre el estado del periodo de evaluación, que se respaldan unos a otros, de manera que si borramos una clave de registro será inútil dado que hay otra que guarda la misma información y da al programa razones para seguir diciendonos que somos unos bastardos...

Solo hay una forma de erradicar esta lacra de nuestro HD, y es usando dos poderosas herramientas: FileMon y RegMon.

El uso de estas herramientas es muy sencillo, y solo necesitareis unos consejos para arrancar Sentinel de raiz de vuestro ordenador:

Las entradas de registro que usa suelen ser muy parecidas a las que usa windows, desconfia de todas ;)
Desconfia especialmente de las que contienen valores numéricos aparentemente inútiles para la ejecución y configuración del programa.
Confirma tus sospechas en el listado de cadenas de IDA
Los archivos suelen tener atributos de "oculto" y "readonly", no lo olvides.
No descartes los archivos DLL y comprueba si su cabezera realmente es la de un archivo PE de Windows, si no tienen la palabra MZ al principio, de librería solo tienen la extensión.
Cualquier archivo que carezca de espacios y su información parezca estar comprimida es altamente sospechoso.

Ahora puedes encontrarlos por tu cuenta o ver los resultados obtenidos por mi (estos son los usados por delphi 5, no estoy seguro de que en otros programas sean los mismos...):

Entradas de registro:

HKLM\SOFTWARE\Rainbow Technologies\
HKLM\SOFTWARE\ntpad
HKLM\SOFTWARE\CLSYSTEM
HKLM\Software\Description

Archivos:

C:\WINDOWS\SYSTEM\0001.TMP
C:\WINDOWS\SYSTEM\SYSPRS7.DLL
C:\WINDOWS\SYSTEM\SYSPRS7.TGZ
C:\WINDOWS\SYSTEM\LSPRST7.DLL
C:\WINDOWS\SYSTEM\LSPRST7.TGZ
C:\WINDOWS\SYSTEM\T0000001.TMP
C:\WINDOWS\SYSTEM\CLAUTH1.DLL
C:\WINDOWS\SYSTEM\CLAUTH2.DLL
C:\WINDOWS\SYSTEM\SSPRS.DLL
C:\WINDOWS\SYSTEM\SSPRS.TGZ
C:\Archivos de programa\Borland\Delphi5\Bin\0001.TMP
C:\Archivos de programa\Borland\Delphi5\Bin\servdat.slm

Este es principal punto debil de sentinel, la facilidad con la que se elimina de nuestro sistema y da via libre a un "nuevo" periodo de evaluación.

Infectando...

Ahora llega el momento de plantearnos los posible puntos de ataque:

Parchear el programa para que se ejecute aunque el periodo de evaluación haya sido excedido: excesivamente complicado, teniendo en cuenta la complicada arquitectura interna de del programa y el hecho de que las dll´s que acompañan al programa también hacen comprobaciones al inicio de la aplicación y a lo largo de esta (si, efectivamente, para comprobarlo elimina alguna de las llaves del registro mientras Delphi está en ejecución y espera durante unos minutos...)

Sustituir Activator.exe por otro programa que (evidentemente) no tenga en cuenta los periodos de evaluación y elimine rastros del sistema para dejar el sistema "como a sentinel le gusta": totalmente inútil debido a que Delphi mantiene abiertos parte de los archivos referentes al sistema de protección mientras se ejecuta Activator, lo que deniega a nuestra aplicación borrarlos, ya que otra aplicación los está usando.

Hacer algunos retoques a Caitf32.dll: También es inútil debido a que esta librería cumple más que nada funciones "de cara al usuario". Los procesos realmente complicados los hace (o mas bien los repite) el programa que estemos crackeando.

Revertir la criptografía del sistema de licencias: Sin comentarios.

Desviar el entrypoint de Delphi32.exe hacia un pequeño recorte que ejecute un programa "asesino" que limpie el sistema de todas las entradas de registro y archivos "molestos"; así como hacer que este recorte espere a la terminación total de nuestro programa asesino para devolver el control al programa original: Genial!, una solución sencilla de llevar a cabo y que asegura la ejecución del programa con casi un 95% de efectividad.

Veamos que condiciones debe cumplir nuestra aplicación asesina:

- Se deben eliminar TODAS las referencias de delphi5 en el sistema
- Debe esperar a que Windows finalize las tareas que se le han encomendado, ya que ni una entrada de registro ni un archivo es borrado en el mismo momento en que llamamos a un RegDeleteKey o DeleteFile. Para estos menesteres serán mas que suficientes unos 3 segundos.

Para deleite de los detallistas, vamos a hacer nuestro programa precisamente con Delphi 5 (es como hacer el arma con la que vas a suicidarte...) Aquí se encuentra el código:

var
reg : tregistry;
sysp : pchar;
delp : string;
counter : byte;

begin

form1.Show;
application.ProcessMessages;

//Borrar entradas del registro
reg := tregistry.Create;
reg.RootKey := HKEY_LOCAL_MACHINE;
reg.DeleteKey('SOFTWARE\Rainbow Technologies');
reg.DeleteKey('software\ntpad');
reg.DeleteKey('SOFTWARE\CLSYSTEM');
reg.DeleteKey('Software\Description');
reg.CloseKey;
reg.Free;

//Eliminar archivos de \system
getsystemdirectory(sysp, 100);
deletefile(sysp + '\' + '0001.TMP');
deletefile(sysp + '\' + 'SYSPRS7.DLL');
deletefile(sysp + '\' + 'SYSPRS7.TGZ');
deletefile(sysp + '\' + 'LSPRST7.DLL');
deletefile(sysp + '\' + 'LSPRST7.TGZ');
deletefile(sysp + '\' + 'T0000001.TMP');
deletefile(sysp + '\' + 'CLAUTH1.DLL');
deletefile(sysp + '\' + 'CLAUTH2.DLL');
deletefile(sysp + '\' + 'SSPRS.DLL');
deletefile(sysp + '\' + 'SSPRS.TGZ');

//Eliminar archivos de la carpeta de Delphi32.exe
delp := extractfilepath(application.exename);
deletefile(delp + '0001.TMP');
deletefile(delp + 'servdat.slm');

//Esperar 3 segundos hasta que se borren todos los archivos y entradas
counter := 1;
while counter <= 6 do
begin
 sleep(500);
 inc(counter);
 progressbar1.StepBy(1);
end;

end;

El código es tremendamente sencillo. Sólo se necesita insertarlo en el evento FormCreate de una ventana y añadir a esta un control ProgressBar.

Ahora llega la parte mas engorrosa de todo este tinglado, el hacer que nuestro programa se ejecute al iniciar delphi32.exe, que este último espere a la terminación del primero, y que prosiga su ejecución. Esto lo vamos a hacer con un recorte de código que sigue el siguiente esquema:

- El programa asesino se inicia y eliminia archivos y entradas del registro.
- Espera durante 3'5 segundos a que nuestro programa se inicialize y termine sus tareas
- Finaliza la ejecución de nuestro programa, se liberan recursos y se devuelve el código a delphi32.exe

El procedimiento para hacer este recorte se ve dificultado por un factor adicional: las dos funciones de la API que necesitamos, Shell32:ShellExecuteA (para ejecutar la aplicación asesina) y Kernel:Sleep (para "dormir" el programa durante 3'5 segundos) no se encuentran en la tabla de importaciones de Delphi32.exe.

Para remediar este problema usaremos un programa llamado IIDKing, que permite añadir a un programa varias funciones de UNA SOLA dll. También permite añadir a la sección creada espacio adicional para nuestro recorte de código. Sin mas miramientos, añadimos la función Shell32:ShellExecuteA y unos 0x300 bytes para nuestro recorte.

Ahora vamos a ver el código que debemos añadir a la sección creada por IIDKing (que adopta precisamente el nombre de este programa):

.004F9160: 6A00         push 000 
.004F9162: 6A00         push 000 
.004F9164: 6A00         push 000 
.004F9166: 6800914F00   push 0004F9100 <- Nombre del programa asesino (crack.exe)
.004F916B: 680A914F00   push 0004F910A <- Nombre de la acción a realizar (open) 
.004F9170: 6A00         push 000 
.004F9172: FF15A8904F00 call d,[0004F90A8] <- Llamada a ShellExecuteA 
.004F9178: 680F914F00   push 0004F910F <- Nombre de la librería Kernel32.dll
.004F917D: FF1590144900 call d,[000491490] <- Llamada a GetModuleHandleA
.004F9183: 681C914F00   push 0004F911C <- Nombre de la función (Sleep)
.004F9188: 50           push eax <- Handle del módulo Kernel32.dll
.004F9189: FF1594144900 call d,[000491494] <- Llamada a GetProcAddress
.004F918F: 68AC0D0000   push 000000DAC <- Número de milisegundos a esperar 
.004F9194: FFD0         call eax <- Llamada a Kernel:Sleep()
.004F9196: 68802A4900   push 000492A80 <- Punto de entrada original de delphi
.004F919B: C3           retn
		 

Notas sobre el recorte:

- Sé que esta manera de llevar a cabo este procedimiento se puede hacer de formas mas rápidas y fáciles, pero creedme, esta es de las pocas que funcionan. Snippet Creator permite añadir varias importaciones al ejecutable y así quitarse de encima el engorro de llamar a GetModuleHandle y GetProcAddress, pero Sentinel no acepta un modificación tan brutal del programa y muestra un error a la hora de iniciar la verdadera aplicación.

- No debes olvidar introducir antes que este código las cadenas necesarias separadas entre ellas por un byte 00, para luego referenciarlas desde los lugares oportunos del código; estas cadenas son:

Crack.exe, open, Kernel32.dll, Sleep

- Es evidente que para que este recote se ejecute hay que desviar el entrypoint del programa hacia la primera instrucción de este recorte. El editor PE de ProcDump es idóneo para esta tarea, teniendo en cuenta que

entrypoint = RVA del snippet - ImageBase.

- Las direcciones usadas para llamar a GetModuleHandle y GetProcAddress se pueden encontrar desensamblando el programa con W32Dasm y buscando una llamada cualquiera a estas dos funciones.

- Las llamadas a la API usadas son muy sencillas y no merecen explicación, recomiendo usar la ayuda de la API de Win32 que encontrarás en cualquier compilador de Microsoft.

Eliminando la nag

Pienso que si has entendido el tutorial hasta aquí este apartado no es necesario. De todas formas resumo una forma rápida y cómoda de hacerlo.

0.- Desensambla Caitf32.dll
1.- Busca dentro del listado de nombres del IDA Pro la función j_CreateProcessA.
2.- Haz doble click y ve a la dirección en la que se llama a esta función.
3.- Retorcede hasta el principio de la subrutina que tienes ante tus ojos y salta a la dirección desde la que es llamada
4.- Modifica el Call de esa dirección por un MOV EAX, 00002716

Ahora en vez de llamar a la subrutina que muestra la nag pondrá en EAX el valor que devolvería este si pulsásemos el boton TRY y proseguirá sin estorbar mas con ninguna NAG. (El valor 2716 ha sido sacado de la documentación incluida con el Kit de evaluación de Sentinel).

Anotaciones finales

Otro aspecto de este sistema, es que contiene también en su número de licencia encriptado la fecha límite de ejecución de esta trial, eso quiere decir que no se puede ejecutar después de Junio del 2002. Sobre este tema tengo tres cosas que decir:

1.- Estas licencias suelen tener largos periodos de evaluación, para garantizar que todos los usuarios tengan el producto a su disposición antes de que aparezca otra versión, por lo que antes de que esta versión deje de ser operativa Borland tendrá ya un Delphi 6 o algo así en el mercado.
2.- Lo cierto es que no tengo muy claro que será de mi vida dentro de 2 años, y tengo cosas mas importantes de las que preocuparme que asegurarme un entorno de desarrollo visual para mi futuro ;).
3.- No he conseguido evitar esta "protección", aunque tampoco lo he intentado demasiado :P pienso que no debe ser muy difícil, pero debido al enorme bucle en el que se enfrasca Delphi32.exe, debe ser como mínimo "complicadillo".

Bueno, pues hasta aquí llega mi primer tutorial sobre un sistema de protección comercial. He leido otros tutoriales sobre Rainbow Sentinel LM, pero todos se enfocaban a métodos que no daban ningun tipo de seguridad frente a posibles contratiempos o que simplemente no explicaban como ni por qué se realizaban ciertas operaciones. También he encontrado algunos que garantizan la ejecución ilimitada en la máquina del que lo crackea, pero fuera de esta el crack es totalmente inútil. Yo tengo la seguridad de que el lector de este manual será capaz de crackear de manera segura y estable cualquier programa "acorazado" con Sentinel LM 2.0.

Sin mas comentarios me despido del lector y agradezco el tiempo invertido en leer mi manual. Como es normal en mis tutoriales, admito cualquier crítica mediante la dirección habitual.

Página oficial del grupo K-FoR: http://pagina.de/kfor
Mi dirección de E-Mail: [email protected]



You are inside Reversed Minds pages.

por Mr. Silver / WKT!
La información aquí vertida es exclusivamente para uso educacional, no puedo hacerme responsable del uso que se haga de esta, por lo que atiendo a la honradez de cada uno :), recuerda que debes comprar el software que utilices :)