-
Notifications
You must be signed in to change notification settings - Fork 58
Packet Resolver
This only works for packets which are sent from the server to the client.
A working Maple2. Setup guide here
Understanding how packets work. Tutorial here
First connect to your server.
Find the OP Code you want to resolve in SendOp.cs (Maple2.Server.Core\Constants\SendOp.cs).
In your chat type the following command: /debug resolve (opcode), it accepts the values in these formats: 81, 0081, 0x81, 0x0081
Now the resolver will send a packet to the client with the selected opcode, if the client reports that there was an error with the packet, the resolver will read the error and use the given hint from the error logger.
The errors from the client look something like this: ["sock_exception"] "BCNetworkService::ProcessPacket [type=170][offset=13][hint=Decode4]"
The resolver now will use that hint and add an INT (Since the hint is "Decode4") to the end of the packet and send it again until the client doesn't give any more errors.
The structure will be saved to an text file in /PacketStructures, they will have the opcode and the name for easy finding.
With the structure saved in the text file, you can change the values of each function to change the behavior of the packet. Packets normally have multiple headers, so you can change the part in which defines the header and delete the rest, then the resolver will continue from the last part.
UserEnv 0x00AA has a bunch of different headers. On the first use it'll just send zeros so nothing major happened. This is the result:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.UserEnv);
pWriter.WriteByte();
pWriter.WriteInt();Lets try to decode with header 8, so we will change the structure to:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.UserEnv);
pWriter.WriteByte(8);Now the resolver will run and the result is this:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.UserEnv);
pWriter.WriteByte(8);
pWriter.WriteInt();
pWriter.WriteInt();Since this has already been decoded, we know that the first int is a loop count. So we can change the value of it and see how the loop structure looks like.
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.UserEnv);
pWriter.WriteByte(8);
pWriter.WriteInt(2); // loop countAnd this is the result:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.UserEnv);
pWriter.WriteByte(8);
pWriter.WriteInt(2); // loop count
pWriter.WriteInt(); // 1
pWriter.WriteInt(); // 1
pWriter.WriteInt(); // 2
pWriter.WriteInt(); // 2
pWriter.WriteInt();Now we can see that the mode 8 of the packet 0x00AA has structure like this:
Short - OPCODE
Byte - Header/Mode
Int - Loop counter
Int - Some value
Int - Some value
Int - Some valueUsing the packet resolver on the packet from the Understanding packet tutorial, we can finally find the correct structure and it looks like this:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.ResponseCube);
pWriter.WriteByte(20);
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteUnicodeString();
pWriter.WriteLong();
pWriter.WriteLong();
pWriter.WriteByte();Some packets have branches. It can be an simple boolean (true/false) or maybe if the item uid is in the character inventory.
For example the packet Ugc 0x006D mode 7, this is the structure:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.Ugc);
pWriter.WriteByte(7);
pWriter.WriteLong();
pWriter.WriteByte();Changing the last byte to one, this is the difference:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.UGC);
pWriter.WriteByte(7);
pWriter.WriteLong();
pWriter.WriteByte(1);
pWriter.WriteByte();
pWriter.WriteInt();
pWriter.WriteLong();
pWriter.WriteLong();
pWriter.WriteUnicodeString();
pWriter.WriteUnicodeString();
pWriter.WriteLong();
pWriter.WriteUnicodeString();
pWriter.WriteByte();
pWriter.WriteByte();
pWriter.WriteLong();
pWriter.WriteByte();
pWriter.WriteUnicodeString();Sometimes if there is a loop inside the structure it'll need a value different from zero, but what about item UID?
For example the packet ItemPutOn 0x0025, this is the structure (Maple2.Server.Game\Packets\EquipPacket.cs):
ByteWriter pWriter = Packet.Of(SendOp.ItemPutOn);
pWriter.WriteInt(player.ObjectId);
pWriter.WriteInt(item.Id);
pWriter.WriteLong(item.Uid);
pWriter.WriteUnicodeString(item.EquipSlot().ToString());
pWriter.WriteInt(item.Rarity);
pWriter.WriteByte(type);
pWriter.WriteClass<Item>(item);Lets see how the structure looks using the resolver:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.ItemPutOn);
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteLong();
pWriter.WriteUnicodeString();
pWriter.WriteInt();
pWriter.WriteByte();It's almost the same but it's missing everything from the WriteClass function! The client didn't return an error because it couldn't find the item UID we sent with the resolver (It's always zero), let's change the structure to have some correct values and try again:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.ItemPutOn);
pWriter.WriteInt(10000126); // character object id
pWriter.WriteInt(12060107); // item id
pWriter.WriteLong(39); // item uid
pWriter.WriteUnicodeString("RI"); // equip slot
pWriter.WriteInt(4); // item rarity
pWriter.WriteByte();And here is the result from the resolver:
#Generated by Maple2 PacketStructureResolver
ByteWriter pWriter = Packet.Of(SendOp.ItemPutOn);
pWriter.WriteInt(10000126);
pWriter.WriteInt(12060107);
pWriter.WriteLong(39);
pWriter.WriteUnicodeString("RI");
pWriter.WriteInt(4);
pWriter.WriteByte();
pWriter.WriteInt(); // Write item starts here!
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteLong();
pWriter.WriteLong();
pWriter.WriteLong();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteByte();
pWriter.WriteLong();
pWriter.WriteShort();
pWriter.WriteByte();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteByte();
pWriter.WriteShort();
pWriter.WriteShort();
pWriter.WriteInt();
pWriter.WriteShort();
pWriter.WriteShort();
pWriter.WriteInt();
pWriter.WriteShort();
pWriter.WriteShort();
pWriter.WriteInt();
pWriter.WriteShort();
pWriter.WriteShort();
pWriter.WriteInt();
pWriter.WriteShort();
pWriter.WriteShort();
pWriter.WriteInt();
pWriter.WriteShort();
pWriter.WriteShort();
pWriter.WriteInt();
pWriter.WriteShort();
pWriter.WriteShort();
pWriter.WriteInt();
pWriter.WriteShort();
pWriter.WriteShort();
pWriter.WriteInt();
pWriter.WriteShort();
pWriter.WriteShort();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteByte();
pWriter.WriteLong();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteByte();
pWriter.WriteInt();
pWriter.WriteByte();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteByte();
pWriter.WriteInt();
pWriter.WriteInt();
pWriter.WriteByte();
pWriter.WriteByte();
pWriter.WriteByte();
pWriter.WriteByte();
pWriter.WriteByte();
pWriter.WriteLong();
pWriter.WriteLong();
pWriter.WriteUnicodeString();