#!/usr/bin/env python3 class RNG: def __init__(self): self.rng = [0xe3, 0x34, 0xad, 0x30] def next(self): self.rng[0] += 1 self.rng[0] &= 0xff self.rng[1] ^= self.rng[0] self.rng[1] ^= self.rng[3] self.rng[2] += self.rng[1] self.rng[2] &= 0xff self.rng[3] += (self.rng[2] >> 1) ^ self.rng[1] self.rng[3] &= 0xff return self.rng[3] class FunnyCode: def __init__(self): self.code = self.gencode() self.cache = {} def __str__(self): return " ".join(map(lambda x: "%02x" % x, self.code)) def gencode(self): rng = RNG() code = [] for x in range(0x400): val1 = rng.next() while val1 == 0: val1 = rng.next() val2 = rng.next() while True: val2 &= 0xf8 if val2 in [0x00, 0x08, 0xf8]: val2 = rng.next() continue break code.append(0x0e) # ld c, n8 code.append(val1) code.append(0x09) # add hl, bc code.append(0x15) # dec d code.append(0xc8) # ret z code.append(0x1d) # dec e if x < 0x14: code.append(0x20) # jr nz, o8 code.append(val2 & 0x7f) elif x >= 0x400 - 0x14: code.append(0x18) # jr o8 code.append((val2 & 0x7f) + 0x80) else: code.append(0x20) # jr nz, o8 code.append(val2) return code def runcode(self, offset, de): key = offset << 16 | de if key in self.cache: return self.cache[key] hl = 0 bc = 0 d = de >> 8 e = de & 0xff while True: # de = d << 8 | e # print("0x%04x"%offset, "bc=0x%04x"%bc, "de=0x%04x"%de, "hl=0x%04x"%hl) c = self.code[offset + 1] bc = (bc & 0xff00) | c hl = (hl + bc) & 0xffff d -= 1 d &= 0xff if d == 0: break e -= 1 e &= 0xff if self.code[offset + 6] == 0x20 and e == 0: offset += 8 else: jr = self.code[offset + 7] if jr >= 0x80: jr -= 0x100 offset = (offset + 8) + jr self.cache[key] = hl return hl class PasswordHash: def __init__(self, password): self.hash = self.hashpass(password) self.valid = True if (self.hash[0] & 0xe000) != 0: self.valid = False if (self.hash[0] & 0x0007) != 0: self.valid = False def swap(self, val): vl = (val & 0xf0) >> 4 vh = (val & 0x0f) << 4 return vh | vl def hashpass(self, password): c = password[0] & 0xf b = self.swap(password[0]) & 0x03 c = ((password[1] & 0xf) + self.swap(c)) & 0xff b = ((self.swap(password[1]) & 0x03) + ((b << 2) & 0xff)) & 0xff c1 = c c = password[2] & 0xf b = ((self.swap(password[2]) & 0x03) + ((b << 2) & 0xff)) & 0xff c = ((password[3] & 0xf) + self.swap(c)) & 0xff b = ((self.swap(password[3]) & 0x03) + ((b << 2) & 0xff)) & 0xff return (password[4] << 8) | b, (c << 8) | c1 passchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789?!" def convpass(password): return bytearray(passchars.index(x) for x in password) if __name__ == "__main__": wanted = [ 0xadaa, 0xac39, 0x002f ] from sys import argv if len(argv) > 1 and argv[1] == "valid": for x in argv[2:]: pwd = convpass(x) password = PasswordHash(pwd) print(*map(hex, password.hash)) if password.valid: print(x) exit() if len(argv) > 1 and argv[1] == "run": code = FunnyCode() for x in argv[2:]: pwd = convpass(x) password = PasswordHash(pwd) result = code.runcode(*password.hash) if result in wanted: print(hex(result), x) exit() code = FunnyCode() pwd = convpass("BEPISBEPISBEPIS") password = PasswordHash(pwd) print(password.hash) if not password.valid: print("Password invalid!") exit(1) print(hex(code.runcode(*password.hash))) # val = code.runcode(0, 0) # print(hex(val)) # if val != 0x1a51: # exit(1) # val = code.runcode(0x1200, 0xf814) # print(hex(val)) # if val != 0x4031: # exit(1) # print("success")