Se nos entrega un ELF que decompilado presenta este aspecto:
/* This file was generated by the Hex-Rays decompiler version 8.4.0.240320. Copyright (c) 2007-2021 Hex-Rays <info@hex-rays.com> Detected compiler: GNU C++ */ #include <defs.h> //------------------------------------------------------------------------- // Function declarations __int64 (**init_proc())(void); __int64 sub_401020(); __int64 sub_401030(); // weak __int64 sub_401040(); // weak __int64 sub_401050(); // weak __int64 sub_401060(); // weak __int64 sub_401070(); // weak // int puts(const char *s); // int printf(const char *format, ...); // __int64 __isoc99_scanf(const char *, ...); weak // void __noreturn exit(int status); void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void)); void dl_relocate_static_pie(); char *deregister_tm_clones(); __int64 register_tm_clones(); char *_do_global_dtors_aux(); __int64 frame_dummy(); int __fastcall main(int argc, const char **argv, const char **envp); _BYTE *__fastcall encode(__int64 a1); __int64 __fastcall validar(const char *a1); int banner(); int comprar(); void _libc_csu_fini(void); // idb void term_proc(); // int __fastcall _libc_start_main(int (__fastcall *main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void *stack_end); // __int64 _gmon_start__(void); weak //------------------------------------------------------------------------- // Data declarations _UNKNOWN _libc_csu_init; const char a31mparaSeguirU[43] = "\x1B[31mPara seguir usando este producto deber"; // idb const char a32myaPuedesSeg[61] = "\x1B[32mYa puedes seguir afinando tus instrumentos (y tus flags "; // idb const char aDirigaseANuest[21] = "\nDirigase a nuestra p"; // idb __int64 (__fastcall *_frame_dummy_init_array_entry)() = &frame_dummy; // weak __int64 (__fastcall *_do_global_dtors_aux_fini_array_entry)() = &_do_global_dtors_aux; // weak __int64 (*qword_404010)(void) = NULL; // weak char _bss_start; // weak //----- (0000000000401000) ---------------------------------------------------- __int64 (**init_proc())(void) { __int64 (**result)(void); // rax result = &_gmon_start__; if ( &_gmon_start__ ) return (__int64 (**)(void))_gmon_start__(); return result; } // 404090: using guessed type __int64 _gmon_start__(void); //----- (0000000000401020) ---------------------------------------------------- __int64 sub_401020() { return qword_404010(); } // 404010: using guessed type __int64 (*qword_404010)(void); //----- (0000000000401030) ---------------------------------------------------- __int64 sub_401030() { return sub_401020(); } // 401030: using guessed type __int64 sub_401030(); //----- (0000000000401040) ---------------------------------------------------- __int64 sub_401040() { return sub_401020(); } // 401040: using guessed type __int64 sub_401040(); //----- (0000000000401050) ---------------------------------------------------- __int64 sub_401050() { return sub_401020(); } // 401050: using guessed type __int64 sub_401050(); //----- (0000000000401060) ---------------------------------------------------- __int64 sub_401060() { return sub_401020(); } // 401060: using guessed type __int64 sub_401060(); //----- (0000000000401070) ---------------------------------------------------- __int64 sub_401070() { return sub_401020(); } // 401070: using guessed type __int64 sub_401070(); //----- (00000000004010D0) ---------------------------------------------------- // positive sp value has been detected, the output may be wrong! void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void)) { __int64 v3; // rax int v4; // esi __int64 v5; // [rsp-8h] [rbp-8h] BYREF char *retaddr; // [rsp+0h] [rbp+0h] BYREF v4 = v5; v5 = v3; _libc_start_main( (int (__fastcall *)(int, char **, char **))main, v4, &retaddr, (void (*)(void))_libc_csu_init, _libc_csu_fini, a3, &v5); __halt(); } // 4010DA: positive sp value 8 has been found // 4010E1: variable 'v3' is possibly undefined //----- (0000000000401100) ---------------------------------------------------- void dl_relocate_static_pie() { ; } //----- (0000000000401110) ---------------------------------------------------- char *deregister_tm_clones() { return &_bss_start; } // 404050: using guessed type char _bss_start; //----- (0000000000401140) ---------------------------------------------------- __int64 register_tm_clones() { return 0LL; } //----- (0000000000401180) ---------------------------------------------------- char *_do_global_dtors_aux() { char *result; // rax if ( !_bss_start ) { result = deregister_tm_clones(); _bss_start = 1; } return result; } // 404050: using guessed type char _bss_start; //----- (00000000004011B0) ---------------------------------------------------- __int64 frame_dummy() { return register_tm_clones(); } //----- (00000000004011B6) ---------------------------------------------------- int __fastcall main(int argc, const char **argv, const char **envp) { int v4; // [rsp+10h] [rbp-10h] BYREF int v5; // [rsp+14h] [rbp-Ch] unsigned __int64 v6; // [rsp+18h] [rbp-8h] v6 = __readfsqword(0x28u); v5 = 0; puts("\n\x1B[31m -----------Se le ha acabado el periodo de prueba gratuito-----------\n"); puts(a31mparaSeguirU); do { banner(); __isoc99_scanf("%d", &v4); if ( v4 == 3 ) exit(0); if ( v4 > 3 ) goto LABEL_10; if ( v4 == 1 ) { comprar(); continue; } if ( v4 == 2 ) v5 = validar("%d"); else LABEL_10: puts("Opcion invalida, pruebe otra vez"); } while ( !v5 ); puts(a32myaPuedesSeg); return 0; } // 4010B0: using guessed type __int64 __isoc99_scanf(const char *, ...); //----- (0000000000401291) ---------------------------------------------------- _BYTE *__fastcall encode(__int64 a1) { _BYTE *result; // rax int i; // [rsp+14h] [rbp-4h] for ( i = 0; i <= 33; ++i ) { if ( *(char *)(i + a1) <= 96 || *(char *)(i + a1) > 122 ) { if ( *(char *)(i + a1) <= 64 || *(char *)(i + a1) > 90 ) { result = (_BYTE *)*(unsigned __int8 *)(i + a1); *(_BYTE *)(i + a1) = (_BYTE)result; } else { result = (_BYTE *)(i + a1); *result = (5 * ((char)*result - 65) + 8) % 26 + 65; } } else { result = (_BYTE *)(i + a1); *result = (5 * ((char)*result - 97) + 8) % 26 + 97; } } return result; } //----- (00000000004013DB) ---------------------------------------------------- __int64 __fastcall validar(const char *a1) { int i; // [rsp+Ch] [rbp-64h] char v3[48]; // [rsp+10h] [rbp-60h] BYREF __int64 v4[6]; // [rsp+40h] [rbp-30h] BYREF v4[5] = __readfsqword(0x28u); qmemcpy(v4, "RisgAv{rIU_ihHwvIxA_sAppCsziq3vzC}", 34); printf("\nIntroduce tu licencia: "); __isoc99_scanf("%s", v3); encode((__int64)v3); for ( i = 0; i <= 33; ++i ) { if ( v3[i] != *((_BYTE *)v4 + i) ) { puts("\n\x1B[31mTu licencia es incorrecta\x1B[37m\n"); return 0LL; } } puts("\n\x1B[32mEres un crack, lo conseguiste\x1B[37m"); return 1LL; } // 4010B0: using guessed type __int64 __isoc99_scanf(const char *, ...); // 4013DB: using guessed type char var_60[48]; //----- (00000000004014CE) ---------------------------------------------------- int banner() { puts(" ___________OPCIONES___________"); puts(" | 1: Comprar licencia premium |"); puts(" | 2: Validar clave de licencia |"); puts(" | 3: Salir |"); puts(" ------------------------------"); return printf("> "); } //----- (0000000000401526) ---------------------------------------------------- int comprar() { return puts(aDirigaseANuest); } //----- (0000000000401540) ---------------------------------------------------- void __fastcall _libc_csu_init(unsigned int a1, __int64 a2, __int64 a3) { signed __int64 v3; // rbp __int64 i; // rbx init_proc(); v3 = &_do_global_dtors_aux_fini_array_entry - &_frame_dummy_init_array_entry; if ( v3 ) { for ( i = 0LL; i != v3; ++i ) (*(&_frame_dummy_init_array_entry + i))(); } } // 403E10: using guessed type __int64 (__fastcall *_frame_dummy_init_array_entry)(); // 403E18: using guessed type __int64 (__fastcall *_do_global_dtors_aux_fini_array_entry)(); //----- (00000000004015B0) ---------------------------------------------------- void _libc_csu_fini(void) { ; } //----- (00000000004015B8) ---------------------------------------------------- void term_proc() { ; } // nfuncs=33 queued=21 decompiled=21 lumina nreq=0 worse=0 better=0 // ALL OK, 21 function(s) have been successfully decompiled
Para resolver el juego y obtener una licencia válida, nos fijamos en el proceso de validación que se encuentra en la función validar
(líneas 237 a 258). Esta función compara una entrada de licencia codificada con una licencia codificada almacenada en el programa.
La licencia almacenada es "RisgAv{rIU_ihHwvIxA_sAppCsziq3vzC}"
, y se utiliza la función encode
(líneas 207 a 234) para codificar la entrada del usuario antes de compararla. La función encode
aplica un cifrado simple a la entrada, alterando los caracteres alfabéticos según una fórmula específica.
La función de cifrado encode
realiza lo siguiente:
- Si el carácter es una letra minúscula (a-z), se convierte según la fórmula
(5 * (char - 97) + 8) % 26 + 97
. - Si el carácter es una letra mayúscula (A-Z), se convierte según la fórmula
(5 * (char - 65) + 8) % 26 + 65
.
Nos construimos una función en Python para decodificar la Flag y reto superado.
def decode(encoded_char): if 'a' <= encoded_char <= 'z': original_char = chr(((ord(encoded_char) - 97 - 8) * 21) % 26 + 97) elif 'A' <= encoded_char <= 'Z': original_char = chr(((ord(encoded_char) - 65 - 8) * 21) % 26 + 65) else: original_char = encoded_char return original_char encoded_license = "RisgAv{rIU_ihHwvIxA_sAppCsziq3vzC}" decoded_license = "".join(decode(char) for char in encoded_license) print("Licencia descifrada:", decoded_license)