Cmiatron v10.6 - tutorial por Crackz -Traducido por CORINTO, 17 de Mayo de 2001- - Webpage. incluyendo código fuente. Este tutorial marca el final de mi actual serie sobre HASP, y no es recomen dada para iniciados porque voy a hablar sobre temas de ingeniería inversa bastante complicados. Un mensaje para cuando los desarrolladores de Cimatron lean esto, que yo se que lo harán :-), esta será la última versión de alguno de sus productos que voy a explicar cómo crackearla, dudo sin embargo que puedan conciliar el sueño fácilmente, porque será inevitable que alguien esté preparado para ocupar mi lugar, y distribuir libremente dicho software, bastante bueno por otra parte. Hemos visto en anteriores tutoriales sobre HASP como localizar fácilmente la rutina principal del HASP, el proceso de crackeo de los mismos era bastante simple, usar un editor HEX para localizar la cadena 'HASPDOSDRV' y cambiar el siguiente E9(JMP) a E8(CALL), entonces parchear el "entry point" a este, varios F8 más abajo del CALL[EBP+00] el cual está justo después de que CreateFileA llame a cualquiera de los dispositivos HASP. Obviamente todo lo que vuestra nueva rutina necesitaba era accionar el código de servicio en BH apropiadamente, y no voy a explicarlo otra vez, coged vuestro 'haspman.pdf' y hechad un vistazo a la sección ASM. Si realmente estais interesado en el crackeo de HASP entonces, codificar o convertir el generador de UCL HASP debería ser una prioridad, y si sois un poco vagos, podeis mandarme un e-mail y os enviaré un archivo de unos 600 bytes que es el que uso para emular todas las funciones de MemoHASP. Por supuesto HASP no puede hacerlo fácil y en la versión 6 se veía la manifestación de un 'empacado', que es un encriptador PE, que tiene algunos trucos bastante buenos, confíando en un 'dongle' para hacer la desencriptación. Esto normalmente toma la forma de una llamada de servicio 1 IsHasp(), seguido de un servicio 2 a HaspCode() dos veces, y decrementando el código origen. La respuesta a esto ya es conocida, todo lo que necesitáis es parchear los códigos de retorno precisos y volcar el programa desencriptado usando vuestro desencriptador favorito(muy recomendado el IceDump). La versión 7 sin embargo distingue un cambio significativo. Primeramente, HASP comenzó a darse cuenta de que ciertos inversores rusos estaban haciendo dinero vendiendo VXDs de HASP que eran activadas usando llaves de registro(ver el enlace al principio de este ejercicio a UCL). Ahora os voy a mostrar por primera vez como se hace esto. Los drivers para HASP Windows 95/98 consisten en dos archivos, hasp95.vxd y hasp95dl.vxd, como debeis haber imaginado hasp95.vxd es el driver estático y hasp95dl.vxd es cargado dinámicamente(dl). Los rusos enfocaron sus ataques al driver dinámico: Control_0 CMP EAX, 7 JZ loc_C0000000 CMP EAX, 9 JZ loc_C0000002 CMP EAX, 1Eh JZ loc_C000000D CMP EAX, 2 JZ loc_C000001A CMP EAX, 23h <-- W32_DeviceIOControl. JZ loc_C000009E CLC <-- Trace out service by clearing CF. El procedimiento Control realmente solo es una expresión switch(establece algo a si/no encendido o apagado), que probablemente habeis visto un millón de veces en C o lenguajes del estilo. Por supesto, HASP, como buen 'VXD' aprobado por Micro$oft, es llamado a través de un buen interfaz aprobado por Micro$soft: DeviceIOControl. Cuando EAX=23 es el momento de realizar alguna acción. El contenido en ESI es entonces la llave, especificamente el valor de [ESI+0C], cuando este es 2 tenemos un servicio HASP en proceso, cuando [ESI+0C] es -1/0/1/3/4 son ejecutadas otras tareas, buscadlas vosotros mismos, cargando vuestro objetivo HASP, entrando en SoftIce y tecleando 'vxd hasp95dl' y entonces estableciendo un bpmb en la dirección del control del procedimiento. Todos los 'de-HASPers', lo que hacen es reescribir esta rutina de transferencia, para ello desencriptan los parametros del HASP(los cuales en este nivel están basados en XOR CON AAh y en ROR con 4), para accionar el servicio, esto es, retornando las respuestas que esperan dichos parametros, y ejecutando un VMMCall_RegOpenKey y un _RegQueryValueEx si es necesario y ¡¡voila!!, reencriptamos el servicio y lo traceamos(trace out). Yo hice exactamente lo mismo usando la v3.81 de los drivers del HASP en alrededor de una hora, y ahora tengo una bonita selección de software 'operativo'. La mayoría de los colegas rusos también almacenaron varios 'dongles' simulados del hasp95dl.vxd. Por supuesto HASP se enteró de esto y primeramente lo contrarrestó publicando continuamente drivers actualizados, esto significaba claro está que los de-HASPers debían ser también continuamente actualizados. La gente de HASP se dio cuenta que esto no podía continuar así indefinidamente, y cambiaron sus tácticas, y esto marca el punto donde la versión 7 entra en escena. Ahora podeis empezar con cualquiera de los programas de Cimatron para este tutorial(mejor RiSE), muchos de los programas principales son solo 'loaders' de las correpondientes DLLs. Yo elegí chkddf.exe/chkddf.dll porque en comparación son pequeños para desensamblarlos(hay otros 31 archivos que trabajan exactamente como este). Lo primero que hice fue poner un bpx en CreateFileA a este driver, pero sin esperar que funcionara entonces probé un montón de breakpoints(incluyendo DeviceIOControl), el único que funcionó fue MessageBoxA, y a partir de ahí podeis tracear hacia atrás, pero dejadme probar algo primero. En primer lugar un bpmb al procedimiento de control de hasp95dl.vxd y entonces ejecutar chkddf.exe , no salta, ¿por qué?, bien, el cuerpo de la nueva versión desencripta la auténtica rutina de comunicación el mismo, por eso los emuladores de sustitución a bajo nivel del vxd están acabados. 1C003CFC CALL 1C003C40 <-- Aquí. 1C003D01 TEST EAX, EAX 1C003D03 MOV DWORD PTR [1C0327F8], EAX 1C003D08 JZ 1C003D1F 1C003D1F PUSH 1C030054 <-- "Protection Device Not Found".-->Dispositivo de protección no encontrado CALL 1C003CFC -->es donde encontrarás tu primera parada. Tuve Una pequeña intuición con la 'StringRef' quizás :- 1C003D40 SUB ESP, 100 <--hace algo de sitio en la pila 1C003D46 PUSH ESI 1C003D47 PUSH EDI 1C003D48 XOR ESI, ESI <-- Borra ESI. 1C003D4A CALL 1C008D60 <-- Aquí dentro debe haber algo. 1C003D4F TEST EAX, EAX 1C003D51 JZ 1C003D65 1C003D53 PUSH 1C03007C <-- "Your version of the HASP driver is too old". ("tu versión del controlador HASP es demasiado antigua") Date cuenta que nuestro problema era que no podíamos encontrar dónde la protección abría comunica ciones entre el HASP y el programa, una pequeña intuición os dice que debe haber algo debajo de CALL 1C008D60, sino cómo podría determinar que la versión es demasiado antigua. 1C008D60 PUSH 1C033DD0 1C008D65 PUSH 1C033DCC 1C008D6A PUSH 1C033DC8 1C008D6F PUSH 1C033DC4 <-- Estas serán por supuesto las direcciones de retorno para los parámetros. 1C008D74 PUSH 0 1C008D76 PUSH 0 1C008D78 PUSH 0 1C008D7A PUSH 0 1C008D7C PUSH 1 <-- Servicio. 1C008D7E CALL 1C01E000 <-- ¡Este es el comienzo de la seccion .data!. 1C008D83 MOV ECX, DWORD PTR [1C033DCC] 1C008D89 XOR EAX, EAX <-- Borra EAX. 1C008D8B ADD ESP, 24 <-- Limpia la pila. 1C008D8E CMP ECX, FFFFFF99 <-- -103. 1C008D91 SETE AL <-- Flag AL. 1C008D94 RET Ahora estamos consiguiendo algo, se pasan un montón de parámetros a CALL 1C01E000, que es realmente el comienzo de la sección .data, ¡y sin desensamblar con w32Dasm!. Aquí es donde está el meollo. Vamos a poner un breakpoint en este punto(1c01e000), y ver como prosigue el código. Bien, no voy a decíroslo todo, pero si os diré que tracear este código es como nadar en petróleo, parte del código es realmente demencial :-), en las primeras fracciones del mismo deberíais distinguir entre 'ruido' y código 'real', hay un montón de mierda, algo así como dos de cada tres instrucciones no hacen nada, observa el siguiente código:- :1C01E006 PUSHAD <-- Salva todos los registros. :1C01E007 ADD AL,00 <-- Basura. :1C01E009 XCHG ESI,ESI <-- Basura. :1C01E00B MOV AH,AH <-- Basura. :1C01E00D CALL 1C0298D2 <-- CALL real. :1C0298D4 MOV EDX,[ESP] <-- Real. :1C0298D7 JA 1C0298D9 <-- Basura. :1C0298D9 SUB ESP,-04 <-- Real. :1C0298DC SHLD EBX,ECX,80 <-- Basura. :1C0298E0 MOV EBP,ESP <-- Real. :1C0298E2 XCHG BH,BH <-- BAsura. :1C0298E4 ADD EBP,FFFFFFF4 <-- establece EBP. :1C0298EA LEA EDI,[EDI] <-- BAsura. :1C0298EC MOV EBX,1F8DFE10 <-- Basura. :1C0298F1 XCHG BH,BH <-- Basura. ¿Por qué os enseño esto?, bueno, este nuevo objeto encriptado está muy bien codificado para oscurecer el código y su traceo, y aquí es donde entra el buen hacer del cracker, yo vi un montón de código que parecía notablemente familiar al de la versión 6 pero no trabaja como yo esperaba, por ejemplo:- :0072F067 PUSH 0072B6C6 :0072F06C CALL 00729D68 <-- haspreg()-->Fucnión de registro de HASP. :0072F071 MOV EDI,[ESP+3C] :0072F075 MOV [EDI],EAX <-- Retorna parte 1. :0072F077 MOV EDI,[ESP+40] :0072F07B MOV [EDI],EBX <-- Retorna parte 2. :0072F07D MOV EDI,[ESP+44] :0072F081 MOV [EDI],ECX <-- Retorna parte 3. :0072F083 MOV EDI,[ESP+48] :0072F087 MOV [EDI],EDX <-- Retorna parte 4. :0072F089 ADD ESP,04 <-- Corrige la pila. :0072F08C POPAD <-- Restaura los registros. Con estos apuntes de aquí arriba, os habreis dado cuenta de lo obvio, no es necesario estudiar la desencriptación porque nuestros códigos de retorno son verificados fuera de la aplicación (todos los parámetros son colocados en la pila del objeto encriptado listos para ser accionados (iniciar la comunicación)). Pero más tarde veremos cómo esto podría haber causado problemas si no fuera por la sobrecarga(overload) de la principal DLL (cimit.DLL) de la protección de Cimatron. Por lo tanto todo lo que tenemos que hacer es insertar nuestra rutina de emulación al comienzo de la sección .data y accionar el servicio, por el trozo anterior de código sabemos que las direcciones de retorno son colocadas en la protección :-) Voy a publicar aquí mi rutina completa de emulación, tal cual es, puede ser pegada en los otros 31 archivos protegidos con vuestro editor hexadecimal(con el tiempo se encontrará la forma de hacerlo dentro de cimit.DLL, pero todavía no). El perspicaz que hay dentro de vosotros os habra avisado de un problema rápidamente. Cuando se llama al servicio 2 el único parámetro que se le pasa es el código origén(64) y no las passwords del desarrollador, por lo tanto estamos ante un objetivo absolutamente desconocido y tendríamos un problema, afortunadamente yo sabía que eran 2209/713D desde la versión 10, de hecho podríamos haberlas descubierto en cimit.DLL también. Por lo tanto los de Cimatron si estais leyendo esto , tomad nota de estos dos errores. 1) Estais usando apenas un código origen(64) y vuestras passwords son conocidas. 2) Al haber usado la versión 6 para proteger cimit.DLL, es fácil recuperar vuestras passwords. Obviamente podemos parchear los códigos correctos de retorno sin preocuparnos. PUSHAD (60) <-- Salva todos los registros. CALL $+5 (E8 00 00 00 00) <-- nuestro emulador. POP EBP (5D) <-- consigue la dirección actual. XOR EAX, EAX (33 C0) <-- borra EAX. MOV EAX, [ESP+24] (8B 44 24 24) <-- Servicio. CMP AX, 1 (66 3D 01 00) <-- comprobación IsHasp()(comprueba la presencia de HASP. JNE $+8 (75 08) <-- Chequea el próximo servicio. MOV EDI, [ESP+38] (8B 7C 24 38) <-- Dirección de retorno de Parte 1. MOV [EDI], EAX (89 07) <-- HASP encontrado. POPAD (61) <-- Restaura todos los registros. RET (C3) <-- // IsHasp(). CMP AX, 2h (66 3D 02 00) <-- comprobación HaspCode(). JNE $+2A (75 2A) <-- Chequea el próximo servicio. MOV AX, 3FA1 (66 B8 A1 3F) <-- Código retorno 1. MOV EDI, [ESP+38] (8B 7C 24 38) MOV [EDI], EAX (89 07) MOV AX, FF26 (66 B8 26 FF) <-- Código retorno 2. MOV EDI, [ESP+3C] (8B 7C 24 3C) MOV [EDI], EAX (89 07) MOV AX, 5EE7 (66 B8 E7 5E) <-- Código retorno 3. MOV EDI, [ESP+40] (8B 7C 24 40) MOV [EDI], EAX (89 07) MOV AX, 4955 (66 B8 55 49) <-- Código retorno 4. MOV EDI, [ESP+44] (8B 7C 24 44) MOV [EDI], EAX (89 07) POPAD (61) RET (C3) <-- // HaspCode(). CMP AX, 4Bh (66 3D 4B 00) JNE $+2D (75 2D) <-- Finge siempre el retorno correcto. MOV EDI, [ESP+38] (8B 7C 24 38) <-- Consigue dirección de lectura. MOV EAX, [EDI] (8B 07) <-- mueve a EAX. LEA EDI, [EBP+68] (8D 7D 68) <-- comienzo de la memoria emulada (16 bytes). ADD EDI, EAX (03 F8) <-- Suma la dirección a leer. MOV AL, BYTE PTR [EDI] (8A 07) <-- la coloca en AL. MOV EDI, [ESP+3C] (8B 7C 24 3C) <-- Código retorno 2. MOV [EDI], EAX (89 07) XOR EAX, EAX (33 C0) <-- Borra EAX. MOV EDI, [ESP+40] (8B 7C 24 40) <-- Código retorno 3. MOV [EDI], EAX (89 07) POPAD (61) RET (C3) // ReadByte(). db 16 (memoria emulada). XOR EAX, EAX (33 C0) <-- Borra EAX. MOV EDI, [ESP+38] (8B 7C 24 38). MOV [EDI], EAX (89 07). MOV EDI, [ESP+3C] (8B 7C 24 3C). MOV [EDI], EAX (89 07). MOV EDI, [ESP+40] (8B 7C 24 40). MOV [EDI], EAX (89 07). MOV EDI, [ESP+44] (8B 7C 24 44). MOV [EDI], EAX (89 07). POPAD (61). RET (C3). Fijaos que aquí emulo solo 3 servicios(1, 2 y 4B), si examinais de cerca el código vereis que se hace referencia a muchos otros servicios(4, 32, 46, 48, 49 y 4a), pero el código nunca puede ser alcanzado, por supuesto con un programa como Cimatron y otras 31 DLLs para desproteger, puedes calcular el tiempo que llevaría desensamblar cada DLL y también emular esos servicios sin referenciar, y es inaceptable. Con el servicio 4B se leen 2 bytes, las direcciones C y D, y se les hace un XOR con 8000h y debe ser igual al ID de tu dongle, esto es, si el ID de un dongle es 0614 este requiere 8614 => word C=14 y word D=86. Arrancad vuestro recién parcheado chkddf.exe, y bien, como ya sabes, funciona :-) La principal DLL de Cimatron es cimit.DLL, esta ejecuta el programa principal y es además su protección. En vez de aplicar sólo la versión 7, Cimatron ha aplicado también la versión 6. En lugar de darte todo el crack 'mascado', solo te describiré como lo hice, y te dejo la implementación a ti. Primero hay que localizar la versión 6, puedes hacerlo con el habitual bpx en FreeEnvironmentStringsA, el programa también chequea que está el dongle Cimagrafi y comprueba estos passwords :-), yo aquí elegí hacer alguna redirección, puedes encontrar fácilmente el salto JMP HASPDOSDRV y redireccionar el JMP al CALL a tu propia rutina -esto significa que debes encontrar donde se desencripte el código para este salto JMP(fácil con bpr). Sin embargo la versión 7 es desencriptada por la v. 6, lo que significa que no puedes simplemente pegar tu rutina de emulación al comienzo de la sección .data, tienes que encontrar donde se desencripta(bpr otra vez). - Te aviso que esto pondrá a prueba tu paciencia en cuanto que hay un montón de instrucciones de copia 'de' y 'a' con las que haberselas. No creía que fuera práctico trabajarse todos los byte desencriptados que se requieren para generar mi rutina de emulación completa(que para cimit.DLL alcanza los 672 bytes), así que solo desencripté un 'long JMP' a otra rutina que coloqué en el espacio libre al final de .reloc, recuerda que realmente no nos importa cómo leches se desencripta la versión 7, no vamos a hacer nunca una llamada a ese lugar. En la versión distribuida de este crack tuve que emular el servicio 3, e hice un trabajo bastante torpe al modificar las características de la cabecera PE, por eso pude escribir un salto JMP sobre uno JNZ(no muy agradable estéticamente). Para aquellos de vosotros que uséis la opción RE_ENGE, necesitaréis un número de registro para poder salvarlo correctamente. Mi buen amigo prs parcheó la DLL para vosotros, sin embargo yo anduve la milla extra y forcé que aceptara 00061E21 como un código válido. Esto es todo, no hay aquí disponible ningún crack para perdedores, id y haced algo de trabajo vosotros mismos :-) Si alguien de Cimatron se toma la molestia de mandarme un correo electrónico quizás tengamos una conversación civilizada. © 1999CrackZ, 18 de Diciembre de 1999. ___________________________________________________________________________________ Como seguro que esta traducción tendrá errores y puntos que no han quedado claros, mándame tus dudas a : elcorinto@hotmail.com CORINTO. Piensa, y que no te cojan !!!.