You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
4.6 KiB
169 lines
4.6 KiB
#!/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")
|
|
|