From d6772f6db296dd1dc1bb24c2a0af6fe17f47ffbb Mon Sep 17 00:00:00 2001 From: hkc Date: Mon, 4 Sep 2023 22:03:31 +0300 Subject: [PATCH] Uhh i forgot --- .gitignore | 1 + README.md | 78 ++++++++++++++++++++++++ bta_proxy/__main__.py | 22 +++---- bta_proxy/dpi.py | 56 ++++++++--------- bta_proxy/entitydata.py | 9 ++- bta_proxy/packets/base.py | 8 ++- bta_proxy/packets/packet138playerlist.py | 3 +- bta_proxy/packets/packet24mobspawn.py | 2 +- tools/packetreader.py | 8 +-- 9 files changed, 137 insertions(+), 50 deletions(-) create mode 100644 README.md diff --git a/.gitignore b/.gitignore index c87ba3b..09562d6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ packets.txt packets.txt.gz packets*.txt packets*.txt.gz +/packets/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..024c242 --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +| ID | Packet name | Ready | ++=====+==================================+=======+ +| 000 | Packet0KeepAlive | YES | +| 001 | Packet1Login | YES | +| 002 | Packet2Handshake | YES | +| 003 | Packet3Chat | YES | +| 004 | Packet4UpdateTime | YES | +| 005 | Packet5PlayerInventory | YES | +| 006 | Packet6SpawnPosition | YES | +| 007 | Packet7UseEntity | YES | +| 008 | Packet8UpdateHealth | YES | +| 009 | Packet9Respawn | YES | +| 010 | Packet10Flying | YES | +| 011 | Packet11PlayerPosition | YES | +| 012 | Packet12PlayerLook | YES | +| 013 | Packet13PlayerLookMove | YES | +| 014 | Packet14BlockDig | YES | +| 015 | Packet15Place | YES | +| 016 | Packet16BlockItemSwitch | YES | +| 017 | Packet17Sleep | YES | +| 018 | Packet18Animation | YES | +| 019 | Packet19EntityAction | YES | +| 020 | Packet20NamedEntitySpawn | YES | +| 021 | Packet21PickupSpawn | YES | +| 022 | Packet22Collect | YES | +| 023 | Packet23VehicleSpawn | YES | +| 024 | Packet24MobSpawn | YES | +| 025 | Packet25EntityPainting | YES | +| 027 | Packet27Position | No | +| 028 | Packet28EntityVelocity | YES | +| 029 | Packet29DestroyEntity | YES | +| 030 | Packet30Entity | YES | +| 031 | Packet31RelEntityMove | YES | +| 032 | Packet32EntityLook | YES | +| 033 | Packet33RelEntityMoveLook | YES | +| 034 | Packet34EntityTeleport | YES | +| 035 | Packet35EntityNickname | YES | +| 038 | Packet38EntityStatus | YES | +| 039 | Packet39AttachEntity | YES | +| 040 | Packet40EntityMetadata | YES | +| 041 | Packet41EntityPlayerGamemode | YES | +| 050 | Packet50PreChunk | YES | +| 051 | Packet51MapChunk | YES | +| 052 | Packet52MultiBlockChange | YES | +| 053 | Packet53BlockChange | YES | +| 054 | Packet54PlayNoteBlock | YES | +| 056 | Packet56RequestChunk | No | +| 060 | Packet60Explosion | YES | +| 061 | Packet61PlaySoundEffect | YES | +| 070 | Packet70Bed | No | +| 071 | Packet71Weather | No | +| 072 | Packet72UpdatePlayerProfile | YES | +| 073 | Packet73WeatherStatus | YES | +| 100 | Packet100OpenWindow | YES | +| 101 | Packet101CloseWindow | YES | +| 102 | Packet102WindowClick | YES | +| 103 | Packet103SetSlot | YES | +| 104 | Packet104WindowItems | YES | +| 105 | Packet105UpdateProgressbar | YES | +| 106 | Packet106Transaction | YES | +| 107 | Packet107UpdateCreativeInventory | YES | +| 108 | Packet108SetHotbarOffset | YES | +| 130 | Packet130UpdateSign | YES | +| 131 | Packet131MapData | YES | +| 132 | Packet132SetMobSpawner | YES | +| 133 | Packet133OpenGuidebook | YES | +| 134 | Packet134ItemData | YES | +| 135 | Packet135PlacementMode | YES | +| 136 | Packet136SendKey | YES | +| 137 | Packet137UpdateFlag | YES | +| 138 | Packet138PlayerList | YES | +| 139 | Packet139SetPaintingMotive | YES | +| 140 | Packet140TileEntityData | YES | +| 141 | Packet141UpdateFlag | YES | +| 142 | Packet142OpenFlagWindow | YES | +| 143 | Packet143PhotoMode | YES | +| 200 | Packet200Statistic | YES | +| 255 | Packet255KickDisconnect | YES | diff --git a/bta_proxy/__main__.py b/bta_proxy/__main__.py index dea1187..db897f9 100644 --- a/bta_proxy/__main__.py +++ b/bta_proxy/__main__.py @@ -1,27 +1,27 @@ # x-run: cd .. && python -m bta_proxy '201:4f8c:4ea:0:71ec:6d7:6f1b:a4f9' import asyncio -from argparse import ArgumentParser -from sys import argv +from argparse import ArgumentParser, Namespace from bta_proxy.proxy import BTAProxy -MAX_SIZE = 0x400000 +parser = ArgumentParser("bta_proxy", description="Better Than Adventure proxy with Deep Packet Inspection") +parser.add_argument("remote_host", type=str) +parser.add_argument("remote_port", type=int, default=25565) +parser.add_argument("--bind", type=str, default="127.0.0.1") +parser.add_argument("--bind-port", type=int, default=25565) - -async def main(args: list[str]): +async def main(args: Namespace): loop = asyncio.get_running_loop() - port: int = 25565 - if len(args) >= 2: - port = int(args[1]) - server = await asyncio.start_server(BTAProxy(args[0], port, loop).handle_client, "localhost", 25565) + proxy = BTAProxy(args.remote_host, args.remote_port, loop) + server = await asyncio.start_server(proxy.handle_client, args.bind, args.bind_port) print("listening on", str.join(", ", [str(s.getsockname()) for s in server.sockets])) - print("forwarding to", args[0], port) + print("forwarding to", args.remote_host, args.remote_port) async with server: await server.serve_forever() if __name__ == '__main__': - asyncio.run(main(argv[1:])) + asyncio.run(main(parser.parse_args())) diff --git a/bta_proxy/dpi.py b/bta_proxy/dpi.py index 93e7324..9ed59c3 100644 --- a/bta_proxy/dpi.py +++ b/bta_proxy/dpi.py @@ -25,7 +25,7 @@ async def inspect_client(queue: Queue, addr: tuple[str, int]): last_time = time.time() - f = open_gzip("packets-%s-%d-client.txt.gz" % addr, "wt") + f = open_gzip("packets-%d-%s-%d-client.txt.gz" % (int(time.time()), addr[0], addr[1]), "wt") get_event_loop().create_task(queue_writer(queue, stream_queue, f)) stats: dict[int, int] = {} @@ -43,14 +43,14 @@ async def inspect_client(queue: Queue, addr: tuple[str, int]): stats[pkt.packet_id] = stats.get(pkt.packet_id, 0) + 1 match pkt.packet_id: - # case Packet10Flying.packet_id: - # continue - # case Packet11PlayerPosition.packet_id: - # continue - # case Packet12PlayerLook.packet_id: - # continue - # case Packet13LookMove.packet_id: - # continue + case Packet10Flying.packet_id: + continue + case Packet11PlayerPosition.packet_id: + continue + case Packet12PlayerLook.packet_id: + continue + case Packet13LookMove.packet_id: + continue case _: print(f"C {delta*1000:+8.1f}ms {pkt}") if pkt.packet_id == Packet255KickDisconnect.packet_id: @@ -68,7 +68,7 @@ async def inspect_server(queue: Queue, addr: tuple[str, int]): last_time = time.time() - f = open_gzip("packets-%s-%d-server.txt.gz" % addr, "wt") + f = open_gzip("packets-%d-%s-%d-server.txt.gz" % (int(time.time()), addr[0], addr[1]), "wt") get_event_loop().create_task(queue_writer(queue, stream_queue, f)) stats: dict[int, int] = {} @@ -86,26 +86,26 @@ async def inspect_server(queue: Queue, addr: tuple[str, int]): stats[pkt.packet_id] = stats.get(pkt.packet_id, 0) + 1 match pkt.packet_id: - # case Packet53BlockChange.packet_id: - # continue - # case Packet50PreChunk.packet_id: - # continue - # case Packet51MapChunk.packet_id: - # continue - # case Packet34EntityTeleport.packet_id: - # continue - # case Packet28EntityVelocity.packet_id: - # continue - # case Packet31RelEntityMove.packet_id: - # continue - # case Packet32EntityLook.packet_id: - # continue - # case Packet33RelEntityMoveLook.packet_id: - # continue + case Packet53BlockChange.packet_id: + continue + case Packet50PreChunk.packet_id: + continue + case Packet51MapChunk.packet_id: + continue + case Packet34EntityTeleport.packet_id: + continue + case Packet28EntityVelocity.packet_id: + continue + case Packet31RelEntityMove.packet_id: + continue + case Packet32EntityLook.packet_id: + continue + case Packet33RelEntityMoveLook.packet_id: + continue # case Packet73WeatherStatus.packet_id: # continue - # case Packet52MultiBlockChange.packet_id: - # continue + case Packet52MultiBlockChange.packet_id: + continue case _: print(f"S {delta*1000:+8.1f}ms {pkt}") finally: diff --git a/bta_proxy/entitydata.py b/bta_proxy/entitydata.py index 889b01b..09fdd96 100644 --- a/bta_proxy/entitydata.py +++ b/bta_proxy/entitydata.py @@ -6,6 +6,10 @@ from dataclasses import dataclass from bta_proxy.itemstack import ItemStack +from logging import getLogger + +logger = getLogger(__name__) + class DataItemType(Enum): BYTE = 0 SHORT = 1 @@ -25,7 +29,8 @@ class EntityData: @classmethod async def read_from(cls, dis: AsyncDataInputStream) -> list[DataItem]: items = [] - while (data := await dis.read()) != 0x7F: + while (data := await dis.read()) not in (127, 255): + logger.debug(f"Read byte: {data} (type={(data & 0xE0) >> 5}, id={data & 0x1F})") item_type = DataItemType((data & 0xE0) >> 5) item_id: int = data & 0x1F match item_type: @@ -49,7 +54,7 @@ class EntityData: @classmethod def read_from_sync(cls, dis: SyncDataInputStream) -> list[DataItem]: items = [] - while (data := dis.read()) != 0x7F: + while (data := dis.read()) not in (127, 255): item_type = DataItemType((data & 0xE0) >> 5) item_id: int = data & 0x1F match item_type: diff --git a/bta_proxy/packets/base.py b/bta_proxy/packets/base.py index 51dac97..5cb66fb 100644 --- a/bta_proxy/packets/base.py +++ b/bta_proxy/packets/base.py @@ -60,6 +60,11 @@ class Packet: await Packet.read_field(stream, args, fields) for _ in range(length) ] + case "tuple", *tuples: + out = [] + for tup in tuples: + out.append(await Packet.read_field(stream, tup, fields)) + return tuple(out) case "uint": return await stream.read_uint() case "int": @@ -190,7 +195,8 @@ class Packet: for key, _ in self.FIELDS: if "?" in key: key, cond = key.split("?", 1) - fields.append(f"{key}={getattr(self, key, None)!r} if {cond}") + fields.append(f"{key}={getattr(self, key, None)!r} depending on {cond}") else: fields.append(f"{key}={getattr(self, key)!r}") return f'<{pkt_name} {str.join(", ", fields)}>' + diff --git a/bta_proxy/packets/packet138playerlist.py b/bta_proxy/packets/packet138playerlist.py index 118e76b..d945851 100644 --- a/bta_proxy/packets/packet138playerlist.py +++ b/bta_proxy/packets/packet138playerlist.py @@ -3,6 +3,5 @@ from .base import Packet class Packet138PlayerList(Packet, packet_id=138): FIELDS = [ ('n_players', 'int'), - ('players', ('list', 'n_players', 'str')), - ('scores', ('list', 'n_players', 'int')), + ('players', ('list', 'n_players', 'tuple', 'str', 'int')), ] diff --git a/bta_proxy/packets/packet24mobspawn.py b/bta_proxy/packets/packet24mobspawn.py index ff18e18..f923e41 100644 --- a/bta_proxy/packets/packet24mobspawn.py +++ b/bta_proxy/packets/packet24mobspawn.py @@ -11,5 +11,5 @@ class Packet24MobSpawn(Packet, packet_id=24): ('pitch', 'byte'), ('metadata', 'entitydata'), ('nickname', 'string'), - ('chatcolor', 'byte'), + ('chatcolor', 'ubyte'), ] diff --git a/tools/packetreader.py b/tools/packetreader.py index d93074a..86a1d91 100644 --- a/tools/packetreader.py +++ b/tools/packetreader.py @@ -37,7 +37,7 @@ class CustomFormatter(logging.Formatter): return formatter.format(record) streamhandler = logging.StreamHandler() -streamhandler.setLevel(logging.INFO) +streamhandler.setLevel(logging.DEBUG) streamhandler.setFormatter(CustomFormatter()) @@ -55,15 +55,13 @@ async def amain(stream: AsyncDataInputStream): while True: try: pkt = await Packet.read_packet(stream) - logger.info(f"we just got a package {pkt.__class__.__name__}") - for key, _ in pkt.FIELDS: - logger.info(f"=== pkt.{key} = {getattr(pkt, key)!r}") + logger.info(f"we just got a package {pkt!r}") except EOFError: logger.warning("EOFError") break except Exception as e: logger.error(e) - logger.warning("ignoring it :)") + raise e logger.info("exiting")