elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Estamos en la red social de Mastodon


+  Foro de elhacker.net
|-+  Programación
| |-+  Ingeniería Inversa (Moderadores: karmany, .:UND3R:., MCKSys Argentina)
| | |-+  CrackMe if you can II (Reloaded)
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: CrackMe if you can II (Reloaded)  (Leído 4,775 veces)
Karman


Desconectado Desconectado

Mensajes: 673



Ver Perfil WWW
CrackMe if you can II (Reloaded)
« en: 29 Octubre 2007, 19:00 pm »

Estaba un poco al dope últimamente y decidí crear este nuevo crackme... en el no hay ninguna ciencia nueva... pero incluye un par de cosas que vi en unos programas que estuve crackeando últimamente... aquí os dejo:

http://h1.ripway.com/karman/Files/crackme2.rar

No creo que sea recomendable para principiantes... pero si quieren pueden echarle un vistazo...

Solucionado por:

x4uth (Keygen y tuto)

S2

PD: "NO PUBLIQUEN CLAVES... MÁNDENMELAS POR PRIVADO Y YO LAS COLOCARÉ AQUÍ"... je

« Última modificación: 9 Noviembre 2007, 15:58 pm por Karman » En línea

Karman


Desconectado Desconectado

Mensajes: 673



Ver Perfil WWW
Re: CrackMe if you can II (Reloaded)
« Respuesta #1 en: 5 Noviembre 2007, 21:08 pm »

parece que se les ha complicado mucho...  :P ... a mi tb cuando tuve que crackear un programa con ese sistema... pero de última... no es necesario un user y pass... con que me den el offset y el valor a modificar ya va... (pero tampoco 10 ni del mensaje sino para que el programa funcione)...  :xD

S2

PD: es un jne -> je
En línea

x4uth

Desconectado Desconectado

Mensajes: 88


Ver Perfil
Re: CrackMe if you can II (Reloaded)
« Respuesta #2 en: 9 Noviembre 2007, 12:26 pm »

Tuturial:

empiezo poniendo bp en GetDlgItemTextA meto cualquier dato en el crackme y vemos que para en el kernel, execute until usercode u caemos en
00401F03  |.  E8 78100000   CALL <JMP.&USER32.GetDlgItemTextA>
q es caundo lee el nombre, mas abajo hay otro similar al del pass, asi que aqui estamos, el problema es que si seguimos debugando vemos que estamos en una especie de "message handler", y aqui no es donde procesa los datos, bueno alli vimos que guardo el nombre en 4061A0, asi que ponemos dump 4061A0, y le colocamos un bp Memory on access
alli paro en
0040142B  |.  8038 00       CMP BYTE PTR DS:[EAX],0
alli vemos una funcion que nos recuerda al crackme 1 de karman, comprobamos las entradas y salidas , la salida de EAX esta sospechosa, pero si ejecutamos hasta el ret vemos que esta al final del "message handler" y no hace anda con EAX, asi que no le damos mucha importancia a esta parte
vuelvo a colocar un bpm on acesss pues lo habia quitado para no tener q dar f9 20 veces en la funcion anterior

esta ves cae en 00401759 MOV DWORD PTR SS[ESP+4],crackme.004061A0  , esta metiendo el dato en el stack para llamar un CALL que tiene ad+ de ese otros dos argumentos, uno es
00401755  MOV DWORD PTR SS:[ESP+8],EAX  que es la longitud del nombre y otro q es una zona de memoria con ceros, otra ves quito el bpm para que no moleste debugueo la funcion, no voy a explicar el ensamblador, supongo que todos podeis saber lo q hace debugandola, basicamente va haciendo un xor de todas los caracteres del nombre y un caracter constante que obtiene de [EAX+404078], los resultados de la operacion los guarda en la zona de ceros

al salir del CALL va entrar en otro, esta ves con 2 argumentos , uno es el pass y otro otra zona de ceros
esta tiene dos bucles uno recorre el pass restandole 'A' a cada caracter si es mayor de '?' y restandole 16h en caso contrario, despues entra en otro bucle que hace operaciones logicas con el pass y guarda los resultados en la zona de ceros, pero cada caracter de salida esta formado por 2 de entrada, los caracters pares del pass (0, 2 , 4 ) forman los 4 bits de mayor peso de los BYTEs y los impares la parte baja.

al salir de ese CALL, hace una llamada a(kernel32.SetEvent), y no podemos seguir traceando a mano, bueno seguimos la misma estrategia
buscamos 00401761 en el dump (aqui se guardo el resultado de las operaciones con el nombre) y le ponemos un bpm on acesss, f9 y caemos en
0040167E MOV EAX,DWORD PTR DS:[EDX+EAX]
se trata de una funcion que tratando los priemros 8 bytes los de los resultados anteriores como 2 DWORD, le hace un XOR a estos con otro DWORD que optiene con un AND de otras 2 constantes, asi que lo podemos ver en conjunto como un simple XOR

cuando termina , hace lo mismo con el pass procesado.

despues hace un XOR con las 4 DWORDs, (2 del pass y 2 del name) y comprueba q este sea 0, comprobamos que cuando es 0 nos da el mensaje bueno y cuando es diferente de 0 nos da el mensaje malo, asi que tenemos que lograr que este XOR sea 0.
sabemos que si (a XOR b)==0  entonces a==b

llamando pf al pass procesado final y nf al nombre prosesado final , y p1,n1 al primer procesado del nombre y pass respectivamente
ad+ pf[0] es la primera DWORD obtenida y pf[1] la segunda

j={0,1}

0 = pf[j] XOR  nf[j]
pf[j] = (p1[j] XOR c1[j]) <--  si le mandamos una cadena
de nulos a la funcion que hace el XOR final del pass podemos obtener c1[j] pues (a XOR 0) == a

0 = pf[j] XOR p1[j] XOR c1[j]

p1[j] = pf[j] XOR c1[j]

ahi ya sabemos cuando tiene que dar el primer procesado del pass, asi que solo queda revertir esa funcion

aqui os pongo el codigo en C++ del generador de claves que hize yo

Código:
#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>

#define DWORD unsigned int
#define BYTE unsigned char


//0404078h
char const1[8*10];
char const2[16];
char const3[16];


void ShowDump(char* buff, DWORD s)
{
//muestra el contenido de una zona de memoria en hexdecimal
int j,i;
i=0;
for (i=0;i<s;i+=8) {

for (j=i;(j-i)<8;j++){
if (!(j<s)) {
printf ("   ");
continue;

}
if ((unsigned char)buff[j] <= 0xF) printf("0");
printf("%X ",(unsigned char)buff[j]);
if ((j-i)==3) printf("| ");
}

for (j=i;j<s && (j-i)<8;j++){
if (j==i) printf("| ");
if (buff[j]) printf("%c ",buff[j]);
else printf(". ");
}
printf("\n");
}
}

void name1(char * nombre,DWORD len,char * buff)
{
//primer procesamiento del name
  int j,i;
  char c;
 
  for (j=0;j<=7;j++)
  {
  buff[j]=const1[j];
  for (i=0;i<len;i++)
  {
  c=nombre[i];
  c+=c;
  c=c^buff[j];
  buff[j]=c;
  }
  }
}

void pass1(char *pass,char *buff) {
//primer procesamiento del pass
DWORD j;
BYTE b;
char l,h;
for (j=0;pass[j];j++) {
   if (pass[j] > '?') pass[j]-='A'; //se queda con el valor numerico
   else pass[j]-=0x16; //???
}
BYTE i;
for (i=0;i<=7;i++){

l = pass[2*i];
_asm SAR l,1
l &= 0xF; //bit bajo
h = pass[2*i+1];
_asm SAR h,1
_asm SHL h,4
buff[i]=h|l;
}
}

void reversePass1(char *pass,char *buff) {
//revierte el primer proceso del pass
BYTE i,j,b,h,l;
for (j=0;j<8;j++)
{
//bit de menor peso
b=buff[j];
b&=0xF;
b<<=1;
pass[j*2]=b+'A';
//bit de mayor peso
b=buff[j];
b>>=4;
b<<=1;
pass[j*2+1]=b+'A';

}
}

void getDWORD(char * buff,char *cadena,char * garb)
{
DWORD j,i,k;
DWORD *ptrG,*ptrG2,*ptrB;
for (j=0;j<8;j++) buff[j]=cadena[j];
for (j=0;j<=1;j++)
{
for (i=0;i<=1;i++){
if (j==i) continue;

k=2*j+i;
k <<= 2;
ptrG = (DWORD*)((2*i+j)*4+garb);
ptrG2 = (DWORD*)(garb+k);
ptrB = (DWORD*)(buff+(j*4));

k = ptrG[0] & ptrG2[0];
ptrB[0] ^= k;
}
}

}

int main(int argc, char *argv[])
{
char username[16],pass[32],nbuff[16],pbuff[16],n2buff[16],p2buff[16];
memset(const1,0,sizeof(const1));
memset(username,0,sizeof(username));
memset(pass,0,sizeof(pass));
memset(nbuff,0,sizeof(nbuff));   
memset(n2buff,0,sizeof(n2buff));
memset(pbuff,0,sizeof(pbuff));
memset(p2buff,0,sizeof(p2buff));



memcpy(const1,"\x4C\x0D\x18\x6A\x3F\xB9\x25\xE7\xBD\x96\x9A\x91\xDF\x8F\x9E\x8F\x1E\xDE\xDE\xDE\xDF\xA6\x9E\xDF\x8B\x9A\x91\x9A\x8C\xDF\x9E\x93\x98\x90\xDF\x8F\x9E\x8D\x9E\xDF\x8D\x9A\x9C\x90\x8D\x9B\x9E\x8D\xDF\x9C\x8A\x9E\x91\x9B\x90\xDF\x8C\x9A\x9E\x8C\xDF\x89\x96\x9A\x95\x90\xD7\xC0\xC0\xC0\xC0\xD6\x00\x00\x00\x00\x00\x00\x00\x00",sizeof(const1));
memcpy(const2,"\x0D\xEB\xD0\x68\xE4\x6A\x9D\x48\x81\x56\xA3\xE3\x9E\x85\xF1\x7D",sizeof(const2));
memcpy(const3,"\xCA\x78\x8E\x2C\xD5\x61\xA9\x17\xB4\xA5\x96\x87\xF0\xE1\xD2\xC3",sizeof(const3));
system("CLS");
printf("Usuario:");
scanf("%s",username);
strcpy(pass,"");

system("CLS");
ShowDump(username,sizeof(username));
ShowDump(pass,sizeof(pass));
name1(username,strlen(username),nbuff);
ShowDump(nbuff,sizeof(nbuff));
pass1(pass,pbuff);
ShowDump(pbuff,sizeof(pbuff));
getDWORD(n2buff,nbuff,const2);
ShowDump(n2buff,sizeof(n2buff));
getDWORD(p2buff,pbuff,const3);
ShowDump(p2buff,sizeof(p2buff));


//final
DWORD *pdw1,*pdw2;
pdw1=(DWORD*)n2buff;
pdw2=(DWORD*)p2buff;
DWORD res[2];
char * ver= (char*)&res;
memset(pbuff,0,sizeof(pbuff));
memset(pass,0,sizeof(pass));
res[0]=pdw1[0]^pdw2[0];
res[1]=pdw1[1]^pdw2[1];

for (int j=0;j<8;j++) pbuff[j]=ver[j];
reversePass1(pass,pbuff);
ShowDump(ver,8);
ShowDump(pass,sizeof(pass));
for (int j=0;j<80;j++) printf("-");
printf("Usuario:%s\nClave:%s\n",username,pass);

system("PAUSE");
return EXIT_SUCCESS;
}



podeis bajaros el keygen ya compilado aqui ->
http://rapidshare.com/files/68490778/karman02gen.rar.html

una combinacion valida
user: x4uth
pass: ECIEGKOMCMAS]MU]

 
En línea

Karman


Desconectado Desconectado

Mensajes: 673



Ver Perfil WWW
Re: CrackMe if you can II (Reloaded)
« Respuesta #3 en: 9 Noviembre 2007, 16:03 pm »

Te pasaste x4uth...  ;D... muy bueno el tuto... la simplificaste bien... sigue así...  :D

S2
En línea

karmany
Moderador
***
Desconectado Desconectado

Mensajes: 1.615


Sueñas que sueñas


Ver Perfil WWW
Re: CrackMe if you can II (Reloaded)
« Respuesta #4 en: 9 Noviembre 2007, 17:22 pm »

Muy bueno x4uth...y enhorabuena por resolverlo.


Primeramente Karman quisiera darte mi enhorabuena por tan expléndido CrackMe, realmente a mí me costó encontrarle el punto... Me ha gustado mucho y si no tienes paciencia no lo solucionas.

Sólo quería añadir (ahora que ya está todo resuelto) un par de cosas que he visto en el crackme y me parecen muy dignas de contar aquí. Yo lo soluciné por otro lado:
El MessageBox que aparece al pulsar "Aceptar" lo tenemos en 401FF5 y proviene de una comparación con 0E2D0.
Después de indagar bastante descubrí que Karman malignamente crea dos Threads que son los que nos complican la vida. Al final de uno de los Threads que se ejecutan (en 401859) veremos una CALL y esa CALL va a parar a un SendMessage y le da un valor sorprendente: 0E2D0!!
A partir de ahí nos manda al MessageBox.

Pues bien el puntero que carga la cadena de "chico malo" lo tenemos un poco antes de 401859 y si nos fijamos la cadena de "chico bueno" está en un puntero así definido:
Puntero a cadena "chico bueno" = puntero a cadena "chico malo" + 4

Por lo tanto el salto que nos registra o no, está en 40183B. Ese salto no se tiene que cumplir, así que si ponemos un BP en 401837, podremos ver el resultado de la comparación y el resultado tiene que dar 0.

Para mi nombre "karmany" puse el BP comentado y descubrí que si ponemos de serial 8 dígitos, pues es muy sencillo porque cada dígito modifica un valor.
Así que me costó muy poco descubrir que:
Nombre: karmany
Serial: hpiw1g1q
por ej. porque hay varias soluciones...

Un saludo
karmany

Editado después:
--He comprobado que mi serial no funciona siempre (si se pone nada más ejecutar el programa, va bien) pero como x4uth lo ha resuelto expléndidamente pues no merece que siga investigando más.
« Última modificación: 10 Noviembre 2007, 14:56 pm por karmany » En línea

Karman


Desconectado Desconectado

Mensajes: 673



Ver Perfil WWW
Re: CrackMe if you can II (Reloaded)
« Respuesta #5 en: 9 Noviembre 2007, 18:55 pm »

jejeje... si... eso de los threads lo están utilizando ahora porque es una forma simple de "ocultar código" (en programas grandes se complica llevarle el hilo) eliminando la secuencialidad...  :o ... me alegra que les haya gustado mi crackme... después algún otro día que esté al dopes armaré otro con las cosas que veo en distintos programas...  ;)

S2
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines