Como hacer un Key Generator para el Winzip 7.0 por Black Fenix |
Otra vez estoy aqu�, esta vez vamos a subir un poco el list�n y vamos a hacer un generador de numeros de serie para el WinZip 7.0. que es lo que un verdadero cracker debe saber hacer.
SoftIce para windows
W32Dasm
Turbo Pascal, para hacer el Key Generator (Opcional)
Como siempre pondremos en marcha el SoftIce antes de ejecutar el programa luego ejecutamos el programa. Cada vez que lo ejecutamos aparece una ventana que nos comunica que el programa es una versi�n totalmente funcional pero no registrada, dandonos la opci�n de continuar, salir o introducir el numero de registro.
Esta �ltima opci�n es la que seleccionaremos haciendo click sobre el boton 'Enter Registration Code'.Ahora nos aparece una ventana donde podemos introducirle los siguientes datos:
Name:
Registration #:
Esto es el nombre y el c�digo de registros, actuaremos como es habitual en este tipo de casos.
Activamos el SoftIce (Ctrl+D) y ponemos un bpx getdlgitemtexta, salimos del SoftIce (Ctrl+D) e introducimos los datos por ejemplo
Name : Black Fenix
Registration #: 12345
pulsamos Ok y
Boom! estamos de nuevo en el SoftIce el bpx a surtido efecto, pulsamos F12 y aterrizamos en el c�digo fuente del ejecutable del programa WinZip32.exe en estos momentos el programa est� leyendo el nombre que le hubiesemos introducido, en mi caso 'Black Fenix' la direcci�n donde lo almacena est� en EBX puedes
comprobarlo haciendo D EBX (dentro del SoftIce).
Pulsamos g para seguir con la ejecuci�n del programa y de nuevo apareceremos en el SoftIce, esta vez el programa esta leyendo el numero que le hemos introducido, F12 y estaremos en el c�digo del ejecutable. Ahora vamos a ir trazando paso a paso y vamos a ir viendo que es lo que hace el programa con el nombre y nuestro n�mero no v�lido.
Esto es lo que podemos ver despues de pulsar F12.
|
:00408036 | FF150C844600 | Call dword ptr [0046840C] | |
:0040803C | 56 | push esi | // En esta direcci�n est� nuestro numero (malo) |
:0040803D | E857160200 | call 00429699 | // llama a una funci�n (descartada) |
:00408042 | 59 | pop ecx | |
:00408043 | 56 | push esi | // En esta direcci�n est� nuestro numero (malo) |
:00408044 | E879160200 | call 004296C2 | // llama a una funci�n (descartada) |
:00408049 | 803D28D9470000 | cmp byte ptr [0047D928], 00 | // mira si el primer caracter del nombre es NULL |
:00408050 | 59 | pop ecx | |
:00408051 | 745F | je 004080B2 | // salta si es NULL |
:00408053 | 803D58D9470000 | cmp byte ptr [0047D958], 00 | // mira si el primer caracter del n�mero es NULL |
:0040805A | 7456 | je 004080B2 | // salta si es NULL |
:0040805C | E8EAFAFFFF | call 00407B4B | // llama a una funci�n que retorna un valor en EAX |
:00408061 | 85C0 | test eax, eax | // esto es sospechoso |
:00408063 | 744D | je 004080B2 | // salta si es 0 hmmm... |
:00408065 | 53 | push ebx |
Un vistazo a este c�digo nos permite afirmar con toda seguridad que si el numero o la cadena no se introdujeron (esto se comprueba con los cmp byte ptr [XXXXXXXXX], 0) el programa salta a una parte donde se nos comunica que los datos introducidos no son correctos. Tambi�n sucede lo mismo si al regresar de la llamada a 407B4B EAX es igual a 0, esto es muuyyyy sospechoso, por lo que al llegar a esta funci�n pulsaremos F8 para trazarla paso a paso.
Trazando poco a poco dentro de la funci�n anterior iremos viendo como el programa realiza una serie de operaciones sobre el nombre, entre ellas supresi�n de espacios etc. Pero no ser� hasta llegar a la posici�n de c�digo 407C0E donde el programa empuja a la pila el nombre y posteriormente nos aparecer� un misterioso numero.
:00407C0E | 8D85C0FEFFFF | lea eax, dword ptr [ebp+FFFFFEC0] | // lee direcci�n vacia |
:00407C14 | 50 | push eax | // la pasa como parametro |
:00407C15 | 57 | push edi | // EDI apunta a nuestro numero |
:00407C16 | E8AB000000 | call 00407CC6 | |
:00407C1B | 59 | pop ecx | |
:00407C1C | BE58D94700 | mov esi, 0047D958 | // ESI apunta a nuestro numero |
:00407C21 | 59 | pop ecx | |
:00407C22 | 8D85C0FEFFFF | lea eax, dword ptr [ebp+FFFFFEC0] | // lee direcci�n del otro n�mero misterioso |
:00407C28 | 56 | push esi | // empuja nuestro numero a la pila |
:00407C29 | 50 | push eax | // empuja el otro numero a la pila |
:00407C2A | E8D1FC0400 | call 00457900 | // llama a una misteriosa funci�n |
:00407C2F | F7D8 | neg eax | // invierte EAX |
Despues de llamar a la funcion 407cc6, el codigo siguiente obtiene un numero misterioso de la pila y lo pasa como argumento junto con nuestro otro numero a la funci�n 457900 esta funci�n retorna con un valor en EAX que resulta ser un 0 o un 1 segun la 'semejanza' de los dos numeros. En mi caso el numero misterioso resulta ser '252714DB' y da la casualidad que si lo introducimos como numero de serie junto con el nombre 'Black Fenix' el programa se registrar�. ( Si introduces tu numero junto con tu nombre luego podras des-registrar el programa buscando el nombre y borrandolo del editor de registros de Windows, esta en la Carpeta WinZip y la clave es SN).
Ya has deducido que funci�n es la que calcula el numero v�lido, claro es muy f�cil la funci�n es la 407CC6. Bueno pues ahora borramos todos los bpx con BC * y ponemos un bpx en 00407CC6.
Pulsaremos G y continuaremos con la ejecuci�n del programa reciendo el mensaje de error correspondiente. Volvemos a pulsar en OK y esta vez estaremos en la funci�n 407CC6. Pulsamos F8 para trazarla paso a paso.
:00407CC6 | 55 | push ebp | ||
:00407CC7 | 8BEC | mov ebp, esp | ||
:00407CC9 | 51 | push ecx | ||
:00407CCA | 8B4D08 | mov ecx, dword ptr [ebp+08] | // Coge puntero al nombre | |
:00407CCD | 8365FC00 | and dword ptr [ebp-04], 00000000 | ||
:00407CD1 | 53 | push ebx | ||
:00407CD2 | 56 | push esi | ||
:00407CD3 | 8A11 | mov dl, byte ptr [ecx] | // lee primer caracter | |
:00407CD5 | 57 | push edi | // prepara registros | |
:00407CD6 | 33C0 | xor eax, eax | ||
:00407CD8 | 8BF1 | mov esi, ecx | // copia puntero al nombre | |
:00407CDA | 33FF | xor edi, edi | // EDI es el contador de caracteres | |
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407CF1(U) | ||||
// Esta parte calcula la segunda parte // del c�digo v�lido y lo deja en [ebp-4] | ||||
:00407CDC | 84D2 | test dl, dl | // comprueba que no sea un caracter nulo | |
:00407CDE | 7413 | je 00407CF3 | // si es nulo, fin de cadena y de calculo | |
:00407CE0 | 660FB6D2 | movzx dx, dl | // extiende el caracter a DX | |
:00407CE4 | 8BDF | mov ebx, edi | // copia contador de caracteres | |
:00407CE6 | 0FAFDA | imul ebx, edx | // multiplica contador x caracter actual | |
:00407CE9 | 015DFC | add dword ptr [ebp-04], ebx | // lo suma a la segunda parte del codigo finbal | |
:00407CEC | 8A5601 | mov dl, byte ptr [esi+01] | // coge siguiente caracter | |
:00407CEF | 47 | inc edi | // incrementa contador | |
:00407CF0 | 46 | inc esi | // y puntero | |
:00407CF1 | EBE9 | jmp 00407CDC | // pasa al siguiente caracter // Aqu� se inicia el c�lculo de la primera parte // del c�digo v�lido | |
:00407CF3 | C705ECD3470001000000 | mov dword ptr [0047D3EC], 00000001 | ||
:00407CFD | 8BF1 | mov esi, ecx | // copia puntero al nombre | |
:00407CFF | 8A09 | mov cl, byte ptr [ecx] | // coge el primer caracter | |
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407D1C(U) | ||||
:00407D01 | 84C9 | test cl, cl | // comprueba si es 0 | |
:00407D03 | 7419 | je 00407D1E | // salta a 407D1E si lo es | |
:00407D05 | 660FB6C9 | movzx cx, cl | // extiende cl sin signo a CX (CX=caracter actual) | |
:00407D09 | 6821100000 | push 00001021 | // empuja 1021h = 4219 | |
:00407D0E | 51 | push ecx | // y el caracter actual | |
:00407D0F | 50 | push eax | // y eax (la primera vez EAX = 0 ) | |
:00407D10 | E82A000000 | call 00407D3F | // llama a una funci�n (ver m�s abajo) // que realiza un c�lculo con el caracter actual | |
:00407D15 | 8A4E01 | mov cl, byte ptr [esi+01] | // coge el siguiente caracter de la cadena | |
:00407D18 | 83C40C | add esp, 0000000C | // ajusta puntero de pila | |
:00407D1B | 46 | inc esi | // incrementa el puntero de la cadena | |
:00407D1C | EBE3 | jmp 00407D01 | // salta hacia atras 407D01 | |
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407D03(C) | ||||
:00407D1E | 0FB74DFC | movzx ecx, word ptr [ebp-04] | // coge 4 ultimos digitos del c�digo | |
:00407D22 | 83C063 | add eax, 00000063 | // a�ade 63 a los 4 primeros digitos del c�digo | |
:00407D25 | 51 | push ecx | // empuja a la pila | |
:00407D26 | 0FB7C0 | movzx eax, ax | // extiende los 4 primeors digitos del codigo a EAX | |
:00407D29 | 50 | push eax | // empuja EAX | |
* Possible StringData Ref from Data Obj //"%04X%04X" | ||||
:00407D2A | 6884F44600 | push 0046F484 | // esta funci�n se encarga de unirlos | |
:00407D2F | FF750C | push [ebp+0C] | // y salvarlos como una cadena de caracteres | |
:00407D32 | E869E20400 | call 00455FA0 | // de longitud m�xima 8 caracteres y en formato hexadecimal | |
:00407D37 | 83C410 | add esp, 00000010 | // si la primera parte del c�digo tiene m�s de cuatro | |
:00407D3A | 5F | pop edi | // caracteres, estos prevaleceran sobre la segunda | |
:00407D3B | 5E | pop esi | // parte del c�digo de la cual se suprimiran los | |
:00407D3C | 5B | pop ebx | // caracteres necesarios por la izquierda para dar | |
:00407D3D | C9 | leave | // cabida a los de la primera parte del c�digo | |
:00407D3E | C3 | ret | ||
* Referenced by a CALL at Addresses: |:00407D10 , :00407DFB | ||||
:00407D3F | 55 | push ebp | // guarda estado de la pila | |
:00407D40 | 8BEC | mov ebp, esp | ||
:00407D42 | 8B4508 | mov eax, dword ptr [ebp+08] | // eax = coge c�digo actual | |
:00407D45 | 56 | push esi | ||
:00407D46 | 33C9 | xor ecx, ecx | ||
:00407D48 | 6A08 | push 00000008 | // empuja 8 a la pila | |
:00407D4A | 8A6D0C | mov ch, byte ptr [ebp+0C] | // lee caracter pasado en CH | |
:00407D4D | 5A | pop edx | // inicia un contador con 8 pasos | |
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407D65(C) | ||||
:00407D4E | 8BF1 | mov esi, ecx | // copia caracter a esi | |
:00407D50 | 33F0 | xor esi, eax | // XOR con c�digo actual | |
:00407D52 | 66F7C60080 | test si, 8000 | // comprueba si es� por debajo de 8000h | |
:00407D57 | 7407 | je 00407D60 | // si salta | |
:00407D59 | 03C0 | add eax, eax | // no, duplica el codigo actual | |
:00407D5B | 334510 | xor eax, dword ptr [ebp+10] | // hace un xor con 1021h (ver argumentos antes del call) | |
:00407D5E | EB02 | jmp 00407D62 | // salta hacia abajo | |
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407D57(C) | ||||
:00407D60 | D1E0 | shl eax, 1 | // desplaza un bit a la izquierda el codigo actual | |
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407D5E(U) | ||||
:00407D62 | D1E1 | shl ecx, 1 | // desplaza un bit a la izquierda el caracter actual | |
:00407D64 | 4A | dec edx | // decrementa contador | |
:00407D65 | 75E7 | jne 00407D4E | // sigue si no es 0 | |
:00407D67 | 5E | pop esi | ||
:00407D68 | 5D | pop ebp | ||
:00407D69 | C3 | ret |
Bueno, es una rutina bastante larga pero con los comentarios que he puesto creo que podras entenderla sin problemas. Pero todo no queda aqu� ya que si seguimos la ejecuci�n del programa podremos comprobrar que se vuelve a generar otro numero sospechoso, a partir de una cadena que equivale a nuestro nombre pero
esta vez el nombre entero est� en minusculas. Esto quiere decir que el programa tiene dos numeros de registro v�lidos por nombre, uno para el nombre tal y como se introdujo y otro para el nombre en minusculas. Para nuestra decepci�n el programa no usa la misma rutina de c�lculo pero si que es muy similar a la que usa para calcular el primer c�digo, aqu� tienes un volcado de la rutina. S�lo he marcado lo que la hace diferente, el resto se comporta igual que la anterior.
:00407D6A | 55 | push ebp | ||
:00407D6B | 8BEC | mov ebp, esp | ||
:00407D6D | 81ECCC000000 | sub esp, 000000CC | ||
:00407D73 | 53 | push ebx | ||
:00407D74 | 56 | push esi | ||
:00407D75 | 57 | push edi | ||
:00407D76 | 8D8534FFFFFF | lea eax, dword ptr [ebp+FFFFFF34] | // Parte de este c�digo es para | |
:00407D7C | FF7508 | push [ebp+08] | // comprobar que | |
:00407D7F | 33DB | xor ebx, ebx | // el primer c�digo | |
:00407D81 | 895DFC | mov dword ptr [ebp-04], ebx | // se gener� correctamente | |
:00407D84 | 33FF | xor edi, edi | // | |
:00407D86 | 50 | push eax | // | |
:00407D87 | E894E00400 | call 00455E20 | // | |
:00407D8C | 59 | pop ecx | // | |
:00407D8D | 8D8534FFFFFF | lea eax, dword ptr [ebp+FFFFFF34] | // | |
:00407D93 | 59 | pop ecx | // | |
:00407D94 | 50 | push eax | // | |
:00407D95 | E836D60500 | call 004653D0 | // | |
:00407D9A | 80BD34FFFFFF00 | cmp byte ptr [ebp+FFFFFF34], 00 | // | |
:00407DA1 | 59 | pop ecx | // | |
:00407DA2 | 8DB534FFFFFF | lea esi, dword ptr [ebp+FFFFFF34] | // | |
:00407DA8 | 741F | je 00407DC9 | // | |
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407DC7(C) | ||||
:00407DAA | 0FB606 | movzx eax, byte ptr [esi] | ||
:00407DAD | 50 | push eax | // + | |
:00407DAE | E85DF80400 | call 00457610 | // + Esta es una de la diferencia respecto a la otra // + Esta funci�n comprueba la validez del caracter actual // + retornando un valor <> de 0 si es v�lido // + rutina | |
:00407DB3 | 85C0 | test eax, eax | // + si retorna 0 | |
:00407DB5 | 59 | pop ecx | // + el caracter no es v�lido y no se tiene | |
:00407DB6 | 740B | je 00407DC3 | // + en cuenta para el c�lculo | |
:00407DB8 | 660FB606 | movzx ax, byte ptr [esi] | ||
:00407DBC | 0FAFC3 | imul eax, ebx | ||
:00407DBF | 0145FC | add dword ptr [ebp-04], eax | ||
:00407DC2 | 43 | inc ebx | ||
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407DB6(C) | ||||
:00407DC3 | 46 | inc esi | ||
:00407DC4 | 803E00 | cmp byte ptr [esi], 00 | ||
:00407DC7 | 75E1 | jne 00407DAA | ||
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407DA8(C) | ||||
:00407DC9 | 80BD34FFFFFF00 | cmp byte ptr [ebp+FFFFFF34], 00 | ||
:00407DD0 | C705ECD3470001000000 | mov dword ptr [0047D3EC], 00000001 | ||
:00407DDA | 8DB534FFFFFF | lea esi, dword ptr [ebp+FFFFFF34] | ||
:00407DE0 | 7429 | je 00407E0B | ||
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407E09(C) | ||||
:00407DE2 | 0FB606 | movzx eax, byte ptr [esi] | ||
:00407DE5 | 50 | push eax | // + | |
:00407DE6 | E825F80400 | call 00457610 | // + Esta es otra de las diferencias respecto a | |
:00407DEB | 85C0 | test eax, eax | // + a la otra rutina se comporta igual que | |
:00407DED | 59 | pop ecx | // + el call anterior (si caracter no es valido | |
:00407DEE | 7415 | je 00407E05 | // + no lo procesa) | |
:00407DF0 | 660FB606 | movzx ax, byte ptr [esi] | // + | |
:00407DF4 | 6821100000 | push 00001021 | ||
:00407DF9 | 50 | push eax | ||
:00407DFA | 57 | push edi | ||
:00407DFB | E83FFFFFFF | call 00407D3F | ||
:00407E00 | 83C40C | add esp, 0000000C | ||
:00407E03 | 8BF8 | mov edi, eax | ||
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407DEE(C) | ||||
:00407E05 | 46 | inc esi | ||
:00407E06 | 803E00 | cmp byte ptr [esi], 00 | ||
:00407E09 | 75D7 | jne 00407DE2 | ||
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00407DE0(C) | ||||
:00407E0B | 0FB745FC | movzx eax, word ptr [ebp-04] | ||
:00407E0F | 8B750C | mov esi, dword ptr [ebp+0C] | ||
:00407E12 | 83C763 | add edi, 00000063 | ||
:00407E15 | 50 | push eax | ||
:00407E16 | 0FB7C7 | movzx eax, di | ||
:00407E19 | 50 | push eax | ||
* Possible StringData Ref from Data Obj //"%04u%04u" | ||||
:00407E1A | 6890F44600 | push 0046F490 | ||
:00407E1F | 56 | push esi | ||
:00407E20 | E87BE10400 | call 00455FA0 | ||
:00407E25 | 83C410 | add esp, 00000010 | ||
:00407E28 | 80660800 | and byte ptr [esi+08], 00 | ||
:00407E2C | 5F | pop edi | ||
:00407E2D | 5E | pop esi | ||
:00407E2E | 5B | pop ebx | ||
:00407E2F | C9 | leave | ||
:00407E30 | C3 | ret | ||
// Este es el volcado de la rutina llamada en los puntos marcados con + de la rutina anterior: | ||||
:00457610 | 833DBC63470001 | cmp dword ptr [004763BC], 00000001 | // comprueba algo ?? | |
:00457617 | 7E13 | jle 0045762C | // este salto no se realiza si se esta // introduciendo un numero de registro | |
:00457619 | 8B442404 | mov eax, dword ptr [esp+04] | ||
:0045761D | 6803010000 | push 00000103 | // Pasa 103h a como primer argumento | |
:00457622 | 50 | push eax | // Este argumento es el c�digo del caracter // actual | |
:00457623 | E8F82D0000 | call 0045A420 | // Llama a la funci�n | |
:00457628 | 83C408 | add esp, 00000008 | ||
:0045762B | C3 | ret |
Este es el volcado de la rutina llamada en la rutina anterior. Esta rutina retorna un valor segun el caracter pasado por la anterior, se usa para comprobar si los caracteres del nombre introducido van a ser procesados. Si retorna 0, el caracter no ser� tenido en cuenta cuando se realiza el c�lculo del segundo c�digo.
:0045A420 | 51 | push ecx | ||
:0045A421 | 8B4C2408 | mov ecx, dword ptr [esp+08] | ||
:0045A425 | 56 | push esi | ||
:0045A426 | 8D4101 | lea eax, dword ptr [ecx+01] | ||
:0045A429 | 3D00010000 | cmp eax, 00000100 | ||
:0045A42E | 7715 | ja 0045A445 | // este salto nunca se realiza cuando se esta introduciendo un c�digo de registros | |
:0045A430 | 8B15B0614700 | mov edx, dword ptr [004761B0] | // Carga puntero a un tabla | |
:0045A436 | 33C0 | xor eax, eax | // borra EAX | |
:0045A438 | 668B044A | mov ax, word ptr [edx+2*ecx] | // usa el c�digo del caracter pasado como �ndice a una tabla | |
:0045A43C | 8B4C2410 | mov ecx, dword ptr [esp+10] | // lee 103h en ecx | |
:0045A440 | 23C1 | and eax, ecx | // Realiza un AND con 103h sobre | |
:0045A442 | 5E | pop esi | // el valor de la tabla | |
:0045A443 | 59 | pop ecx | ||
:0045A444 | C3 | ret | // resultado en eax, este resultado es comprobado por las rutina marcadas con + |
El problema reside en la tabla, tenemos que copiarla para poder reproducir el algoritmo. Su contenido lo podemos encontrar a partir de la direcci�n 4761B0, son exactamente 256 valores uno por cada c�digo de caracter.
Bueno, ahora examina las dos rutinas y crea el programilla en Pascal o C que genere los dos numeros. Yo lo he hecho en Pascal, aqu� tienes el c�digo fuente. Pero recuerda copiarlo no te aportar� saber y tampoco pretenderas que te lo den todo hecho eh??.
Vuelve a examinar este documento e intenta hacerlo por ti mismo si a�n tienes dudas. Si necesitas desensamblar el WinZip puedes usar el W32Dasm para examinar mejor las rutinas aqu� expuestas.
Tambien encontrar�s el programa compilado en el mismo lugar que este documento (wzipkg.exe).
Program winzip7_KeyGenerator;
Uses Crt,strings;
{ Esta es la tabla que el WinZip usa para calcular el segundo c�digo }
Const Table:array [0..255] of byte = (
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$20,$00,$28,$00,$28,$00,$28,$00,$28,$00,$28,$00,$20,$00,$20,$00,
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$48,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,
$84,$00,$84,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$81,$00,$81,$00,$81,$00,$81,$00,$81,$00,$81,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$82,$00,$82,$00,$82,$00,$82,$00,$82,$00,$82,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$10,$00,$10,$00,$10,$00,$10,$00,$20,$00);
Var Name,Name2:string[80];
charb:byte;
Function ComputeCode2(Cadena:string):longint;
Var j:byte;
code,chard:longint;
Begin
code:=0;
for j:=1 to length(Cadena) do
Begin
chard:=ord(cadena[j]);
code:=code+(chard*(j-1));
End;
ComputeCode2:=(code shl 16) shr 16;
End;
Function ComputeCode2b(Cadena:string):longint;
Var j,k:byte;
code,chard:longint;
Begin
code:=0;
k:=0;
for j:=1 to length(Cadena) do
Begin
chard:=ord(cadena[j]);
if boolean(Table[chard*2] and $103) then
Begin
code:=code+(chard*k);
inc(k);
End;
End;
ComputeCode2b:=(code shl 16) shr 16;
End;
Function ComputeCode1(keygen: word; charb: byte; code:longint):longint;
Var j:word;
charw1,charw2:longint;
Begin
charw1:=charb shl 8;
For j:=1 to 8 do
Begin
charw2:=charw1;
charw2:=((charw2 XOR code) shl 16) shr 16;
if charw2<=$8000 then
Begin
code:=code shl 1;
End
Else
Begin
code:=code+code;
code:=(code XOR keygen);
End;
charw1:=charw1 shl 1;
End;
ComputeCode1:=code;
End;
{ Las 3 rutinas siguientes son de Trevor Carlsen }
Function Byte2Hex(numb : Byte): String; { Byte a hex String }
Const HexChars : Array[0..15] of Char = '0123456789ABCDEF';
begin
Byte2Hex[0] := #2; Byte2Hex[1] := HexChars[numb shr 4];
Byte2Hex[2] := HexChars[numb and 15];
end; { Byte2Hex }
Function Numb2Hex(numb: Word): String; { Word a hex String.}
begin
Numb2Hex := Byte2Hex(hi(numb))+Byte2Hex(lo(numb));
end; { Numb2Hex }
Function Long2Hex(L: LongInt): String; { LongInt a hex String }
begin
Long2Hex := Numb2Hex(L shr 16) + Numb2Hex(L);
end; { Long2Hex }
FUNCTION LowerCase( s: STRING ): STRING; ASSEMBLER;
ASM
PUSH DS
CLD
LDS SI, s
XOR AX, AX
LODSB
XCHG AX, CX
LES DI, @Result
MOV BYTE PTR ES:[DI], CL
INC DI
JCXZ @@3
@@1: LODSB
CMP AL, 'A'
JB @@2
CMP AL, 'Z'
JA @@2
OR AL, $20
@@2: STOSB
LOOP @@1
@@3: POP DS
END;
Var i:byte;
codigo1a,codigo2a,codigo1b,codigo2b:longint;
c1:string;
c2:string[4];
codigo2:string[8];
Begin
textcolor(7);
Writeln('WinZip 7.0 Key Generator by Black Fenix (c) 1999:');
Writeln('-------------------------------------------------');
Write('Enter your name: ');
Readln(Name);
Name2:=Name;
Name2:=LowerCase(Name2);
codigo1a:=0;
codigo2a:=0;
codigo1b:=0;
codigo2b:=0;
for i:=1 to length(Name) do
Begin
charb:=ord(Name[i]);
if charb<>0 then
Begin
codigo1a:=ComputeCode1($1021,charb,codigo1a);
End Else break;
charb:=ord(Name2[i]);
if boolean(Table[word(charb*2)] and $103) then
Begin
codigo1b:=ComputeCode1($1021,charb,codigo1b);
End
End;
codigo1a:=((codigo1a+$63) shl 16) shr 16;
codigo1b:=((codigo1b+$63) shl 16) shr 16;
codigo2a:=ComputeCode2(Name);
codigo2b:=ComputeCode2b(Name2);
{ convierte a cadena la primera parte del segundo codigo }
str(codigo1b,c1);
{ convierte a cadena la segunda parte del segundo c�digo }
{ con un longitud m�xima de 4 caracteres }
str(codigo2b:4,c2);
{ concatena los dos c�digo, Nota: nunca sobrepasaran los 8 caracteres ya que -> codigo2[8]:string }
codigo2:=c1+c2;
write('Valid registration numbers are: ');
textcolor(15);
writeln(Numb2Hex(codigo1a),Numb2Hex(codigo2a),' or ',codigo2);
textcolor(7);
End.
You are inside Reversed Minds pages. por
Mr. Silver
/ WKT! |