| (keygenme) Wait, it was all linear? Always have been. |
[Click to reveal]The Solve.py(for my wửiteup,forgot to mention):
#!/usr/bin/env python3
"""Solver for Leenear's (keygenme) 'Wait, it was all linear? Always have been.'
Usage: python3 solve.py ./crackme
Pure Python 3, no dependencies."""
import struct, sys
from fractions import Fraction
M32, N = 0xFFFFFFFF, 1 << 64
data = open(sys.argv[1] if len(sys.argv) > 1 else 'crackme', 'rb').read()
# .rodata: file offset = vaddr - delta (anchor on the "password> " string at 0x2004)
delta = 0x2004 - data.find(b'password> ')
ro = lambda va, n: data[va - delta: va - delta + n]
# target constants, in output order O0..O7
T = struct.unpack('<8q', ro(0x20b0, 16) + ro(0x20c0, 16) + ro(0x2090, 16) + ro(0x20a0, 16))
# per-word XOR constants applied to the 8 input dwords
XORC = [0x9e3779b9, 0x7f4a7c15, 0xf39cc060, 0x5cedc834,
0x2b3e1e9b, 0xa54ff53a, 0x510e527f, 0x1f83d9ab]
# diagonal term of output k: DMUL[k] * X[DIDX[k]]
DIDX = [3, 0, 5, 2, 7, 4, 1, 6]
DMUL = [0x5f, 0x75, 0x33, 0x47, 0x21, 0x3f, 0x21, 0x79]
def xs(s): # xorshift32 (13,17,5); returns (after<<13, after>>17, final)
u = (s ^ (s << 13)) & M32
v = (u ^ (u >> 17)) & M32
return u, v, (v ^ (v << 5)) & M32
# rebuild the coefficient table the binary generates at runtime
s, rows = 0x6054d23c, []
for i in range(8):
_, t, s = xs(s); i0 = ((t & 1) + i + 1) & 7
_, _, s = xs(s); c0 = s % 15 - 7
_, t, s = xs(s); i1 = (i + (t & 1) + 3) & 7
_, _, s = xs(s); c1 = s % 15 - 7
_, t, s = xs(s); i2 = (i + (t & 1) + 5) & 7
_, _, s = xs(s); c2 = s % 15 - 7
rows.append((i0, i1, i2, c0, c1, c2))
# O_k = DMUL[k]*X[DIDX[k]] + 256*(c0*X[i0] + c1*X[i1] + c2*X[i2]) (mod 2^64)
A = [[0] * 8 for _ in range(8)]
for k, (i0, i1, i2, c0, c1, c2) in enumerate(rows):
A[k][DIDX[k]] += DMUL[k]
A[k][i0] += 256 * c0
A[k][i1] += 256 * c1
A[k][i2] += 256 * c2
# Gauss-Jordan over Q; det(A) is odd so every denominator is invertible mod 2^64
m = [[Fraction(v) for v in A[r]] + [Fraction(T[r])] for r in range(8)]
for c in range(8):
p = next(r for r in range(c, 8) if m[r][c] != 0)
m[c], m[p] = m[p], m[c]
m[c] = [v / m[c][c] for v in m[c]]
for r in range(8):
if r != c and m[r][c] != 0:
f = m[r][c]
m[r] = [a - f * b for a, b in zip(m[r], m[c])]
pw = b''
for k in range(8):
x = m[k][8]
x = x.numerator * pow(x.denominator, -1, N) % N
assert x < 1 << 32, 'solution out of range'
pw += struct.pack('<I', x ^ XORC[k])
print(pw.decode())
print('flag{%s}' % pw.decode())
|
2026-10-07 10:36 |