Como siempre pondremos en marcha
el SoftIce antes de ejecutar el programa luego ejecutamos
el programa.Iremos al Menú/Help/Register, nos aparecerá
un cuadro de diálogo donde se nos solicitan los siguientes
datos: Nombre, Compañia y código de registro.
Introduciremos lo siguiente:
Your Name: Black Fenix
Company: reversed
Registration Code: 1234567
Seguidamente pulsaremos en
OK, y como era de esperar nos aparecerá un mensaje de
error informandonos que el código de registro no es válido.
El mensaje dice lo siguiente:
![teleportdlg.jpg]()
Salimos del programa y nos
vamos al W32DAsm, desensamblamos el ejecutable (pro.exe)
y hacemos click en el botón de referencias a cadenas. Buscaremos
la cadena que aparece en el cuadro de mensaje
"We're sorry! The ...." cuando
la encontremos haremos doble click sobre esta. Veremos que
el W32DAsm nos muestra el siguiente código:
:00425705 |
8D4DF0 |
lea
ecx, dword ptr [ebp-10] |
:00425708 |
EB2F |
jmp
00425739 |
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:004256D7(C) |
:0042570A |
8945F0 |
mov
dword ptr [ebp-10], eax |
*
Possible Reference to String Resource ID=07033: "We're
sorry! The registration number you entered appears to"
|
:0042570D |
68791B0000 |
push
00001B79 |
:00425712 |
8D4DF0 |
lea
ecx, dword ptr [ebp-10] |
:00425715 |
C745FC06000000 |
mov
[ebp-04], 00000006 |
:0042571C |
E8EAD50100 |
call
00442D0B |
:00425721 |
53 |
push
ebx |
:00425722 |
53 |
push
ebx |
:00425723 |
FF75F0 |
push
[ebp-10] |
:00425726 |
C745FC07000000 |
mov
[ebp-04], 00000007 |
:0042572D |
E8EF3F0200 |
call
00449721 |
:00425732 |
834DFCFF |
or
dword ptr [ebp-04], FFFFFFFF |
:00425736 |
8D4DF0 |
lea
ecx, dword ptr [ebp-10] |
Como podemos comprobar si examinamos
el código, en la línea 42570d se hace referencia a la cadena
que estamos buscando, ahora, vamos a buscar el salto que
nos envia a este lugar. Vemos que hay un salto en 4256d7
que hace referencia a la línea que hay por encima de 42570d,
por lo que vamos a ver que es lo que hace que se nos envie
aquí. nos desplazaremos por la ventana de código hasta llegar
a la línea 4256d7 y veremos lo siguiente:
:004256C4 |
8D4DF0 |
lea
ecx, dword ptr [ebp-10] |
:004256C7 |
EB70 |
jmp
00425739 |
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:00425691(C) |
:004256C9 |
57 |
push
edi |
//
pasa como parametro la dirección del Nombre a registrar
|
:004256CA |
E809090000 |
call
00425FD8 |
//
Esta función cálcula el número de série válido y lo
retorna en EAX |
:004256CF |
85C0 |
test
eax, eax |
//
si EAX<>0 el número que hay en EAX es el número
válido, si EAX=0 no se puede calcular un número para
el nombre introducido |
:004256D1 |
A174B34700 |
mov
eax, dword ptr [0047B374] |
:004256D6 |
59 |
pop
ecx |
:004256D7 |
7531 |
jne
0042570A |
//
salta a mostrar el mensaje de error |
:004256D9 |
8945F0 |
mov
dword ptr [ebp-10], eax |
*
Possible Reference to String Resource ID=07032: "You
haven't entered a valid username. Your username must
be" |
:004256DC |
68781B0000 |
push
00001B78 |
:004256E1 |
8D4DF0 |
lea
ecx, dword ptr [ebp-10] |
:004256E4 |
C745FC04000000 |
mov
[ebp-04], 00000004 |
Parece que la llamada en 4256CA,
condiciona bastante el salto que nos envia al mensaje de
error, por lo que vamos a comprobar que es lo que se le
pasa a esta función poniendole un BPX en el Soft-Ice. Ejecutamos
el programa, vamos a Menu/Help/Register, rellenamos los
datos igual que antes y antes de pulsar Enter activamos
el Soft-Ice y ponemos un BPX MessageBoxA, salimos del Soft-Ice
(Ctrl+D) y pulsamos OK, el BPX habrá surtido efecto y estaremos
de nuevo en el Soft-Ice. Pulsamos F12 para ir al código
que llamó al cuadro de mensaje, y ahora ya podremos poner
un BPX en 4256CA. Salimos del Soft-Ice y volvemos a pulsar
el botón OK. Ahora se activará el Soft-Ice antes de que
aparezca el cuadro de diálogo y estaremos en la línea 4256CA,
vamos a ver a que apunta EDI con:
>d edi
En la ventana de datos veremos
que aparece nuestro nombre (Black Fenix para el ejemplo),
ya sabemos que ha esta función se le pasa la dirección de
nuestro nombre, por lo que es posible que esta sea nuestra
función.Pulsaremos F10 para que se ejecute la llamada. Hechando
un vistazo a los registros que se han modificado, veremos
que EAX contiene el siguiente valor: 51FAE285, vamos a ver
el valor decimal de este número con:
> ? eax
Veremos que EAX tiene el valor
decimal 1375396485
mmm..., parece
un número válido. Probemosló. Salimos del Soft-Ice (Ctrl+D)
y cambiamos el número 1234567 por 1375396485, pulsamos OK
y sorpresa, el programa se ha registrado. Bueno ya sabemos
que función se encarga de realizar el cálculo del número
y ademas sabemos que lo devuelve en EAX, si examinamos el
código anterior veremos que lo que se comprueba, es que
ese número no sea 0. Volveremos a desensamblar el EXE y
iremos a la posición de código 4256CA, luego iremos a la
llamada que se hace en esta línea (call 00425fd8) con Goto/Code
Location (introduce 425fd8 y pulsa OK). Allí veremos el
siguiente código,(recuerda que EDI apuntaba al nombre antes
de entrar a la función).
:00425FD8 |
57 |
push
edi |
//
guarda puntero al nombre |
:00425FD9 |
8B7C2408 |
mov
edi, dword ptr [esp+08] |
//
copia la dirección del nombre |
:00425FDD |
85FF |
test
edi, edi |
//
mira si es válida <> NULL |
:00425FDF |
7409 |
je
00425FEA |
//
si es NULL no se puede calcular el número |
:00425FE1 |
57 |
push
edi |
//
guarda puntero a la cadena |
:00425FE2 |
E879560000 |
call
0042B660 |
//
esta función cálcula la longitud, resultado en en EAX
|
:00425FE7 |
59 |
pop
ecx |
:00425FE8 |
EB02 |
jmp
00425FEC |
//
salta para continuar con el cálculo del número |
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:00425FDF(C) |
:00425FEA |
33C0 |
xor
eax, eax |
//
devuelve 0, ya que el nombre introducido es una cadena
nula |
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:00425FE8(U) |
:00425FEC |
83F805 |
cmp
eax, 00000005 |
//
comprueba que la longitud del nombre sea > 5 |
:00425FEF |
7304 |
jnb
00425FF5 |
//
si no es inferior salta y continua con el cálculo |
:00425FF1 |
33C0 |
xor
eax, eax |
//
error, el numero es inferior a 5 caracteres |
:00425FF3 |
5F |
pop
edi |
//
restaura la pila |
:00425FF4 |
C3 |
ret
|
//
y vuelve |
|
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:00425FEF(C) |
:00425FF5 |
53 |
push
ebx |
:00425FF6 |
56 |
push
esi |
:00425FF7 |
BEA4E4FE5D |
mov
esi, 5DFEE4A4 |
//
carga un valor constante en ESI |
:00425FFC |
33DB |
xor
ebx, ebx |
//
pone EBX a 0 (prepara el contador) |
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:0042601E(U) |
:00425FFE |
85FF |
test
edi, edi |
//
vuelve a comprobar que la cadena no sea nula |
:00426000 |
7409 |
je
0042600B |
//
si edi apunta a una cadena nula, no se puede calcular
el número |
:00426002 |
57 |
push
edi |
//
pasa puntero a la cadena |
:00426003 |
E858560000 |
call
0042B660 |
//
cálcula longitud , resultado en EAX |
:00426008 |
59 |
pop
ecx |
:00426009 |
EB02 |
jmp
0042600D |
//
continua con el cálculo |
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:00426000(C) |
:0042600B |
33C0 |
xor
eax, eax |
//
no se puede calcular el número EAX=0 |
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:00426009(U) |
:0042600D |
83C0FC |
add
eax, FFFFFFFC |
//
suma FFFFFFFC a la longitud de la cadena (equivale a
restarle 4) |
:00426010 |
3BD8 |
cmp
ebx, eax |
//
comprueba si el contador >= que EAX |
:00426012 |
730C |
jnb
00426020 |
//
si es inferior salta y fin del cálculo |
:00426014 |
33343B |
xor
esi, dword ptr [ebx+edi] |
//
hace XOR de la constante con los 4 caracteres a los
que apunta [EDI+EBX] |
:00426017 |
F6C340 |
test
bl, 40 |
//
mira si el byte bajo del contador supera 64 caracteres
(40h) |
:0042601A |
7401 |
je
0042601D |
//
si es asi salta |
:0042601C |
43 |
inc
ebx |
//
incrementa contador de caracteres |
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:0042601A(C) |
:0042601D |
43 |
inc
ebx |
//
incrementa contador de caracteres |
:0042601E |
EBDE |
jmp
00425FFE |
//
salta para continuar con el cálculo |
*
Referenced by a (U)nconditional or (C)onditional Jump
at Address: |:00426012(C) |
:00426020 |
8BC6 |
mov
eax, esi |
//
copia el número calculado a eax |
:00426022 |
5E |
pop
esi |
//
restaura la pila |
:00426023 |
5B |
pop
ebx |
:00426024 |
5F |
pop
edi |
:00426025 |
C3 |
ret
|
//
retorna de la función con el número válido en EAX |
|
Bueno, examinando el código,
ya podemos asegurar que aquí se calcula el número válido,
si analizamos el algoritmo de cálculo veremos que es bastante
sencillo. Primero se comprueba que el nombre apunte a una
cadena válida, luego que tenga una longitud => que 5
caracteres, luego se carga un valor constante en ESI (5DFEE4A4),
se inicializa un contador a 0 (EBX), se vuelve a calcular
la longitud del nombre (cosa innecesaria) y se va haciendo
un XOR con los cuatro carácteres del nombre que son apuntados
por EDI+EBX sobre ESI dentro de un bucle que se procesa
longitud(nombre)-4 veces. Tambien se comprueba que el contador
de carácteres EBX no sea superior que 64, en caso de que
esto sea así se incrementa el contador doblemente. Una vez
computado el número, se copia a EAX y se retorna de la función.
Bueno es hora de implementar
un algoritmo en Pascal que realize este cálculo, esta vez
he usado el compilador gratuito Free Pascal de 32 bits en
su versión windows.
Program TelePort_Pro_v1_29_KeyGen;
Uses Crt;
Const Seed=$5DFEE4A4;
Var Name:string[80];
Nlength,contador:integer;
regnum:dword;
dptr:^dword;
Begin
textcolor(10);
Writeln('Teleport Pro v1.29. Key Generator By Black Fenix 15/01/2000');
textcolor(15);
Writeln('-----------------------------------------------------------');
textcolor(7);
Writeln;
Write('Enter your name (min 5 characters):');
readln(Name);
Nlength:=length(Name);
if (Nlength<5) then
Begin
Writeln('Sorry, the length of the name must be greater than 5 characters.');
Halt(0);
End;
// copia puntero al primer caracter
regnum:=seed;
Nlength:=Nlength+$fffffc; { es lo mismo que restarle 4, pero así lo hacemos igual que el original :-) }
contador:=1;
while (contador<=Nlength) do
Begin
dptr:=@Name[contador];
regnum:=regnum xor dptr^;
if (contador=$40) then
Begin
writeln('hola');
inc(contador);
End;
inc(contador);
End;
writeln;
Write('Your registration number is:');
textcolor(15);
write(regnum);
textcolor(7);
writeln;
End.
|