# ------------------------------------------------------------ if __name__ == "__main__": TARGET = 0x56C9A4F2
# ------------------------------------------------------------ # 2. Reverse the custom transform def invert_transform(b): """Given transformed byte b = ROL8(c ^ 0x5A, 3), recover original c.""" # Inverse of ROL8 by 3 is ROR8 by 3 r = ((b >> 3) | (b << 5)) & 0xFF c = r ^ 0x5A return c
# 3. Invert the per‑byte transform to get the actual serial serial_bytes = bytes(invert_transform(b) for b in transformed) serial = serial_bytes.decode('latin-1') # keep raw bytes, printable check later print("[+] Serial candidate:", serial) Adeko 9 Crack 56
Find an input string s (9 bytes) such that CRC32( b_0 … b_8 ) == 0x56C9A4F2 . 4.2. CRC‑32 is linear over GF(2) CRC‑32 with a fixed polynomial is a linear operation:
| Tool | Purpose | |------|---------| | | Verify that the binary is not packed. | | x64dbg (or OllyDbg ) | Dynamic debugging, breakpoints, watch registers. | | Ghidra 10.2 | Static disassembly & de‑compilation. | | Strings | Quick view of embedded literals. | | Python 3.10 | Write a small key‑generator script (optional). | | procmon / Process Explorer | Observe any hidden anti‑debug syscalls. | Tip: Run the binary once under a debugger to confirm the presence of anti‑debug checks (e.g., IsDebuggerPresent , CheckRemoteDebuggerPresent ). If they crash the program, we’ll patch them out later. 3. Static Analysis 3.1. Basic PE info File Type: PE32+ (64‑bit) Entry point: 0x140001010 Sections: .text 0x2000 (code) .rdata 0x1000 (read‑only data) .data 0x0800 (mutable data) .rsrc 0x0400 (resources – contains UI strings) The .rdata section contains the two strings we’ll see in the UI: | | Ghidra 10
#!/usr/bin/env python3 import binascii import struct
int main(int argc, char **argv) char input[64]; puts("Enter your serial: "); gets_s(input, sizeof(input)); if (check_serial(input) == 0) puts("Invalid serial! Try again."); return 1; puts("Correct! Welcome, Adeko."); return 0; 9) print("[+] Transformed bytes (b_i):"
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))
transformed = reverse_crc_bytes(TARGET, 9) print("[+] Transformed bytes (b_i):", transformed)
# Instead of a complicated generic reverse, we exploit the fact that # CRC‑32 with polynomial 0xEDB88320 is reversible byte‑by‑byte. # The following tiny routine does it: def reverse_crc_bytes(target, nbytes): crc = target out = [] for _ in range(nbytes): # The low byte of the CRC is the byte that was processed last, # after the forward step it becomes (crc ^ byte) & 0xFF. # So to reverse, we take the low byte as the original data byte. b = crc & 0xFF out.append(b) crc = (crc ^ TABLE[b]) >> 8 return list(reversed(out))
If we denote the post‑transform byte as b_i = t(i) , the CRC algorithm is applied to the sequence b_0 … b_8 .