Generación de Seriales II
Anteriormente ya había publicado una primera versión de como conseguir el número de serie de un programa (Generación de Seriales) en aquella oportunidad, las cosas eran más sencillas, el número de serie requerido se mostraba dentro del código Assembler, por lo que no era necesario realizar un análisis del algoritmo que lo generaba, solo era cuestión de buscar y bingo.
Este caso es diferente, llevaba días usando un programa de prueba. Llegado el día 15, me solicitaba que realizara un registro, justo cuando más necesitaba del dichoso programa. Para salvar el problema busque por otros programas que me salvaran del apuro, pero me quedo como tarea conseguir el número de serie para registrarlo y continuar usándolo.
Varios días después me he puesto en la tarea de hacerlo, y después de varias horas lo he conseguido. Aquí les dejo el detalle del proceso, como siempre, solo con fines educativos.
Empezamos cargando la aplicación en OllyDbg, presionamos F9, para que se ejecute el programa hasta que nos muestre la pantalla inicial donde nos solicitará el registro. Seleccionamos la opción Register Info y nos pedirá el ingreso del usuario y del número de serie. En este punto probamos a ingresar cualquier dato. Nos mostrará el siguiente mensaje de alerta indicándonos que los datos son incorrectos.

Una vez que nos muestra el mensaje, vamos a OllyDbg y presionamos F12 para poner pausa a la ejecución del programa, presionamos Alt+K aquí podremos ver las llamadas a las funciones.

Dentro de estas destaca una última llamada en la instrucción 00401C41, posteriormente se tiene la llamada a la función que se encarga de mostrar el mensaje de advertencia al usuario de que la clave es incorrecta.
En OllyDbg, ponemos un punto de interrupción en la instrucción 0041C41 presionando F2, reiniciamos la ejecución del programa en OllyDbg, presionamos Ctrl+F2, posteriormente F9, hasta que se muestre la pantalla de registro, ingresamos los datos y nuevamente presionamos en el botón de registro. Esta vez se detendrá en el punto de interrupción, antes de mostrarnos el mensaje.

Unas líneas más arriba podemos ver las cadenas de texto con los mensajes que se muestran. Si vemos más arriba podremos encontrar algunos de los mensajes mostrados en la pantalla de registro, en estos ponemos un punto de interrupción en la dirección 00401BD6 (esta es una dirección aleatoria), se podría escoger cualquier otra dirección cercana a estos mensajes, ya que después de mostrar los mensajes es que se debería realizar la verificación del número de serie. En mi caso seleccione la dirección 00401BD6.
Reiniciamos posteriormente la ejecución del programa hasta el punto de interrupción. Aquí empieza nuestro análisis. Vemos que en la dirección 00401BE6 se verifica si se ingreso el nombre del usuario en la respectiva caja de texto, sino se ingreso se va a la dirección 00401C41, que es donde se muestra el mensaje de error. En este caso ingresamos todos los datos, así que pasará esta validación.

En la dirección 00401BFA realiza la misma comparación para el número de serie, que para nuestro caso también pasará. Si continuamos la inspección unas direcciones mas abajo, podremos ver que en la dirección 00401C09 se realiza la llamada a una función en la dirección 00402BE0, que recibe como parámetro el nombre de usuario. Presionamos F8 hasta que la ejecución llegue a la dirección 00401C09, una vez aquí presionamos F7 para entrar a ver esta función.

Aquí podemos ver que en la dirección 00402BE8 se recupera la longitud del nombre de usuario, se inicializan algunas variables y se empieza a recuperar cada carácter del nombre de usuario. Se verifica en la dirección 00402BF1 si es menor al Hexadecimal 41, que corresponde a 65 en decimal, es decir el carácter “A” en código ASCII. En la dirección 00402BFA se verifica que sea menor que el hexadecimal 5A, que equivale al decimal 90, la letra “Z” en código ASCII. Es decir si es el carácter esta dentro del rango de la A a la Z, se salta hasta la dirección 00402C0A. De lo contrario se realiza una conversión de las letras minúsculas a mayúsculas. Para ello se le resta 32 al código ASCII, 20 en hexadecimal, 00402C05.
En la dirección 00402C0F se empiezan a realizar algunas operaciones, en las que se va sumando los valores de los códigos ASCII presentes en EAX y los almacena en EDI (ADD EDI, EAX) posteriormente incrementa el contador ECX en la dirección 00402C11 y recupera el siguiente carácter de la cadena en nuestro caso, de la cadena “cesar”. Se continua hasta completar toda la cadena, al final EDI contendrá la suma de los valores ASCII de cada carácter presente en la cadena del nombre de usuario. Para el caso mostrado el valor es 16E, este valor es almacenado en EAX y en la dirección 00402C25 se realiza una operación XOR con el número 2468 (hexadecimal), en este caso el resultado de esta operación es 2506 (hexadecimal). Unas lineas más abajo se termina la función, devuelve el resultado y la ejecución continua en la función principal.
Una vez en la función principal el numero devuelto es almacenado en el registro EBP el cual será comparado más tarde con el registro EAX. En 00401C1C se efectúa otra llamada a una función, en este caso la función en la dirección 00402C30. Veamos está función en detalle.

Dentro de esta función podemos ver lo siguiente, a partir del número de serie ingresado, se recupera su longitud (dirección 00402C37) y se inicia un bucle por cada carácter presente en el número de serie. En la dirección 00402C3E se realiza una operación en la que se asigna a EDX el valor del contenido de ESI + ESI * 4, en la dirección 00402C43 se recupera el siguiente carácter y se disminuye el contador en 1, el valor ASCII del carácter actual se almacena en ESI y se efectúa la siguiente operación ESI = ESI + EDX*2 – 30. Estas operaciones se muestran en el siguiente seudo-código. Se repite la operación por cada carácter y se almacena el resultado en EAX, en la dirección 00402C59. Finalmente antes de devolver el resultado, se efectúa una operación XOR entre el valor de EAX y el número 1357 (hexadecimal).
funcion validar(nroSerie){
var1 = 0
i = 0
si longitud(nroSerie) > 0 entonces
hacer
var2 = var1 + var1 * 4 // todas las operaciones en hexadecimal
var1 = 0
var1 = nroSerie[i] //carácter en la posición i
i = i + 1
var1 = var1 + var2 * 2 – 30 //todas las operaciones en hexadecimal
hasta i < longitud(nroSerie)
fin si
var1 = var1 XOR 1357 //1357 en hexadecimal
return var1
}
El resultado de esta función es devuelto a la función principal donde se compara EBP con EAX (00401C24), recordemos que EBP contiene el resultado de la primera función. Si ambos resultados son iguales nos mostrará el mensaje “Thank you for using XXXX, register successfully”. De lo contrario nos mostrará el mensaje “Sorry, register failed, please try again”

A partir de aquí y con los algoritmos de verificación de la clave conocidos podemos obtener el número de serie valido, en este caso para el nombre de usuario “cesar”. El resultado de ejecutar la función para convertir a mayúsculas el nombre de usuario nos devolvía el valor 2506. A partir de este número realizamos las operaciones inversas a las mostradas en la función validar, para obtener el número de serie.
Empezamos realizando una operación XOR entre 2506 y 1357
2506 XOR 1357 = 3651
Este número es el último valor de la variable var1, a partir de aquí requeriremos realizar dos operaciones, la primera para hallar var2 y la segunda para buscar por el caracter.
var2 = (3651 – var1 + 30) / 2
var1 = var2 / 5
Estas son las operaciones inversas de las mostradas en la función validar, aquí var1 será el caracter buscado, empezaremos asignado un caracter al azar, teniendo en consideración que al reemplazar var1 el resultado de dicha función debe ser divisible por “D = 2*5” (hexadecimal). Todas las operaciones son en hexadecimal. Empezaremos por el caracter I que corresponde al ASCII 73 (49 en hexadecimal) al calcular los valores tendriamos.
var2 = (3651 – 49 + 30) / 2 = 1B1C
var1 = 1B1C / 5 = 56C
A partir de aqui se repetiran las operaciones, queda como labor del lector completar las operaciones necesarias. El resultado final de estas operaciones es que el número de serie buscado es =88I, reiniciamos la ejecución del programa normalmente y probamos con el valor.

Listo nuestro programa ha sido registrado. A partir de aquí ya se puede elaborar el Keygen necesario para obtener los números de serie que se requieran.
