| ESTUDIO COLECTIVO DE DESPROTECCIONES Última Actualizacion: 25/10/2001 |
Programa | Crackme de Mr.Silver nº 1 | W95 / W98 / NT
Descripción | Crackme de Mr.Silver nº 1
Tipo | Serial
Tipo de Tutorial | [X]Original, []Adaptación, []Aplicación, []Traducción
Url | http://crackme.whiskeykontekila.org
Protección | Tecnicas anti-debugging, encriptacion TEA
Dificultad | 1) Principiante, 2) Amateur, 3) Aficionado, 4) Profesional, 5) Especialista
Herramientas | SoftIce, Masm
Objetivo | Keygenerator
Cracker | Crick
Fecha | 14 de Octubre de 2001
AL ATAQUE
Mr.Silver, tu primer crackme... mmm... ¡juer! ¡¿cómo serán los siguientes?! Vamos a ver q es lo q has hecho: Empezamos por el OEP q es lo suyo. 0167:004010D0 55 PUSH EBP 0167:004010D1 8BEC MOV EBP,ESP 0167:004010D3 83EC08 SUB ESP,08 0167:004010D6 53 PUSH EBX 0167:004010D7 56 PUSH ESI 0167:004010D8 57 PUSH EDI 0167:004010D9 6A00 PUSH 00 0167:004010DB FF150C104000 CALL [KERNEL32!GetModuleHandleA] Hasta aquí, lo normal. 0167:004010E1 8BF8 MOV EDI,EAX 0167:004010E3 8D45FC LEA EAX,[EBP-04] 0167:004010E6 50 PUSH EAX ;pOldProtect 0167:004010E7 6A04 PUSH 04 ;NewProtect = PAGE_READWRITE 0167:004010E9 6800020000 PUSH 00000200 ;Size 0167:004010EE 57 PUSH EDI ;Address 0167:004010EF FF1508104000 CALL [KERNEL32!VirtualProtect] Desprotege 512 bytes de la cabecera del exe para, a continuación, machacar esa zona con CEROS. Se jodió el DUMP!!! 0167:004010F5 B980000000 MOV ECX,00000080 0167:004010FA 33C0 XOR EAX,EAX 0167:004010FC F3AB REPZ STOSD En realidad sólo sobreescribe 128 bytes. EDI contiene el ImageBase = ModuleHandle = 400000. 0167:004010FE 6810154000 PUSH 00401510 0167:00401103 FF1504104000 CALL [KERNEL32!SetUnhandledExceptionFilter] Lo siguiente es modificar la rutina de manejo de las excepciones desatendidas. Ahora apuntan a la rutina q hay en 401510. A partir de aquí, cualquier excepción q se produzca pasará a ser analizada por esa rutina. 0167:00401109 8B3538104000 MOV ESI,[USER32!DialogBoxParamA] 0167:0040110F 56 PUSH ESI 0167:00401110 FF1500104000 CALL [KERNEL32!GetCurrentThread] 0167:00401116 50 PUSH EAX 0167:00401117 E8A4030000 CALL 004014C0 0167:0040111C 83C408 ADD ESP,08 Llama a la rutina q hay en 4014C0 pasándole dos parámetros: La dirección de la función DialogBoxParamA de la API USER32.DLL y el identificador del hilo (Thread) actual. Esta rutina lo q hace es poner un breakpoint en la dirección de la función q se le pasa como parámetro y lo hace modificando directamente el "contexto" del proceso cuyo hilo se pasa como segundo parámetro. Y de paso jodiendo a algún debugger q otro :( [El SICE funciona :)] (Mirad los comentarios en esa rutina) 0167:0040111F 90 NOP 0167:00401120 90 NOP 0167:00401121 90 NOP 0167:00401122 90 NOP Estos NOP'S son cosa del compilador de C del Silver ;) 0167:00401123 B8D0104000 MOV EAX,004010D0 0167:00401128 BB1F114000 MOV EBX,0040111F 0167:0040112D 2BD8 SUB EBX,EAX 0167:0040112F 895DF8 MOV [EBP-08],EBX 0167:00401132 8B4DF8 MOV ECX,[EBP-08] 0167:00401135 68F4164000 PUSH 004016F4 0167:0040113A 51 PUSH ECX 0167:0040113B 68D0104000 PUSH 004010D0 0167:00401140 E84B000000 CALL 00401190 A 401190 se llama con 3 parámetros: La dirección de inicio de una zona de memoria (4010D0), el tamaño de la zona de memoria con la q va a trabajar y la dirección donde pondrá el resultado. Si mirais los comentarios de esta rutina, vereis q lo q hace es usando como fuente los 80h bytes que empiezan en 4010D0 genera un código de 16 bytes (4 DWORDS) q luego usará :) Luego, ojito con tocar esa zona de memoria !!! Si parcheais ahí, el resto no funcionará. 0167:00401145 8B4508 MOV EAX,[EBP+08] Esto no lo entiendo (me lo expliquen). Mete en EAX el primer parámetro q se le pase al programa principal (siempre vale 0) ¿¿¿...??? 0167:00401148 83C40C ADD ESP,0C 0167:0040114B A3F0164000 MOV [004016F0],EAX Ese "0" lo mete en 4016F0. 0167:00401150 6A00 PUSH 00 0167:00401152 68F0114000 PUSH 004011F0 0167:00401157 6A00 PUSH 00 0167:00401159 6A65 PUSH 65 0167:0040115B 50 PUSH EAX 0167:0040115C FFD6 CALL ESI Acordaros q ESI todavía contiene la dirección de "DialogBoxParamA", luego aquí la está llamando. En los parámetros le está pasando como dirección del DlgProc: 4011F0 y si desensamblais esa zona de código vereis q está encriptada!!! Ahora es cuando entra en juego el BreakPoint q se puso antes. En cuanto se llama a DialogBoxParam, salta el Breakpoint y, por tratarse de una excepción, se transfiere el control al manejador de excepciones (recordad q estaba en 401510) El manejador identifica la excepción y lo q hace, en este caso, es desencriptar la zona [4011F0..401470[, con la clave q calculó antes, y luego volver a ejecutar la instrucción q produjo la excepción. 0167:0040115E 5F POP EDI 0167:0040115F 5E POP ESI 0167:00401160 83F8FF CMP EAX,-01 0167:00401163 5B POP EBX 0167:00401164 751F JNZ 00401185 Si al volver de la API la función DialogBoxParamA devuelve -1, es q se ha producido algún error y se muestra el mensaje: "Can not create dialog!" y el programa acaba. Nota: Este error se produce en Win95 y W2k Pro y puede ser debido a que el compilador está pasando como hInstance a DialogBoxParamA (en el PUSH EAX, EAX=0) un CERO, cuando debería ser 400000h (que es lo q devuelve GetModuleHandleA) 0167:00401166 6A30 PUSH 30 0167:00401168 687C104000 PUSH 0040107C 0167:0040116D 6864104000 PUSH 00401064 0167:00401172 6A00 PUSH 00 0167:00401174 FF153C104000 CALL [USER32!MessageBoxA] 0167:0040117A B8FF000000 MOV EAX,000000FF Valor de salida del programa: -1 = error! 0167:0040117F 8BE5 MOV ESP,EBP 0167:00401181 5D POP EBP 0167:00401182 C21000 RET 0010 Si al salir de DialogBoxParamA no hay error, se sale del programa con un 0 = ok! 0167:00401185 33C0 XOR EAX,EAX 0167:00401187 8BE5 MOV ESP,EBP 0167:00401189 5D POP EBP 0167:0040118A C21000 RET 0010 0167:0040118D 90 NOP 0167:0040118E 90 NOP 0167:0040118F 90 NOP Más NOP'S del compilador :( Esta es la rutina q genera una clave de 16 bytes (128 bits) para desencriptar la zona [4011F0-401470[ Recibe tres parámetros: La dirección de la zona de memoria de donde cogerá los bytes para generar la clave. El tamaño de esa zona. La dirección en donde dejará la clave generada. 0167:00401190 8B442408 MOV EAX,[ESP+08] Carga en EAX el tamaño de la zona = 4F 0167:00401194 53 PUSH EBX 0167:00401195 56 PUSH ESI 0167:00401196 8BF0 MOV ESI,EAX 0167:00401198 83E603 AND ESI,03 0167:0040119B 57 PUSH EDI 0167:0040119C 8B7C2410 MOV EDI,[ESP+10] 0167:004011A0 03F0 ADD ESI,EAX 0167:004011A2 C1EE02 SHR ESI,02 En ESI está el tamaño de bloque de memoria = 14h = 20d bytes. 0167:004011A5 56 PUSH ESI ;tamaño 0167:004011A6 57 PUSH EDI ;dirección de inicio 0167:004011A7 6A01 PUSH 01 ;Esta variable cambia en cada llamada. Comienza valiendo 1. 0167:004011A9 E822040000 CALL 004015D0 En 4015D0 se genera a partir de esos 20 bytes un DWORD (4 bytes) que formarán parte de la clave final. Lo devuelve en EAX. 0167:004011AE 8B5C2424 MOV EBX,[ESP+24] EBX apunta a la zona donde se irá escribiendo la clave. 0167:004011B2 8D0C3E LEA ECX,[EDI+ESI] 0167:004011B5 56 PUSH ESI ;tamaño 0167:004011B6 51 PUSH ECX ;dirección de inicio (siguiente bloque de 20 bytes) 0167:004011B7 50 PUSH EAX ;La variable vale ahora el primer DWORD de la clave. 0167:004011B8 8903 MOV [EBX],EAX ;Guarda el primer DWORD de la clave en su sitio. 0167:004011BA E811040000 CALL 004015D0 ;Genera el segundo DWORD. 0167:004011BF 8D1477 LEA EDX,[ESI*2+EDI] 0167:004011C2 56 PUSH ESI ;tamaño 0167:004011C3 52 PUSH EDX ;siguiente bloque 0167:004011C4 50 PUSH EAX ;segundo DWORD 0167:004011C5 894304 MOV [EBX+04],EAX ;Guarda el segundo DWORD 0167:004011C8 E803040000 CALL 004015D0 ;Genera el tercer DWORD 0167:004011CD 8D0C77 LEA ECX,[ESI*2+EDI] 0167:004011D0 56 PUSH ESI 0167:004011D1 03F1 ADD ESI,ECX 0167:004011D3 894308 MOV [EBX+08],EAX ;Guarda el tercer DWORD 0167:004011D6 56 PUSH ESI 0167:004011D7 50 PUSH EAX 0167:004011D8 E8F3030000 CALL 004015D0 ;Genera el cuarto y último DWORD 0167:004011DD 83C430 ADD ESP,30 0167:004011E0 89430C MOV [EBX+0C],EAX ;Guarda el cuarto DWORD 0167:004011E3 5F POP EDI 0167:004011E4 5E POP ESI 0167:004011E5 5B POP EBX 0167:004011E6 C3 RET ;Restaura la pila y vuelve. Este es el DlgProc del DialogBox principal. 0167:004011F0 8B442408 MOV EAX,[ESP+08] 0167:004011F4 83EC54 SUB ESP,54 0167:004011F7 2D10010000 SUB EAX,00000110 0167:004011FC 53 PUSH EBX 0167:004011FD 55 PUSH EBP 0167:004011FE 56 PUSH ESI 0167:004011FF 57 PUSH EDI 0167:00401200 0F8410020000 JZ 00401416 0167:00401206 48 DEC EAX 0167:00401207 740C JZ 00401215 0167:00401209 5F POP EDI 0167:0040120A 5E POP ESI 0167:0040120B 5D POP EBP 0167:0040120C 33C0 XOR EAX,EAX 0167:0040120E 5B POP EBX 0167:0040120F 83C454 ADD ESP,54 0167:00401212 C21000 RET 0010 Este es el ciclo de mensajes, si el mensaje es WM_INITDIALOG = 110 se salta a 401416. Si es WM_COMMAND = 111 se salta a 401215 y si es otro mensaje se continúa en el ciclo. 0167:00401215 8B442470 MOV EAX,[ESP+70] 0167:00401219 25FFFF0000 AND EAX,0000FFFF 0167:0040121E 48 DEC EAX 0167:0040121F 7423 JZ 00401244 0167:00401221 48 DEC EAX 0167:00401222 0F85E2010000 JNZ 0040140A Aquí se procesa WM_COMMAND, si se ha pulsado el botón (ID=1) se salta a 401244 y si se quiere cerrar la ventana se continúa por aquí: 0167:00401228 8B442468 MOV EAX,[ESP+68] 0167:0040122C 6A00 PUSH 00 0167:0040122E 50 PUSH EAX 0167:0040122F FF1530104000 CALL [USER32!EndDialog] 0167:00401235 5F POP EDI 0167:00401236 5E POP ESI 0167:00401237 5D POP EBP 0167:00401238 B801000000 MOV EAX,00000001 0167:0040123D 5B POP EBX 0167:0040123E 83C454 ADD ESP,54 0167:00401241 C21000 RET 0010 Se llama a EndDialog y se sale. Aquí se empieza a procesar el unlock code y el serial que se hayan introducido. 0167:00401244 8B742468 MOV ESI,[ESP+68] 0167:00401248 8B3D2C104000 MOV EDI,[USER32!GetDlgItem] 0167:0040124E 8D4C2420 LEA ECX,[ESP+20] 0167:00401252 6A41 PUSH 41 0167:00401254 51 PUSH ECX 0167:00401255 68E9030000 PUSH 000003E9 0167:0040125A 56 PUSH ESI 0167:0040125B FFD7 CALL EDI 0167:0040125D 8B1D28104000 MOV EBX,[USER32!GetWindowTextA] 0167:00401263 50 PUSH EAX 0167:00401264 FFD3 CALL EBX ;Lee el serial 0167:00401266 83F840 CMP EAX,40 ;Tiene que tener 64 bytes 0167:00401269 0F8588010000 JNZ 004013F7 ;Si no: fuera! 0167:0040126F 8D542414 LEA EDX,[ESP+14] 0167:00401273 6A09 PUSH 09 0167:00401275 52 PUSH EDX 0167:00401276 68EA030000 PUSH 000003EA 0167:0040127B 56 PUSH ESI 0167:0040127C FFD7 CALL EDI 0167:0040127E 50 PUSH EAX 0167:0040127F FFD3 CALL EBX ;Lee el unlock code 0167:00401281 83F808 CMP EAX,08 ;Tiene que tener 8 bytes 0167:00401284 0F854E010000 JNZ 004013D8 ;Si no: fuera! 0167:0040128A 8B2D20104000 MOV EBP,[MSVCRT!strtoul] Carga en EBP la dirección de la función "strtoul" de la librería MSVCRT.DLL Esta función no la he usado nunca y no sabía lo que hacía. Ahora ya lo sé, y supongo que "strtoul" quiere decir STRingTOUnsignedLong. 0167:00401290 8D442470 LEA EAX,[ESP+70] 0167:00401294 6A10 PUSH 10 0167:00401296 8D4C2418 LEA ECX,[ESP+18] 0167:0040129A 33FF XOR EDI,EDI 0167:0040129C 50 PUSH EAX 0167:0040129D 51 PUSH ECX 0167:0040129E 897C247C MOV [ESP+7C],EDI 0167:004012A2 FFD5 CALL EBP 0167:004012A4 8B54247C MOV EDX,[ESP+7C] 0167:004012A8 8944241C MOV [ESP+1C],EAX 0167:004012AC 83C40C ADD ESP,0C 0167:004012AF 803A00 CMP BYTE PTR [EDX],00 0167:004012B2 0F8552010000 JNZ 0040140A Lo primero que hace es convertir el unlock code a un DWORD, eso lo hace "strtoul" y devuelve en EAX el DWORD y en EDX si ha habido error o no. Es decir, si el unlock code estaba formado por caracteres que forman dígitos HEX. Por ejemplo: '1FC9240E' son los ocho caracteres que se pueden transformar en un DWORD (1FC9240E). Si es un DWORD correcto se sigue por aquí: 0167:004012B8 33DB XOR EBX,EBX ;EBX=0 0167:004012BA 8D742421 LEA ESI,[ESP+21] ;ESI apunta al segundo caracter del serial 0167:004012BE 885C246E MOV [ESP+6E],BL bucle: 0167:004012C2 8B442410 MOV EAX,[ESP+10] ;Carga el unlock code (DWORD) en EAX 0167:004012C6 8BCF MOV ECX,EDI ;ECX variará desde 0 hasta 1F 0167:004012C8 D3E8 SHR EAX,CL ;Rota el unlock code a la derecha CL bits 0167:004012CA A801 TEST AL,01 ;El bit 0 es un 1? 0167:004012CC 7561 JNZ 0040132F ;SI: salta a 40132F para continuar el bucle. Los 1's no nos interesan. ;NO: era un 0. Estos sí que nos interesan. 0167:004012CE 8A4EFF MOV CL,[ESI-01] ;Mete en CL un caracter del serial 0167:004012D1 8A16 MOV DL,[ESI] ;Mete en DL el caracter siguiente del serial Recordad que el serial son 64 bytes y su formato debe ser igual que en el unlock code, es decir, caracteres que formen bytes hexadecimales, luego DLCL forman un byte HEX en ASCII. ok? 0167:004012D3 884C246C MOV [ESP+6C],CL 0167:004012D7 8D442470 LEA EAX,[ESP+70] 0167:004012DB 6A10 PUSH 10 0167:004012DD 8D4C2470 LEA ECX,[ESP+70] 0167:004012E1 50 PUSH EAX 0167:004012E2 51 PUSH ECX 0167:004012E3 88542479 MOV [ESP+79],DL 0167:004012E7 FFD5 CALL EBP 0167:004012E9 8B54247C MOV EDX,[ESP+7C] 0167:004012ED 83C40C ADD ESP,0C 0167:004012F0 803A00 CMP BYTE PTR [EDX],00 0167:004012F3 0F85A5000000 JNZ 0040139E Se llama con DLCL a "strtoul" y si la conversión es correcta en EAX (concrétamente en AL) estará el byte resultado. 0167:004012F9 8A4C4420 MOV CL,[EAX*2+ESP+20] 0167:004012FD 8A544421 MOV DL,[EAX*2+ESP+21] ESP+20 apunta al serial en ASCII (al que introdujimos), y ahora usa EAX como índice para cargar en CL y DL otros dos caracteres del serial que formarán otro byte. 0167:00401301 884C246C MOV [ESP+6C],CL 0167:00401305 8D442470 LEA EAX,[ESP+70] 0167:00401309 6A10 PUSH 10 0167:0040130B 8D4C2470 LEA ECX,[ESP+70] 0167:0040130F 50 PUSH EAX 0167:00401310 51 PUSH ECX 0167:00401311 88542479 MOV [ESP+79],DL 0167:00401315 FFD5 CALL EBP 0167:00401317 83C40C ADD ESP,0C 0167:0040131A 8883E0164000 MOV [EBX+004016E0],AL El byte convertido es YA parte de la clave de 16 bytes (similar a la anterior) que se usará más adelante para desencriptar otra zona de código. 0167:00401320 43 INC EBX ;Se incrementa el contador de bytes producidos. 0167:00401321 83FB10 CMP EBX,10 ;LLevamos más de 16 (=10h)? 0167:00401324 7752 JA 00401378 ;SÍ: Serial incorrecto y fuera! 0167:00401326 8B542470 MOV EDX,[ESP+70] 0167:0040132A 803A00 CMP BYTE PTR [EDX],00 0167:0040132D 7549 JNZ 00401378 ;Si el byte no era correcto: tmb fuera! 0167:0040132F 47 INC EDI ;EDI lleva la cuenta de las rotaciones 0167:00401330 83C602 ADD ESI,02 ;Actualiza el puntero al serial 0167:00401333 83FF1F CMP EDI,1F ;Hemos rotado los 32 bits del unlock code? 0167:00401336 7E8A JLE 004012C2 ;NO: seguimos en el bucle Si os habeis fijado lo que hace este bucle es que por cada bit del unlock code (convertido en DWORD) que esté a cero, toma su posición (de 0 a 1F) y la utiliza como índice para conseguir dos bytes ASCII del serial que luego convierte a un sólo byte HEX, y vuelve a utilizar ese byte como índice dentro del serial para coger otros dos bytes del serial que también convertirá en un solo byte HEX y ése es ya parte del código de 16 bytes que formarán la clave. ¿Un poco lioso no? Mejor un ejemplo: Unlock Code = E18B556A En binario: +-------+-------+-------+-------+-------+-------+-------+-------+ | E | 1 | 8 | B | 5 | 5 | 6 | A | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|1|1|0|0|0|0|1|1|0|0|0|1|0|1|1|0|1|0|1|0|1|0|1|0|1|1|0|1|0|1|0| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Si contais vereis que hay 16 0's y 16 1's. Serial = 0E72016B066E690C64106C136318431D6B65085F111F0563430A1E17036F6F55 Si mapeamos el unlock code en binario sobre el serial, tendremos algo como esto: +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Posición:|1F |1E |1D |1C |1B |1A |19 |18 |17 |16 |15 |14 |13 |12 |11 |10 |0F |0E |0D |0C |0B |0A |09 |08 |07 |06 |05 |04 |03 |02 |01 |00 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Valor:|5|5|6|F|6|F|0|3|1|7|1|E|0|A|4|3|6|3|0|5|1|F|1|1|5|F|0|8|6|5|6|B|1|D|4|3|1|8|6|3|1|3|6|C|1|0|6|4|0|C|6|9|6|E|0|6|6|B|0|1|7|2|0|E| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Mapa:| 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ En las posiciones en las que hay un 0 hay valores que van desde 00 hasta 1F. Son los índices a las posiciones del serial que contienen los bytes de la clave. Por ejemplo: el primer 0 del unlock code está en el bit 0, en esa posición del serial tenemos 0Eh que, si lo usamos como índice dentro del serial, vemos que la posición 0Eh contiene 43h = primer byte de la clave. Y así hasta completar los 16 bytes de la clave indexados por los 16 ceros del unlock code. ok? Nota: La clave de este serial NO es la buena :( Para comprender lo siguiente, primero hay que ver lo que hace el programa cuando recibe WM_INITDIALOG en 401416. 0167:00401338 8B15F0164000 MOV EDX,[004016F0] ;=0 0167:0040133E 6A00 PUSH 00 0167:00401340 6870144000 PUSH 00401470 0167:00401345 6A00 PUSH 00 0167:00401347 6A66 PUSH 66 0167:00401349 52 PUSH EDX ;Otra vez 0. Debería ser 400000. 0167:0040134A FF1538104000 CALL [USER32!DialogBoxParamA] Al producirse la llamada a la API, salta el BreakPoint y el manejador de excepciones la identificará e intentará desencriptar la zona [401470..4014C0[ con la clave que ha extraido del serial. Después devolverá el control al DlgProc que empieza en 401470. Obviamente, si no se ha desencriptado bien esa zona, los resultados son impredecibles. Aunque si se produce una nueva excepción (que es lo más probable) el manejador finalizará el proceso. 0167:00401350 83F8FF CMP EAX,-01 0167:00401353 756F JNZ 004013C4 0167:00401355 6A30 PUSH 30 0167:00401357 687C104000 PUSH 0040107C 0167:0040135C 6864104000 PUSH 00401064 0167:00401361 6A00 PUSH 00 0167:00401363 FF153C104000 CALL [USER32!MessageBoxA] 0167:00401369 5F POP EDI 0167:0040136A 5E POP ESI 0167:0040136B 5D POP EBP 0167:0040136C B8FF000000 MOV EAX,000000FF 0167:00401371 5B POP EBX 0167:00401372 83C454 ADD ESP,54 0167:00401375 C21000 RET 0010 Si a la salida del DialogBox no hay error, se continúa por 4013C4 que llama a ExitProcess y se acabó. Pero si lo hay se muestra el mensaje: "Can not create dialog!" Esta rutina muestra el mensaje: "Invalid serial number" 0167:00401378 8B442468 MOV EAX,[ESP+68] 0167:0040137C 6A30 PUSH 30 0167:0040137E 685C104000 PUSH 0040105C 0167:00401383 6844104000 PUSH 00401044 0167:00401388 50 PUSH EAX 0167:00401389 FF153C104000 CALL [USER32!MessageBoxA] 0167:0040138F 5F POP EDI 0167:00401390 5E POP ESI 0167:00401391 5D POP EBP 0167:00401392 B801000000 MOV EAX,00000001 0167:00401397 5B POP EBX 0167:00401398 83C454 ADD ESP,54 0167:0040139B C21000 RET 0010 Esta rutina muestra el mensaje: "Invalid serial number" (Sí, está repetida!!! Estos compiladoreeees... :( ) 0167:0040139E 8B4C2468 MOV ECX,[ESP+68] 0167:004013A2 6A30 PUSH 30 0167:004013A4 685C104000 PUSH 0040105C 0167:004013A9 6844104000 PUSH 00401044 0167:004013AE 51 PUSH ECX 0167:004013AF FF153C104000 CALL [USER32!MessageBoxA] 0167:004013B5 5F POP EDI 0167:004013B6 5E POP ESI 0167:004013B7 5D POP EBP 0167:004013B8 B801000000 MOV EAX,00000001 0167:004013BD 5B POP EBX 0167:004013BE 83C454 ADD ESP,54 0167:004013C1 C21000 RET 0010 Si todo ha ido bien, el programa saldrá por aquí después de habernos dicho lo buenos que somos ;) 0167:004013C4 6A00 PUSH 00 0167:004013C6 FF1510104000 CALL [KERNEL32!ExitProcess] 0167:004013CC 5F POP EDI 0167:004013CD 5E POP ESI 0167:004013CE 5D POP EBP 0167:004013CF 33C0 XOR EAX,EAX 0167:004013D1 5B POP EBX 0167:004013D2 83C454 ADD ESP,54 0167:004013D5 C21000 RET 0010 Esta rutina muestra el mensaje: "Unlock code must be 8 chars long." 0167:004013D8 6A40 PUSH 40 0167:004013DA 68C8104000 PUSH 004010C8 0167:004013DF 68A4104000 PUSH 004010A4 0167:004013E4 56 PUSH ESI 0167:004013E5 FF153C104000 CALL [USER32!MessageBoxA] 0167:004013EB 5F POP EDI 0167:004013EC 5E POP ESI 0167:004013ED 5D POP EBP 0167:004013EE 33C0 XOR EAX,EAX 0167:004013F0 5B POP EBX 0167:004013F1 83C454 ADD ESP,54 0167:004013F4 C21000 RET 0010 Esta rutina muestra el mensaje: "Serial must be 64 chars long." 0167:004013F7 6A40 PUSH 40 0167:004013F9 68C8104000 PUSH 004010C8 0167:004013FE 6884104000 PUSH 00401084 0167:00401403 56 PUSH ESI 0167:00401404 FF153C104000 CALL [USER32!MessageBoxA] 0167:0040140A 5F POP EDI 0167:0040140B 5E POP ESI 0167:0040140C 5D POP EBP 0167:0040140D 33C0 XOR EAX,EAX 0167:0040140F 5B POP EBX 0167:00401410 83C454 ADD ESP,54 0167:00401413 C21000 RET 0010 Aquí se procesa WM_INITDIALOG. 0167:00401416 A138104000 MOV EAX,[USER32!DialogBoxParamA] 0167:0040141B 50 PUSH EAX 0167:0040141C FF1500104000 CALL [KERNEL32!GetCurrentThread] 0167:00401422 50 PUSH EAX 0167:00401423 E898000000 CALL 004014C0 Con la llamada a 4014C0 se vuelve a poner un BreakPoint en DialogBoxParamA. 0167:00401428 8B742470 MOV ESI,[ESP+70] 0167:0040142C 8B3D34104000 MOV EDI,[USER32!SendDlgItemMessageA] 0167:00401432 83C408 ADD ESP,08 0167:00401435 6A00 PUSH 00 0167:00401437 6A40 PUSH 40 0167:00401439 68C5000000 PUSH 000000C5 0167:0040143E 68E9030000 PUSH 000003E9 0167:00401443 56 PUSH ESI 0167:00401444 FFD7 CALL EDI 0167:00401446 6A00 PUSH 00 0167:00401448 6A08 PUSH 08 0167:0040144A 68C5000000 PUSH 000000C5 0167:0040144F 68EA030000 PUSH 000003EA 0167:00401454 56 PUSH ESI 0167:00401455 FFD7 CALL EDI 0167:00401457 5F POP EDI 0167:00401458 5E POP ESI 0167:00401459 5D POP EBP 0167:0040145A B801000000 MOV EAX,00000001 0167:0040145F 5B POP EBX 0167:00401460 83C454 ADD ESP,54 0167:00401463 C21000 RET 0010 Se pintan las cajas de introducción de texto y se vuelve. 0167:00401466 90 NOP 0167:00401467 90 NOP 0167:00401468 90 NOP 0167:00401469 90 NOP 0167:0040146A 90 NOP 0167:0040146B 90 NOP 0167:0040146C 90 NOP 0167:0040146D 90 NOP 0167:0040146E 90 NOP 0167:0040146F 90 NOP Más NOP's del compilador. Aquí empieza el DlgProc del DialogBox que se mostrará únicamente si el serial es correcto. Como podeis ver, el código no tiene mucho sentido: está encriptado!!! Para los que les interese, en el DialogBox se muestran dos mensajes: "Cool!! You've keygened this proggy, what do you think it was easy?" "Coded by Mr. Silver of [WKT!], big thanks to MrJade, Sirene, NeSTe and Duffie for their great support. You guys deceive the whole world. " 0167:00401470 A09B2CE8FE MOV AL,[FEE82C9B] 0167:00401475 D4B9 AAM 0167:00401477 EB5E JMP 004014D7 0167:00401479 F680AC606857D2 TEST BYTE PTR [EAX+576860AC],D2 0167:00401480 47 INC EDI 0167:00401481 D509 AAD 0167:00401483 A9C3D1780A TEST EAX,0A78D1C3 0167:00401488 CC INT 3 0167:00401489 6E OUTSB 0167:0040148A F4 HLT 0167:0040148B BBBC416992 MOV EBX,926941BC 0167:00401490 FFC9 DEC ECX 0167:00401492 6E OUTSB 0167:00401493 0086D7A8DC10 ADD [ESI+10DCA8D7],AL 0167:00401499 AF SCASD 0167:0040149A 1212 ADC DL,[EDX] 0167:0040149C F9 STC 0167:0040149D 2329 AND EBP,[ECX] 0167:0040149F 1CB0 SBB AL,B0 0167:004014A1 2C6D SUB AL,6D 0167:004014A3 90 NOP 0167:004014A4 5B POP EBX 0167:004014A5 C5D4 LDS EDX,ESP 0167:004014A7 D835FA7E96BE FDIV REAL4 PTR [BE967EFA] 0167:004014AD 53 PUSH EBX 0167:004014AE 9E SAHF 0167:004014AF D8BD13EBC473 FDIVR REAL4 PTR [EBP+73C4EB13] 0167:004014B5 F60D13FDE0C9F3 TEST BYTE PTR [C9E0FD13],F3 0167:004014BC 0281ED3781EC ADD AL,[ECX+EC8137ED] Esta es la rutina que putea a los debuggers (bueno, al SICE NO XDD) 004014C0 /$ 81EC CC020000 SUB ESP,2CC ;Hace hueco en la pila para guardar el contexto 004014C6 |. 56 PUSH ESI 004014C7 |. 8BB424 D4020000 MOV ESI,DWORD PTR SS:[ESP+2D4] ;Thread 004014CE |. 8D4424 04 LEA EAX,DWORD PTR SS:[ESP+4] 004014D2 |. 50 PUSH EAX ; /pContext 004014D3 |. 56 PUSH ESI ; |hThread 004014D4 |. FF15 18104000 CALL DWORD PTR DS:[<&KERNEL32.GetThreadContext>>; \GetThreadContext Carga el contexto del thread que se le pasa como parámetro en la zona pContext (en la pila) 004014DA |. 8B8C24 D8020000 MOV ECX,DWORD PTR SS:[ESP+2D8] ;DialogBoxParamA 004014E1 |. 8D5424 04 LEA EDX,DWORD PTR SS:[ESP+4] 004014E5 |. 52 PUSH EDX ; /pContext 004014E6 |. 56 PUSH ESI ; |hThread 004014E7 |. C74424 0C 1000010>MOV DWORD PTR SS:[ESP+C],10010 ; | 004014EF |. C74424 24 0102000>MOV DWORD PTR SS:[ESP+24],201 ; | 004014F7 |. 894C24 10 MOV DWORD PTR SS:[ESP+10],ECX ; | 004014FB |. FF15 14104000 CALL DWORD PTR DS:[<&KERNEL32.SetThreadContext>>; \SetThreadContext Si mirais la estructura CONTEXT (por ejemplo en el artículo sobre el SEH de Silver) vereis que lo que está modificando aquí es el contenido de ContextFlags, DR7 y DR0. Una buena técnica para no tener que bajar al ring-0 !!!! Para poder hacer esas modificaciones hay que cambiar el valor de ContextFlags según lo siguiente: CONTEXT_i386 equ 00010000h CONTEXT_i486 equ 00010000h CONTEXT_CONTROL equ CONTEXT_i386 OR 00000001h CONTEXT_INTEGER equ CONTEXT_i386 OR 00000002h CONTEXT_SEGMENTS equ CONTEXT_i386 OR 00000004h CONTEXT_FLOATING_POINT equ CONTEXT_i386 OR 00000008h CONTEXT_DEBUG_REGISTERS equ CONTEXT_i386 OR 00000010h Como estamos modificando los registros de depuración, el valor de ContextFlags deberá ser: CONTEXT_i386 OR CONTEXT_DEBUG_REGISTERS (10010h) El valor de DR7 lo cambia a 201h, mirando la estructura de este registro vereis que pone a 1 el flag GE (Global Exact), pone a 1 también el L0 (Local 0) y el resto lo pone a 0. Es decir, pone un BreakPoint de un byte de tamaño (LEN0=0), en ejecución(R/W0=0) y en DR0 (L0=1,GE=1). Sólo falta cargar el DR0 con la dirección (DialogBoxParamA) y recargar el contexto para que se encuentre activo. 00401501 |. 5E POP ESI 00401502 |. 81C4 CC020000 ADD ESP,2CC 00401508 \. C3 RETN 0167:00401509 90 NOP 0167:0040150A 90 NOP 0167:0040150B 90 NOP 0167:0040150C 90 NOP 0167:0040150D 90 NOP 0167:0040150E 90 NOP 0167:0040150F 90 NOP Joder con los NOP's >:( "La madre del cordero" Rutina de manejo de excepciones desatendidas (Unhandled Exceptions) 0167:00401510 8B442404 MOV EAX,[ESP+04] ;Puntero al EXCEPTION_RECORD 0167:00401514 53 PUSH EBX 0167:00401515 8B5804 MOV EBX,[EAX+04] ;Puntero al CONTEXTO del proceso que causa la excepción 0167:00401518 8B00 MOV EAX,[EAX] ;EAX apunta al EXCEPTION_RECORD 0167:0040151A 813804000080 CMP DWORD PTR [EAX],80000004 ;El primer DWORD de EXCEPTION_RECORD es ExceptionCode Lo compara con STATUS_SINGLE_STEP = 80000004, es decir, comprueba que se trate de un BreakPoint de ejecución. 0167:00401520 0F8596000000 JNZ 004015BC ;Si no lo fuera salta a 4015BC 0167:00401526 8B8BC4000000 MOV ECX,[EBX+000000C4] ;Carga en ECX el valor de ESP desde el CONTEXTO 0167:0040152C 56 PUSH ESI 0167:0040152D 57 PUSH EDI 0167:0040152E 8B7110 MOV ESI,[ECX+10] ;En ESI carga la dirección que se le pasó a DialogBoxParamA como DlgProc (La extrae de la pila del proceso a través del CONTEXTO) 0167:00401531 81FEF0114000 CMP ESI,004011F0 ;Esta es la dirección del primer DlgProc 0167:00401537 7530 JNZ 00401569 Como las dos partes que desencriptan la zona de código correspondiente son básicamente iguales, sólo explicaré una de ellas. 0167:00401539 B870144000 MOV EAX,00401470 0167:0040153E 2DF0114000 SUB EAX,004011F0 0167:00401543 99 CDQ 0167:00401544 83E207 AND EDX,07 0167:00401547 03C2 ADD EAX,EDX 0167:00401549 C1F803 SAR EAX,03 0167:0040154C 85C0 TEST EAX,EAX 0167:0040154E 7E4F JLE 0040159F 0167:00401550 8BF8 MOV EDI,EAX 0167:00401552 68F4164000 PUSH 004016F4 0167:00401557 56 PUSH ESI 0167:00401558 56 PUSH ESI 0167:00401559 E8E2000000 CALL 00401640 0167:0040155E 83C40C ADD ESP,0C 0167:00401561 83C608 ADD ESI,08 0167:00401564 4F DEC EDI 0167:00401565 75EB JNZ 00401552 0167:00401567 EB36 JMP 0040159F 0167:00401569 81FE70144000 CMP ESI,00401470 ;Esta es la dirección del segundo DlgProc 0167:0040156F 752E JNZ 0040159F 0167:00401571 B8C0144000 MOV EAX,004014C0 ;Fin zona a desencriptar 0167:00401576 2D70144000 SUB EAX,00401470 ;Fin-Inicio zona a desencriptar 0167:0040157B 99 CDQ 0167:0040157C 83E207 AND EDX,07 0167:0040157F 03C2 ADD EAX,EDX 0167:00401581 C1F803 SAR EAX,03 0167:00401584 85C0 TEST EAX,EAX 0167:00401586 7E17 JLE 0040159F 0167:00401588 8BF8 MOV EDI,EAX ;Tamaño zona bucle: 0167:0040158A 68E0164000 PUSH 004016E0 ;Clave de 16 bytes (128 bits) (extraída del serial) 0167:0040158F 56 PUSH ESI ;Inicio zona 0167:00401590 56 PUSH ESI 0167:00401591 E8AA000000 CALL 00401640 ;Desencripta 8 bytes = 2 DWORDS 0167:00401596 83C40C ADD ESP,0C 0167:00401599 83C608 ADD ESI,08 0167:0040159C 4F DEC EDI 0167:0040159D 75EB JNZ 0040158A ;Sigue en el bucle Aquí se llega siempre que la excepción fuera STATUS_SINGLE_STEP. 0167:0040159F 5F POP EDI 0167:004015A0 C7430400000000 MOV DWORD PTR [EBX+04],00000000 0167:004015A7 C7431800070000 MOV DWORD PTR [EBX+18],00000700 0167:004015AE C70317000100 MOV DWORD PTR [EBX],00010017 Lo que se hace aquí es eliminar el BreakPoint: DR0=0 DR7=700 (Rsvd=1,GE=1,LE=1, el resto a 0) ContextFlags=CONTEXT_i386 OR CONTEXT_DEBUG_REGISTERS OR CONTEXT_CONTROL OR CONTEXT_INTEGER OR CONTEXT_SEGMENTS 0167:004015B4 5E POP ESI 0167:004015B5 83C8FF OR EAX,-01 ;EXCEPTION_CONTINUE_EXECUTION 0167:004015B8 5B POP EBX 0167:004015B9 C20400 RET 0004 Se devuelve EXCEPTION_CONTINUE_EXECUTION con lo que se ejecutará de nuevo la instrucción que causó la excepción. 0167:004015BC 68FF000000 PUSH 000000FF 0167:004015C1 FF1510104000 CALL [KERNEL32!ExitProcess] 0167:004015C7 33C0 XOR EAX,EAX ;EXCEPTION_CONTINUE_SEARCH 0167:004015C9 5B POP EBX 0167:004015CA C20400 RET 0004 Si la excepción no era STATUS_SINGLE_STEP, el programa llama a ExitProcess y termina. 0167:004015CD 90 NOP 0167:004015CE 90 NOP 0167:004015CF 90 NOP Otro puñao de NOP's :) Esta rutina genera un DWORD que devuelve en EAX y que forma parte de la primera clave de 16 bytes (ver más arriba) 0167:004015D0 55 PUSH EBP 0167:004015D1 8BEC MOV EBP,ESP 0167:004015D3 53 PUSH EBX 0167:004015D4 56 PUSH ESI 0167:004015D5 8B4508 MOV EAX,[EBP+08] ;Tercer parámetro (variable) 0167:004015D8 8B5D08 MOV EBX,[EBP+08] 0167:004015DB 25FFFF0000 AND EAX,0000FFFF 0167:004015E0 C1EB10 SHR EBX,10 0167:004015E3 81E3FFFF0000 AND EBX,0000FFFF 0167:004015E9 8B5510 MOV EDX,[EBP+10] ;Primer parámetro (tamaño) 0167:004015EC 8B750C MOV ESI,[EBP+0C] ;Segundo parámetro (dirección zona) 0167:004015EF 33C9 XOR ECX,ECX 0167:004015F1 8DA42400000000 LEA ESP,[ESP+00000000] ;Esto no hace nada 0167:004015F8 8DA42400000000 LEA ESP,[ESP+00000000] ;Esto no hace nada 0167:004015FF 90 NOP ;Esto no hace nada bucle: 0167:00401600 8A0E MOV CL,[ESI] 0167:00401602 03C1 ADD EAX,ECX 0167:00401604 3DF1FF0000 CMP EAX,0000FFF1 0167:00401609 7C05 JL 00401610 0167:0040160B 2DF1FF0000 SUB EAX,0000FFF1 0167:00401610 03D8 ADD EBX,EAX 0167:00401612 81FBF1FF0000 CMP EBX,0000FFF1 0167:00401618 7C06 JL 00401620 0167:0040161A 81EBF1FF0000 SUB EBX,0000FFF1 0167:00401620 46 INC ESI 0167:00401621 4A DEC EDX 0167:00401622 75DC JNZ 00401600 ;Sigue en el bucle 0167:00401624 C1E310 SHL EBX,10 0167:00401627 81E30000FFFF AND EBX,FFFF0000 0167:0040162D 0BC3 OR EAX,EBX 0167:0040162F 5E POP ESI 0167:00401630 5B POP EBX 0167:00401631 5D POP EBP 0167:00401632 C3 RET 0167:00401633 90 NOP 0167:00401634 90 NOP 0167:00401635 90 NOP 0167:00401636 90 NOP 0167:00401637 90 NOP 0167:00401638 90 NOP 0167:00401639 90 NOP 0167:0040163A 90 NOP 0167:0040163B 90 NOP 0167:0040163C 90 NOP 0167:0040163D 90 NOP 0167:0040163E 90 NOP 0167:0040163F 90 NOP Rutina de desencriptación. MrSilver ha usado el TEA (Tiny Encryption Algorithm) Lo podeis ver en el keygen. 0167:00401640 83EC08 SUB ESP,08 0167:00401643 53 PUSH EBX 0167:00401644 55 PUSH EBP 0167:00401645 56 PUSH ESI 0167:00401646 8B742420 MOV ESI,[ESP+20] ;ESI apunta a la clave 0167:0040164A 8B442418 MOV EAX,[ESP+18] ;EAX apunta al inicio de la zona 0167:0040164E 57 PUSH EDI 0167:0040164F 8B3E MOV EDI,[ESI] ;Primer DWORD de la clave 0167:00401651 BA2037EFC6 MOV EDX,C6EF3720 0167:00401656 8B08 MOV ECX,[EAX] ;Primer DWORD a desencriptar 0167:00401658 8B4004 MOV EAX,[EAX+04] ;Segundo DWORD a desencriptar 0167:0040165B 897C2414 MOV [ESP+14],EDI 0167:0040165F 8B7E04 MOV EDI,[ESI+04] ;Segundo DWORD de la clave 0167:00401662 897C2410 MOV [ESP+10],EDI 0167:00401666 8B7E08 MOV EDI,[ESI+08] ;Tercer DWORD de la clave 0167:00401669 8B760C MOV ESI,[ESI+0C] ;Cuarto DWORD de la clave 0167:0040166C 897C2424 MOV [ESP+24],EDI 0167:00401670 8974241C MOV [ESP+1C],ESI 0167:00401674 BF20000000 MOV EDI,00000020 bucle: 0167:00401679 8B5C241C MOV EBX,[ESP+1C] 0167:0040167D 8B6C2424 MOV EBP,[ESP+24] 0167:00401681 8BF1 MOV ESI,ECX 0167:00401683 C1EE05 SHR ESI,05 0167:00401686 03F3 ADD ESI,EBX 0167:00401688 8BD9 MOV EBX,ECX 0167:0040168A C1E304 SHL EBX,04 0167:0040168D 03DD ADD EBX,EBP 0167:0040168F 8B6C2414 MOV EBP,[ESP+14] 0167:00401693 33F3 XOR ESI,EBX 0167:00401695 8D1C0A LEA EBX,[ECX+EDX] 0167:00401698 33F3 XOR ESI,EBX 0167:0040169A 8B5C2410 MOV EBX,[ESP+10] 0167:0040169E 2BC6 SUB EAX,ESI 0167:004016A0 8BF0 MOV ESI,EAX 0167:004016A2 C1EE05 SHR ESI,05 0167:004016A5 03F3 ADD ESI,EBX 0167:004016A7 8BD8 MOV EBX,EAX 0167:004016A9 C1E304 SHL EBX,04 0167:004016AC 03DD ADD EBX,EBP 0167:004016AE 33F3 XOR ESI,EBX 0167:004016B0 8D1C02 LEA EBX,[EAX+EDX] 0167:004016B3 33F3 XOR ESI,EBX 0167:004016B5 81C24786C861 ADD EDX,61C88647 0167:004016BB 2BCE SUB ECX,ESI 0167:004016BD 4F DEC EDI 0167:004016BE 75B9 JNZ 00401679 ;Sigue en el bucle 0167:004016C0 8B542420 MOV EDX,[ESP+20] 0167:004016C4 5F POP EDI 0167:004016C5 5E POP ESI 0167:004016C6 5D POP EBP 0167:004016C7 890A MOV [EDX],ECX ;ECX = primer DWORD desencriptado 0167:004016C9 894204 MOV [EDX+04],EAX ;EAX = segundo DWORD desencriptado 0167:004016CC 5B POP EBX 0167:004016CD 83C408 ADD ESP,08 0167:004016D0 C3 RET Conclusiones: Crackme interesante. Vemos buenas técnicas anti-debugging y cómo modificar el contexto de un programa a pelo. Aunque esto último ya lo utilizó ni2 en su crackme#3. Aunque la clave es fija (supongo que conoceis los problemas de distribuir programas con claves fijas), el unlock code y el serial son variables, lo que le dota de cierta flexibilidad. He hecho un keygen que genera el unlock code y el serial. Pero en el interior del serial no está la clave buena. Lo he hecho símplemente para que veais cómo se puede implementar ese keygen. (Está hecho en Win32ASM con MASM) También os meto un Brute Force para el que tenga varios Main-Frames en su casa y quiera petarlo a lo bruto. ;) Saludos. Crick Keygen & Brute Force
[ Entrada | Documentos Genéricos | WkT! Web Site ]
[ Todo el ECD | x Tipo de Protección | x Fecha de Publicación | x Orden Alfabético ]
(c) Whiskey Kon Tekila [WkT!] - The Original Spanish Reversers. Si necesitas contactar con nosotros , lee esto antes e infórmate de cómo puedes ayudarnos