From 999ccdcb19c75107e9617ebe962cfdac126adbfc Mon Sep 17 00:00:00 2001 From: KimLS Date: Thu, 17 Oct 2024 22:53:33 -0700 Subject: [PATCH] Add experimental decompression support. --- .../stream_parser/ConsoleHostedService.cs | 89 +++++++++++++++++-- .../ConsoleHostedServiceOptions.cs | 9 +- .../Properties/launchSettings.json | 4 +- 3 files changed, 89 insertions(+), 13 deletions(-) diff --git a/utils/stream_parser/stream_parser/ConsoleHostedService.cs b/utils/stream_parser/stream_parser/ConsoleHostedService.cs index 69e071072..7779c1688 100644 --- a/utils/stream_parser/stream_parser/ConsoleHostedService.cs +++ b/utils/stream_parser/stream_parser/ConsoleHostedService.cs @@ -13,6 +13,7 @@ using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; +using Ionic.Zlib; namespace StreamParser { @@ -72,7 +73,7 @@ namespace StreamParser { if(o.Dump) { - DumpConnectionToTextFile(c.Value, o.Output, o.Decrypt); + DumpConnectionToTextFile(c.Value, o.Output, o.Decrypt, o.DecompressOpcodes); } if(o.Csv) @@ -153,7 +154,7 @@ namespace StreamParser }); } - private void DumpConnectionToTextFile(ParsedConnection c, string output, bool decrypt) + private void DumpConnectionToTextFile(ParsedConnection c, string output, bool decrypt, IEnumerable decompressOpcodes) { try { @@ -213,12 +214,58 @@ namespace StreamParser break; default: { + bool reported_decompressed = false; int opcode = BitConverter.ToUInt16(data.Slice(0, 2)); - File.AppendAllText(path, - string.Format("{0} [Opcode: 0x{1}, Size: {2}] ({3})\n", dir, opcode.ToString("X4"), data.Length - 2, p.Time.ToString("s"))); + foreach (var decompressOpcode in decompressOpcodes) + { + if (opcode == decompressOpcode && data.Length > 12) + { + if (data[10] == 0x78 && data[11] == 0xDA) + { + var totalLen = BitConverter.ToInt32(data.Slice(6, 4)); + if (totalLen > 0) + { + var decompressed = Inflate(data.Slice(10)); + if(decompressed != null) + { + var decompressed_gp = new GamePacket(decompressed); + File.AppendAllText(path, + string.Format("{0} [Opcode: 0x{1}, Size (decompressed): {2}] ({3})\n", dir, opcode.ToString("X4"), totalLen, p.Time.ToString("s"))); - var gp = new GamePacket(data.Slice(2)); - File.AppendAllText(path, string.Format("{0}\n", gp.ToString())); + File.AppendAllText(path, string.Format("{0}\n", decompressed_gp.ToString())); + reported_decompressed = true; + break; + } + } + } + else if (data[6] == 0x78 && data[7] == 0xDA) + { + var totalLen = BitConverter.ToInt32(data.Slice(2, 4)); + if (totalLen > 0) + { + var decompressed = Inflate(data.Slice(6)); + if (decompressed != null) + { + File.AppendAllText(path, + string.Format("{0} [Opcode: 0x{1}, Size (decompressed): {2}] ({3})\n", dir, opcode.ToString("X4"), totalLen, p.Time.ToString("s"))); + + var decompressed_gp = new GamePacket(decompressed); + File.AppendAllText(path, string.Format("{0}\n", decompressed_gp.ToString())); + reported_decompressed = true; + break; + } + } + } + } + } + + if (!reported_decompressed) + { + File.AppendAllText(path, + string.Format("{0} [Opcode: 0x{1}, Size: {2}] ({3})\n", dir, opcode.ToString("X4"), data.Length - 2, p.Time.ToString("s"))); + var gp = new GamePacket(data.Slice(2)); + File.AppendAllText(path, string.Format("{0}\n", gp.ToString())); + } } break; } @@ -230,6 +277,36 @@ namespace StreamParser } } + private byte[] Inflate(ReadOnlySpan data) + { + try + { + using (var out_stream = new MemoryStream()) + using (var in_stream = new MemoryStream(data.ToArray())) + { + const int bufferLen = 4096; + var buffer = new byte[bufferLen]; + using (var zs = new ZlibStream(in_stream, CompressionMode.Decompress)) + { + int r = 0; + do + { + r = zs.Read(buffer, 0, bufferLen); + out_stream.Write(buffer, 0, r); + } while (r == bufferLen); + } + + var ret = out_stream.ToArray(); + return ret; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error inflating data"); + return null; + } + } + private class CsvRow { public int Index { get; set; } diff --git a/utils/stream_parser/stream_parser/ConsoleHostedServiceOptions.cs b/utils/stream_parser/stream_parser/ConsoleHostedServiceOptions.cs index ae7e5da00..de560175d 100644 --- a/utils/stream_parser/stream_parser/ConsoleHostedServiceOptions.cs +++ b/utils/stream_parser/stream_parser/ConsoleHostedServiceOptions.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; using CommandLine; namespace StreamParser @@ -23,5 +19,8 @@ namespace StreamParser [Option("decrypt", Default = false, HelpText = "Decrypt the \"Encrypted\" packets.")] public bool Decrypt { get; set; } + + [Option("decompress", Default = false, HelpText = "Which opcodes to attempt to decompress")] + public IEnumerable DecompressOpcodes { get; set; } } } diff --git a/utils/stream_parser/stream_parser/Properties/launchSettings.json b/utils/stream_parser/stream_parser/Properties/launchSettings.json index 493c4e30c..894e77546 100644 --- a/utils/stream_parser/stream_parser/Properties/launchSettings.json +++ b/utils/stream_parser/stream_parser/Properties/launchSettings.json @@ -2,8 +2,8 @@ "profiles": { "stream_parser": { "commandName": "Project", - "commandLineArgs": "--input input/cap_login_to_zone_10_16_2024.pcap --output output_test/ --text --decrypt", + "commandLineArgs": "--input input/cap_login_to_zone_10_16_2024.pcap --output output_test/ --text --decrypt --decompress 16742 168 30346", "workingDirectory": "E:\\Projects\\stream_parser\\stream_parser\\bin\\Debug\\net6.0\\" } } -} \ No newline at end of file +}