StartClean v1.24 Key Generator By Black Fenix |
Bienvenidos a mi tercer tutorial sobre cracking, en esta entrega vamos a seguir con los keygens, esta vez haremos uno para el programa StartClean v1.24.
SoftIce para Windows
Vista Rápida (QuickView de Windows)
Turbo Pascal, para hacer el Key Generator (Opcional)
Para poder hacer el programa que nos genere los numeros válidos, necesitamos saber como hace el programa para generar un numero de serie a partir del nombre que le hemos dado, esto significa encontrar la rutina que se encarga de esto dentro del ejecutable.
Iremos a lo fácil, haremos click con el botón derecho del mouse sobre el ejecutable y pincharemos en Vista Rápida. Hechamos un vistazo a la lista de funciones que importa de la libreria KERNEL32.DLL y vemos que entre ellas se encuentra lstrcmpA, está función sirve para comparar dos cadenas de caracteres aquí tienes su descripción detallada:
intlstrcmp(
LPCTSTR lpString1, // puntero a la primera cadena
LPCTSTR lpString2 // puntero a la segunda cadena
);
Si la cadena lpString1 = lpString2 el valor de retorno es igual a 0 si no será diferente que 0. ¿ Es probable que el programa use esta función para comparar el numero de serie válido con el numero de serie que nosotros le introducimos aleatoriamente ?, Si en el caso que nos ocupa, pero no suele ser muy normal ya que la mayoria de programas usan sus propias funciones de comparación para dificultar el trabajo a los crackers. Dado que este programa es pequeño en tamaño yo supongo que el autor prefirió usar las funciones del Kernel a crearse las suyas propias para así no aumentar el tamaño del ejecutable. Pero es igual más fácil para nosotros. Manos a la obra.
Con el SoftIce residente ejecutamos el programa y hacemos click en el botón Register. aparece una ventana donde podemos introducir el Nombre y el numero de serie, yo he usado lo siguiente:
Nombre: Black Fenix
Key: 12345
Antes de pulsar Ok, entramos en el SoftIce (Ctrl+D) y ponemos un bpx en lstrcmpA, salimos del SoftIce (Ctrl+D) y pulsamos Ok. Boom!! El breakpoint a surtido efecto, estamos al inicio de la rutina lstrcmpA. Ahora vamos a ver quien la llamó, pulsamos F12 una vez y estaremos debajo de la llamada a lstrcmpA, veremos algo así:
PUSH 406030 -> Pasa una dirección (donde se guardará el numero de serie válido)
PUSH 406130 -> Y otra que es nuestro nombre 'Black Fenix' en mi caso
CALL 401280 -> Llama a la rutina que calcula el numero de serie válido
LEA EAX,[ESP+18] -> Dirección de nuestro numero de serie '12345'
ADD ESP,08 -> reajusta la pila
PUSH EAX -> Primera cadena a comparar es nuestro numero de serie '12345'
PUSH 406030 -> se comparará con el numero de seria válido
CALL [KERNEL32!lstrcmp] -> llama a lstrcmp
TEST EAX,EAX -> EAX es el resultado de la comparación (Estamos aquí !! )
JNZ 401271 -> si <> 0 no són iguales ( nos envia al mensaje de error)
Puedes comprobar las cadenas dentro del SoftIce poniendo un bpx en la llamada a lstrcmp pulsando g y de nuevo en el botón OK, ahora puedes hacer:
d 406030 -> Veras el numero de serie válido '2136-20406-2641-509'
d eax -> Nuestro numero '12345'
Bueno, ahora podriamos modificar el salto despues del TEST EAX,EAX y el programa se registraria con cualquier numero, pero como lo que nos interesa es no modificar el ejecutable y crear un generador de números válidos, lo que tenemos que examinar a continuacion es el CALL 401280 que es la rutina que se encarga de generar el número válido:
Pues ponemos un bpx en esta y volvemos a ejecutar el programa con los mismo datos que hasta ahora, pulsamos Ok y ya estaremos de nuevo en SoftIce pulsamos F8 y entraremos en la rutina 401280 iremos paso a paso hasta llegar a la dirección 4012D2 (Todo lo que hay antes basicamente se encarga de inicializar la cadena donde se copiará el numero válido con ceros ):
:004012A2 BD6A000000 mov ebp, 0000006A // Inicializa ebp con 6A (ebp es donde se guarda el código en formato numérico. El valor inicial del código será 6Ah = 106 decimal Nota: EDI contiene la dirección de la función CharNext //......................... //.................... //........................................... ................................................................................................................... :004012D2 0FBE08 movsx ecx, byte ptr [eax] // Lee caracter del nombre Black Fenix :004012D5 50 push eax // pasa la cadena como parametro de CharNext :004012D6 8D6C4D00 lea ebp, dword ptr [ebp+2*ecx] // codigo1 = codigo1 + 2 x caracter :004012DA FFD7 call edi // llama a CharNext :004012DC 803800 cmp byte ptr [eax], 00 // es el último caracter (si acaba en NULL) :004012DF 75F1 jne 004012D2 // No, pasa al siguiente caracter * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004012D0(C) :004012E1 8D442410 lea eax, dword ptr [esp+10] // carga puntero a buffer vacio :004012E5 55 push ebp // Pasa el primer codigo codigo1 * Possible StringData Ref from Data Obj //"%d-" :004012E6 6874624000 push 00406274 // "%d-" // como numero + un guión de separación :004012EB 50 push eax // pasa dirección del buffer vacio donde copiar el numero * Reference To: USER32.wsprintfA, Ord:0249h :004012EC FF15D4924000 Call dword ptr [004092D4] // llama a wsprintfA (Esto escribe en la cadena pasada el primer codigo con formato XXXXX- :004012F2 8D44241C lea eax, dword ptr [esp+1C] // y lo añade a la cadena donde se almacenará el numero :004012F6 83C40C add esp, 0000000C // resultante :004012F9 50 push eax :004012FA 56 push esi * Reference To: KERNEL32.lstrcatA, Ord:0266h :004012FB FF153C924000 Call dword ptr [0040923C] // llama a lstrcatA (concatena dos cadenas, ver más abajo) :00401301 8BC3 mov eax, ebx :00401303 803B00 cmp byte ptr [ebx], 00 :00401306 7412 je 0040131A * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401318(C) :00401308 0FBE08 movsx ecx, byte ptr [eax] // Lee caracter del nombre 'Black Fenix' :0040130B 03C9 add ecx, ecx // caracter=caracter+caracter :0040130D 50 push eax // pasa puntero al nombre para CharNext :0040130E 8D14C9 lea edx, dword ptr [ecx+8*ecx] // codigoaux = caracter*8+caracter :00401311 03EA add ebp, edx // codigo = codigoaux+codigo :00401313 FFD7 call edi // Llama a CharNext :00401315 803800 cmp byte ptr [eax], 00 // es el último caracter? :00401318 75EE jne 00401308 // No, pasa al siguiente * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401306(C) :0040131A 8D442410 lea eax, dword ptr [esp+10] // esto :0040131E 55 push ebp // da formato * Possible StringData Ref from Data Obj //"%d-" :0040131F 6874624000 push 00406274 // al segundo código :00401324 50 push eax // de la forma * Reference To: USER32.wsprintfA, Ord:0249h :00401325 FF15D4924000 Call dword ptr [004092D4] // XXXXX- :0040132B 8D44241C lea eax, dword ptr [esp+1C] // y :0040132F 83C40C add esp, 0000000C // lo :00401332 50 push eax // concatena :00401333 56 push esi // al primer * Reference To: KERNEL32.lstrcatA, Ord:0266h :00401334 FF153C924000 Call dword ptr [0040923C] // codigo quedando XXXXX-XXXXX- :0040133A 8BC3 mov eax, ebx :0040133C 803B00 cmp byte ptr [ebx], 00 :0040133F 7418 je 00401359 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401357(C) :00401341 0FBE08 movsx ecx, byte ptr [eax] // Lee caracter de 'Black Fenix' :00401344 50 push eax // pasa puntero a la cadena para CharNext :00401345 8D2C89 lea ebp, dword ptr [ecx+4*ecx] // código = caracter*4+caracter :00401348 8D0C69 lea ecx, dword ptr [ecx+2*ebp] // codigo = codigo*2+caracter :0040134B 8D2C4D01000000 lea ebp, dword ptr [2*ecx+00000001] // codigo = codigo*2+1 :00401352 FFD7 call edi // llama a CharNext :00401354 803800 cmp byte ptr [eax], 00 // es el último caracter ? :00401357 75E8 jne 00401341 // No, pasa al siguiente
Nota: este bucle es un poco inutil ya que no se suman los valores que se obtiene con cada caracter, esto significa que el codigo siempre será sobre el último caracter de la cadena
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040133F(C) :00401359 8D442410 lea eax, dword ptr [esp+10] // esto :0040135D 55 push ebp // da formato * Possible StringData Ref from Data Obj //"%d-" :0040135E 6874624000 push 00406274 // al tercer codigo :00401363 50 push eax // de la forma * Reference To: USER32.wsprintfA, Ord:0249h :00401364 FF15D4924000 Call dword ptr [004092D4] // XXXXX- :0040136A 8D44241C lea eax, dword ptr [esp+1C] // y lo concatena :0040136E 83C40C add esp, 0000000C // al :00401371 50 push eax // primero :00401372 56 push esi // y segundo * Reference To: KERNEL32.lstrcatA, Ord:0266h :00401373 FF153C924000 Call dword ptr [0040923C] // quedando XXXXX-XXXXX-XXXXX- :00401379 8BC3 mov eax, ebx :0040137B 803B00 cmp byte ptr [ebx], 00 :0040137E 7412 je 00401392 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401390(C) :00401380 0FBE08 movsx ecx, byte ptr [eax] // lee caracter de 'Black Fenix' :00401383 50 push eax // pasa la cadena como argumento de CharNext :00401384 8D2C8D1D000000 lea ebp, dword ptr [4*ecx+0000001D] // código = 4*caracter+1d :0040138B FFD7 call edi // llama a CharNext :0040138D 803800 cmp byte ptr [eax], 00 // es el último caracter ? :00401390 75EE jne 00401380 // No, pasa al siguiente caracter Nota: este bucle es un poco inutil ya que no se suman los valores que se obtiene con cada caracter, esto significa que el codigo siempre será sobre el último caracter de la cadena
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040137E(C) :00401392 8D442410 lea eax, dword ptr [esp+10] // da formato :00401396 55 push ebp // al último código * Possible StringData Ref from Data Obj //"%d" // de la forma :00401397 6870624000 push 00406270 // XXXXX :0040139C 50 push eax * Reference To: USER32.wsprintfA, Ord:0249h :0040139D FF15D4924000 Call dword ptr [004092D4] :004013A3 8D44241C lea eax, dword ptr [esp+1C] // concatena :004013A7 83C40C add esp, 0000000C // el último :004013AA 50 push eax // código :004013AB 56 push esi // con los restantes * Reference To: KERNEL32.lstrcatA, Ord:0266h :004013AC FF153C924000 Call dword ptr [0040923C] // quedando XXXXX-XXXXX-XXXXX-XXXXX :004013B2 5D pop ebp :004013B3 5F pop edi :004013B4 5E pop esi :004013B5 5B pop ebx :004013B6 81C400010000 add esp, 00000100 :004013BC C3 ret
En el código aparece un función llamada lstrcat, esta función se encarga de concatenar dos cadenas terminadas en nulo, aquí tienes una descripción de su funcionamiento.
La función lstrcat añade una cadena al final de otra (concatena cadenas)
LPTSTRlstrcat(
LPTSTR lpString1, // dirección del buffer para las cadenas contatenadas
LPCTSTR lpString2 // dirección de la cadena que se añadira a la cadena lpString1
);
Parametros:
lpString1 -> Puntero a una cadena terminadas en nulo. El buffer debe ser lo suficientemente grande para contener las dos cadenas.
lpString2 -> Puntero a una cadena terminada en nulo que será añadida a lpString1
Retorna:
Si la función tiene exito retorna un puntero a lpString1.
Si la función falla retorna NULL.
Como puedes comprobar una rutina bastante sencilla. Se basa en la suma de los codigos ASCII de los caracteres que componen el nombre introducido.
El primer codigo se calcularia así:
codigo=6Ah
inicio
leer caracter
codigo=codigo ASCII caracter * 2 + codigo
pasar a siguiente caracter
si caracter <>0 ir a inicio
El segundo
codigo=Primer codigo
inicio
leer caracter
codigoaux=codigo ASCII caracter * 8 + codigo ASCII caracter
codigo=codigo+codigoaux
pasar a siguiente caracter
si caracter <>0 ir a inicio
El tercero
codigo = 0
inicio
leer caracter
codigo=((código ASCII caracter*4+codigo ASCII caracter)*2+codigo ASCII caracter)*2+1
pasar al siguiente caracter
si caracter <>0 ir a inicio
Nota: este bucle es una chorrada ya que el código siempre será en base al último caracter de la cadena, pero es así como lo calcula el programa (probablemente sea un fallo del programador).
El cuarto
codigo = 0
inicio
leer caracter
codigo:=código ASCII caracter*4+$1d;
pasar al siguiente caracter
si caracter <>0 ir a inicio
Nota: este bucle tambien es una chorrada ya que el código siempre sera en base al último caracter de la cadena, pero es así como lo calcula el programa (probablemente sea otro fallo del programador)
Bueno ahora ya puedes escribir un programilla en C o Pascal que genere los numeros. Para los más vagos aquí teneis el código fuente de un programilla en Pascal que genera los numeros ( no esta muy currao pero funciona) :
Nota: Para des-registrar el programa una vez registrado busca la cadena Start Clean en el editor de registros de Windows y elimina la carpeta del mismo nombre una vez encontrada.
Program StartClean_KeyGenerator;
Uses crt;
Var auxcode,code1,code2,code3,code4,i:word;
caracter:byte;
Name:string[80];
strlen:word;
Begin
Writeln('StartClean v1.2 Key Generator by Black Fenix.');
Writeln('---------------------------------------------');
Write('Enter your name:');
read(Name);
Writeln;
strlen:=length(Name);
code1:=$6a;
for i:=1 to strlen do
Begincaracter:=ord(Name[i]);
code1:=caracter*2+code1;End;
code2:=code1;
for i:=1 to strlen do
Begincaracter:=ord(Name[i]);
caracter:=caracter*2;
auxcode:=caracter*8+caracter;
code2:=auxcode+code2;End;
code3:=0;
for i:=1 to strlen do
Begincaracter:=ord(Name[i]);
code3:=((caracter*4+caracter)*2+caracter)*2+1;End;
code4:=0;
for i:=1 to strlen do
Begincaracter:=ord(Name[i]);
code4:=caracter*4+$1d;End;
Write('The registration number is: ');
Writeln(code1,'-',code2,'-',code3,'-',code4);
Writeln('Enjoy it!');
End.
You are inside Reversed Minds pages. por
Mr. Silver
/ WKT! |