| Keygen Me |
0. SSZFV-9SCML-6E7J3-WT9R8-X9JB
1. YFMMR-HAZYU-DGRXK-58ANM-WBJ3
2. JU5L7-G4FRA-LD7R7-7C4YB-HBVK
3. LWRZR-75XTP-SW3VN-Z634W-88Q4
4. FHAFL-BG5LU-FUGUQ-PCHG2-TH86
5. W7664-MM59P-VTNA8-2CPYW-L6UD
6. ZNSET-TD4YC-X79EY-WJQV4-92P5
7. FCTE6-2CJBZ-ZB9YB-NTXRH-HEBV
To resolve it - bp on:
call memcmp
In sub_14000BB10 after call sub_1400063A0, RVA: BC9D
Then insert AAAAA-AAAAA-AAAAA-AAAAA-AAAA in license key and check registers:
RAX : 00000076A35F16C8 &"FCTE6-2CJBZ-ZB9YB-NTXRH-HEBV"
RBX : 00000211B7421640 "FCTE6-2CJBZ-ZB9YB-NTXRH-HEBV"
RCX : 00000211B74216D0 "AAAAA-AAAAA-AAAAA-AAAAA-AAAA"
RDX : 00000211B7421640 "FCTE6-2CJBZ-ZB9YB-NTXRH-HEBV" |
2026-02-22 07:45 |
| Continental |
Here's how I did it: In main I looked at the logic — the password is run through a transforming function, the result is compared via memcmp against a reference value at unk_1400150B8. The transforming function (sub_140002190) on call allocates a VirtualAlloc page of 0x1000 bytes, copies bytecode from stack qword-constants (0x37 bytes) into it, and returns a pointer to the verification function. This is a custom stack VM with its own ISA. Next I decided to reverse the VM architecture: [0x000..0x0FF] bytecode, [0x100..0x3FF] data memory where the input is placed, [0x400..0x41F] register file R0..R7, [0x420..0x51F] call stack, and flags at offsets 0x520–0x528 (SP, PC, running, ZF, CF, SF, OF). Then I extracted the bytecode from the stack constants in IDA. We get a loop over the password bytes: each byte is XORed with 0xAA and with the low byte of key R2, then shifted left by (R2 & 0xF) bits, the result is masked with &0xFF. After each iteration the key mutates: key = (key << 1) ^ 0x55. Set a breakpoint after the transform call, enter any password — I used "12345678" — read the result from RAX. Verify the algorithm with a3=0 — all 8 bytes matched. a3 is confirmed as zero (clean environment, no antidebug detections). Read the reference from unk_1400150B8 via dump in x64dbg: EE C0 00 00 B0 58 80 D0. Invert the transform by brute-forcing all 256 values at each position. Positions 2–3 are fully wildcard (shift ≥ 8, any byte produces 0x00). Positions 4–7 yield 8 solutions each (shift = 3, only the lower 5 bits of the input matter), giving pairs R/r, I/i, C/c. Result: password of the form D[A/1/I/...][ any][any][_/?][R/r][I/i][C/c] (DA??_RIC and so on). I did not attempt to patch anything. I am using a translator, so my words may not come across the way I wrote them in the original. My script for it:
from itertools import product
def transform_byte(b, key):
xored = b ^ 0xAA ^ (key & 0xFF)
shift = key & 0x0F
return (xored << shift) & 0xFF
def next_key(key):
return ((key << 1) ^ 0x55) & 0xFFFFFFFF
def transform(password: bytes, a3: int = 0) -> bytes:
key = a3 & 0xFFFFFFFF
result = []
for b in password:
result.append(transform_byte(b, key))
key = next_key(key)
return bytes(result)
def solve(target: bytes, a3: int = 0):
key = a3 & 0xFFFFFFFF
per_pos = []
for i, t in enumerate(target):
valid = [b for b in range(256) if transform_byte(b, key) == t]
printable = [chr(b) for b in valid if 0x20 <= b < 0x7F]
print(f"pos[{i}]: {len(valid)} solutions, printable: {printable}")
per_pos.append(valid)
key = next_key(key)
return per_pos
test = transform(b"12345678", a3=0)
print("transform('12345678', a3=0) =", test.hex())
print("expected: 9ba00000e0787008")
print()
target = bytes([0xEE, 0xC0, 0x00, 0x00, 0xB0, 0x58, 0x80, 0xD0])
print(f"Solving for target: {target.hex()}\n")
per_pos = solve(target, a3=0)
printable_pos = [[b for b in pos if 0x20 <= b < 0x7F] for pos in per_pos]
WILDCARD_FIXED = ord('A')
fixed_pos = []
for i, pos in enumerate(printable_pos):
if len(pos) > 95:
print(f"pos[{i}] is wildcard (shift>=8), fixing to '{chr(WILDCARD_FIXED)}'")
fixed_pos.append([WILDCARD_FIXED])
else:
fixed_pos.append(pos)
print(f"\nTotal combinations to check: {1}")
for p in fixed_pos:
print(f" x{len(p)}", end="")
print()
print("\nAll printable candidates:")
count = 0
for combo in product(*fixed_pos):
pwd = bytes(combo).decode('ascii')
print(f" '{pwd}'")
count += 1
print(f"\nTotal: {count}") |
2026-02-19 13:40 |