From d1361e330bffc816494d6b7833cd2ab276b9b0e7 Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 3 Dec 2024 20:46:22 +0100 Subject: [PATCH] Drop ancient zlib dependency in favor of native .NET library calls. Due to different naming of those compression libraries per OS there is a custom dll import resolver used. --- WowPacketParser/Misc/FlushCode.cs | 10 ++ WowPacketParser/Misc/Packet.cs | 78 ++-------------- WowPacketParser/Misc/ZLibHelper.cs | 92 +++++++++++++++++++ WowPacketParser/Misc/ZStream.cs | 17 ++++ .../Parsing/Parsers/SessionHandler.cs | 5 +- WowPacketParser/Program.cs | 19 ++++ WowPacketParser/WowPacketParser.csproj | 1 - 7 files changed, 146 insertions(+), 76 deletions(-) create mode 100644 WowPacketParser/Misc/FlushCode.cs create mode 100644 WowPacketParser/Misc/ZLibHelper.cs create mode 100644 WowPacketParser/Misc/ZStream.cs diff --git a/WowPacketParser/Misc/FlushCode.cs b/WowPacketParser/Misc/FlushCode.cs new file mode 100644 index 0000000000..844a3f2c74 --- /dev/null +++ b/WowPacketParser/Misc/FlushCode.cs @@ -0,0 +1,10 @@ +namespace WowPacketParser.Misc +{ + public enum FlushCode + { + NoFlush = 0, + SyncFlush = 2, + Finish = 4, + Block = 5 + } +} diff --git a/WowPacketParser/Misc/Packet.cs b/WowPacketParser/Misc/Packet.cs index 1e41a15651..7fc5c37c7c 100644 --- a/WowPacketParser/Misc/Packet.cs +++ b/WowPacketParser/Misc/Packet.cs @@ -1,9 +1,9 @@ using Google.Protobuf.WellKnownTypes; -using Ionic.Zlib; using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net; +using System.Runtime.InteropServices; using System.Text; using WowPacketParser.Enums; using WowPacketParser.Enums.Version; @@ -95,26 +95,7 @@ public void AddSniffData(StoreNameType type, int id, string data) Storage.SniffData.Add(item, TimeSpan); } - public bool TryInflate(int inflatedSize, int index, byte[] arr, ref byte[] newarr) - { - try - { - if (!SessionHandler.ZStreams.ContainsKey(index)) - SessionHandler.ZStreams[index] = new ZlibCodec(CompressionMode.Decompress); - SessionHandler.ZStreams[index].InputBuffer = arr; - SessionHandler.ZStreams[index].NextIn = 0; - SessionHandler.ZStreams[index].AvailableBytesIn = arr.Length; - SessionHandler.ZStreams[index].OutputBuffer = newarr; - SessionHandler.ZStreams[index].NextOut = 0; - SessionHandler.ZStreams[index].AvailableBytesOut = inflatedSize; - SessionHandler.ZStreams[index].Inflate(FlushType.Sync); - return true; - } - catch (ZlibException) - { - return false; - } - } + public void ResetInflateStream() => ZLibHelper.ResetInflateStream(ConnectionIndex); public Packet Inflate(int inflatedSize, bool keepStream = true) { @@ -127,36 +108,12 @@ public Packet Inflate(int inflatedSize, bool keepStream = true) if (keepStream) { int idx = ConnectionIndex; - while (!TryInflate(inflatedSize, idx, arr, ref newarr) && idx <= 4) + while (!ZLibHelper.TryInflate(inflatedSize, idx, arr, ref newarr) && idx <= 4) idx += 1; } else { - /*try - { - var inflater = new Inflater(true); - inflater.SetInput(arr, 0, arr.Length); - inflater.Inflate(newarr, 0, inflatedSize); - } - catch (ICSharpCode.SharpZipLib.SharpZipBaseException) - { - var inflater = new Inflater(true); - inflater.SetInput(arr, 0, arr.Length); - inflater.Inflate(newarr, 0, inflatedSize); - }*/ - var stream = new ZlibCodec(CompressionMode.Decompress) - { - InputBuffer = arr, - NextIn = 0, - AvailableBytesIn = arr.Length, - OutputBuffer = newarr, - NextOut = 0, - AvailableBytesOut = inflatedSize - }; - - stream.Inflate(FlushType.None); - stream.Inflate(FlushType.Finish); - stream.EndInflate(); + ZLibHelper.Inflate(inflatedSize, arr, newarr); } // Cannot use "using" here @@ -178,35 +135,12 @@ public Packet Inflate(int arrSize, int inflatedSize, bool keepStream = true) if (keepStream) { int idx = ConnectionIndex; - while (!TryInflate(inflatedSize, idx, arr, ref newarr) && idx <= 4) + while (!ZLibHelper.TryInflate(inflatedSize, idx, arr, ref newarr) && idx <= 4) idx += 1; } else { - /*try - { - var inflater = new Inflater(true); - inflater.SetInput(arr, 0, arr.Length); - inflater.Inflate(newarr, 0, inflatedSize); - } - catch (ICSharpCode.SharpZipLib.SharpZipBaseException) - { - var inflater = new Inflater(true); - inflater.SetInput(arr, 0, arr.Length); - inflater.Inflate(newarr, 0, inflatedSize); - }*/ - var stream = new ZlibCodec(CompressionMode.Decompress) - { - InputBuffer = arr, - NextIn = 0, - AvailableBytesIn = arr.Length, - OutputBuffer = newarr, - NextOut = 0, - AvailableBytesOut = inflatedSize - }; - stream.Inflate(FlushType.None); - stream.Inflate(FlushType.Finish); - stream.EndInflate(); + ZLibHelper.Inflate(inflatedSize, arr, newarr); } // Cannot use "using" here diff --git a/WowPacketParser/Misc/ZLibHelper.cs b/WowPacketParser/Misc/ZLibHelper.cs new file mode 100644 index 0000000000..34717fb6b1 --- /dev/null +++ b/WowPacketParser/Misc/ZLibHelper.cs @@ -0,0 +1,92 @@ +using System; +using System.Runtime.InteropServices; +using WowPacketParser.Parsing.Parsers; + +namespace WowPacketParser.Misc +{ + internal partial class ZLibHelper + { + private const string CompressionLib = "compression_native"; + + [LibraryImport(CompressionLib, EntryPoint = "CompressionNative_InflateInit2_")] + private static partial int InflateInit2(ref ZStream zStream, int windowBits); + + [LibraryImport(CompressionLib, EntryPoint = "CompressionNative_Inflate")] + private static partial int Inflate(ref ZStream zStream, FlushCode flush); + + [LibraryImport(CompressionLib, EntryPoint = "CompressionNative_InflateEnd")] + private static partial int InflateEnd(ref ZStream zStream); + + public static void ResetInflateStream(int connectionIndex) + { + ref var zStream = ref CollectionsMarshal.GetValueRefOrAddDefault(SessionHandler.ZStreams, connectionIndex, out bool exists); + + InflateInit2(ref zStream, 15); + } + + public static bool TryInflate(int inflatedSize, int index, byte[] arr, ref byte[] newarr) + { + try + { + ref var zStream = ref CollectionsMarshal.GetValueRefOrAddDefault(SessionHandler.ZStreams, index, out bool exists); + + if (!exists) + { + var initResult = InflateInit2(ref zStream, 15); + + if (initResult != 0) + return false; + } + + nint uncompressedDataPtr = Marshal.AllocHGlobal(inflatedSize); + nint compressedDataPtr = Marshal.AllocHGlobal(arr.Length); + + Marshal.Copy(arr, 0, compressedDataPtr, arr.Length); + + zStream.AvailIn = (uint)arr.Length; + zStream.NextIn = compressedDataPtr; + zStream.AvailOut = (uint)inflatedSize; + zStream.NextOut = uncompressedDataPtr; + + Inflate(ref zStream, FlushCode.SyncFlush); + + Marshal.Copy(uncompressedDataPtr, newarr, 0, inflatedSize); + + Marshal.FreeHGlobal(compressedDataPtr); + Marshal.FreeHGlobal(uncompressedDataPtr); + + return true; + } + catch (Exception) + { + return false; + } + } + + public static void Inflate(int inflatedSize, byte[] arr, byte[] newarr) + { + ZStream zStream = default; + + InflateInit2(ref zStream, 15); + + nint uncompressedDataPtr = Marshal.AllocHGlobal(inflatedSize); + nint compressedDataPtr = Marshal.AllocHGlobal(arr.Length); + + Marshal.Copy(arr, 0, compressedDataPtr, arr.Length); + + zStream.AvailIn = (uint)arr.Length; + zStream.NextIn = compressedDataPtr; + zStream.AvailOut = (uint)inflatedSize; + zStream.NextOut = uncompressedDataPtr; + + Inflate(ref zStream, FlushCode.NoFlush); + Inflate(ref zStream, FlushCode.Finish); + InflateEnd(ref zStream); + + Marshal.Copy(uncompressedDataPtr, newarr, 0, inflatedSize); + + Marshal.FreeHGlobal(compressedDataPtr); + Marshal.FreeHGlobal(uncompressedDataPtr); + } + } +} diff --git a/WowPacketParser/Misc/ZStream.cs b/WowPacketParser/Misc/ZStream.cs new file mode 100644 index 0000000000..5cabb3ed1a --- /dev/null +++ b/WowPacketParser/Misc/ZStream.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; + +namespace WowPacketParser.Misc +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct ZStream + { + internal nint NextIn; + internal nint NextOut; + internal nint Msg; + + readonly nint InternalState; + + internal uint AvailIn; + internal uint AvailOut; + } +} diff --git a/WowPacketParser/Parsing/Parsers/SessionHandler.cs b/WowPacketParser/Parsing/Parsers/SessionHandler.cs index 41cca878c3..641d5aedf4 100644 --- a/WowPacketParser/Parsing/Parsers/SessionHandler.cs +++ b/WowPacketParser/Parsing/Parsers/SessionHandler.cs @@ -1,4 +1,3 @@ -using Ionic.Zlib; using System; using System.Collections.Generic; using System.Text; @@ -10,7 +9,7 @@ namespace WowPacketParser.Parsing.Parsers public static class SessionHandler { public static WowGuid LoginGuid; - public static Dictionary ZStreams = new Dictionary(); + public static Dictionary ZStreams = new Dictionary(); [Parser(Opcode.SMSG_AUTH_CHALLENGE, ClientVersionBuild.Zero, ClientVersionBuild.V4_0_1a_13205)] public static void HandleServerAuthChallenge(Packet packet) @@ -559,7 +558,7 @@ public static void HandleMessageOfTheDay(Packet packet) public static void HandleResetCompressionContext(Packet packet) { packet.ReadInt32("Unk?"); - ZStreams[packet.ConnectionIndex] = new ZlibCodec(CompressionMode.Decompress); + packet.ResetInflateStream(); } } } diff --git a/WowPacketParser/Program.cs b/WowPacketParser/Program.cs index 465d284678..c147a34603 100644 --- a/WowPacketParser/Program.cs +++ b/WowPacketParser/Program.cs @@ -3,6 +3,8 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; using System.Threading; using WowPacketParser.Loading; using WowPacketParser.Misc; @@ -15,6 +17,23 @@ public static class Program { private static void Main(string[] args) { + NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), (libraryName, assembly, searchPath) => + { + if (libraryName.Equals("compression_native", StringComparison.OrdinalIgnoreCase)) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return NativeLibrary.Load("System.IO.Compression.Native.dll", assembly, searchPath); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + return NativeLibrary.Load("libSystem.IO.Compression.Native.dylib", assembly, searchPath); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + return NativeLibrary.Load("libSystem.IO.Compression.Native.so", assembly, searchPath); + } + + return default; + }); + SetUpWindowTitle(); SetUpConsole(); diff --git a/WowPacketParser/WowPacketParser.csproj b/WowPacketParser/WowPacketParser.csproj index ea37eaab6f..5d54bbfc17 100644 --- a/WowPacketParser/WowPacketParser.csproj +++ b/WowPacketParser/WowPacketParser.csproj @@ -5,7 +5,6 @@ -