From 0b91e177a887c643e170bb04b034548a5a6c2e0a Mon Sep 17 00:00:00 2001 From: Dime Date: Fri, 19 Jun 2026 10:20:19 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E4=BD=BF=E7=94=A8=E8=BD=AF=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BedrockLauncher.Core/BedrockCore.cs | 2 +- .../CoreOption/LocalGamePackageOptions.cs | 7 + .../GdkDecode/MsiXVDDecoder.cs | 159 +++++++++++++++++- TestProject/Program.cs | 27 ++- 4 files changed, 177 insertions(+), 18 deletions(-) diff --git a/BedrockLauncher.Core/BedrockCore.cs b/BedrockLauncher.Core/BedrockCore.cs index ca96be8..1426cce 100644 --- a/BedrockLauncher.Core/BedrockCore.cs +++ b/BedrockLauncher.Core/BedrockCore.cs @@ -189,7 +189,7 @@ await Task.Run((async () => MinecraftGameTypeVersion.Beta => _DEFINE_REF2.pre, _=>null }); - var msiXvdDecoder = new MsiXVDDecoder(cik); + var msiXvdDecoder = new MsiXVDDecoder(cik, options.UseHardwareDecode); var msiXvdStream = new MsiXVDStream(options.FileFullPath); msiXvdStream.Parse(); options.InstallStates?.Report(InstallStates.Extracting); diff --git a/BedrockLauncher.Core/CoreOption/LocalGamePackageOptions.cs b/BedrockLauncher.Core/CoreOption/LocalGamePackageOptions.cs index 9790b42..b8029a1 100644 --- a/BedrockLauncher.Core/CoreOption/LocalGamePackageOptions.cs +++ b/BedrockLauncher.Core/CoreOption/LocalGamePackageOptions.cs @@ -60,6 +60,13 @@ public class LocalGamePackageOptions /// Title Name only being used When it is in Uwp mode /// public string? GameName; + + /// + /// Gets or sets whether to use hardware-accelerated AES-NI/SSE2 decoding for GDK packages. + /// Set to false to use software-based AES decryption (compatible with CPUs lacking AES-NI support). + /// Default is true (hardware decode). + /// + public bool UseHardwareDecode { get; set; } = true; } /// diff --git a/BedrockLauncher.Core/GdkDecode/MsiXVDDecoder.cs b/BedrockLauncher.Core/GdkDecode/MsiXVDDecoder.cs index 3bdd250..e3ea6be 100644 --- a/BedrockLauncher.Core/GdkDecode/MsiXVDDecoder.cs +++ b/BedrockLauncher.Core/GdkDecode/MsiXVDDecoder.cs @@ -2,20 +2,59 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using CryptAes = System.Security.Cryptography.Aes; +using SysCrypt = System.Security.Cryptography; namespace BedrockLauncher.Core.GdkDecode; -public class MsiXVDDecoder +public class MsiXVDDecoder : IDisposable { public KeySinagl d; public KeySinagl t; + private readonly bool _useHardware; + private readonly CryptAes? _swAesD; + private readonly CryptAes? _swAesT; - public MsiXVDDecoder(CikKey key) + public MsiXVDDecoder(CikKey key) : this(key, true) { - d.Init(key.DKey,true); - t.Init(key.TKey,false); } + public MsiXVDDecoder(CikKey key, bool useHardware) + { + _useHardware = useHardware; + if (useHardware) + { + d.Init(key.DKey, true); + t.Init(key.TKey, false); + _swAesD = null; + _swAesT = null; + } + else + { + _swAesD = CryptAes.Create(); + _swAesD.KeySize = 128; + _swAesD.Key = key.DKey; + _swAesD.Mode = SysCrypt.CipherMode.ECB; + _swAesD.Padding = SysCrypt.PaddingMode.None; + + _swAesT = CryptAes.Create(); + _swAesT.KeySize = 128; + _swAesT.Key = key.TKey; + _swAesT.Mode = SysCrypt.CipherMode.ECB; + _swAesT.Padding = SysCrypt.PaddingMode.None; + } + } + + public int Decrypt(ReadOnlySpan input, Span output, ReadOnlySpan tweakIv) + { + if (_useHardware) + return DecryptHardware(input, output, tweakIv); + else + return DecryptSoftware(input, output, tweakIv); + } + + #region Hardware Decode (AES-NI / SSE2) + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128 Gf128Mul(Vector128 iv, Vector128 mask) { @@ -26,7 +65,7 @@ private static Vector128 Gf128Mul(Vector128 iv, Vector128 mask return Sse2.Xor(tmp1, tmp2); } - public int Decrypt(ReadOnlySpan input, Span output, ReadOnlySpan tweakIv) + private int DecryptHardware(ReadOnlySpan input, Span output, ReadOnlySpan tweakIv) { if (tweakIv.Length < 16) return 0; @@ -134,10 +173,10 @@ public int Decrypt(ReadOnlySpan input, Span output, ReadOnlySpan in0, Vector128 in1, Vector128 in2, @@ -268,4 +307,108 @@ public void DecryptBlocks8( out7 = Aes.DecryptLast(b7, key); } + #endregion + + #region Software Decode (managed AES) + + private int DecryptSoftware(ReadOnlySpan input, Span output, ReadOnlySpan tweakIv) + { + if (tweakIv.Length < 16) + return 0; + + int length = Math.Min(input.Length, output.Length); + if (length == 0) + return 0; + + int remainingBlocks = length >> 4; + int leftover = length & 0xF; + + if (leftover != 0) + remainingBlocks--; + + if (remainingBlocks <= 0 && leftover == 0) + return 0; + + byte[] tweak = new byte[16]; + _swAesT!.EncryptEcb(tweakIv[..16], tweak, SysCrypt.PaddingMode.None); + + Span tempIn = stackalloc byte[16]; + Span tempOut = stackalloc byte[16]; + int offset = 0; + + while (remainingBlocks > 0) + { + XorBytes(input.Slice(offset, 16), tweak, tempIn); + _swAesD.DecryptEcb(tempIn, tempOut, SysCrypt.PaddingMode.None); + XorBytes(tempOut, tweak, output.Slice(offset, 16)); + Gf128MulSoftware(tweak); + offset += 16; + remainingBlocks--; + } + + if (leftover != 0) + { + byte[] finalTweak = tweak[..]; // copy: finalTweak = Gf128Mul(tweak) + Gf128MulSoftware(finalTweak); + + XorBytes(input.Slice(offset, 16), finalTweak, tempIn); + _swAesD.DecryptEcb(tempIn, tempOut, SysCrypt.PaddingMode.None); + XorBytes(tempOut, finalTweak, output.Slice(offset, 16)); + + Span currentOut = output.Slice(offset, 16); + ReadOnlySpan nextIn = input.Slice(offset + 16, leftover); + Span nextOut = output.Slice(offset + 16, leftover); + + Span temp = stackalloc byte[16]; + + for (int i = 0; i < leftover; i++) + { + nextOut[i] = currentOut[i]; + temp[i] = nextIn[i]; + } + + for (int i = leftover; i < 16; i++) + { + temp[i] = currentOut[i]; + } + + XorBytes(temp, tweak, tempIn); + _swAesD.DecryptEcb(tempIn, tempOut, SysCrypt.PaddingMode.None); + XorBytes(tempOut, tweak, output.Slice(offset, 16)); + } + + return length; + } + + private static void XorBytes(ReadOnlySpan a, ReadOnlySpan b, Span result) + { + for (int i = 0; i < 16; i++) + result[i] = (byte)(a[i] ^ b[i]); + } + + private static void Gf128MulSoftware(Span iv) + { + int carryBit127 = (iv[15] >> 7) & 1; + int carryBit63 = (iv[7] >> 7) & 1; + + for (int i = 7; i > 0; i--) + iv[i] = (byte)((iv[i] << 1) | (iv[i - 1] >> 7)); + iv[0] <<= 1; + + for (int i = 15; i > 8; i--) + iv[i] = (byte)((iv[i] << 1) | (iv[i - 1] >> 7)); + iv[8] <<= 1; + + if (carryBit63 != 0) iv[8] ^= 0x01; + if (carryBit127 != 0) iv[0] ^= 0x87; + } + + #endregion + + public void Dispose() + { + _swAesD?.Dispose(); + _swAesT?.Dispose(); + GC.SuppressFinalize(this); + } } \ No newline at end of file diff --git a/TestProject/Program.cs b/TestProject/Program.cs index 50b31f2..3499d31 100644 --- a/TestProject/Program.cs +++ b/TestProject/Program.cs @@ -1,6 +1,7 @@ using BedrockLauncher.Core; using BedrockLauncher.Core.CoreOption; -using System.Diagnostics; +using Windows.Management.Deployment; +using BedrockLauncher.Core.Utils; namespace TestProject { @@ -10,15 +11,23 @@ static void Main(string[] args) { var bedrockCore = new BedrockCore(); bedrockCore.InitAsync().Wait(); - var launchOptions = new LaunchOptions() + + bedrockCore.InstallPackageAsync(new LocalGamePackageOptions() { - GameFolder = "D:\\BedrockBoot\\bedrock_versions\\1.21.11401", - GameType = MinecraftGameTypeVersion.Release, - MinecraftBuildType = MinecraftBuildTypeVersion.UWP, - LaunchArgs = "minecraft://creator/?Editor=true" - }; - var process = bedrockCore.LaunchGameAsync(launchOptions).Result; - Console.WriteLine(process.Id); + FileFullPath = @"D:\BedrockBoot\version_save\1.26.2.insPack", + Type = MinecraftBuildTypeVersion.GDK, + GameTypeVersion = MinecraftGameTypeVersion.Release, + InstallDstFolder = Path.GetFullPath(@"E:\GDK_TestInstall\1.26_2"), + UseHardwareDecode = false, + DeployProgress = new Progress(p => + Console.WriteLine($"Deploy: {p.percentage}%")), + ExtractionProgress = new Progress(p => + Console.WriteLine($"Extract: [{p.CurrentCount}/{p.TotalCount}] {p.FileName}")), + InstallStates = new Progress(s => + Console.WriteLine($"State: {s}")), + }).Wait(); + + Console.WriteLine("Install done."); } } } From 8daa4fffc1a7ab59a48fafcfc613a3b1bc9b241a Mon Sep 17 00:00:00 2001 From: Dime Date: Fri, 19 Jun 2026 10:22:13 +0800 Subject: [PATCH 2/4] chore: update version --- BedrockLauncher.Core/BedrockLauncher.Core.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BedrockLauncher.Core/BedrockLauncher.Core.csproj b/BedrockLauncher.Core/BedrockLauncher.Core.csproj index b893b52..c860bf5 100644 --- a/BedrockLauncher.Core/BedrockLauncher.Core.csproj +++ b/BedrockLauncher.Core/BedrockLauncher.Core.csproj @@ -20,11 +20,11 @@ true - 2.0.4.4-dev + 2.0.4.5-dev - 2.0.4.4 + 2.0.4.5 From a2dbe0f8bd0b8eb4fb17632fc9663cab5a57b4ad Mon Sep 17 00:00:00 2001 From: Dime Date: Fri, 3 Jul 2026 09:14:18 +0800 Subject: [PATCH 3/4] fix: Fixed the bug where quotes weren't added when starting instances with spaces --- BedrockLauncher.Core/BedrockCore.cs | 2 +- BedrockLauncher.Core/BedrockLauncher.Core.csproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BedrockLauncher.Core/BedrockCore.cs b/BedrockLauncher.Core/BedrockCore.cs index 1426cce..65628e6 100644 --- a/BedrockLauncher.Core/BedrockCore.cs +++ b/BedrockLauncher.Core/BedrockCore.cs @@ -291,7 +291,7 @@ public async Task LaunchGameAsync(LaunchOptions options) { FileName = "cmd.exe", ArgumentList = - { "/c", "start", fullPath, string.IsNullOrEmpty(options.LaunchArgs) ? "" : options.LaunchArgs }, + { "/c", "start", $"\"{fullPath}\"", string.IsNullOrEmpty(options.LaunchArgs) ? "" : options.LaunchArgs }, UseShellExecute = false, CreateNoWindow = true }); diff --git a/BedrockLauncher.Core/BedrockLauncher.Core.csproj b/BedrockLauncher.Core/BedrockLauncher.Core.csproj index c860bf5..8d3f3db 100644 --- a/BedrockLauncher.Core/BedrockLauncher.Core.csproj +++ b/BedrockLauncher.Core/BedrockLauncher.Core.csproj @@ -20,11 +20,11 @@ true - 2.0.4.5-dev + 2.0.4.6-dev - 2.0.4.5 + 2.0.4.6 From fed2c50dda77d4f800f146a1de0b7979beb83f96 Mon Sep 17 00:00:00 2001 From: Dime Date: Fri, 3 Jul 2026 09:31:51 +0800 Subject: [PATCH 4/4] fix: Fixed the bug where quotes weren't added when starting instances with spaces --- BedrockLauncher.Core/BedrockCore.cs | 5 +++-- BedrockLauncher.Core/BedrockLauncher.Core.csproj | 4 ++-- TestProject/Program.cs | 10 ++++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/BedrockLauncher.Core/BedrockCore.cs b/BedrockLauncher.Core/BedrockCore.cs index 65628e6..3136e94 100644 --- a/BedrockLauncher.Core/BedrockCore.cs +++ b/BedrockLauncher.Core/BedrockCore.cs @@ -287,11 +287,12 @@ public async Task LaunchGameAsync(LaunchOptions options) .ToDictionary(p => p.Id, p => GetStartTimeSafe(p)); DateTime launchTime = DateTime.Now; + string cmdLine = $"/c start \"\" \"{fullPath}\" {options.LaunchArgs}"; + Process.Start(new ProcessStartInfo { FileName = "cmd.exe", - ArgumentList = - { "/c", "start", $"\"{fullPath}\"", string.IsNullOrEmpty(options.LaunchArgs) ? "" : options.LaunchArgs }, + Arguments = cmdLine, UseShellExecute = false, CreateNoWindow = true }); diff --git a/BedrockLauncher.Core/BedrockLauncher.Core.csproj b/BedrockLauncher.Core/BedrockLauncher.Core.csproj index 8d3f3db..c26618a 100644 --- a/BedrockLauncher.Core/BedrockLauncher.Core.csproj +++ b/BedrockLauncher.Core/BedrockLauncher.Core.csproj @@ -20,11 +20,11 @@ true - 2.0.4.6-dev + 2.0.4.7-dev - 2.0.4.6 + 2.0.4.7 diff --git a/TestProject/Program.cs b/TestProject/Program.cs index 3499d31..adb05ff 100644 --- a/TestProject/Program.cs +++ b/TestProject/Program.cs @@ -12,7 +12,7 @@ static void Main(string[] args) var bedrockCore = new BedrockCore(); bedrockCore.InitAsync().Wait(); - bedrockCore.InstallPackageAsync(new LocalGamePackageOptions() + /*bedrockCore.InstallPackageAsync(new LocalGamePackageOptions() { FileFullPath = @"D:\BedrockBoot\version_save\1.26.2.insPack", Type = MinecraftBuildTypeVersion.GDK, @@ -25,8 +25,14 @@ static void Main(string[] args) Console.WriteLine($"Extract: [{p.CurrentCount}/{p.TotalCount}] {p.FileName}")), InstallStates = new Progress(s => Console.WriteLine($"State: {s}")), - }).Wait(); + }).Wait();*/ + bedrockCore.LaunchGameAsync(new() + { + MinecraftBuildType = MinecraftBuildTypeVersion.GDK, + GameFolder = "E:\\Bedrock Test\\bedrock_versions\\1.26.3202", + GameType = MinecraftGameTypeVersion.Release + }); Console.WriteLine("Install done."); } }