mirror of
https://github.com/rafi1212122/BLHX.Server.git
synced 2025-12-12 22:44:36 +01:00
118 lines
4.2 KiB
C#
118 lines
4.2 KiB
C#
using System;
|
|
using System.Buffers.Binary;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using Newtonsoft.Json;
|
|
using BLHX.Server.Common.Proto;
|
|
using PcapDotNet.Core;
|
|
using PcapDotNet.Packets;
|
|
using ProtoBuf;
|
|
|
|
namespace BLHX.Server.PcapParser
|
|
{
|
|
class PcapParser
|
|
{
|
|
static MemoryStream memoryStream = new MemoryStream();
|
|
|
|
static void Main(string[] args)
|
|
{
|
|
// Check command line
|
|
if (args.Length != 1)
|
|
{
|
|
Console.WriteLine("usage: " + Environment.GetCommandLineArgs()[0] + " <filename>");
|
|
return;
|
|
}
|
|
|
|
// Create the offline device
|
|
OfflinePacketDevice selectedDevice = new OfflinePacketDevice(args[0]);
|
|
|
|
// Open the capture file
|
|
using (PacketCommunicator communicator =
|
|
selectedDevice.Open(65536, // portion of the packet to capture, 65536 guarantees that the whole packet will be captured on all the link layers
|
|
PacketDeviceOpenAttributes.Promiscuous, // promiscuous mode
|
|
1000)) // read timeout
|
|
{
|
|
// Read and dispatch packets until EOF is reached
|
|
communicator.ReceivePackets(0, DispatcherHandler);
|
|
}
|
|
|
|
ProcessPackets();
|
|
}
|
|
|
|
private static void DispatcherHandler(Packet packet)
|
|
{
|
|
var payload = packet.Ethernet.IpV4.Tcp.Payload;
|
|
if (payload.Length < 1)
|
|
return;
|
|
|
|
// print packet timestamp and packet length
|
|
Console.WriteLine(packet.Timestamp.ToString("yyyy-MM-dd hh:mm:ss.fff") + " length:" + payload.Length);
|
|
memoryStream.Write(payload.ToArray(), 0, payload.Length);
|
|
}
|
|
|
|
private static void ProcessPackets()
|
|
{
|
|
List<BLHXPacket> packets = new List<BLHXPacket>();
|
|
|
|
byte[] msBytes = memoryStream.ToArray();
|
|
int readLen = 0;
|
|
while (readLen < msBytes.Length)
|
|
{
|
|
var gamePacket = new BLHXPacket(msBytes.AsSpan(readLen).ToArray());
|
|
readLen += gamePacket.length + BLHXPacket.LENGTH_SIZE;
|
|
packets.Add(gamePacket);
|
|
|
|
try
|
|
{
|
|
var protoClass = Assembly.GetExecutingAssembly().GetType($"BLHX.Server.Common.Proto.p{gamePacket.command.ToCategory()}.{gamePacket.command}");
|
|
using (var ms = new MemoryStream(gamePacket.bytes))
|
|
{
|
|
gamePacket.body = Serializer.Deserialize(protoClass, ms);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
Console.WriteLine($"{gamePacket.command} failed to deserialize, {BitConverter.ToString(gamePacket.bytes).Replace("-", "")}");
|
|
}
|
|
}
|
|
|
|
Console.WriteLine($"Got {packets.Count} packet(s)");
|
|
File.WriteAllText("packets.json", JsonConvert.SerializeObject(packets));
|
|
}
|
|
}
|
|
|
|
static class CommandExtensions
|
|
{
|
|
public static string ToCategory(this Command command)
|
|
{
|
|
string cmdStr = ((ushort)command).ToString();
|
|
return cmdStr.Substring(0, Math.Min(2, cmdStr.Length)); ;
|
|
}
|
|
}
|
|
|
|
class BLHXPacket
|
|
{
|
|
public const int LENGTH_SIZE = 2;
|
|
public const int HEADER_SIZE = 5;
|
|
public readonly ushort length;
|
|
public readonly byte flag;
|
|
public readonly Command command;
|
|
public readonly ushort id;
|
|
public readonly byte[] bytes;
|
|
public object body;
|
|
|
|
public BLHXPacket(byte[] recv)
|
|
{
|
|
length = BinaryPrimitives.ReadUInt16BigEndian(recv);
|
|
flag = recv[LENGTH_SIZE];
|
|
command = (Command)BinaryPrimitives.ReadUInt16BigEndian(recv.AsSpan(LENGTH_SIZE + 1));
|
|
id = BinaryPrimitives.ReadUInt16BigEndian(recv.AsSpan(HEADER_SIZE));
|
|
bytes = new byte[length - HEADER_SIZE];
|
|
Array.Copy(recv, HEADER_SIZE + LENGTH_SIZE, bytes, 0, length - HEADER_SIZE);
|
|
}
|
|
|
|
public T Decode<T>() where T : IExtensible => Serializer.Deserialize<T>(bytes.AsSpan());
|
|
}
|
|
} |