Hola que tal, la verdad este reto algo distinto a los que había visto y quiero agradecer a m4rtyr y PeterPunk por la ayuda prestada siempre en esta zona.
Humildemente les daré la explicación de como lo resolví.
Primero que nada necesitamos conocimiento sobre las funciones de la API de Windows empleadas por el Reto:
ReadFile:
Código: Seleccionar todo
http://msdn.microsoft.com/en-us/library/aa365467(v=vs.85).aspx
CreateFile:
Código: Seleccionar todo
http://msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx
Bien empecemos.
1- Analizamos las funciones principales que realiza el archivo que no tiene que ver con lo que nos interesa:
Código: Seleccionar todo
00401000 > $ 6A 00 PUSH 0 ; |/pModule = NULL
00401002 . E8 64020000 CALL <JMP.&KERNEL32.GetModuleHandleA> ; |\GetModuleHandleA
00401007 . A3 77214000 MOV DWORD PTR DS:[402177],EAX ; |
0040100C . C705 97214000>MOV DWORD PTR DS:[402197],4003 ; |
00401016 . C705 9B214000>MOV DWORD PTR DS:[40219B],reverseM.00401>; |
00401020 . C705 9F214000>MOV DWORD PTR DS:[40219F],0 ; |
0040102A . C705 A3214000>MOV DWORD PTR DS:[4021A3],0 ; |
00401034 . A1 77214000 MOV EAX,DWORD PTR DS:[402177] ; |
00401039 . A3 A7214000 MOV DWORD PTR DS:[4021A7],EAX ; |
0040103E . 6A 04 PUSH 4 ; |/RsrcName = 4.
00401040 . 50 PUSH EAX ; ||hInst => 00400000
00401041 . E8 3F030000 CALL <JMP.&USER32.LoadIconA> ; |\LoadIconA
00401046 . A3 AB214000 MOV DWORD PTR DS:[4021AB],EAX ; |
0040104B . 68 007F0000 PUSH 7F00 ; |/RsrcName = IDC_ARROW
00401050 . 6A 00 PUSH 0 ; ||hInst = NULL
00401052 . E8 C8020000 CALL <JMP.&USER32.LoadCursorA> ; |\LoadCursorA
00401057 . A3 AF214000 MOV DWORD PTR DS:[4021AF],EAX ; |
Lo que esto hace es cargar icono y cursor.
Ahora vemos que las siguientes lineas empiezan a meter parámetros en la pila para llamar a la función CreateFile:
Código: Seleccionar todo
0040105C . 6A 00 PUSH 0 ; |/hTemplateFile = NULL
0040105E . 68 6F214000 PUSH reverseM.0040216F ; ||Attributes = READONLY|HIDDEN|SYSTEM|ARCHIVE|TEMPORARY|402048
00401063 . 6A 03 PUSH 3 ; ||Mode = OPEN_EXISTING
00401065 . 6A 00 PUSH 0 ; ||pSecurity = NULL
00401067 . 6A 03 PUSH 3 ; ||ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
00401069 . 68 000000C0 PUSH C0000000 ; ||Access = GENERIC_READ|GENERIC_WRITE
0040106E . 68 79204000 PUSH reverseM.00402079 ; ||FileName = "Keyfile.txt"
00401073 . E8 0B020000 CALL <JMP.&KERNEL32.CreateFileA> ; |\CreateFileA
Aquí nos dejaron 2 pistas, la primera es que abre un archivo existente "Keyfile.txt" - OPEN_EXISTING, y crea el handle para poder trabajar con ese archivo. Como todos sabemos las funciones siempre retornan un valor para poder evaluar con condiciones los errores.
Luego viene una comparación:
El cual compara si el valor que retorno CreateFile es igual a -1 que corresponde a la constante INVALID_HANDLE_VALUE, esto quiere decir que no se pudo abrir el archivo seguramente por que no existe.
Al realizar comparación las banderas cambian y seguido hay un salto el cual trabaja así:
Código: Seleccionar todo
0040107B . /75 1D JNZ SHORT reverseM.0040109A ; |
0040107D . |6A 00 PUSH 0 ; |/Style = MB_OK|MB_APPLMODAL
0040107F . |68 00204000 PUSH reverseM.00402000 ; ||Title = " ReverseMe"
00401084 . |68 17204000 PUSH reverseM.00402017 ; ||Text = "No esta Registrado"
00401089 . |6A 00 PUSH 0 ; ||hOwner = NULL
0040108B . |E8 D7020000 CALL <JMP.&USER32.MessageBoxA> ; |\MessageBoxA
00401090 . |E8 24020000 CALL <JMP.&KERNEL32.ExitProcess> ; \ExitProcess
00401095 . |E9 83010000 JMP reverseM.0040121D
0040109A > \6A 00 PUSH 0 ; /pOverlapped = NULL
Si la comparación fue exitosa con -1, se activara la bandera Zero, e ignorará el salto, por lo cual seguirá al mensaje que nos dirá que no está registrado.
Pero si la comparación no fue exitosa(se pudo abrir el archivo), saltara a la dirección 0040109A, donde se empiezan a ingresar parámetros a la pila para llamar a la función ReadFile:
Código: Seleccionar todo
0040109A > \6A 00 PUSH 0 ; /pOverlapped = NULL
0040109C . 68 73214000 PUSH reverseM.00402173 ; |pBytesRead = reverseM.00402173
004010A1 . 6A 46 PUSH 46 ; |BytesToRead = 46 (70.)
004010A3 . 68 1A214000 PUSH reverseM.0040211A ; |Buffer = reverseM.0040211A
004010A8 . 50 PUSH EAX ; |hFile
004010A9 . E8 2F020000 CALL <JMP.&KERNEL32.ReadFile> ; \ReadFile
Aquí podemos ver que leerá 70 caracteres, pero debemos tener en cuenta 2 cosas, el parámetro pBytesRead correspondiente en la función al parámetro __out_opt LPDWORD lpNumberOfBytesRead, es decir un buffer donde se almacenaran la cantidad de bytes que fueron leídos.
Luego viene la siguiente operación lógica con fin de comparar y realizar otro salto interesante:
Código: Seleccionar todo
004010AE . 85C0 TEST EAX,EAX
004010B0 . 75 02 JNZ SHORT reverseM.004010B4
004010B2 . EB 43 JMP SHORT reverseM.004010F7
Como les había dicho toda función retorna un valor y TEST funciona como un AND, el cual va byte por bit por bit comparando, si ambos bits sin 1 el resultado será 1, esto lo hace con todos los bits de EAX, esto con el fin de saber si se pudo Leer satisfactoriamente el archivo, si no se pudo leer pasara al salto JMP, el cual saltara al mensaje que dice que el KeyFile es incorrecto, veamos lo que sigue.
Si se pudo leer el archivo saltará a la siguiente rutina:
Código: Seleccionar todo
004010B4 > \33DB XOR EBX,EBX
004010B6 . 33F6 XOR ESI,ESI
004010B8 . 833D 73214000>CMP DWORD PTR DS:[402173],10
004010BF . 7C 36 JL SHORT reverseM.004010F7
004010C1 > 8A83 1A214000 MOV AL,BYTE PTR DS:[EBX+40211A]
004010C7 . 3C 00 CMP AL,0
004010C9 . 74 08 JE SHORT reverseM.004010D3
004010CB . 3C 2D CMP AL,2D
004010CD . 75 01 JNZ SHORT reverseM.004010D0
004010CF . 46 INC ESI
004010D0 > 43 INC EBX
004010D1 .^ EB EE JMP SHORT reverseM.004010C1
004010D3 > 83FE 08 CMP ESI,8
004010D6 . 7C 1F JL SHORT reverseM.004010F7
004010D8 . E9 28010000 JMP reverseM.00401205
Primeramente limpia los registros ESI y EBX, luego compara el contenido de la dirección 402173 correspondiente al Buffer donde se almacenaron la cantidad de bytes leídos, si esa cantidad es igual o mayor a 0x10 = 16h, entonces seguirá a la siguiente acción, la cual mueva al registro AL, el valor del primer cada carácter de KeyFile.txt, lo compara con un carácter Nulo, para saber si ya terminó de leer la cadena, si no es carácter nulo, entonces, compara el carácter con 2D equivalente al carácter "-", si corresponde incrementará el valor de ESI, y EBX, este último para seguir la comparación con cada carácter, osea que comparará que los 8 primeros caracteres sean iguales a 8 "-", como sabemos que 8?, por que si nos damos cuenta cada que compara si es igual a "-" aumenta el registro ESI, y cuando llega al carácter nulo comprueba si ESI es igual o mayor a 8.
El último JMP es el salto al mensaje de estamos registrados.
Con esto concluir que necesita mínimo 16 caracteres en el KeyFile.txt, los 8 primeros deben ser "-" y el resto lo que tu quieras.
Saludos y espero ayan entendido, aprendí bastante de él y espero ustedes también.