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.
463 lines
9.9 KiB
463 lines
9.9 KiB
#!/usr/bin/env python3
|
|
|
|
import json
|
|
from urllib.request import Request, urlopen
|
|
from base64 import b64encode, b64decode
|
|
from binascii import hexlify, unhexlify
|
|
from random import randrange
|
|
from os.path import isfile, isdir
|
|
from os import mkdir
|
|
from time import time
|
|
|
|
charmap = {
|
|
' ': 0x00,
|
|
'é': 0x1B,
|
|
'0': 0xA1,
|
|
'1': 0xA2,
|
|
'2': 0xA3,
|
|
'3': 0xA4,
|
|
'4': 0xA5,
|
|
'5': 0xA6,
|
|
'6': 0xA7,
|
|
'7': 0xA8,
|
|
'8': 0xA9,
|
|
'9': 0xAA,
|
|
'!': 0xAB,
|
|
'?': 0xAC,
|
|
'.': 0xAD,
|
|
'-': 0xAE,
|
|
'…': 0xB0,
|
|
'“': 0xB1,
|
|
'”': 0xB2,
|
|
'‘': 0xB3,
|
|
'’': 0xB4,
|
|
'♂': 0xB5,
|
|
'♀': 0xB6,
|
|
',': 0xB8,
|
|
'/': 0xBA,
|
|
'A': 0xBB,
|
|
'B': 0xBC,
|
|
'C': 0xBD,
|
|
'D': 0xBE,
|
|
'E': 0xBF,
|
|
'F': 0xC0,
|
|
'G': 0xC1,
|
|
'H': 0xC2,
|
|
'I': 0xC3,
|
|
'J': 0xC4,
|
|
'K': 0xC5,
|
|
'L': 0xC6,
|
|
'M': 0xC7,
|
|
'N': 0xC8,
|
|
'O': 0xC9,
|
|
'P': 0xCA,
|
|
'Q': 0xCB,
|
|
'R': 0xCC,
|
|
'S': 0xCD,
|
|
'T': 0xCE,
|
|
'U': 0xCF,
|
|
'V': 0xD0,
|
|
'W': 0xD1,
|
|
'X': 0xD2,
|
|
'Y': 0xD3,
|
|
'Z': 0xD4,
|
|
'a': 0xD5,
|
|
'b': 0xD6,
|
|
'c': 0xD7,
|
|
'd': 0xD8,
|
|
'e': 0xD9,
|
|
'f': 0xDA,
|
|
'g': 0xDB,
|
|
'h': 0xDC,
|
|
'i': 0xDD,
|
|
'j': 0xDE,
|
|
'k': 0xDF,
|
|
'l': 0xE0,
|
|
'm': 0xE1,
|
|
'n': 0xE2,
|
|
'o': 0xE3,
|
|
'p': 0xE4,
|
|
'q': 0xE5,
|
|
'r': 0xE6,
|
|
's': 0xE7,
|
|
't': 0xE8,
|
|
'u': 0xE9,
|
|
'v': 0xEA,
|
|
'w': 0xEB,
|
|
'x': 0xEC,
|
|
'y': 0xED,
|
|
'z': 0xEE,
|
|
'$': 0xFF,
|
|
}
|
|
charmap_rev = {}
|
|
for x, y in charmap.items():
|
|
charmap_rev[y] = x
|
|
def translate(str):
|
|
d = bytearray()
|
|
for x in str:
|
|
d.append(charmap[x])
|
|
d.append(0xff)
|
|
return d
|
|
def translate_rev(bytes):
|
|
s = ""
|
|
for c in bytes:
|
|
if c == 0xff:
|
|
break
|
|
s += charmap_rev[c]
|
|
return s
|
|
|
|
class BitstreamReader():
|
|
def __init__(self, bytes, bytesize=8):
|
|
self.bytes = bytes
|
|
self.bytesize = bytesize
|
|
self.pos = 0
|
|
self.bits = 0
|
|
self.value = 0
|
|
|
|
def remaining(self):
|
|
if self.pos < len(self.bytes):
|
|
return True
|
|
if self.bits > 0:
|
|
return True
|
|
return False
|
|
|
|
def read(self, count):
|
|
while self.bits < count:
|
|
if self.pos >= len(self.bytes):
|
|
break
|
|
self.value |= (self.bytes[self.pos] & ((1 << self.bytesize) - 1)) << self.bits
|
|
self.bits += self.bytesize
|
|
self.pos += 1
|
|
|
|
ret = self.value & ((1 << count) - 1)
|
|
self.value >>= count
|
|
self.bits -= count
|
|
return ret
|
|
|
|
def bitpack(code, origbits, destbits):
|
|
newcode = []
|
|
reader = BitstreamReader(code, origbits)
|
|
while reader.remaining():
|
|
newcode.append(reader.read(destbits))
|
|
return newcode
|
|
|
|
def ror(val, bits):
|
|
return val >> bits | ((val << (32 - bits)) & (2 ** 32 - 1))
|
|
|
|
class Client:
|
|
def __init__(self, user, pwd):
|
|
self.token = None
|
|
self.uid = None
|
|
self.login(user, pwd)
|
|
|
|
def makereq(self, endpoint, *args, **kwargs):
|
|
req = Request("https://fools2022.online/%s" % endpoint, *args, **kwargs)
|
|
req.add_header("User-Agent", "fools2022-client/1.1.0")
|
|
req.add_header("Content-Type", "application/x-www-form-urlencoded")
|
|
req.add_header("Accept-Encoding", "identity")
|
|
if self.token:
|
|
req.add_header("X-Foolssessiontoken", self.token)
|
|
return req
|
|
|
|
def makepkt(self, cmd, data):
|
|
data = bitpack(data, 8, 32)
|
|
rnd = randrange(256)
|
|
|
|
pkt = [rnd << 8 | cmd] + data
|
|
|
|
magic = 0xf0dbeb15
|
|
for x in pkt:
|
|
magic = ror(magic, 5)
|
|
magic ^= x
|
|
magic += x * 2
|
|
pkt[0] = (magic & (2**16-1)) << 16 | pkt[0]
|
|
pkt = b64encode(bytes(bitpack(pkt, 32, 8)))
|
|
return self.makereq("packet/%s" % self.uid, data=pkt)
|
|
|
|
def login(self, user, pwd):
|
|
data = {"u": user, "p": pwd}
|
|
data = json.dumps(data).encode()
|
|
req = self.makereq("login", data=data)
|
|
res = json.loads(urlopen(req).read().decode())
|
|
self.token = res["data"]["session"]
|
|
self.uid = res["data"]["uid"]
|
|
|
|
def getmap(self, mapid, pos=(0,0)):
|
|
data = [mapid >> 0, mapid >> 8, pos[0], pos[1]]
|
|
req = self.makepkt(0x01, data)
|
|
rev = b64decode(urlopen(req).read().decode())
|
|
print(hexlify(rev).decode())
|
|
return rev
|
|
|
|
def trendset(self, text):
|
|
data = bytearray()
|
|
for i, x in enumerate(text):
|
|
data.append(x)
|
|
data.append(0xff)
|
|
req = self.makepkt(0x04, data)
|
|
rev = b64decode(urlopen(req).read().decode()).decode()
|
|
print(rev)
|
|
|
|
def cave3(self, text):
|
|
data = bytearray(unhexlify("ffffffffffffffffffff"))
|
|
for i, x in enumerate(text):
|
|
data[i] = x
|
|
req = self.makepkt(0x06, data)
|
|
print(urlopen(req).read().decode())
|
|
|
|
def cave4gen(self, text):
|
|
data = bytearray()
|
|
for i, x in enumerate(text):
|
|
data.append(ord(x))
|
|
data.append(0xff)
|
|
req = self.makepkt(0x07, data)
|
|
rev = b64decode(urlopen(req).read().decode())[:-1].decode()
|
|
print(rev)
|
|
|
|
def cave4chk(self, cert):
|
|
data = cert.encode() + b"\xff"
|
|
req = self.makepkt(0x08, data)
|
|
rev = b64decode(urlopen(req).read().decode())
|
|
print(rev)
|
|
rev = rev[4:-1]
|
|
for x in range(0, len(rev), 16):
|
|
print(rev[x:x+16])
|
|
|
|
def lotto(self):
|
|
data = b""
|
|
req = self.makepkt(0x05, data)
|
|
rev = b64decode(urlopen(req).read().decode())
|
|
print(hexlify(rev).decode())
|
|
|
|
def complete(self):
|
|
data = bytearray(unhexlify("ef7fffff7fe0ffff000000000000000000000000000000000000000000000000"))
|
|
data = bytearray(unhexlify("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
|
|
req = self.makepkt(0x02, data)
|
|
rev = b64decode(urlopen(req).read().decode()).decode()
|
|
print(rev)
|
|
|
|
maps = [
|
|
0x0000,
|
|
0x0100,
|
|
0x0110,
|
|
0x0210,
|
|
0x0327,
|
|
0x0364,
|
|
0x043A,
|
|
0x0523,
|
|
0x0565,
|
|
0x0566,
|
|
0x062F,
|
|
0x0667,
|
|
0x0668,
|
|
0x0669,
|
|
0x066A,
|
|
0x0734,
|
|
0x0824,
|
|
0x0932,
|
|
0x096B,
|
|
0x098A,
|
|
0x0A32,
|
|
0x0B2D,
|
|
0x0C2C,
|
|
0x0D3E,
|
|
0x0E3C,
|
|
0x0E6C,
|
|
0x0F3B,
|
|
0x103B,
|
|
0x106D,
|
|
0x113D,
|
|
0x116E,
|
|
0x123D,
|
|
0x1321,
|
|
0x1337,
|
|
0x1432,
|
|
0x146F,
|
|
0x152D,
|
|
0x1631,
|
|
0x1639,
|
|
0x1670,
|
|
0x1671,
|
|
0x1672,
|
|
0x1720,
|
|
0x1730,
|
|
0x1731,
|
|
0x1732,
|
|
0x182A,
|
|
0x1927,
|
|
0x1A3C,
|
|
0x1A73,
|
|
0x1B37,
|
|
0x1C2C,
|
|
0x1D3B,
|
|
0x1E33,
|
|
0x1E92,
|
|
0x1F3A,
|
|
0x1F79,
|
|
0x1F7A,
|
|
0x2001,
|
|
0x202F,
|
|
0x207B,
|
|
0x2125,
|
|
0x2174,
|
|
0x223A,
|
|
0x2275,
|
|
0x2276,
|
|
0x2277,
|
|
0x232D,
|
|
0x2435,
|
|
0x2478,
|
|
0x2536,
|
|
0x2632,
|
|
0x2725,
|
|
0x2731,
|
|
0x2791,
|
|
0x2833,
|
|
0x2939,
|
|
0x2B29,
|
|
0x2B7C,
|
|
0x2B7D,
|
|
0x2B7E,
|
|
0x2C29,
|
|
0x2D27,
|
|
0x2E2B,
|
|
0x2F38,
|
|
0x2F7F,
|
|
0x2F80,
|
|
0x2F81,
|
|
0x302C,
|
|
0x3120,
|
|
0x318B,
|
|
0x318C,
|
|
0x318D,
|
|
0x318E,
|
|
0x318F,
|
|
0x3190,
|
|
0x3191,
|
|
0x323F,
|
|
0x3336,
|
|
0x3420,
|
|
0x3482,
|
|
0x353C,
|
|
0x3621,
|
|
0x3724,
|
|
0x3828,
|
|
0x3920,
|
|
0x3A3E,
|
|
0x3B22,
|
|
0x3B30,
|
|
0x3B31,
|
|
0x3B32,
|
|
0x3C36,
|
|
0x3D20,
|
|
0x3D83,
|
|
0x3E31,
|
|
0x3E90,
|
|
0x3F3D,
|
|
0x4026,
|
|
0x412E,
|
|
0x423A,
|
|
0x432A,
|
|
0x4384,
|
|
0x4430,
|
|
0x4528,
|
|
0x4530,
|
|
0x4585,
|
|
0x472B,
|
|
0x4786,
|
|
0x4787,
|
|
0x4788,
|
|
0x482B,
|
|
0x4889,
|
|
0x4933,
|
|
0x4A34,
|
|
0x4B3A,
|
|
0x4C21,
|
|
0x4C93,
|
|
0x4D3A,
|
|
0x4E22,
|
|
0x4F21,
|
|
0x506F,
|
|
0x5133,
|
|
0x5134,
|
|
0x5135,
|
|
0x5136,
|
|
0x5137,
|
|
0x5160,
|
|
0x5211,
|
|
]
|
|
maps_skip = [
|
|
# YEET maps (not always accessible)
|
|
0x5133,
|
|
0x5134,
|
|
0x5135,
|
|
0x5136,
|
|
0x5137,
|
|
0x5160
|
|
]
|
|
|
|
if __name__ == "__main__":
|
|
from time import sleep
|
|
from sys import argv
|
|
|
|
c = Client(open(".user").read().strip(), open(".pass").read().strip())
|
|
sleep(1)
|
|
if argv[1] == "map":
|
|
c.getmap(int(argv[2], 0))
|
|
if argv[1] == "maps":
|
|
fun_map = c.getmap(0x1670)
|
|
fun_value = int(translate_rev(fun_map[0x25b:0x260]))
|
|
print("Fun value:", fun_value)
|
|
fdir = "maps_%03d" % fun_value
|
|
if not isdir(fdir):
|
|
mkdir(fdir)
|
|
sleep(1)
|
|
|
|
# fdir = "maps"
|
|
# for x in range(0x10000):
|
|
for x in maps:
|
|
fname = "%s/%04X.map" % (fdir, x)
|
|
if isfile(fname):
|
|
continue
|
|
if x in maps_skip:
|
|
continue
|
|
print("Getting map %s..." % fname)
|
|
m = c.getmap(x)
|
|
open(fname, "wb").write(m)
|
|
sleep(1)
|
|
if argv[1] == "trend":
|
|
c.trendset(translate(argv[2]))
|
|
if argv[1] == "cave3":
|
|
c.cave3(translate(argv[2]))
|
|
if argv[1] == "cave4gen":
|
|
c.cave4gen(argv[2])
|
|
if argv[1] == "cave4chk":
|
|
c.cave4chk(argv[2])
|
|
if argv[1] == "complete":
|
|
c.getmap(int(argv[2], 0))
|
|
sleep(1)
|
|
c.complete()
|
|
if argv[1] == "lotto":
|
|
c.lotto()
|
|
if argv[1] == "yeet":
|
|
game_corner_map = c.getmap(0x1A73)
|
|
sleep(1)
|
|
yeet_map_id = game_corner_map[0x8B0] << 0
|
|
yeet_map_id |= game_corner_map[0x8B1] << 8
|
|
yeet_map = c.getmap(yeet_map_id)
|
|
game_corner_map_fname = "maps_changing/1A73_%04X.map" % yeet_map_id
|
|
if not isfile(game_corner_map_fname):
|
|
open(game_corner_map_fname, "wb").write(game_corner_map)
|
|
yeet_map_fname = "maps/%04X.map" % yeet_map_id
|
|
if not isfile(yeet_map_fname):
|
|
open(yeet_map_fname, "wb").write(yeet_map)
|
|
sleep(1)
|
|
results_map = c.getmap(0x5160)
|
|
results_map_fname = "maps_changing/5160_%d.map" % time()
|
|
open(results_map_fname, "wb").write(results_map)
|
|
if argv[1] == "funroll":
|
|
fun_map = c.getmap(0x472b, (15, 10))
|
|
if argv[1] == "funcheck":
|
|
fun_map = c.getmap(0x1670)
|
|
fun_value = int(translate_rev(fun_map[0x25b:0x260]))
|
|
print(fun_value)
|
|
|