# Solution for R0-Crew Crackme Contest-2016.1
# by FeS
import sys, struct
from random import randint
def print_list(l, cnt=0):
res = ""
n = cnt
if len(l) > cnt:
n = len(l)
for i in range(n):
res += " %08X " % l[i]
print(res)
# Functions mul32 = A * B
def mul32(a, b):
return (a * b) & 0xFFFFFFFF
# Extended Euclidean algorithm
def xgcd(x,y):
a0=1; b0=0
a1=0; b1=1
if x<0:
x *= -1
a0 = -1
if y<0:
y *= -1
b1 = -1
if x<y:
x,y,a0,b0,a1,b1 = y,x,a1,b1,a0,b0
while 1:
times = x/y
x -= times*y
a0 -= times*a1
b0 -= times*b1
if x==0:
break
x,y,a0,b0,a1,b1 = y,x,a1,b1,a0,b0
return [y,a1,b1]
# Find multiplicative inverse
def invmod(x,p):
[gcd,a,b] = xgcd(x,p)
if gcd != 1:
raise ValueError
if a<0:
a += p;
return a
# found the key
K = [0] * 4
# hex values from command line
res = [0] * 4
# MAIN
USAGE = "Usage: crackme_solution.py X1 X2 X3 X4 filename_key\n" +\
"\tX1..4 - hex values in the format 0x1234ABCD\n" +\
"\tfilename_key - write key file"
# read input arguments
argsCount = len(sys.argv)
if argsCount < 6:
print USAGE
sys.exit(1)
for i in range(1, 5):
numsz = sys.argv[i]
if numsz[:2] != "0x":
print("[-] ERR. Invalid format in hex value")
sys.exit(2)
res[i-1] = int(numsz[2:], 16)
filename = sys.argv[5]
print("[+] Starting. Values for the key")
print_list(res)
# prepare for const (00407568)
# assignment:
# CODE:00404C06 shr esi, 10h
# CODE:00404C09 mov ds:end_esi, esi
ebx = 0x10DCD
esi = 1
for i in range(16):
esi = (esi * (ebx + 1)) & 0xFFFFFFFF
ebx = (ebx * ebx) & 0xFFFFFFFF
end_esi = esi >> 16
# module N
p = (1<<32)
# calculate multiplicative inverse
end_esi_inv = invmod(end_esi, p)
#vector_MT (The Mersenne Twister init array)
state = [0]*65536
for i in range(1,65536):
state[i] = ((0x10DCD * state[i-1]) + 1) & 0xFFFFFFFF
# Generate hex value
# A = Ki & FFFF0000
# A' = A * end_esi
# B = Ki & 0000FFFF
# Value = A' * state_not_1[B] + state[B]
# Solution
# B (low_index) = Value & 0000FFFF
# delta = (state[B+1] - state[B])
# Search in i=0..FFFF -> hi_index = delta * (i << 16) + state[B]
# A = A' * end_esi_inv = (hi_index << 16) * end_esi_inv
# Key = A | low_index
for val in range(len(res)):
search = res[val]
low_index = 0
hi_index = 0
delta = 0
for i in range(65536):
if (state[i] & 0xFFFF) == (search & 0xFFFF):
low_index = i
if low_index > 0:
delta = (state[(low_index + 1) & 0xFFFF] - state[low_index]) & 0xFFFFFFFF
for i in range(65536):
k = (mul32(i << 16, delta) + state[low_index]) & 0xFFFFFFFF
if k == search:
hi_index = i
break
A = mul32(hi_index << 16, end_esi_inv)
K[val] = A | low_index
print("[+] Found keys")
print_list(K)
# Write the solution in key file
txt = struct.pack("<L", 1)
txt += struct.pack("<L", randint(0,1000000))
for i in range(len(K)):
txt += struct.pack("<L", K[i])
open(filename, "wb").write(txt)