Introducción

Aquí tenemos un Crackme clásico creado por Scarebyte hallá por el año 2000 y que cuenta con varias fases siendo un crackme muy interesante para iniciarse o simplemente para divertirse. Al estar realizado en Delphi, los apartados de las checkboxes y de las trackbars se simplifican y mucho, pero aún así hay que currarselo un poco para dejar todo bien atado. Si os fijáis en las soluciones que aparecen en crackmes.de, en aquellos años se usaba DEDE y aunque yo usaré otra herramienta, DEDE sigue siendo igual de útil.

Desempacado

PEiD nos dice que nos enfrentamos a ASPack 1.08.03 -> Alexey Solodovnikov, así que vamos al lío.

Eliminar la NAG

17-02-2016 12-46-19_nag

Tan sencillo como poner un Breakpoint a User32.MessageBoxA. La llamada a NOPear está en la dirección 441CF2.

Password

Desde las string references localizamos los mensajes de chico bueno y chico malo que nos llevan al código a analizar.

0044C3CD   |.  E8 5294FDFF     CALL CrackMe_.00425824
0044C3D2   |.  8B45 FC         MOV EAX,[LOCAL.1]
0044C3D5   |.  E8 9A76FBFF     CALL CrackMe_.00403A74
0044C3DA   |.  83F8 0C         CMP EAX,0C                             ; Lengh C = 12
0044C3DD   |.  0F85 53010000   JNZ CrackMe_.0044C536		      ; Salto a chico malo
0044C3E3   |.  8D55 FC         LEA EDX,[LOCAL.1]
0044C3E6   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C3EC   |.  E8 3394FDFF     CALL CrackMe_.00425824
0044C3F1   |.  8B45 FC         MOV EAX,[LOCAL.1]
0044C3F4   |.  8038 43         CMP BYTE PTR DS:[EAX],43               ; 1º dígito serial = C
0044C3F7   |.  0F85 27010000   JNZ CrackMe_.0044C524		      ; Salto a chico malo
0044C3FD   |.  8D55 F8         LEA EDX,[LOCAL.2]
0044C400   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C406   |.  E8 1994FDFF     CALL CrackMe_.00425824
0044C40B   |.  8B45 F8         MOV EAX,[LOCAL.2]
0044C40E   |.  8078 03 6F      CMP BYTE PTR DS:[EAX+3],6F             ; 4º dígito serial = o
0044C412   |.  0F85 0C010000   JNZ CrackMe_.0044C524			; Salto a chico malo
0044C418   |.  8D55 F4         LEA EDX,[LOCAL.3]
0044C41B   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C421   |.  E8 FE93FDFF     CALL CrackMe_.00425824
0044C426   |.  8B45 F4         MOV EAX,[LOCAL.3]
0044C429   |.  8078 08 6F      CMP BYTE PTR DS:[EAX+8],6F             ; 9º dígito serial = o
0044C42D   |.  0F85 F1000000   JNZ CrackMe_.0044C524			; Salto a chico malo
0044C433   |.  8D55 F0         LEA EDX,[LOCAL.4]
0044C436   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C43C   |.  E8 E393FDFF     CALL CrackMe_.00425824
0044C441   |.  8B45 F0         MOV EAX,[LOCAL.4]
0044C444   |.  8078 01 6C      CMP BYTE PTR DS:[EAX+1],6C             ; 2º dígito serial = l
0044C448   |.  0F85 D6000000   JNZ CrackMe_.0044C524			; Salto a chico malo
0044C44E   |.  8D55 EC         LEA EDX,[LOCAL.5]
0044C451   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C457   |.  E8 C893FDFF     CALL CrackMe_.00425824
0044C45C   |.  8B45 EC         MOV EAX,[LOCAL.5]
0044C45F   |.  8078 04 20      CMP BYTE PTR DS:[EAX+4],20             ; 5º dígito serial = espacio
0044C463   |.  0F85 BB000000   JNZ CrackMe_.0044C524			; Salto a chico malo
0044C469   |.  8D55 E8         LEA EDX,[LOCAL.6]
0044C46C   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C472   |.  E8 AD93FDFF     CALL CrackMe_.00425824
0044C477   |.  8B45 E8         MOV EAX,[LOCAL.6]
0044C47A   |.  8078 0A 52      CMP BYTE PTR DS:[EAX+A],52             ; 11º dígito serial = R
0044C47E   |.  0F85 A0000000   JNZ CrackMe_.0044C524									; Salto a chico malo
0044C484   |.  8D55 E4         LEA EDX,[LOCAL.7]
0044C487   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C48D   |.  E8 9293FDFF     CALL CrackMe_.00425824
0044C492   |.  8B45 E4         MOV EAX,[LOCAL.7]
0044C495   |.  8078 07 75      CMP BYTE PTR DS:[EAX+7],75             ; 8º dígito serial = u
0044C499   |.  0F85 85000000   JNZ CrackMe_.0044C524									; Salto a chico malo
0044C49F   |.  8D55 E0         LEA EDX,[LOCAL.8]
0044C4A2   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C4A8   |.  E8 7793FDFF     CALL CrackMe_.00425824
0044C4AD   |.  8B45 E0         MOV EAX,[LOCAL.8]
0044C4B0   |.  8078 09 6E      CMP BYTE PTR DS:[EAX+9],6E             ; 10º dígito serial = n
0044C4B4   |.  75 6E           JNZ SHORT CrackMe_.0044C524		; Salto a chico malo
0044C4B6   |.  8D55 DC         LEA EDX,[LOCAL.9]
0044C4B9   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C4BF   |.  E8 6093FDFF     CALL CrackMe_.00425824
0044C4C4   |.  8B45 DC         MOV EAX,[LOCAL.9]
0044C4C7   |.  8078 02 6E      CMP BYTE PTR DS:[EAX+2],6E             ; 3º dígito serial = n
0044C4CB   |.  75 57           JNZ SHORT CrackMe_.0044C524		; Salto a chico malo
0044C4CD   |.  8D55 D8         LEA EDX,[LOCAL.10]
0044C4D0   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C4D6   |.  E8 4993FDFF     CALL CrackMe_.00425824
0044C4DB   |.  8B45 D8         MOV EAX,[LOCAL.10]
0044C4DE   |.  8078 05 69      CMP BYTE PTR DS:[EAX+5],69             ; 6º dígito serial = i
0044C4E2   |.  75 40           JNZ SHORT CrackMe_.0044C524	      ; Salto a chico malo
0044C4E4   |.  8D55 D4         LEA EDX,[LOCAL.11]
0044C4E7   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C4ED   |.  E8 3293FDFF     CALL CrackMe_.00425824
0044C4F2   |.  8B45 D4         MOV EAX,[LOCAL.11]
0044C4F5   |.  8078 0B 6E      CMP BYTE PTR DS:[EAX+B],6E             ; 12º dígito serial = n
0044C4F9   |.  75 29           JNZ SHORT CrackMe_.0044C524	      ; Salto a chico malo
0044C4FB   |.  8D55 D0         LEA EDX,[LOCAL.12]
0044C4FE   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C504   |.  E8 1B93FDFF     CALL CrackMe_.00425824
0044C509   |.  8B45 D0         MOV EAX,[LOCAL.12]
0044C50C   |.  8078 06 67      CMP BYTE PTR DS:[EAX+6],67             ; 7º dígito serial = g
0044C510   |.  75 12           JNZ SHORT CrackMe_.0044C524	      ; Salto a chico malo
0044C512   |.  BA 78C54400     MOV EDX,CrackMe_.0044C578              ;  ASCII "Right Password"
0044C517   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C51D   |.  E8 3293FDFF     CALL CrackMe_.00425854
0044C522   |.  EB 22           JMP SHORT CrackMe_.0044C546
0044C524   |>  BA 90C54400     MOV EDX,CrackMe_.0044C590              ;  ASCII "Wrong Password"
0044C529   |.  8B83 E8020000   MOV EAX,DWORD PTR DS:[EBX+2E8]
0044C52F   |.  E8 2093FDFF     CALL CrackMe_.00425854
0044C534   |.  EB 10           JMP SHORT CrackMe_.0044C546
0044C536   |>  BA 90C54400     MOV EDX,CrackMe_.0044C590              ;  ASCII "Wrong Password"
	
Chequeo rápido
ABCD EFGHIJK
Clno iguonRn
	
; 1º  dígito serial = C
; 4º  dígito serial = o
; 9º  dígito serial = o
; 2º  dígito serial = l
; 5º  dígito serial = espacio
; 11º dígito serial = R
; 8º  dígito serial = u
; 10º dígito serial = n
; 3º  dígito serial = n
; 6º  dígito serial = i
; 12º dígito serial = n
; 7º  dígito serial = g

Básicamente chequea la frase «Cool Running» de forma desordenada como se ve justo encima, siendo el password correcto «Clno iguonRn«. Os dejo el código para que lo analicéis.

Nº serie asociado a un nombre

De nuevo con las string references localizamos el código.

0044C648  /.  55            PUSH EBP
0044C649  |.  8BEC          MOV EBP,ESP
0044C64B  |.  83C4 F8       ADD ESP,-8
0044C64E  |.  53            PUSH EBX
0044C64F  |.  56            PUSH ESI
0044C650  |.  33C9          XOR ECX,ECX
0044C652  |.  894D F8       MOV [LOCAL.2],ECX
0044C655  |.  8BF0          MOV ESI,EAX
0044C657  |.  33C0          XOR EAX,EAX
0044C659  |.  55            PUSH EBP
0044C65A  |.  68 83C74400   PUSH CrackMe_.0044C783
0044C65F  |.  64:FF30       PUSH DWORD PTR FS:[EAX]
0044C662  |.  64:8920       MOV DWORD PTR FS:[EAX],ESP
0044C665  |.  33C0          XOR EAX,EAX
0044C667  |.  8945 FC       MOV [LOCAL.1],EAX
0044C66A  |.  A1 80F84400   MOV EAX,DWORD PTR DS:[44F880]        ;  Eax = Nombre
0044C66F  |.  E8 0074FBFF   CALL CrackMe_.00403A74
0044C674  |.  83F8 06       CMP EAX,6                            ;  Cmp lengh nombre con 6
0044C677  |.  0F8E F0000000 JLE CrackMe_.0044C76D                ;  Salta si <= 6
0044C67D  |.  A1 80F84400   MOV EAX,DWORD PTR DS:[44F880]        ;  Eax = Nombre
0044C682  |.  E8 ED73FBFF   CALL CrackMe_.00403A74
0044C687  |.  83F8 14       CMP EAX,14                           ;  Cmp lengh nombre con 20 (14h)
0044C68A  |.  0F8D DD000000 JGE CrackMe_.0044C76D                ;  salta si >= 20
0044C690  |.  A1 80F84400   MOV EAX,DWORD PTR DS:[44F880]
0044C695  |.  E8 DA73FBFF   CALL CrackMe_.00403A74
0044C69A  |.  85C0          TEST EAX,EAX
0044C69C  |.  7E 17         JLE SHORT CrackMe_.0044C6B5
0044C69E  |.  BA 01000000   MOV EDX,1
0044C6A3  |>  8B0D 80F84400 /MOV ECX,DWORD PTR DS:[44F880]       ;  Bucle in
0044C6A9  |.  0FB64C11 FF   |MOVZX ECX,BYTE PTR DS:[ECX+EDX-1]
0044C6AE  |.  014D FC       |ADD [LOCAL.1],ECX                   ;  Suma dig nombre y guarda en 12FBC4
0044C6B1  |.  42            |INC EDX
0044C6B2  |.  48            |DEC EAX
0044C6B3  |.^ 75 EE         \JNZ SHORT CrackMe_.0044C6A3         ;  Bucle out
0044C6B5  |>  A1 84F84400   MOV EAX,DWORD PTR DS:[44F884]        ;  Eax = Compañia
0044C6BA  |.  E8 B573FBFF   CALL CrackMe_.00403A74
0044C6BF  |.  83F8 02       CMP EAX,2                            ;  Cmp lengh compañia con 2
0044C6C2  |.  7E 18         JLE SHORT CrackMe_.0044C6DC          ;  Salta si <= 2
0044C6C4  |.  A1 84F84400   MOV EAX,DWORD PTR DS:[44F884]        ;  Eax = Compañia
0044C6C9  |.  E8 A673FBFF   CALL CrackMe_.00403A74
0044C6CE  |.  83F8 08       CMP EAX,8                            ;  Cmp lengh compañia con 8
0044C6D1  |.  7D 09         JGE SHORT CrackMe_.0044C6DC          ;  Salta si >= 8
0044C6D3  |.  8B45 FC       MOV EAX,[LOCAL.1]                    ;  Eax = sum nombre
0044C6D6  |.  6BC0 02       IMUL EAX,EAX,2                       ;  Sum nombre * 2
0044C6D9  |.  8945 FC       MOV [LOCAL.1],EAX
0044C6DC  |>  68 98C74400   PUSH CrackMe_.0044C798               ;  ASCII "I Love Cracking and "
0044C6E1  |.  8D55 F8       LEA EDX,[LOCAL.2]
0044C6E4  |.  8B45 FC       MOV EAX,[LOCAL.1]
0044C6E7  |.  E8 68B0FBFF   CALL CrackMe_.00407754
0044C6EC  |.  FF75 F8       PUSH [LOCAL.2]                       ;  sum del nombre
0044C6EF  |.  68 B8C74400   PUSH CrackMe_.0044C7B8               ;  ASCII " Girls ;)"
0044C6F4  |.  B8 8CF84400   MOV EAX,CrackMe_.0044F88C
0044C6F9  |.  BA 03000000   MOV EDX,3
0044C6FE  |.  E8 3174FBFF   CALL CrackMe_.00403B34               ;  Concatena 1º frase + sum nombre + 2ºfrase
0044C703  |.  33C0          XOR EAX,EAX
0044C705  |.  8945 FC       MOV [LOCAL.1],EAX
0044C708  |.  A1 88F84400   MOV EAX,DWORD PTR DS:[44F888]        ;  Eax = Serial
0044C70D  |.  E8 6273FBFF   CALL CrackMe_.00403A74
0044C712  |.  8BD8          MOV EBX,EAX
0044C714  |.  A1 8CF84400   MOV EAX,DWORD PTR DS:[44F88C]
0044C719  |.  E8 5673FBFF   CALL CrackMe_.00403A74
0044C71E  |.  3BD8          CMP EBX,EAX                          ;  Compara tamaño frase con tamaño serial
0044C720  |.  75 4B         JNZ SHORT CrackMe_.0044C76D
0044C722  |.  A1 88F84400   MOV EAX,DWORD PTR DS:[44F888]
0044C727  |.  E8 4873FBFF   CALL CrackMe_.00403A74
0044C72C  |.  85C0          TEST EAX,EAX
0044C72E  |.  7E 27         JLE SHORT CrackMe_.0044C757
0044C730  |.  BA 01000000   MOV EDX,1
0044C735  |>  8B0D 88F84400 /MOV ECX,DWORD PTR DS:[44F888]	; Bucle in -->
0044C73B  |.  0FB64C11 FF   |MOVZX ECX,BYTE PTR DS:[ECX+EDX-1]
0044C740  |.  034D FC       |ADD ECX,[LOCAL.1]
0044C743  |.  8B1D 8CF84400 |MOV EBX,DWORD PTR DS:[44F88C]
0044C749  |.  0FB65C13 FF   |MOVZX EBX,BYTE PTR DS:[EBX+EDX-1]	; Compara dígito a dígito nuestro serial
0044C74E  |.  2BCB          |SUB ECX,EBX			; con la concatenación anterior
0044C750  |.  894D FC       |MOV [LOCAL.1],ECX
0044C753  |.  42            |INC EDX
0044C754  |.  48            |DEC EAX
0044C755  |.^ 75 DE         \JNZ SHORT CrackMe_.0044C735	; <-- Bucle out
0044C757  |>  837D FC 00    CMP [LOCAL.1],0
0044C75B  |.  75 10         JNZ SHORT CrackMe_.0044C76D		; Salta si algo ha ido mal
0044C75D  |.  8B86 14030000 MOV EAX,DWORD PTR DS:[ESI+314]
0044C763  |.  BA CCC74400   MOV EDX,CrackMe_.0044C7CC           ; "You have found the correct Serial :)"

En resumen

  • Tamaño del nombre entre 7 y 19.
  • Tamaño de la compañía entre 3 y 7 aunque no interviene en el serial.
  • Suma los valores ascii de los dígitos del nombre y lo multiplica por 2.
  • Concatena «I Love Cracking and » + «sum del nombre» + » Girls ;)».

Checkbox

Para afrontar esta parte del reto vamos a usar una herramienta llamada Interactive Delphi Reconstructor o IDR. En su día la mejor herramienta era DEDE, pero IDR a mi parecer es algo más potente.

Básicamente IDR nos permite sin quebraderos de cabeza localizar el código del botón que comprueba la secuencia de checkboxes correcta. Cargamos el crackme en IDR y dentro de la pestaña «Units (F2)«, abajo del todo hacemos doble click sobre «F Crack» y vemos que nos muestra todos los controles del formulario. El botón que nos interesa se llama «SpeedButton3«.

17-02-2016 13-21-14

Si hacemos doble click sobre el nos muestra el código que se muestra a continuación.

crack::TForm1.SpeedButton3Click
 0044C7F4    push       ebp
 0044C7F5    mov        ebp,esp
 0044C7F7    push       0
 0044C7F9    push       ebx
 0044C7FA    mov        ebx,eax
 0044C7FC    xor        eax,eax
 0044C7FE    push       ebp
 0044C7FF    push       44C920
 0044C804    push       dword ptr fs:[eax]
 0044C807    mov        dword ptr fs:[eax],esp
 0044C80A    mov        eax,dword ptr [ebx+324]; TForm1.cb3:TCheckBox
 0044C810    mov        edx,dword ptr [eax]
 0044C812    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C818    test       al,al
>0044C81A    je         0044C8ED
 0044C820    mov        eax,dword ptr [ebx+328]; TForm1.cb5:TCheckBox
 0044C826    mov        edx,dword ptr [eax]
 0044C828    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C82E    test       al,al
>0044C830    je         0044C8ED
 0044C836    mov        eax,dword ptr [ebx+32C]; TForm1.cb6:TCheckBox
 0044C83C    mov        edx,dword ptr [eax]
 0044C83E    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C844    test       al,al
>0044C846    je         0044C8ED
 0044C84C    mov        eax,dword ptr [ebx+358]; TForm1.cb12:TCheckBox
 0044C852    mov        edx,dword ptr [eax]
 0044C854    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C85A    test       al,al
>0044C85C    je         0044C8ED
 0044C862    mov        eax,dword ptr [ebx+364]; TForm1.cb15:TCheckBox
 0044C868    mov        edx,dword ptr [eax]
 0044C86A    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C870    test       al,al
>0044C872    je         0044C8ED
 0044C874    mov        eax,dword ptr [ebx+330]; TForm1.cb20:TCheckBox
 0044C87A    mov        edx,dword ptr [eax]
 0044C87C    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C882    test       al,al
>0044C884    je         0044C8ED
 0044C886    mov        eax,dword ptr [ebx+34C]; TForm1.cb9:TCheckBox
 0044C88C    mov        edx,dword ptr [eax]
 0044C88E    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C894    test       al,al
>0044C896    je         0044C8ED
 0044C898    mov        eax,dword ptr [ebx+354]; TForm1.cb11:TCheckBox
 0044C89E    mov        edx,dword ptr [eax]
 0044C8A0    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C8A6    test       al,al
>0044C8A8    je         0044C8ED
 0044C8AA    mov        eax,dword ptr [ebx+35C]; TForm1.cb13:TCheckBox
 0044C8B0    mov        edx,dword ptr [eax]
 0044C8B2    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C8B8    test       al,al
>0044C8BA    je         0044C8ED
 0044C8BC    mov        eax,dword ptr [ebx+33C]; TForm1.cb19:TCheckBox
 0044C8C2    mov        edx,dword ptr [eax]
 0044C8C4    call       dword ptr [edx+0B8]; TCustomCheckBox.GetChecked
 0044C8CA    test       al,al
>0044C8CC    je         0044C8ED
 0044C8CE    lea        eax,[ebp-4]
 0044C8D1    mov        edx,44C934; 'Ìõô¸ö÷ê¥ó¤ÉÚÀÆ²Äæââîàä¶¶'
 0044C8D6    call       @LStrLAsg
 0044C8DB    lea        eax,[ebp-4]
 0044C8DE    call       0044BF00
 0044C8E3    mov        eax,dword ptr [ebp-4]
 0044C8E6    call       ShowMessage
>0044C8EB    jmp        0044C90A
 0044C8ED    lea        eax,[ebp-4]
 0044C8F0    mov        edx,44C958; 'Åÿæò衦óàù¨ïêçð®øé¤íüàî诹'
 0044C8F5    call       @LStrLAsg
 0044C8FA    lea        eax,[ebp-4]
 0044C8FD    call       0044BF00
 0044C902    mov        eax,dword ptr [ebp-4]
 0044C905    call       ShowMessage
 0044C90A    xor        eax,eax
 0044C90C    pop        edx
 0044C90D    pop        ecx
 0044C90E    pop        ecx
 0044C90F    mov        dword ptr fs:[eax],edx
 0044C912    push       44C927
 0044C917    lea        eax,[ebp-4]
 0044C91A    call       @LStrClr
 0044C91F    ret
<0044C920    jmp        @HandleFinally
<0044C925    jmp        0044C917
 0044C927    pop        ebx
 0044C928    pop        ecx
 0044C929    pop        ebp
 0044C92A    ret

Como podéis apreciar, las checkboxes involucradas son la 3, 5, 6, 9, 11, 12, 13, 15, 19 y 20. Solo nos falta saber cuales se corresponden con esa numeración y aquí ya depende de cada uno, yo en su día saqué los números a mano mediante el orden de tabulación, pero ya que tenemos IDR, el nos va a dar la solución de una forma sencilla y rápida.

Vamos a la pestaña «Forms (F5)«, seleccionamos la opción Form y hacemos doble click sobre el formulario.

17-02-2016 13-29-34

Veréis que aparece el formulario con todos los recursos, incluso los puedes modificar. Localizar los checkboxes ahora es un juego de niños.

17-02-2016 13-30-15

Os dejo un vídeo.

Trackbar

De nuevo, con la ayuda de IDR, localizamos la parte del código y analizamos su funcionamiento. Esta parte es la más divertida ya que requiere de un keygen pero en vez de coger el número de serie de una caja de texto lo obtiene de 5 trackbars como muestra la siguiente imagen.

17-02-2016 12-47-06_trackbar

El código de comprobación es el siguiente.

CPU Disasm
Address   Hex dump          Command                                  Comments
0044C1FF  |.  E8 ECF6FCFF   CALL 0041B8F0                            ; b^3
0044C204  |.  D805 50C34400 FADD DWORD PTR DS:[44C350]               ; b^3+5
0044C20A  |.  D9FA          FSQRT                                    ; sqrt(b^3+5)
0044C20C  |.  E8 F365FBFF   CALL 00402804                            ; Cos(sqrt(b^3+5)) = U
0044C211  |.  DB7D B8       FSTP TBYTE PTR SS:[EBP-48]
0044C214  |.  9B            WAIT
0044C215  |.  D905 54C34400 FLD DWORD PTR DS:[44C354]                ; Coje a
0044C21B  |.  DC45 E8       FADD QWORD PTR SS:[EBP-18]               ; a+1
0044C21E  |.  D9FA          FSQRT                                    ; sqrt(a+1)
0044C220  |.  D9E0          FCHS                                     ; -sqrt(a+1) = V
0044C222  |.  DB6D B8       FLD TBYTE PTR SS:[EBP-48]
0044C225  |.  DEC1          FADDP ST(1),ST
0044C227  |.  DB7D AC       FSTP TBYTE PTR SS:[EBP-54]
0044C22A  |.  9B            WAIT
0044C22B  |.  D905 58C34400 FLD DWORD PTR DS:[44C358]                ; coje c
0044C231  |.  DC4D D8       FMUL QWORD PTR SS:[EBP-28]               ; c*3
0044C234  |.  D805 54C34400 FADD DWORD PTR DS:[44C354]               ; c*3+1
0044C23A  |.  D9ED          FLDLN2                                   ; Ln(c*3+1) = X
0044C23C  |.  D9C9          FXCH ST(1)
0044C23E  |.  D9F1          FYL2X
0044C240  |.  DB6D AC       FLD TBYTE PTR SS:[EBP-54]
0044C243  |.  DEC1          FADDP ST(1),ST                           ; U+V+X
0044C245  |.  DB7D A0       FSTP TBYTE PTR SS:[EBP-60]
0044C248  |.  9B            WAIT
0044C249  |.  D905 5CC34400 FLD DWORD PTR DS:[44C35C]                ; coje d
0044C24F  |.  DC45 D0       FADD QWORD PTR SS:[EBP-30]               ; d+2
0044C252  |.  D9FA          FSQRT                                    ; sqrt(d+2) = Y
0044C254  |.  DB6D A0       FLD TBYTE PTR SS:[EBP-60]
0044C257  |.  DEE1          FSUBRP ST(1),ST                          ; U+V+X+(-Y)
0044C259  |.  D905 58C34400 FLD DWORD PTR DS:[44C358]                ; coje e
0044C25F  |.  DC4D C8       FMUL QWORD PTR SS:[EBP-38]               ; e*3
0044C262  |.  D835 5CC34400 FDIV DWORD PTR DS:[44C35C]               ; (e*3)/2 = Z
0044C268  |.  DEC1          FADDP ST(1),ST                           ; U+V+X+Y+Z
0044C26A  |.  DB2D 60C34400 FLD TBYTE PTR DS:[44C360]
0044C270  |.  DEC1          FADDP ST(1),ST                           ; U+V+X+Y+Z+0.37
0044C272  |.  D80D 6CC34400 FMUL DWORD PTR DS:[44C36C]               ; (U+V+X+Y+Z+0.37)*1000
0044C278  |.  DD5D F0       FSTP QWORD PTR SS:[EBP-10]
0044C27B  |.  9B            WAIT
0044C27C  |.  DD45 F0       FLD QWORD PTR SS:[EBP-10]
0044C27F  |.  E8 9065FBFF   CALL 00402814                            ; Redondea((U+V+X+Y+Z+0,37)*1000)
0044C284  |.  8945 98       MOV DWORD PTR SS:[EBP-68],EAX
0044C287  |.  8955 9C       MOV DWORD PTR SS:[EBP-64],EDX
0044C28A  |.  DF6D 98       FILD QWORD PTR SS:[EBP-68]
0044C28D  |.  83C4 F4       ADD ESP,-0C
0044C290  |.  DB3C24        FSTP TBYTE PTR SS:[LOCAL.33]             
0044C293  |.  9B            WAIT                                     
0044C294  |.  8D45 FC       LEA EAX,[EBP-4]                          
0044C297  |.  E8 68BFFBFF   CALL 00408204                            
0044C29C  |.  8D45 FC       LEA EAX,[EBP-4]
0044C29F  |.  E8 5CFCFFFF   CALL 0044BF00                            ; Llamada de generación de hash
........
0044BF04  |.  8BF0          MOV ESI,EAX
0044BF06  |.  8B06          MOV EAX,DWORD PTR DS:[ESI]               ; EAX = 5415
0044BF08  |.  E8 677BFBFF   CALL 00403A74
0044BF0D  |.  8B15 98EE4400 MOV EDX,DWORD PTR DS:[44EE98]
0044BF13  |.  8902          MOV DWORD PTR DS:[EDX],EAX
0044BF15  |.  8B06          MOV EAX,DWORD PTR DS:[ESI]
0044BF17  |.  E8 587BFBFF   CALL 00403A74
0044BF1C  |.  84C0          TEST AL,AL
0044BF1E  |.  76 38         JBE SHORT 0044BF58
0044BF20  |.  880424        MOV BYTE PTR SS:[LOCAL.3],AL
0044BF23  |.  B3 01         MOV BL,1
0044BF25  |>  B8 1C000000   /MOV EAX,1C
0044BF2A  |.  E8 516AFBFF   |CALL 00402980
0044BF2F  |.  0D 80000000   |OR EAX,00000080
0044BF34  |.  8BFB          |MOV EDI,EBX
0044BF36  |.  81E7 FF000000 |AND EDI,000000FF
0044BF3C  |.  8B16          |MOV EDX,DWORD PTR DS:[ESI]
0044BF3E  |.  0FB6543A FF   |MOVZX EDX,BYTE PTR DS:[EDI+EDX-1]       ; Coje dig a dig el hash, en este caso 5415
0044BF43  |.  33C2          |XOR EAX,EDX                             ; 1 dig XOR 83; 2 dig XOR 89; 3 dig XOR 86; 4 dig XOR 8D
0044BF45  |.  50            |PUSH EAX
0044BF46  |.  8BC6          |MOV EAX,ESI
0044BF48  |.  E8 F77CFBFF   |CALL 00403C44                           
0044BF4D  |.  5A            |POP EDX
0044BF4E  |.  885438 FF     |MOV BYTE PTR DS:[EDI+EAX-1],DL
0044BF52  |.  43            |INC EBX
0044BF53  |.  FE0C24        |DEC BYTE PTR SS:[LOCAL.3]
0044BF56  |.^ 75 CD         \JNZ SHORT 0044BF25
........
0044C2AC  |.  E8 D378FBFF   CALL 00403B84                            ; Llamada a comparación
........
00403BAD  |> /8B0E          /MOV ECX,DWORD PTR DS:[ESI]              ; ECX = nuestro Serial XOReado
00403BAF  |. |8B1F          |MOV EBX,DWORD PTR DS:[EDI]              ; EBX = Serial bueno
00403BB1  |. |39D9          |CMP ECX,EBX                             ; Compara
00403BB3  |. |75 58         |JNE SHORT 00403C0D                      ; Chico malo
00403BB5  |. |4A            |DEC EDX
00403BB6  |. |74 15         |JZ SHORT 00403BCD
00403BB8  |. |8B4E 04       |MOV ECX,DWORD PTR DS:[ESI+4]
00403BBB  |. |8B5F 04       |MOV EBX,DWORD PTR DS:[EDI+4]
00403BBE  |. |39D9          |CMP ECX,EBX
00403BC0  |. |75 4B         |JNE SHORT 00403C0D
00403BC2  |. |83C6 08       |ADD ESI,8
00403BC5  |. |83C7 08       |ADD EDI,8
00403BC8  |. |4A            |DEC EDX
00403BC9  |.^\75 E2         \JNZ SHORT 00403BAD

En resumen

1) Siendo nuestro serial : 1 2 3 4 5
                           a b c d e
 
2) Realiza las operaciones matemáticas:
   Round(((Cos(sqrt(b^3+5)) + (-sqrt(a+1)) + Ln(c*3+1) + (-sqrt(d+2)) + ((e*3)/2))+0.37)*1000))
 
3) Obtenemos un hash resultante de 5415

4) XORea los dígitos de la siguiente manera:
   (5)35 xor 86 = B6
   (4)34 xor 83 = BD
   (1)31 xor 86 = B7
   (5)35 xor 8D = B8
 
 De modo que tenemos B6BDB7B8
 
5) Compara B6BDB7B8 con B5BAB2BA

6) Revertimos el XOR para obtener el hash bueno
   B5 xor 86 = 36(6)
   BA xor 83 = 33(3)
   B2 xor 86 = 34(4)
   BA xor 8D = 37(7)
 
 Luego el hash bueno es 6347
 
7) Debemos hacer fuerza bruta buscando: 
   Round(((Cos(sqrt(b^3+5)) + (-sqrt(a+1)) + Ln(c*3+1) + (-sqrt(d+2)) + ((e*3)/2))+0.37)*1000)) = 6347

Para obtener los seriales válidos podemos hacer bucles recursivos hasta recorrer las 10^5 opciones posibles. Una forma de hacerlo en VBNet es la siguiente.

Dim tmp As Double
Dim an, bn, cn, dn, en As Integer
        For an = 0 To 9
            For bn = 0 To 9
                For cn = 0 To 9
                    For dn = 0 To 9
                        For en = 0 To 9
                            tmp = Round(((Cos(Sqrt((Pow(bn, 3)) + 5)) + (-Sqrt(an + 1)) + Log(cn * 3 + 1) + (-Sqrt(dn + 2)) + ((en * 3) / 2) + 0.37) * 1000))
                            txtdebug.Text = "a-b-c-d-e = Hash || " & an & "-" & bn & "-" & cn & "-" & dn & "-" & en & " = " & tmp
                            If tmp = 6347 Then
                                ListBox1.Items.Add("Serial: " & an & bn & cn & dn & en)
                            End If
                            Application.DoEvents()
                        Next
                    Next
                Next
            Next
        Next

17-02-2016 10-29-59_brute

Os dejo como siempre el crackme y el keygen en los enlaces.

Links


Introducción Tal y como nos adelanta el creador está programado en .NET. Lo abrimos para ver su comportamiento y a
Primeras impresiones El crackme es el típico de usuario y número de serie. Si no introduces un nombre te salta
Introducción Siguiendo con los crackmes que contienen RSA, esta vez tenemos un Keygenme del grupo PGC (Pirates Gone Crazy) que
En una entrada anterior sobre cómo Expediente X abordó la tecnología de vanguardia, comenté que dedicaría un espacio a esos

Introducción

El otro día navegando por la red fuí a dar a un mirror de la gran web «Karpoff Spanish Tutor«. Para los que no la conozcais, debeis saber que fué una referencia para el Cracking en la escena nacional. Contenía manuales, cursos, utilidades y todo lo que te pudieras imaginar y/o necesitar para iniciarte en el mundillo del Cracking. Por aquel entonces yo era un cigoto en esto de la Ingeniería Inversa pero la web de Karpoff sentó mis bases y contribuyó a mi afán por saber y compartir. El lector debería saber que estamos hablando de finales de los 90, por lo que este crackme y sucesivos de la web de Karpoff ahora pueden parecer más fáciles pero hay que tener en cuenta que ahora tenemos mejores herramientas.

El objetivo es sacar un serial valido o hacer un generador de llaves, esta hecho para newbies y no tiene ninguna otra proteccion.

El crackme está hecho en Delphi y no tiene ningún tipo de protección antidebug ni nada por el estilo.

El algoritmo

Abrimos  Delphi Decompiler y buscamos en los eventos el botón de registro, en este caso se llama «focusClick» y vemos que su RVA apunta a la dirección «442AEC«, lo apuntamos y abrimos el crackme con Ollydbg.

03-09-2014 16-54-45

En Olly pulsamos Ctrl+G e introducimos el offset anterior. Un poco más abajo vemos un Call interesante, entramos en el.

03-09-2014 17-34-01

Dentro del Call vemos a simple vista dos funciones muy interesantes como son «GetVolumeInformationA» y «GetUserNameA«.

03-09-2014 17-37-08

Traceamos el código y vemos que obtiene el número de serie del disco C y el usuario de windows y finalmente los concatena. Se puede ver a simple vista en el Stack o Pila.

03-09-2014 17-33-22

No necesitamos saber nada más, probamos el número de serie cazado y funciona. Os adjunto el keygen hecho en C++.

03-09-2014 17-34-51

Links


Con The Ring inauguro una nueva sección llamada Blooper Tech Movie (BTM), algo así como pifias o tomas falsas tecnológicas
Introducción Aquí tenemos un CrackMe diferente a lo que estamos acostumbrados, ya que en vez del típico número de serie
La esperada cuarta entrega de La Jungla de Cristal se metió de lleno en el mundo de los Hackers. Cuando
Introducción Hoy tenemos aquí un crackme hecho en Visual Basic 6 (pcode), pero lo vamos a abordar de una manera

Introducción

Siguiendo con los crackmes que contienen RSA, esta vez tenemos un Keygenme del grupo PGC (Pirates Gone Crazy) que incluso servía para ser admitido en el grupo si mandabas la solución. Como veremos usa RSA32 + MD5 y en la parte de RSA ni siquiera usa el descifrado por lo que es de los sencillitos.

Resumen RSA

Parámetros

p = Primer número primo
q = Segundo número primo
e = Exponente público que cumpla MCD(e,(p-1)*(q-1))==1
n = Módulo público siendo n=p*q
d = Exponente privado que cumpla d=e^(-1) mod ((p-1)*(q-1))

De este modo y n son la parte pública de la clave y d y n la parte privada. Los número primos q se utilizan solo para generar los parámetros y de ahí en adelante se pueden desechar.

Funciones de Cifrado/Descifrado

cifrado = descifrado ^ e mod n
descifrado = cifrado ^ d mod n

Debug

En las referencias de texto se ven a simple vista el exponente público e (10001) y el módulo n (8e701a4c793eb8b739166bb23b49e421)

Text strings referenced in RSA32+MD:.text
Address    Disassembly                                                     Text string
00401848   PUSH    RSA32+MD.00404104                                       ASCII "%.8x%.8x%.8x%.8x"
00401A72   PUSH    RSA32+MD.0040429C                                       ASCII "[PGCTRiAL/2oo2]"
00401AEE   PUSH    RSA32+MD.00404275                                       ASCII "10001"
00401AFE   PUSH    RSA32+MD.0040427B                                       ASCII "8e701a4c793eb8b739166bb23b49e421"
00401B43   PUSH    RSA32+MD.00404404                                       ASCII "Name Must Be >= 1 Character."
00401B57   PUSH    RSA32+MD.00404421                                       ASCII "Key Must Be >= 1 Character."
00401B6D   PUSH    RSA32+MD.0040443D                                       ASCII "Congratulations!"
00401B72   PUSH    RSA32+MD.0040444E                                       ASCII "                 You've done it!
Please send your keygen along with
source code to pgc@dangerous-minds.com
if you would like to be considered as
         a new member of PGC."
00401BE7   PUSH    0                                                       (Initial CPU selection)
00401C47   MOV     [DWORD SS:EBP-24],RSA32+MD.00404119                     ASCII "PGCWinClass"
00401C7C   MOV     [DWORD SS:EBP-24],RSA32+MD.0040424E                     ASCII "STATIC"
00401CDB   PUSH    RSA32+MD.00404115                                       ASCII "PGC"
00401CE0   PUSH    RSA32+MD.00404119                                       ASCII "PGCWinClass"
00401D13   PUSH    RSA32+MD.00404125                                       ASCII "EDIT"
00401D46   PUSH    RSA32+MD.00404125                                       ASCII "EDIT"
00401DFB   PUSH    RSA32+MD.00404115                                       ASCII "PGC"
00401E00   PUSH    RSA32+MD.0040424E                                       ASCII "STATIC"

Rutina de comprobación

00401A0E  /$  53            PUSH    EBX
00401A0F  |.  57            PUSH    EDI
00401A10  |.  56            PUSH    ESI
00401A11  |.  6A 11         PUSH    11                             ; /Count = 11 (17.)
00401A13  |.  68 AC424000   PUSH    RSA32+MD.004042AC              ; |Buffer = RSA32+MD.004042AC
00401A18  |.  FF35 94454000 PUSH    [DWORD DS:404594]              ; |hWnd = NULL
00401A1E  |.  E8 49080000   CALL    <JMP.&USER32.GetWindowTextA>   ; \GetWindowTextA
00401A23  |.  83F8 01       CMP     EAX,1
00401A26  |.  0F8C 17010000 JL      RSA32+MD.00401B43
00401A2C  |.  A3 6D424000   MOV     [DWORD DS:40426D],EAX
00401A31  |.  6A 22         PUSH    22                             ; /Count = 22 (34.)
00401A33  |.  68 BD424000   PUSH    RSA32+MD.004042BD              ; |Buffer = RSA32+MD.004042BD
00401A38  |.  FF35 98454000 PUSH    [DWORD DS:404598]              ; |hWnd = NULL
00401A3E  |.  E8 29080000   CALL    <JMP.&USER32.GetWindowTextA>   ; \GetWindowTextA
00401A43  |.  83F8 01       CMP     EAX,1
00401A46  |.  0F8C 0B010000 JL      RSA32+MD.00401B57
00401A4C  |.  A3 71424000   MOV     [DWORD DS:404271],EAX
00401A51  |.  6A 00         PUSH    0
00401A53  |.  E8 C8080000   CALL    RSA32+MD.00402320
00401A58  |.  A3 69424000   MOV     [DWORD DS:404269],EAX
00401A5D  |.  A1 71424000   MOV     EAX,[DWORD DS:404271]
00401A62  |.  FF35 69424000 PUSH    [DWORD DS:404269]              ; /Arg2 = 00000000
00401A68  |.  68 BD424000   PUSH    RSA32+MD.004042BD              ; |Arg1 = 004042BD
00401A6D  |.  E8 510A0000   CALL    RSA32+MD.004024C3              ; \RSA32+MD.004024C3
00401A72  |.  68 9C424000   PUSH    RSA32+MD.0040429C              ; /StringToAdd = "[PGCTRiAL/2oo2]"
00401A77  |.  68 AC424000   PUSH    RSA32+MD.004042AC              ; |ConcatString = ""
00401A7C  |.  E8 51080000   CALL    <JMP.&KERNEL32.lstrcatA>       ; \lstrcatA
00401A81  |.  68 AC424000   PUSH    RSA32+MD.004042AC              ; /String = ""
00401A86  |.  E8 4D080000   CALL    <JMP.&KERNEL32.lstrlenA>       ; \lstrlenA
00401A8B  |.  68 DF424000   PUSH    RSA32+MD.004042DF              ; /Arg4 = 004042DF
00401A90  |.  68 10454000   PUSH    RSA32+MD.00404510              ; |Arg3 = 00404510
00401A95  |.  50            PUSH    EAX                            ; |Arg2
00401A96  |.  68 AC424000   PUSH    RSA32+MD.004042AC              ; |Arg1 = 004042AC
00401A9B  |.  E8 60F5FFFF   CALL    RSA32+MD.00401000              ; \RSA32+MD.00401000
00401AA0  |.  6A 00         PUSH    0
00401AA2  |.  E8 79080000   CALL    RSA32+MD.00402320
00401AA7  |.  A3 5D424000   MOV     [DWORD DS:40425D],EAX
00401AAC  |.  6A 00         PUSH    0
00401AAE  |.  E8 6D080000   CALL    RSA32+MD.00402320
00401AB3  |.  A3 59424000   MOV     [DWORD DS:404259],EAX
00401AB8  |.  6A 00         PUSH    0
00401ABA  |.  E8 61080000   CALL    RSA32+MD.00402320
00401ABF  |.  A3 61424000   MOV     [DWORD DS:404261],EAX
00401AC4  |.  6A 00         PUSH    0
00401AC6  |.  E8 55080000   CALL    RSA32+MD.00402320
00401ACB  |.  A3 65424000   MOV     [DWORD DS:404265],EAX
00401AD0  |.  B8 02000000   MOV     EAX,2
00401AD5  |.  C1E0 04       SHL     EAX,4
00401AD8  |.  FF35 5D424000 PUSH    [DWORD DS:40425D]              ; /Arg2 = 00000000
00401ADE  |.  68 DF424000   PUSH    RSA32+MD.004042DF              ; |Arg1 = 004042DF
00401AE3  |.  E8 DB090000   CALL    RSA32+MD.004024C3              ; \RSA32+MD.004024C3
00401AE8  |.  FF35 65424000 PUSH    [DWORD DS:404265]              ; /Arg2 = 00000000
00401AEE  |.  68 75424000   PUSH    RSA32+MD.00404275              ; |Arg1 = 00404275 ASCII "10001"
00401AF3  |.  E8 CB090000   CALL    RSA32+MD.004024C3              ; \RSA32+MD.004024C3
00401AF8  |.  FF35 61424000 PUSH    [DWORD DS:404261]              ; /Arg2 = 00000000
00401AFE  |.  68 7B424000   PUSH    RSA32+MD.0040427B              ; |Arg1 = 0040427B ASCII "8e701a4c793eb8b739166bb23b49e421"
00401B03  |.  E8 BB090000   CALL    RSA32+MD.004024C3              ; \RSA32+MD.004024C3
00401B08  |.  FF35 59424000 PUSH    [DWORD DS:404259]
00401B0E  |.  FF35 61424000 PUSH    [DWORD DS:404261]
00401B14  |.  FF35 65424000 PUSH    [DWORD DS:404265]
00401B1A  |.  FF35 5D424000 PUSH    [DWORD DS:40425D]
00401B20  |.  E8 87120000   CALL    RSA32+MD.00402DAC
00401B25  |.  FF35 69424000 PUSH    [DWORD DS:404269]
00401B2B  |.  FF35 59424000 PUSH    [DWORD DS:404259]
00401B31  |.  E8 61080000   CALL    RSA32+MD.00402397
00401B36  |.  85C0          TEST    EAX,EAX
00401B38  |.  74 31         JE      SHORT RSA32+MD.00401B6B
00401B3A  |.  E8 85000000   CALL    RSA32+MD.00401BC4
00401B3F  |.  5E            POP     ESI
00401B40  |.  5F            POP     EDI
00401B41  |.  5B            POP     EBX
00401B42  |.  C3            RET
00401B43  |>  68 04444000   PUSH    RSA32+MD.00404404              ; /Text = "Name Must Be >= 1 Character."
00401B48  |.  FF35 98454000 PUSH    [DWORD DS:404598]              ; |hWnd = NULL
00401B4E  |.  E8 5B070000   CALL    <JMP.&USER32.SetWindowTextA>   ; \SetWindowTextA
00401B53  |.  5E            POP     ESI
00401B54  |.  5F            POP     EDI
00401B55  |.  5B            POP     EBX
00401B56  |.  C3            RET
00401B57  |>  68 21444000   PUSH    RSA32+MD.00404421              ; /Text = "Key Must Be >= 1 Character."
00401B5C  |.  FF35 98454000 PUSH    [DWORD DS:404598]              ; |hWnd = NULL
00401B62  |.  E8 47070000   CALL    <JMP.&USER32.SetWindowTextA>   ; \SetWindowTextA
00401B67  |.  5E            POP     ESI
00401B68  |.  5F            POP     EDI
00401B69  |.  5B            POP     EBX
00401B6A  |.  C3            RET
00401B6B  |>  6A 00         PUSH    0                              ; /Style = MB_OK|MB_APPLMODAL
00401B6D  |.  68 3D444000   PUSH    RSA32+MD.0040443D              ; |Title = "Congratulations!"
00401B72  |.  68 4E444000   PUSH    RSA32+MD.0040444E              ; |Text = "                 You've done it!
Please send your keygen along with
source code to pgc@dangerous-minds.com
if you would like to be considered as
         a new member of PGC."
00401B77  |.  FF35 8C454000 PUSH    [DWORD DS:40458C]              ; |hOwner = NULL
00401B7D  |.  E8 02070000   CALL    <JMP.&USER32.MessageBoxA>      ; \MessageBoxA
00401B82  |.  EB 00         JMP     SHORT RSA32+MD.00401B84
00401B84  |>  FF35 5D424000 PUSH    [DWORD DS:40425D]
00401B8A  |.  E8 BE070000   CALL    RSA32+MD.0040234D
00401B8F  |.  FF35 59424000 PUSH    [DWORD DS:404259]
00401B95  |.  E8 B3070000   CALL    RSA32+MD.0040234D
00401B9A  |.  FF35 61424000 PUSH    [DWORD DS:404261]
00401BA0  |.  E8 A8070000   CALL    RSA32+MD.0040234D
00401BA5  |.  FF35 65424000 PUSH    [DWORD DS:404265]
00401BAB  |.  E8 9D070000   CALL    RSA32+MD.0040234D
00401BB0  |.  FF35 69424000 PUSH    [DWORD DS:404269]
00401BB6  |.  E8 92070000   CALL    RSA32+MD.0040234D
00401BBB  |.  E8 04000000   CALL    RSA32+MD.00401BC4
00401BC0  |.  5E            POP     ESI
00401BC1  |.  5F            POP     EDI
00401BC2  |.  5B            POP     EBX
00401BC3  \.  C3            RET

Como vemos comprueba que tanto el nombre como el número de serie tengan al menos un dígito y a continuación comienza el chequeo del serial. El chequeo es muy sencillo ya que ni siquiera tenemos que buscar los números primos p y q y a continuación n, simplemente podemos obtener el número de serie con la parte pública de la clave (par de número e y n). Lo resumimos a continuación:

  1. Concatena nuestro nombre con la cadena «[PGCTRiAL/2oo2]»
  2. Crea el hash MD5 de la cadena concatenada.
  3. Cifra el hash usando el par de números e y n obtenidos en las referencias de texto.
1. deurus[PGCTRiAL/2oo2]
2. md5(deurus[PGCTRiAL/2oo2]) = dc8a39282da8539d11b8a6aec000c45a
3. dc8a39282da8539d11b8a6aec000c45a^10001 mod 8e701a4c793eb8b739166bb23b49e421 = 1FF83ECC5A65334DA2BC93C675A9BA15

Nombre: deurus
Serial: 1FF83ECC5A65334DA2BC93C675A9BA15
X^Y MOD Z para deurus

Keygen

//
// md5(deurus[PGCTRiAL/2oo2]) = dc8a39282da8539d11b8a6aec000c45a
//
var c = BigInt("0xdc8a39282da8539d11b8a6aec000c45a");
var e = BigInt("0x10001");
var n = BigInt("0x8e701a4c793eb8b739166bb23b49e421");
//
var serial = BigInt(0);
serial = powmod(c, e, n);
document.write(serial.toString(16));
//
//POWMOD
//
function powmod(base, exp, modulus) {
  var accum = BigInt("1");
  var i = BigInt("0");
  var basepow2 = BigInt(base);
  while ((BigInt(exp) >> BigInt(i) > BigInt(0))) {
    if (((BigInt(exp) >> BigInt(i)) & BigInt(1)) == BigInt(1)) {
      accum = (BigInt(accum) * BigInt(basepow2)) % BigInt(modulus);
    }
    basepow2 = (BigInt(basepow2) * BigInt(basepow2)) % BigInt(modulus);
    i++;
  }
  return BigInt(accum);
}

Enlaces

Los retos criptográficos son muy variados y muchas veces la dificultad está en saber a que te enfrentas. En este caso pasa eso, te dan un código y si no has visto algo parecido en la vida, no sabes por donde empezar. El título del autor da una pequeña pista pero para los desconocedores no es suficiente. La pista es el título y dice «WTF?!?» y el código a descifrar es el siguiente:

[-]>[-]<
>+++++++++++[<+++++++++++>-]<.
>+++[<--->-]<-.
>++[<++>-]<++.
+.
>++++[<---->-]<-.
---.
+++.
.
>+++[<+++>-]<.
>+++[<--->-]<+.
>++++[<++++>-]<-.
>++++[<---->-]<--.
>+++[<+++>-]<-.
>++[<-->-]<--.
-.

Si eres una persona con recursos, realizaras varias búsquedas por la red y al final llegarás a la conclusión de que te enfrentas a BRAINFUCK, un lenguaje de programación esotérico como ya vimos en el reto de Root-Me.

Enlaces

Primeras impresiones

Analizamos el programa con PEiD y nos muestra que está hecho en ensamblador.


Unas pruebas introduciendo datos nos muestran que el nombre debe tener entre 3 y 10 dígitos.


Determinando la rutina de creación del serial con Ollydbg

Llegados a este punto tenemos dos opciones que funcionan en el 90% de los casos. La primera es mediante las referenced strings o mediante los names.
 
Para el primer caso, con el keygenme cargado en olly, click derecho y Search > All referenced text strings. Haciendo doble click en “You got it” o en “Bad boy” vamos directamente a la rutina de comprobación del serial o muy cerca de ella en la mayoría de los casos.


Para el segundo caso, haremos click derecho y Search > Name (label) in current módule, o Ctrl+N. Vemos dos llamadas interesantes como son user32.GetDlgItemInt y user32.GetDlgItemTextA. Lo más seguro es que user32.GetDlgItemInt coja del textbox nuestro serial y user32.GetDlgItemTextA coja nuestro nombre. Para este caso colocaríamos breakpoints en las dos llamadas.


En mi caso elijo la primera opción. Nada más pulsar en “You got it” nos fijamos un poco más arriba y vemos las funciones donde coge el nombre y el serial y a simple vista se ven las operaciones que hace con ellos.

Generando un serial válido

Como se muestra en la imagen siguiente, la creación del serial es muy sencilla y al final la comparación es lineal ya que se compara nuestro serial con el serial válido. Veamos el serial válido para el usuario “abc” cuyos dígitos en hexadecimal son 0x61, 0x62 y 0x63.

Letra a
Letra b
Letra c
Suma + 0x61
Suma * 0x20
Suma xor 0xBEFF
Suma / 4
Suma = 0x2CB7
Suma + 0x62
Suma * 0x20
Suma xor 0xBEFF
Suma / 4
Suma = 0x14777
Suma + 0x63
Suma * 0x20
Suma xor 0xBEFF
Suma / 4
Suma = 0xA116F
Suma xor 0xBEA4 = 0xAAFCB
Serial válido = 700363

Generando un keygen con WinASM studio desde cero

Abrimos WinASM studio y pulsamos en File > New Project y en la pestaña dialog elegimos base.

  

Vemos que se nos generan tres archivos, uno con extensión asm, otro con extensión inc y otro con extensión rc. El archivo asm es el que contendrá nuestro código. El archivo inc no lo vamos a usar para simplificar las cosas y el archivo rc es nuestro formulario al que pondremos a nuestro gusto.
Empecemos con el aspecto del formulario. Por defecto viene como se muestra en la siguiente imagen. Que por cierto, es todo lo que necesitamos para un keygen básico.

Y el aspecto final:

Ahora veamos cómo viene nuestro archivo asm inicialmente y que haremos con él. En la siguiente imagen lo indico.

    Encima de la sección .code hemos creado dos secciones como son .data y .data? y hemos declarado las variables necesarias. 
  • szFormat está declarada en formato integer (%i). Más tarde la utilizaremos junto a la función wsprintf para dar formato a un número.
  • szSizeMin: habla por sí misma.
  • szSizeMax: habla por sí misma.
  •  szCap: habla por sí misma.
  • szName: contendrá el nombre introducido.
  • szCode: contendrá el serial válido.
Nuestro código queda de la siguiente manera:

A partir de aquí ya simplemente es escribir el código necesario para generar el serial válido. Una de las ventajas que tiene el ensamblador para hacer keygens sin muchas complicaciones, es que prácticamente es copiar el código que nos muestra Ollydbg. Si os fijáis a continuación, en el botón llamado “IDC_OK” (no le he cambiado el nombre) he puesto todo el código necesario para generar la simple rutina del serial.
Como veis el bucle del nombre es una copia de lo que nos mostró Ollydbg. Una vez que tenemos en EAX nuestro serial válido, mediante la función wsprintf guardamos en la variable szCode el serial válido con formato integer. Finalmente mediante la función SetDlgItemText, mostramos el serial válido en la caja de texto 1002, que es la del serial.

Enlaces


Aquí os dejo un video tutorial. El crackme lo podeis encontrar en crackmes.de.
El reto consiste en dos imágenes (v1.png y v2.png) que, a simple vista, parecen contener ruido aleatorio. Sin embargo, ambas
Intro Hoy tenemos aquí un crackme del año 2000 empacado y con un algoritmo aunque no muy complicado largo de
Continuamos con los BTM awards. Esta vez analizaremos brevemente una escena de la película del casi siempre excelente James Cameron,

El reto consiste en dos imágenes (v1.png y v2.png) que, a simple vista, parecen contener ruido aleatorio. Sin embargo, ambas forman parte de un sistema de criptografía visual en la que cada imagen contiene información parcial que no es interpretable por separado, pero que al combinarse correctamente revelan información oculta.

La trampa está en que la combinación no se hace con operaciones normales como suma, resta o multiplicación. El autor del reto espera que el jugador use una herramienta como StegSolve y pruebe distintas operaciones tipo XOR, AND o MUL hasta encontrar una transformación en la que uno de los métodos muestre algo significativo. El truco está en llegar a la conclusión de que una de las imágenes hay que invertirla antes de combinar ambas imágenes. Todo esto se puede hacer con StegSolve sin necesidad de utilizar ninguna herramienta adicional, pero voy a aprovechar para hacerlo con python y así de paso entendemos como realiza las operaciones StegSolve. En resumen, para resolver el reto basta con:

  1. Invertir (Colour Inversion XOR) una de las imágenes.
  2. Combinar ambas imágenes mediante Analyse > Combine images.
  3. Operación MUL del combinador.

La operación MUL no es una multiplicación normalizada, sino una multiplicación de enteros de 24 bits (0xRRGGBB) con overflow, algo que la mayoría de herramientas no replican correctamente.

¿Por qué aparece la solución con esa combinación

Las imágenes están preparadas para que ciertos bits de color en una imagen sean el complemento de los de la otra. Por tanto:

  • Si se muestran tal cual → parecen ruido
  • Si se combinan mediante XOR → parte de la estructura aparece, pero no se ve el resultado correcto
  • Si se combinan mediante MUL «normal» → tampoco aparece
  • Si se aplica la multiplicación bitwise exacta usada por StegSolve → se alinean las partes ocultas

La operación MUL de StegSolve no es una multiplicación de píxeles, es decir, no hace:

R = (R1 * R2) / 255

sino:

c1 = 0xRRGGBB  (pixel 1)
c2 = 0xRRGGBB  (pixel 2)
resultado = (c1 * c2) & 0xFFFFFF

Con todo esto claro, he preparado un script para combinar las imágenes de forma automática.

import os
import numpy as np
from PIL import Image

# =========================================================
# UTILIDADES
# =========================================================

def ensure_output():
    if not os.path.exists("output"):
        os.makedirs("output")

def load_rgb(path):
    img = Image.open(path).convert("RGB")
    return np.array(img, dtype=np.uint32)

def save_rgb(arr, name):
    Image.fromarray(arr.astype(np.uint8), "RGB").save(os.path.join("output", name))

def invert_xor(arr):
    """Colour Inversion (Xor) de StegSolve."""
    out = arr.copy()
    out[..., :3] = 255 - out[..., :3]
    return out

# =========================================================
# FUNCIONES DE COMBINER EXACTAS DE STEGSOLVE
# =========================================================

def to24(arr):
    """Convierte RGB → entero 0xRRGGBB."""
    return ((arr[..., 0] << 16) |
            (arr[..., 1] << 8)  |
             arr[..., 2])

def from24(c):
    """Convierte entero 0xRRGGBB → RGB."""
    R = (c >> 16) & 0xFF
    G = (c >> 8)  & 0xFF
    B = c & 0xFF
    return np.stack([R, G, B], axis=-1).astype(np.uint8)

# ------------------------------
# Funciones auxiliares
# ------------------------------

def comb_xor(c1, c2):
    return from24((c1 ^ c2) & 0xFFFFFF)

def comb_or(c1, c2):
    return from24((c1 | c2) & 0xFFFFFF)

def comb_and(c1, c2):
    return from24((c1 & c2) & 0xFFFFFF)

def comb_add(c1, c2):
    return from24((c1 + c2) & 0xFFFFFF)

def comb_add_sep(c1, c2):
    R = (((c1 >> 16) & 0xFF) + ((c2 >> 16) & 0xFF)) & 0xFF
    G = (((c1 >> 8)  & 0xFF) + ((c2 >> 8)  & 0xFF)) & 0xFF
    B = ((c1 & 0xFF) + (c2 & 0xFF)) & 0xFF
    return from24((R << 16) | (G << 8) | B)

def comb_sub(c1, c2):
    return from24((c1 - c2) & 0xFFFFFF)

def comb_sub_sep(c1, c2):
    R = (((c1 >> 16) & 0xFF) - ((c2 >> 16) & 0xFF)) & 0xFF
    G = (((c1 >> 8)  & 0xFF) - ((c2 >> 8)  & 0xFF)) & 0xFF
    B = ((c1 & 0xFF) - (c2 & 0xFF)) & 0xFF
    return from24((R << 16) | (G << 8) | B)

def comb_mul(c1, c2):
    """MUL EXACTO StegSolve"""
    return from24((c1 * c2) & 0xFFFFFF)

def comb_mul_sep(c1, c2):
    R = (((c1 >> 16) & 0xFF) * ((c2 >> 16) & 0xFF)) & 0xFF
    G = (((c1 >> 8)  & 0xFF) * ((c2 >> 8)  & 0xFF)) & 0xFF
    B = ((c1 & 0xFF) * (c2 & 0xFF)) & 0xFF
    return from24((R << 16) | (G << 8) | B)

def comb_lightest(c1, c2):
    """Máximo por canal"""
    R = np.maximum((c1 >> 16) & 0xFF, (c2 >> 16) & 0xFF)
    G = np.maximum((c1 >> 8)  & 0xFF, (c2 >> 8)  & 0xFF)
    B = np.maximum(c1 & 0xFF, c2 & 0xFF)
    return from24((R << 16) | (G << 8) | B)

def comb_darkest(c1, c2):
    """Mínimo por canal"""
    R = np.minimum((c1 >> 16) & 0xFF, (c2 >> 16) & 0xFF)
    G = np.minimum((c1 >> 8)  & 0xFF, (c2 >> 8)  & 0xFF)
    B = np.minimum(c1 & 0xFF, c2 & 0xFF)
    return from24((R << 16) | (G << 8) | B)

# Lista de transformaciones
TRANSFORMS = {
    "xor": comb_xor,
    "or": comb_or,
    "and": comb_and,
    "add": comb_add,
    "add_sep": comb_add_sep,
    "sub": comb_sub,
    "sub_sep": comb_sub_sep,
    "mul": comb_mul,
    "mul_sep": comb_mul_sep,
    "lightest": comb_lightest,
    "darkest": comb_darkest,
}

# =========================================================
# GENERACIÓN DE TODAS LAS COMBINACIONES
# =========================================================

def generate_all(imA, imB, labelA, labelB):
    print(f"Generando combinaciones: {labelA} vs {labelB}")

    c1 = to24(imA)
    c2 = to24(imB)

    for name, fun in TRANSFORMS.items():
        out = fun(c1, c2)
        save_rgb(out, f"{labelA}__{labelB}__{name}.png")

    print(f"{labelA}-{labelB} completado.")

# =========================================================
# MAIN
# =========================================================

ensure_output()

print("Cargando imágenes v1.png y v2.png...")
im1 = load_rgb("v1.png")
im2 = load_rgb("v2.png")

print("Generando invertidas estilo StegSolve...")
im1_x = invert_xor(im1)
im2_x = invert_xor(im2)

save_rgb(im1_x, "v1_xored.png")
save_rgb(im2_x, "v2_xored.png")

# Generar las 52 combinaciones:
generate_all(im1,   im2,   "v1",   "v2")
generate_all(im1_x, im2,   "v1x",  "v2")
generate_all(im1,   im2_x, "v1",   "v2x")
generate_all(im1_x, im2_x, "v1x",  "v2x")

print("\nResultados en carpeta ./output/")

A continuación os muestro parte de las imágenes generadas por el script. El secreto oculto era un código QR que nos da la solución al reto.

Intro

Hoy tenemos aquí un crackme del año 2000 empacado y con un algoritmo aunque no muy complicado largo de tracear. Está empacado varias veces, algo poco habitual pero recordemos que es un crackme antiguo. Tras el empacado se encuentra Delphi.

Herramientas

  • PEiD o similar.
  • OllyDbg con plugin OllyDumpEX.
  • Import REConstructor.
  • LordPE (Opcional).

Desempacado multicapa

VideoTutorial del desempacado disponible

Si lo pasamos por PEiD nos dice que Aspack 2.1, Exeinfo no está muy seguro y RDG packer detector en el escaneo avanzado nos encuentra Aspack, UPX y PE-Pack.

En principio nos enfrentamos a Aspack 2.1, abrimos el crackme con OllyDbg y vemos el típico PUSHAD.

01

Pulsamos F8 (Step Over) y a continuación click derecho sobre el registro ESP y Follow in DUMP.

02

Seleccionamos los primeros cuatro bytes útiles del dump y les ponemos un Breakpoint de Hardware, Access y Dword.

04

05

Pulsamos F9 y nos para aquí:

06

Ya tenemos a Aspack contra las cuerdas, pulsamos F8 hasta después del RETN para llegar al OEP (Original Entry Point).

07

Pero en el supuesto OEP vemos otro PUSHAD por lo que esto no ha terminado. Investigando un poco más vemos que la segunda capa se corresponde con PE-PACK 1.0. La estrategia a seguir es la misma, como ya tenemos el breakpoint puesto pulsamos F9 y nos para aquí:

08

Pulsamos F8 y nos llega a otro PUSHAD. Esta vez es UPX.

09

Pulsamos de nuevo F9 y paramos aquí:

10

Pulsamos F8 y esta vez si llegamos al OEP (4576EC).

11

A continuación vamos a dumpear el archivo en memoria. Vamos a plugins > OllyDumpEX, pulsamos sobre «Get EIP as OEP» y finalmente sobre «Dump«.

13

Minimizamos Olly (no cerrar), abrimos el programa ImportREC y seleccionamos el ejecutable «Sweeet1.exe».

14

Pegamos el OEP original (576EC), le damos a AutoSearch y a continuación a Get Imports.

15

Finalmente pulsamos Fix Dump y elegimos el ejecutable dumpeado anteriormente. Esto nos genera un ejecutable dumpeado que es el ejecutable válido.

Ahora PEiD nos dice que estamos tratando con un crackme hecho en Delphi.

Hemos pasado por tres capas de compresión casi idénticas, vamos a analizarlas.

triplecompresion

El algoritmo

Cuando abrimos el crackme nos fijamos en que genera una key. Esta key se genera en función del disco duro desde el que se ejecuta.

Como la secuencia de generación del serial válido es larga os pongo lo más importante muy resumido y con ejemplos como siempre.

El serial es del siguiente tipo:

Serial = 1ªParte-2ªParte-3ªParte
Serial = 0000XXXXX-SerialCalculado-xxxx000Z8

Comprobación del tamaño del nombre
----------------------------------
........
00456EAA    E8 01CCFAFF     CALL sweeet1_Fix_dump_rebuilded.00403AB0
00456EAF    83F8 04         CMP EAX,4    ------------------------------------------------; Nombre >=4                    
00456EB2    7D 13           JGE SHORT sweeet1_Fix_dump_rebuilded.00456EC7
00456EB4    A1 08954500     MOV EAX,DWORD PTR DS:[sweeet1_Fix_dump_rebuilded.459508]
00456EB9    8B00            MOV EAX,DWORD PTR DS:[EAX]
00456EBB    E8 0869FEFF     CALL sweeet1_Fix_dump_rebuilded.0043D7C8
00456EC0    BB 01000000     MOV EBX,1
00456EC5    EB 15           JMP SHORT sweeet1_Fix_dump_rebuilded.00456EDC
00456EC7    83FB 25         CMP EBX,25                                                                                                
00456ECA    7D 0E           JGE SHORT sweeet1_Fix_dump_rebuilded.00456EDA
00456ECC    83C3 32         ADD EBX,32
00456ECF    83C3 1E         ADD EBX,1E
00456ED2    83EB 4F         SUB EBX,4F
00456ED5    83FB 25         CMP EBX,25 -----------------------------------------------; Nombre <=25
00456ED8  ^ 7C F2           JL SHORT sweeet1_Fix_dump_rebuilded.00456ECC
00456EDA    33DB            XOR EBX,EBX
00456EDC    33C0            XOR EAX,EAX
........

1ºBucle - Nuestro nombre (A)
----------------------------
........
00456F55    BE 1B000000     MOV ESI,1B -------------------------------; ESI = 1B
00456F5A    EB 21           JMP SHORT sweeet1_dump_.00456F7D
00456F5C    8D55 D4         LEA EDX,[EBP-2C]
00456F5F    A1 34A84500     MOV EAX,DWORD PTR DS:[sweeet1_dump_.45A8
00456F64    8B80 C4020000   MOV EAX,DWORD PTR DS:[EAX+2C4]
00456F6A    E8 B5DAFCFF     CALL sweeet1_dump_.00424A24
00456F6F    8B45 D4         MOV EAX,DWORD PTR SS:[EBP-2C]
00456F72    0FB64418 FF     MOVZX EAX,BYTE PTR DS:[EBX+EAX-1]---------; Coje digito
00456F77    03F0            ADD ESI,EAX ------------------------------; digito + ESI
00456F79    43              INC EBX
00456F7A    0FAFF3          IMUL ESI,EBX  ----------------------------; multiplica por i (bucle)
00456F7D    8D55 D4         LEA EDX,[EBP-2C]
........

2ºBucle - La key (B)
--------------------
........
00456F9C         |.  BF 1A000000            MOV EDI,1A -------------------------;EDI = 1A
00456FA1         |.  BB 01000000            MOV EBX,1
00456FA6         |.  EB 1E                  JMP SHORT sweeet1_.00456FC6
00456FA8         |>  8D55 D4                /LEA EDX,[LOCAL.11]
00456FAB         |.  A1 34A84500            |MOV EAX,DWORD PTR DS:[45A834]
00456FB0         |.  8B80 D0020000          |MOV EAX,DWORD PTR DS:[EAX+2D0]
00456FB6         |.  E8 69DAFCFF            |CALL sweeet1_.00424A24
00456FBB         |.  8B45 D4                |MOV EAX,[LOCAL.11]
00456FBE         |.  0FB64418 FF            |MOVZX EAX,BYTE PTR DS:[EAX+EBX-1]--;Coje dígito
00456FC3         |.  03F8                   |ADD EDI,EAX -----------------------;Suma dígito a dígito
00456FC5         |.  43                     |INC EBX
00456FC6         |>  8D55 D4                 LEA EDX,[LOCAL.11]
00456FC9         |.  A1 34A84500            |MOV EAX,DWORD PTR DS:[45A834]
00456FCE         |.  8B80 D0020000          |MOV EAX,DWORD PTR DS:[EAX+2D0]
00456FD4         |.  E8 4BDAFCFF            |CALL sweeet1_.00424A24
00456FD9         |.  8B45 D4                |MOV EAX,[LOCAL.11]
00456FDC         |.  E8 CFCAFAFF            |CALL sweeet1_.00403AB0
00456FE1         |.  3BD8                   |CMP EBX,EAX
00456FE3         |.^ 7C C3                  \JL SHORT sweeet1_.00456FA8
........

Generación del serial central
-----------------------------
........
00456FE5         |.  B9 01000000            MOV ECX,1
00456FEA         |.  BB 01000000            MOV EBX,1
00456FEF         |.  8BC7                   MOV EAX,EDI
00456FF1         |.  F7EE                   IMUL ESI ----------; C = A * B
00456FF3         |.  99                     CDQ
........
00456FFD         |.  2345 E8                AND EAX,[LOCAL.6]--; D = A and C
00457000         |.  2355 EC                AND EDX,[LOCAL.5]
00457003         |.  8945 E8                MOV [LOCAL.6],EAX
00457006         |.  8955 EC                MOV [LOCAL.5],EDX
........
00457032         |.  8BC7                   MOV EAX,EDI
00457034         |.  99                     CDQ
00457035         |.  0345 E8                ADD EAX,[LOCAL.6]--; E = D + B
00457038         |.  1355 EC                ADC EDX,[LOCAL.5]
0045703B         |.  8945 E0                MOV [LOCAL.8],EAX
0045703E         |.  8955 E4                MOV [LOCAL.7],EDX
........
00405732           8B4424 10                MOV EAX,DWORD PTR SS:[ESP+10]
00405736           F72424                   MUL DWORD PTR SS:[ESP]
00405739           8BC8                     MOV ECX,EAX
0040573B           8B4424 04                MOV EAX,DWORD PTR SS:[ESP+4]
0040573F           F76424 0C                MUL DWORD PTR SS:[ESP+C]------; F = B * D
00405743           03C8                     ADD ECX,EAX
00405745           8B0424                   MOV EAX,DWORD PTR SS:[ESP]
00405748           F76424 0C                MUL DWORD PTR SS:[ESP+C]------; G = A * F
........
0045705E         |.  0B0424                 OR EAX,DWORD PTR SS:[ESP]-----; Serial central = G or A
........
00457077         |.  E8 FC07FBFF            CALL sweeet1_.00407878
0045707C         |.  8B45 F8                MOV EAX,[LOCAL.2]-------------; EAX = Serial central
........
004570D1         |.  E8 A207FBFF            CALL sweeet1_.00407878
004570D6         |.  8B45 D0                MOV EAX,[LOCAL.12]
004570D9         |.  E8 D2C9FAFF            CALL sweeet1_.00403AB0--------; Obtiene longitud del serial central en hexa
004570DE         |.  8BD8                   MOV EBX,EAX
........
004570D1         |.  E8 A207FBFF            CALL sweeet1_.00407878--------;*Nota

*Nota:
A partir de aquí genera la primera y tercera parte del serial de la siguiente manera:

Serial = 1ªParte-2ªParte-3ªParte
Serial = 0000XXXXX-SerialCalculado-xxxx000Z8

1ºParte = 3ºdigSerial+1ºdigSerial+2ºdigSerial+3ºdigSerial+4ºdigNombreMayu+2ºdigNombreMayu+5ºdigNombreMayu+1ºdigNombreMayu+3ºdigNombreMayu
3ºParte = 3ºdigNombreMin+1ºdigNombreMin+4ºdigNombreMin+2ºdigNombreMin+Tamaño Serial_2ªParte en Hex y de tres dígitos+Z8

 Ejemplo:

Nombre: deurus
Key:    C0C0A000
Serial: 6906REUDU-906297047918-udre00CZ8

1) A = 23A2A (Con nuestro nombre empezando por 1B se lo suma a ESI y se lo multiplica por i (la que toque cada vez))
2) B = 1A1 (Con nuestra Key empezando por 1A va sumando los digitos)
3) C = B * A = 3A0BE6A
4) D = A and C = 3A2A
5) E = D + B = 3BCB (Offset 457035)
6) F = B * D = 5EBE6A (Offset 48704A)
7) G = A * F = D303834164
8) Serial = G or A (Serial = D303834164 or 23A2A = D303837B6E (906297047918))

 A tener en cuenta:

  • 1ªParte del serial siempre mayúsculas.
  • 2ªParte siempre numérico. Usa el registro de 64 bits (Qword) con signo.**Nota
  • 3ªParte siempre minúsculas.

**Nota:

Nombre: deurus.info
Key:    E09FF000
Serial: 9169REUDU-16918236-udre008Z8

Fíjate que: -16918236 = FFFFFFFFFEFDD924

Nombre: deurus
Key:    C0C0A000
Serial: 6906REUDU-906297047918-udre00CZ8

906297047918 = 000000D303837B6E

Links


Intro Os comparto un reto stego que me gustó cuando lo hice hace unos años. En realidad se tarda pocos
Karpoff.es Hace unos días intenté contactar con Karpoff ya que fué una inspiración para mi y muchos otros, lo conseguí
Toda esta aventura comienza con un archivo llamado pretty_raw, sin extensión. Porque sí. Porque las extensiones son una invención heredada
Introducción  Hoy vamos a ver como extraer el script de un ejecutable compilado por Autoit, modificarlo y recompilarlo como nuestro

Intro

Os comparto un reto stego que me gustó cuando lo hice hace unos años. En realidad se tarda pocos minutos en resolverlo pero depende de tus recursos es posible que se te atragante.

Procesando a la víctima

Cuando te has enfrentado a unos cuantos retos stego lo normal es que tengas un arsenal de herramientas por las que vas a pasar a la víctima. En mi caso cuando se trata de imágenes, mi fondo de armario está formado por steganabara y stegsolve. Si con esas dos herramientas no lo veo claro ya empiezo a mirar en sus entrañas y en este caso es justo lo que hace falta, mirar en su interior.

La víctima

imagen original del reto

Estamos ante una imagen GIF de 6,36KB (6513 bytes) cuya resolución es 236×42. Debido a la extensión tenderemos a analizar los frames por si se trata de una animación. Una vez desestimada la animación entran en juego steganabara, stegsolve y demás familia. Si todo lo anterior falla abro el archivo con un editor hexadecimal y lo reviso manualmente por si hay algo que me llama la atención.

Bytes

Explorando el interior del archivo enseguida encontramos algo que llama la atención, una sucesión de bytes con espacios intercalados.

Tras copiar los bytes lo primero es eliminar los espacios y empezar a jugar con ellos. Una de las cosas que podemos hacer es convertir los bytes a ascii y voilá, nos encontramos con lo que parece otro archivo GIF.

Copiamos los bytes con la ayuda de nuestro editor hexadecimal favorito, guardamos el archivo como GIF y reto superado.

Enlaces

Nota: si algo os pide clave es deurus.info

Karpoff.es

Hace unos días intenté contactar con Karpoff ya que fué una inspiración para mi y muchos otros, lo conseguí y se me ocurrió hacerle una entrevista, aquí tenéis el resultado.

Para los recién llegados diré que, Karpoff Spanish Tutor era (y sigue siendo aunque no se actualice), una gran web colaborativa donde encontrar cantidad de manuales y programas en Castellano.

deurus: ¿Qué te llevó a realizar la web?, es decir, que te hizo levantarte una mañana y decir, venga, voy a realizar una web sobre ingeniería inversa.

Karpoff: Pues mira, fue de la siguiente manera. Por aquel entonces (te hablo de los 90 y poco) yo pasaba mi tiempo libre intentando saltar las protecciones de los programas que conseguía generalmente en revistas de informática.

Desconocía que existía un mundillo dedicado a esas artes.

En los años 90 no había internet ni nada parecido que yo sepa, sobre el 95 creo recordar, telefónica saco una cosa que se llamaba Infobia y era una especie de intranet de telefónica donde accedías a un contenido muy limitado, pero te permitía salir de alguna manera bastante limitada también a lo que conocemos como internet (todo era mega lento, velocidades de uno o dos kb por segundo) con módem y llamadas analógicas.

No se como, ya que no existia o no era conocido Google tampoco había casi buscadores, conocí la famosa y maravillosa pagina de «Fravia» dedicada a la ingeniería inversa con muchísima documentación, y proyectos de estudio de protecciones, lamentablemente para el momento hispano, toda la documentación estaba en ingles .

Investigando conocí paginas hispanas con proyectos interesantes (aunque muchas de ellas aun siendo hispanas publicaban todo en ingles)

Conocí también otra pagina, el “ECD” estudio colectivo de desprotecciones + WTK en castellano e ingles que me sorprendió gratamente y donde se publicaban proyectos propios del grupo WTK y de otros grupos como estado+porcino.

los tres grupos hispanos del momento eran WTK, TNT y KUT, pertenecí a TNT durante algún tiempo, aunque el objetivo del grupo no me convencía ya que era exclusivamente la creación de cracks a mansalva por lo que no estuve más de un año.

Yo echaba de menos un sitio como “Fravia” pero en castellano donde todos los interesados pudiéramos colaborar y ayudarnos con temas de ingeniería inversa.

Ya en los 90 y mucho, todo lo relacionado con internet había evolucionado bastante, las conexiones también eran mas rápidas, ya no hacia falta conectarte a infobia sino directamente a internet.

Yo disponía de mucho tiempo libre y empecé un proyecto en solitario “Karpoff Spanish Tutor” mas conocido como “la pagina de karpoff” con proyectos de mi cosecha y con temas que me gustaban mucho, como la programación, los compiladores el software en general etc.

Luego todo lo demás fue llegando poco a poco, a la gente le gustaba y tenia muchísimas ganas de aprender y sobre todo de colaborar.

El proyecto alcanzo unos niveles impresionantes en cuanto a colaboración y recepción de material, había días que estaba mas de 14 horas actualizando la pagina y buscando nuevos servidores para alojarla, ya que me los cerraban casi semanalmente. Y la verdad.. cada vez me costaba mas tiempo mantener la pagina.

Luego gracias a Red Futura tuvimos un hostin de calidad y gratuito.

El proyecto era tan amplio que me fue imposible conciliar vida laboral y vida en internet todo esto empezaba a ser incompatible.

deurus: ¿Empezaste solo o erais un grupo de amiguetes?

Karpoff: Esta te la he contestado en la primera pregunta, vamos… que empecé yo solo.

deurus: ¿Echas de menos el proyecto?

Karpoff: Hoy en día no. Hace falta muchísimo tiempo libre y muchísima dedicación a nivel organizativo.

Echo de menos el movimiento que se creo y la actividad que alcanzo el movimiento cracking hispano. Salían grupos de cracker con nuevos proyectos y paginas hasta de debajo de las piedras 🙂 la ingenieria inversa se puso un poco de moda, conocí a gente muy interesante como Ricardo Narvaja, Numi_tor, Demian y muchas otras personas con muchos conocimientos.

Después de cerrar la pagina todo se quedo un poco cojo y todo el movimiento se empezó a diluir bastante rápido.

deurus: ¿Lo retomarías día de hoy?

Karpoff: La verdad es que no, ya no es mi tiempo, ahora me dedico al trabajo y mi familia y en ratos libres intento reventar algún programa. Sobre todo crackmes.

deurus: ¿Tienes o colaboras activamente en algún proyecto relacionado con la Ingeniería Inversa? 

Karpoff: No, no tengo tiempo. Mantengo contacto por correo con gente de que conocí en esa época y me sorprende que la gente no se olvida de mí. Recibo bastante correo en esta cuenta pidiéndome alguna entrevistilla, opiniones y muchos muchos agradecimientos de mucha gente por la página.

deurus: Yo por aquel entonces tenía 17 años, ¿se le puede preguntar la edad a Karpoff?

Karpoff: Pues yo tengo 45, por aquel entonces tenia unos 29 . La ingeniería inversa siempre fue mi pasión. Desde bien pequeño mi obsesión ha sido conocer como y porque funcionaba todo 🙂 hasta el punto de desmontar todo aquello que me llamaba la atención, mi madre estaba desesperada ya que dejaba todo destripado y muchas veces sin posiblilidad de reparacion.

deurus: ¿Te dedicas a algo relacionado con la informática?

Karpoff: Si, desde esos tiempos me encargo de los sistemas informáticos y equipos técnicos de una empresa bastante conocida, además ese fue uno de los principales motivos del cierre de la página.

Hubo gente interesada en seguir con el proyecto, aunque finalmente todo quedó en nada. Supongo que vieron que el proyecto requería muchísimo tiempo y mucho mucho trabajo.

Me dio mucha lastima no poder seguir con la página y mucha más que nadie se hiciera cargo de ella.

No hace mucho al desaparecer los redireccionadores “come.to” adquirí un dominio “karpoff.es” donde enlace tres mirror de la página para dejar un punto de acceso a ellos.

deurus: Finalmente ¿quieres decir algo a los lectores?

Karpoff: Pues sí, sobre todo dar las gracias a los que me conocen y tuvieron relación con la página, siempre me han hecho sentir grande y siempre tuve mucha colaboración y muchos ánimos por parte de los lectores.

Para los que no me conocen y les gusta la ingeniería inversa, decirles que lo que se aprende crackeando no lo enseñan en ningún sitio 🙂 y es muy muy gratificante.

deurus: Muchas gracias por tu atención, ha sido un placer.

Karpoff: Muchas gracias a ti, me ha hecho mucha ilusión y me ha gustado mucho tu blog.

Saludos !!

Karpoff

Toda esta aventura comienza con un archivo llamado pretty_raw, sin extensión. Porque sí. Porque las extensiones son una invención heredada de CP/M, precursor de MS-DOS, que Windows terminó de popularizar. Porque son innecesarias. Y porque echo de menos cuando los archivos se reconocían por sus permisos… y no por cómo se llamaban.

Como iba diciendo, todo esto comienza mediante el análisis de pretty_raw. Mirando debajo de la falda con un editor hexadecimal encontramos unos cuantos bytes aleatorios hasta dar con una cabecera PNG.

Si atendemos a la captura, justo antes de la cabecera PNG tenemos 116.254 bytes (0x1C61E). Tomad nota que este número será relevante más adelante.

Extraemos el PNG, lo visualizamos y lo pasamos por todas las herramientas habidas y por haber. Nada funciona. Volvemos a visualizarlo con atención y vemos que hace referencia a un archivo llamado flag.png con unas dimensiones que no coinciden con la extraída.

Toca centrarse y pensar en que camino tomar. Hemos gastado tiempo con el PNG extraído y quizá lo mejor sea centrarse en los bytes que inicialmente hemos descartado. En concreto se trata de un bloque de 116.254 bytes, pero espera, 1570×74=116.180 bytes. ¡Mierda!, no coincide exactamente con los bytes extraídos. Bueno, da igual. Si suponemos que el PNG que buscamos no tiene compresión y que cada pixel ocupa un byte (escala de grises y 8 bits), su tamaño depende únicamente de la geometría y de cómo se almacenan las filas en memoria. Vamos a procesarlo con Python para salir de dudas.

import numpy as np
from PIL import Image

INPUT_FILE  = "pretty_raw"
OUTPUT_FILE = "pretty_raw_flag.png"

WIDTH  = 1570 # ¿estás seguro?
HEIGHT = 74
DEPTH  = 8  # bits

# Leer archivo como RAW
with open(INPUT_FILE, "rb") as f:
    raw = f.read()

expected_size = WIDTH * HEIGHT
if len(raw) < expected_size:
    raise ValueError("El archivo no tiene suficientes datos")

# Convertir a array numpy (grayscale 8 bits)
img = np.frombuffer(raw[:expected_size], dtype=np.uint8)
img = img.reshape((HEIGHT, WIDTH))

# Crear imagen
image = Image.fromarray(img, mode="L")
image.save(OUTPUT_FILE)

print(f"Imagen generada correctamente: {OUTPUT_FILE}")

El script nos devuelve un PNG válido pero con las letras torcidas. Tras darle vueltas me di cuenta de que si en el script usamos como WIDTH=1571 en lugar de 1570, la imagen resultante es correcta y tiene todo el sentido del mundo ya que 1571×74=116.254, que son exactamente los bytes que se encuentran antes del png señuelo.

Aunque el ancho visible de la imagen es de 1570 píxeles, cada fila ocupa realmente 1571 bytes. Ese byte adicional actúa como relleno (padding) y forma parte del stride o bytes por fila. Ignorar este detalle lleva a un desplazamiento erróneo acumulativo y por eso se ve la imagen torcida. En este caso concreto da igual ya que el texto se aprecia, pero si el reto hubiera sido más exigente no se vería nada.

Introducción

 Hoy vamos a ver como extraer el script de un ejecutable compilado por Autoit, modificarlo y recompilarlo como nuestro keygen. Como comprobareis si no se ofusca o se toman otro tipo de medidas recuperar información sensible es muy sencillo.

AutoIt es un lenguaje freeware multiproposito y de automatización para Microsoft Windows. Es un Visual Basic Killer, ya que mejora las características de los ejecutables (entre otras portabilidad, velocidad y peso, no fat-coding), y facilitan la programación con un buen repertorio de funciones «pre-diseñadas», y usando un Basic de fácil aprendizaje. Se ha expandido desde sus comienzos de automatización incluyendo muchas mejoras en el diseño del lenguaje de programación y sobre todo en nuevas funcionalidades.

El Script

Func CHECKKEY($USER, $PASS)
Local $OPKEY = "", $SIG = ""
Local $USER_LEN = StringLen($USER)
Local $PASS_LEN = StringLen($PASS)
If $USER_LEN < $PASS_LEN Then
MsgBox(0, "ERROR", "Invalid username or key.")
Exit
ElseIf $USER_LEN < 4 Then
MsgBox(0, "ERROR", "Invalid username or key.")
Exit
EndIf
$PASS_INT = Int($USER_LEN / $PASS_LEN)
$PASS_MOD = Mod($USER_LEN, $PASS_LEN)
$OPKEY = _STRINGREPEAT($PASS, $PASS_INT) & StringLeft($PASS, $PASS_MOD)
For $INDEX = 1 To $USER_LEN
$SIG &= Chr(BitXOR(Asc(StringMid($USER, $INDEX, 1)), Asc(StringMid($OPKEY, $USER_LEN - $INDEX + 1, 1))))
Next
If $SIG = _STRINGREPEAT(Chr(32), $USER_LEN) Then
MsgBox(0, "INFO", "Your key was registered.")
Exit
Else
MsgBox(0, "INFO", "Your key is invalid.")
EndIf
EndFunc

 El Algoritmo

El algoritmo es tremendamente sencillo ya que es nuestro nombre al revés y en mayúsculas.

 Modificando el script para generar nuestro propio keygen

El decompilador se llama myAut2exe y tiene este aspecto.

01-09-2014 11-56-37

Programar en AutoIt es muy sencillo e intuitivo. Nuestro keygen quedaría así.

$MAIN = GUICreate("Another keygen by deurus", 300, 80, -1, -1, 382205952, 385)
$NAME_LBL = GUICtrlCreateLabel("Username", 5, 5, 60, 20, BitOR(4096, 1))
$NAME_INP = GUICtrlCreateInput("", 70, 5, 225, 20, 1)
$PASS_LBL = GUICtrlCreateLabel("Key", 5, 30, 60, 20, BitOR(4096, 1))
$PASS_INP = GUICtrlCreateInput("", 70, 30, 225, 20, 1)
$REGISTER = GUICtrlCreateButton("Register", 5, 55, 60, 20)
$GIVE_UP = GUICtrlCreateButton("Generate", 70, 55, 60, 20)    <- Change name of button, Give Up by Generate
$TASK = GUICtrlCreateButton("?", 140, 55, 20, 20)
$AUTHOR = GUICtrlCreateLabel("keygen by deurus", 165, 55, 130, 20, BitOR(4096, 1))
GUISetState(@SW_SHOW, $MAIN)
While True
    $MSG = GUIGetMsg()
    Switch $MSG
        Case $REGISTER
            Call("CHECKKEY", GUICtrlRead($NAME_INP), GUICtrlRead($PASS_INP))
        Case $GIVE_UP
            Call("GETKEY", GUICtrlRead($NAME_INP), GUICtrlRead($PASS_INP))    <- Add the function to the button
        Case $TASK
            MsgBox(0, "Info", "keygen by deurus")
        Case - 3
            Exit
    EndSwitch
    Sleep(15)
WEnd

Func GETKEY($USER, $PASS)        <- this is our keygen function
    Local $OPKEY = "", $SIG = ""
    Local $USER_LEN = StringLen($USER)
    Local $PASS_LEN = StringLen($USER)
    If $USER_LEN < 4 Then
        GUICtrlSetData($PASS_INP  ,"min 4 chars");
    Else
    For $INDEX = 1 To $USER_LEN
        $SIG = Chr(BitXOR(Asc(StringMid($USER, $INDEX, 1)), 32)) & $SIG
    Next
        GUICtrlSetData($PASS_INP  ,$SIG);
    EndIf
EndFunc

Func CHECKKEY($USER, $PASS)        <- check function, the original
    Local $OPKEY = "", $SIG = ""
    Local $USER_LEN = StringLen($USER)
    Local $PASS_LEN = StringLen($PASS)
    If $USER_LEN < $PASS_LEN Then
        MsgBox(0, "ERROR", "Invalid username or key.")
    ElseIf $USER_LEN < 4 Then
        MsgBox(0, "ERROR", "Invalid username or key.")
        Exit
    EndIf
    $PASS_INT = Int($USER_LEN / $PASS_LEN)
    $PASS_MOD = Mod($USER_LEN, $PASS_LEN)
    $OPKEY = _STRINGREPEAT($PASS, $PASS_INT) & StringLeft($PASS, $PASS_MOD)
    For $INDEX = 1 To $USER_LEN
        $SIG &= Chr(BitXOR(Asc(StringMid($USER, $INDEX, 1)), Asc(StringMid($OPKEY, $USER_LEN - $INDEX + 1, 1))))
    Next
    If $SIG = _STRINGREPEAT(Chr(32), $USER_LEN) Then
        MsgBox(0, "INFO", "Your key was registered.")
    Else
        MsgBox(0, "INFO", "Your key is invalid.")
    EndIf
EndFunc

Este es el resultado.

01-09-2014 12-18-28

Links


Karpoff.es Hace unos días intenté contactar con Karpoff ya que fué una inspiración para mi y muchos otros, lo conseguí
Este BTM va otra vez sobre IPs. Si amigos del séptimo arte, viendo un capítulo de mi querida "The Sinner"
Introducción Objetivo del juego y normas Código inicial Primeras modificaciones Terminando la faena Código ganador Curiosidades Enlaces Introducción Hace tiempo
Intro Se suele decir que para cada problema hay una solución. Si esto lo llevamos al terreno stego podemos decir

Karpoff.es

Hace unos días intenté contactar con Karpoff ya que fué una inspiración para mi y muchos otros, lo conseguí y se me ocurrió hacerle una entrevista, aquí tenéis el resultado.

Para los recién llegados diré que, Karpoff Spanish Tutor era (y sigue siendo aunque no se actualice), una gran web colaborativa donde encontrar cantidad de manuales y programas en Castellano.

deurus: ¿Qué te llevó a realizar la web?, es decir, que te hizo levantarte una mañana y decir, venga, voy a realizar una web sobre ingeniería inversa.

Karpoff: Pues mira, fue de la siguiente manera. Por aquel entonces (te hablo de los 90 y poco) yo pasaba mi tiempo libre intentando saltar las protecciones de los programas que conseguía generalmente en revistas de informática.

Desconocía que existía un mundillo dedicado a esas artes.

En los años 90 no había internet ni nada parecido que yo sepa, sobre el 95 creo recordar, telefónica saco una cosa que se llamaba Infobia y era una especie de intranet de telefónica donde accedías a un contenido muy limitado, pero te permitía salir de alguna manera bastante limitada también a lo que conocemos como internet (todo era mega lento, velocidades de uno o dos kb por segundo) con módem y llamadas analógicas.

No se como, ya que no existia o no era conocido Google tampoco había casi buscadores, conocí la famosa y maravillosa pagina de «Fravia» dedicada a la ingeniería inversa con muchísima documentación, y proyectos de estudio de protecciones, lamentablemente para el momento hispano, toda la documentación estaba en ingles .

Investigando conocí paginas hispanas con proyectos interesantes (aunque muchas de ellas aun siendo hispanas publicaban todo en ingles)

Conocí también otra pagina, el “ECD” estudio colectivo de desprotecciones + WTK en castellano e ingles que me sorprendió gratamente y donde se publicaban proyectos propios del grupo WTK y de otros grupos como estado+porcino.

los tres grupos hispanos del momento eran WTK, TNT y KUT, pertenecí a TNT durante algún tiempo, aunque el objetivo del grupo no me convencía ya que era exclusivamente la creación de cracks a mansalva por lo que no estuve más de un año.

Yo echaba de menos un sitio como “Fravia” pero en castellano donde todos los interesados pudiéramos colaborar y ayudarnos con temas de ingeniería inversa.

Ya en los 90 y mucho, todo lo relacionado con internet había evolucionado bastante, las conexiones también eran mas rápidas, ya no hacia falta conectarte a infobia sino directamente a internet.

Yo disponía de mucho tiempo libre y empecé un proyecto en solitario “Karpoff Spanish Tutor” mas conocido como “la pagina de karpoff” con proyectos de mi cosecha y con temas que me gustaban mucho, como la programación, los compiladores el software en general etc.

Luego todo lo demás fue llegando poco a poco, a la gente le gustaba y tenia muchísimas ganas de aprender y sobre todo de colaborar.

El proyecto alcanzo unos niveles impresionantes en cuanto a colaboración y recepción de material, había días que estaba mas de 14 horas actualizando la pagina y buscando nuevos servidores para alojarla, ya que me los cerraban casi semanalmente. Y la verdad.. cada vez me costaba mas tiempo mantener la pagina.

Luego gracias a Red Futura tuvimos un hostin de calidad y gratuito.

El proyecto era tan amplio que me fue imposible conciliar vida laboral y vida en internet todo esto empezaba a ser incompatible.

deurus: ¿Empezaste solo o erais un grupo de amiguetes?

Karpoff: Esta te la he contestado en la primera pregunta, vamos… que empecé yo solo.

deurus: ¿Echas de menos el proyecto?

Karpoff: Hoy en día no. Hace falta muchísimo tiempo libre y muchísima dedicación a nivel organizativo.

Echo de menos el movimiento que se creo y la actividad que alcanzo el movimiento cracking hispano. Salían grupos de cracker con nuevos proyectos y paginas hasta de debajo de las piedras 🙂 la ingenieria inversa se puso un poco de moda, conocí a gente muy interesante como Ricardo Narvaja, Numi_tor, Demian y muchas otras personas con muchos conocimientos.

Después de cerrar la pagina todo se quedo un poco cojo y todo el movimiento se empezó a diluir bastante rápido.

deurus: ¿Lo retomarías día de hoy?

Karpoff: La verdad es que no, ya no es mi tiempo, ahora me dedico al trabajo y mi familia y en ratos libres intento reventar algún programa. Sobre todo crackmes.

deurus: ¿Tienes o colaboras activamente en algún proyecto relacionado con la Ingeniería Inversa? 

Karpoff: No, no tengo tiempo. Mantengo contacto por correo con gente de que conocí en esa época y me sorprende que la gente no se olvida de mí. Recibo bastante correo en esta cuenta pidiéndome alguna entrevistilla, opiniones y muchos muchos agradecimientos de mucha gente por la página.

deurus: Yo por aquel entonces tenía 17 años, ¿se le puede preguntar la edad a Karpoff?

Karpoff: Pues yo tengo 45, por aquel entonces tenia unos 29 . La ingeniería inversa siempre fue mi pasión. Desde bien pequeño mi obsesión ha sido conocer como y porque funcionaba todo 🙂 hasta el punto de desmontar todo aquello que me llamaba la atención, mi madre estaba desesperada ya que dejaba todo destripado y muchas veces sin posiblilidad de reparacion.

deurus: ¿Te dedicas a algo relacionado con la informática?

Karpoff: Si, desde esos tiempos me encargo de los sistemas informáticos y equipos técnicos de una empresa bastante conocida, además ese fue uno de los principales motivos del cierre de la página.

Hubo gente interesada en seguir con el proyecto, aunque finalmente todo quedó en nada. Supongo que vieron que el proyecto requería muchísimo tiempo y mucho mucho trabajo.

Me dio mucha lastima no poder seguir con la página y mucha más que nadie se hiciera cargo de ella.

No hace mucho al desaparecer los redireccionadores “come.to” adquirí un dominio “karpoff.es” donde enlace tres mirror de la página para dejar un punto de acceso a ellos.

deurus: Finalmente ¿quieres decir algo a los lectores?

Karpoff: Pues sí, sobre todo dar las gracias a los que me conocen y tuvieron relación con la página, siempre me han hecho sentir grande y siempre tuve mucha colaboración y muchos ánimos por parte de los lectores.

Para los que no me conocen y les gusta la ingeniería inversa, decirles que lo que se aprende crackeando no lo enseñan en ningún sitio 🙂 y es muy muy gratificante.

deurus: Muchas gracias por tu atención, ha sido un placer.

Karpoff: Muchas gracias a ti, me ha hecho mucha ilusión y me ha gustado mucho tu blog.

Saludos !!

Karpoff

Este BTM va otra vez sobre IPs. Si amigos del séptimo arte, viendo un capítulo de mi querida «The Sinner» me han vuelto a chirriar los dientes. La verdad que viendo el capítulo no te da tiempo a apreciarlo, únicamente me quedo con que aparece una URL y lo reviso a posteriori (esto lo digo para los curiosos que me preguntáis).

En esta ocasión me tiene un poco inquieto ya que es una serie que cuida enormemente los detalles y el fallo que os voy a mostrar parece intencionado. La imagen en cuestión es esta:

Fotograma del capítulo 2×06

Aparece un buscador con una URL más o menos creíble si no fuera porque la IP que aparece es IMPOSIBLE. La máxima IPv4 es 255.255.255.255, es decir, no han dado ni una, y eso es lo que me tiene mosca. Si hubieran utilizado 82.47.25.29 hubiera quedado bien y estaríamos hablando de un problema de geolocalización de IPs, ya que el rango 82.47.xx.xx le pertenece a UK y deberíamos discernir si el servidor está en EEUU o no…

En definitiva, puede ser un fallo a propósito, un guiño o tener un significado. No se que deciros, bueno si, ¡lo investigaré!

Enlaces

Introducción

Hace tiempo que me aficioné a los retos de Hacking y Cracking, y si bien la mayoría de ellos consisten en desencriptar una clave o realizar ingeniería inversa sobre un ejecutable, también los hay sobre programación pura y dura.

En esta ocasión se nos proporciona un código «muestra» parecido a PHP o C++ y tenemos que ingeniarnoslas para mejorarlo y ganar a la máquina.

Objetivo del juego y normas

El objetivo de esta misión es ganar a Tr0n en su propio juego: las carreras de motos. Se te proporcionará un programa (código) funcional para que veas como se controla el vehiculo. Usando tu inteligencia, tendrás que entender su uso y mejorarlo, ya que no es lo suficientemente bueno como para ganar a Tr0n. Tr0n lleva ya bastante tiempo en la parrilla de juegos y es bastante habilidoso 🙂

Cuando venzas a Tr0n un mínimo de 5 veces consecutivas, se te dará por superada esta prueba.

Buena suerte!!!

[ Available functions / Funciones disponibles ]
direction() returns current direction, change to a new one with direction([newdir])
getX(), getY() returns X and Y coordinates
collisionDistance() | collisionDistance([anydir]) returns the distance until collision
Note: parameters [*dir] can be empty or one of this values: UP DOWN LEFT or RIGHT

[ Constants / Constantes ]
UP DOWN LEFT RIGHT MAX_X MAX_Y

[ Rules / Reglas ]
Try to survive driving your bike and … / Intenta sobrevivir conduciendo tu moto y…
Don’t cross any line / No cruces ninguna línea
or crash with the corners! / o choques con las esquinas!

[ Mission / Mision ]
Use well this controller and beat Tr0n 5 consecutive times to score in this game
Usa bien este controlador y vence a Tr0n 5 veces consecutivas para puntuar en este juego

Código inicial

Nada más comenzar vemos que hemos perdido nuestra primera partida con el siguiente código:

	function controller(playerController $c){
		if($c->direction()==UP && $c->getY()<10){
			if(rand(0,1)==0) $c->direction(LEFT);
				else $c->direction(RIGHT);
			goto done;
		}
		if($c->direction()==DOWN && MAX_Y-$c->getY()<10){
			if(rand(0,1)==0) $c->direction(LEFT);
				else $c->direction(RIGHT);
			goto done;
		}
		if($c->direction()==LEFT && $c->getX()<10){
			if(rand(0,1)==0) $c->direction(UP);
				else $c->direction(DOWN);
			goto done;
		}
		if($c->direction()==RIGHT && MAX_X-$c->getX()<10){
			if(rand(0,1)==0) $c->direction(UP);
				else $c->direction(DOWN);
		}
		done:
	}

Nosotros somos el AZUL y la máquina es el VERDE.

loose_inicial

Primeras modificaciones

Lo primero que tenemos que modificar son las distancias de las coordenadas que estan puestas en «<10» al mínimo, que sería «<2«. También sustituir la aleatoriedad «rand(0,1)==0» por algo más útil y comenzar a usar la función «collisionDistance()«.

Como podéis observar en el código inferior, usamos la función «collisionDistance()» para detectar cuando estamos a punto de chocar «collisionDistance() ==1» y para detectar a que lado nos conviene más girar en función de donde podamos recorrer más distancia «if($c->collisionDistance([LEFT]) >2) $c->direction(LEFT); else $c->direction(RIGHT);«.

if($c->direction()==UP && $c->getY()==1 && $c->collisionDistance() ==1){
			if($c->collisionDistance([LEFT]) >2) $c->direction(LEFT);
				else $c->direction(RIGHT);
		}
if($c->direction()==DOWN && MAX_Y-$c->getY()<2 || $c->collisionDistance() ==1){
			if($c->collisionDistance([LEFT]) >2) $c->direction(LEFT);
				else $c->direction(RIGHT);
		}
if($c->direction()==LEFT && $c->getX()==1 && $c->collisionDistance() ==1){
			if($c->collisionDistance([UP]) >2) 
                                $c->direction(UP);
				else 
                                $c->direction(DOWN);
		}
if($c->direction()==RIGHT && MAX_X-$c->getX()<2 || $c->collisionDistance() ==1){
			if($c->collisionDistance([UP]) >2) $c->direction(UP);
				else $c->direction(DOWN);
				
		}

Terminando la faena

El código anterior de por sí no nos resuelve mucho si no afinamos un poco más, comprobando todos las posibles colisiones y tomando la dirección correcta en función de la mayor distancia a recorrer.

    if($c->collisionDistance([UP])==1 || $c->collisionDistance() ==1){
             if($c->collisionDistance([LEFT]) > $c->collisionDistance([RIGHT]))
               $c->direction(LEFT);
             else 
               $c->direction(RIGHT);
     }
     if($c->collisionDistance([DOWN])==1 || $c->collisionDistance() ==1){
            if($c->collisionDistance([LEFT]) > $c->collisionDistance([RIGHT]))
               $c->direction(LEFT);
             else 
               $c->direction(RIGHT);
     }
     if($c->collisionDistance([RIGHT])==1 || $c->collisionDistance() ==1){
             if($c->collisionDistance([UP]) > $c->collisionDistance([DOWN]))
               $c->direction(UP);
             else 
               $c->direction(DOWN);
     }
     if($c->collisionDistance([LEFT])==1 || $c->collisionDistance() ==1){
          if($c->collisionDistance([UP]) > $c->collisionDistance([DOWN]))
               $c->direction(UP);
             else 
               $c->direction(DOWN);
     }

Código ganador

El código que utilicé yo para ganar a Tron es el siguiente:

function controller(playerController $c){
uno:
if($c->direction()==UP && $c->getY()==1 && $c->collisionDistance() ==1){
			if($c->collisionDistance([LEFT]) >2) $c->direction(LEFT);
				else $c->direction(RIGHT);
				
		}
if($c->direction()==DOWN && MAX_Y-$c->getY()<2 || $c->collisionDistance() ==1){
			if($c->collisionDistance([LEFT]) >2) $c->direction(LEFT);
				else $c->direction(RIGHT);
				
		}
if($c->direction()==LEFT && $c->getX()==1 && $c->collisionDistance() ==1){
			if($c->collisionDistance([UP]) >2) 
                                $c->direction(UP);
				else 
                                $c->direction(DOWN);
				
		}
if($c->direction()==RIGHT && MAX_X-$c->getX()<2 || $c->collisionDistance() ==1){
			if($c->collisionDistance([UP]) >2) $c->direction(UP);
				else $c->direction(DOWN);
				
		}
dos:
    if($c->collisionDistance([UP])==1 || $c->collisionDistance() ==1){
             if($c->collisionDistance([LEFT]) > $c->collisionDistance([RIGHT]))
               $c->direction(LEFT);
             else 
               $c->direction(RIGHT);
     }
     if($c->collisionDistance([DOWN])==1 || $c->collisionDistance() ==1){
            if($c->collisionDistance([LEFT]) > $c->collisionDistance([RIGHT]))
               $c->direction(LEFT);
             else 
               $c->direction(RIGHT);
     }
     if($c->collisionDistance([RIGHT])==1 || $c->collisionDistance() ==1){
             if($c->collisionDistance([UP]) > $c->collisionDistance([DOWN]))
               $c->direction(UP);
             else 
               $c->direction(DOWN);
     }
     if($c->collisionDistance([LEFT])==1 || $c->collisionDistance() ==1){
          if($c->collisionDistance([UP]) > $c->collisionDistance([DOWN]))
               $c->direction(UP);
             else 
               $c->direction(DOWN);
     }
		done:
	}

Mis jugadas ganadoras:

01

02

03

04

05

El código no es infalible ya que como comprabaréis vosotros mismos, no se puede ganar siempre por el mero hecho de la aleatoriedad y de la suerte. Cuando dispongais de un código decente, ejecutarlo varias veces para estar seguros antes de desecharlo.

Curiosidades

Como se suele decir, la banca siempre gana, y en este caso no iba a ser menos y es que en caso de empate ¡la banca gana!

empate

 

Por último deciros que podéis utilizar el código ya que la web detecta los códigos ganadores para que no se repitan.

Enlaces

Intro

Se suele decir que para cada problema hay una solución. Si esto lo llevamos al terreno stego podemos decir que para cada reto hay una herramienta que nos da la solución. En la entrada anterior os comenté que mi fondo de armario son steganabara y stegsolve aunque cuando la imagen es PNG, una herramienta de uso obligatorio es TweakPNG.

La víctima

imagen original del reto

Nos enfrentamos a una imagen PNG de 112KB (115477 bytes) con una resolución de 300×225 píxeles. A priori llama la atención el elevado tamaño VS la baja resolución, lo que aviva nuestras sospechas de que esos KB extras se deban a que haya insertado otro archivo en su interior.

Chunk

Los archivos PNG tienen la peculiaridad de que están divididos en secciones (chunks) en la que algunas son críticas como IHDR (cabecera), IDAT (la imagen) e IEND (final) y otras muchas secundarias como por ejemplo tEXt (para insertar texto). Al explorar el archivo con TweakPNG vemos la cabecera, varios chunks de texto, muchos IDAT que he combinado en uno para mejorar el análisis y la sección final. Si os fijáis, al combinar los IDAT ha cambiado el tamaño del PNG de 115447 a 110893 bytes aunque en este caso sigue siendo un tamaño elevado.

aspecto original de los chunks
aspecto de los chunks tras combinar todos los IDAT en uno

Llama la atención el chunk cHRm de 12595 bytes del que TweakPNG ya nos avisa que no reconoce su contenido. Cargamos la imagen en un editor hexadecimal y buscamos la palabra «Great» que es el texto que hay justo antes del chunk cHRm que nos interesa.

detalle del chunk cHRm en editor hexadecimal

La búsqueda da sus frutos ya que el chunk parece que está formado por un archivo mp4. A partir de aquí tenemos varias opciones, para mí la más limpia es con un editor hexadecimal apuntar los offsets de inicio y fin del chunk y crear un archivo nuevo con el contenido. Otra opción es exportar el chunk desde TweakPNG con extensión mp4 y borrar los bytes del nombre del chunk con un editor hexadecimal, de lo contrario no podréis reproducir el mp4.

nombre del chunk a borrar para que funcione el mp4

Hecho esto, al escuchar el mp4 obtenemos la solución del reto.

Enlaces

Nota: si algo os pide clave es deurus.info