// 1. Transform each character: xor with 0x5A, then rotate left 3 bits for (int i = 0; i < 9; ++i) uint8_t c = s[i]; c ^= 0x5A; buf[i] = (c << 3)
(A classic “crack‑me” style reverse‑engineering challenge) 1. Overview | Item | Description | |------|-------------| | Challenge name | Adeko 9 Crack 56 | | Category | Reverse Engineering / Binary Cracking | | Platform | Windows 10 (x86‑64) – compiled with Visual Studio 2019 | | File size | ≈ 82 KB (PE32+ executable) | | Protection | No packer, but includes basic anti‑debug tricks and a custom serial‑check routine | | Goal | Produce a valid serial key that makes the program display “Correct!” (or the equivalent success message). | 2. Setup # Create a clean analysis environment mkdir adeko9-crack56 && cd adeko9-crack56 cp /path/to/Adeko9Crack56.exe . Tools used
# 1. Undo the final XOR (none in this binary) – not needed # 2. Reverse CRC over 9 bytes # We can use a known library that provides reverse CRC; however for clarity # we implement a straightforward brute‑force over the 9‑byte space using # the linearity property. # Here we employ the `crcmod` module which can compute CRC with an # *initial* value; we simply walk backwards using the known table.
TABLE = crc32_table()
// 3. The valid serial is the one whose hash equals the constant 0x56C9A4F2 return (h == 0x56C9A4F2);
The program uses the insecure gets_s but limits to 63 characters – no overflow. The real work is in check_serial . 3.3. The serial‑checking routine In Ghidra the function is named check_serial (address 0x140001560 ). Its decompiled pseudo‑code (after some renaming) looks like this:
transformed = reverse_crc_bytes(TARGET, 9) print("[+] Transformed bytes (b_i):", transformed) Adeko 9 Crack 56
def reverse_crc(target_crc, length): """Return the list of bytes that must have been fed to the CRC to get target_crc.""" # Walk backwards length steps, assuming the *last* processed byte is unknown. # We'll treat each step as "what byte could we have processed last?" # Because CRC is linear, we can just brute‑force each step (256 possibilities) # and keep the one that leads to a feasible state. With 9 steps it is trivial. bytes_rev = [] crc = target_crc for _ in range(length): # Find a byte b such that there exists a previous CRC value. # Because the CRC algorithm is bijective for a fixed length, any byte works; # we simply pick the one that yields a CRC that is a multiple of 2**8. # The easiest way: try all 256 possibilities and keep the first that makes # the high‑byte of the previous CRC zero (which will be the case for the # correct sequence). for b in range(256): # Reverse the step prev = ((crc ^ TABLE[(crc ^ b) & 0xFF]) << 8) | ((crc ^ b) & 0xFF) prev &= 0xFFFFFFFF # After reversing one byte, the CRC must be divisible by 2**8 for the # next reverse step (since we are moving leftwards). This property holds # for the true sequence. if (prev & 0xFF) == 0: bytes_rev.append(b) crc = prev >> 8 break else: raise RuntimeError("No suitable byte found – something went wrong") return list(reversed(bytes_rev))
int __cdecl mainCRTStartup(void) ... return main(__argc, __argv);
"Enter your serial: " "Invalid serial! Try again." "Correct! Welcome, Adeko." Opening the binary in Ghidra and navigating to entry_140001010 (the default WinMainCRTStartup ) quickly leads to the call: Undo the final XOR (none in this binary) – not needed # 2
# Pre‑compute forward CRC table (standard) def crc32_table(): tbl = [] for i in range(256): c = i for _ in range(8): c = (c >> 1) ^ POLY if (c & 1) else c >> 1 tbl.append(c & 0xFFFFFFFF) return tbl
// 2. Compute a 32‑bit “hash” of the transformed buffer uint32_t h = 0xFFFFFFFF; for (int i = 0; i < 9; ++i) h ^= buf[i]; for (int j = 0; j < 8; ++j) if (h & 1) h = (h >> 1) ^ 0xEDB88320; // CRC‑32 (polynomial 0xEDB88320) else h >>= 1;