dotnet 8 实现 XXTEA 解密核心算法

dotnet 8 实现 XXTEA 解密核心算法

首先创建个目录

F:\program 接下来在这里面干活

查看是否安装dotnet

不记得什么时候装的了,有了直接用。(没装的看底部传送门)

bash 复制代码
F:\program>dotnet --version
8.0.403

初始化临时项目

bash 复制代码
dotnet new console --force
bash 复制代码
F:\program>dotnet new console --force
已成功创建模板"控制台应用"。

正在处理创建后操作...
正在还原 F:\program\program.csproj:
  正在确定要还原的项目...
  已还原 F:\program\program.csproj (用时 48 毫秒)。
已成功还原。

创建 C# 脚本

Program.cs 单文件版

csharp 复制代码
using System;
using System.IO;
using System.Text;

namespace XXTEATools
{
    class XXTEADecryptor
    {
        // ================= 配置区域 =================
        // SIGN: 加密文件的文件头标识(签名)
        // KEY:  XXTEA 加密的密钥
        private static string SIGN = "4meJnPyl"; 
        private static string KEY = "你的密钥"; 
        // ============================================

        static int Main(string[] args)
        {
            // 设置控制台编码为 UTF8,防止中文路径乱码
            Console.OutputEncoding = Encoding.UTF8;

            if (args.Length < 2)
            {
                Console.WriteLine("XXTEA 通用解密工具");
                Console.WriteLine("---------------------------------------");
                Console.WriteLine("用法: XXTEADecryptor.exe <输入文件路径> <输出文件路径>");
                Console.WriteLine("示例: XXTEADecryptor.exe config.lua config_dec.lua");
                return 1;
            }

            string inputPath = args[0];
            string outputPath = args[1];

            if (!File.Exists(inputPath))
            {
                Console.WriteLine($"[错误] 找不到输入文件: {inputPath}");
                return 1;
            }

            try
            {
                byte[] data = File.ReadAllBytes(inputPath);
                byte[] signBytes = Encoding.UTF8.GetBytes(SIGN);

                // 1. 验证文件头标识
                if (!IsMatchSign(data, signBytes))
                {
                    Console.WriteLine($"[跳过] 签名不匹配,非目标加密文件: {Path.GetFileName(inputPath)}");
                    return 1;
                }

                // 2. 剥离签名头部,提取加密负载
                byte[] encryptedData = new byte[data.Length - signBytes.Length];
                Buffer.BlockCopy(data, signBytes.Length, encryptedData, 0, encryptedData.Length);

                // 3. 执行 XXTEA 解密算法
                byte[] keyBytes = Encoding.UTF8.GetBytes(KEY);
                byte[] decryptedData = XXTEA.Decrypt(encryptedData, keyBytes);

                if (decryptedData == null || decryptedData.Length == 0)
                {
                    Console.WriteLine($"[失败] 解密结果为空,请检查密钥(Key)是否正确: {Path.GetFileName(inputPath)}");
                    return 1;
                }

                // 4. 自动处理输出目录
                string outputDir = Path.GetDirectoryName(outputPath);
                if (!string.IsNullOrEmpty(outputDir) && !Directory.Exists(outputDir))
                {
                    Directory.CreateDirectory(outputDir);
                }

                // 5. 保存结果
                File.WriteAllBytes(outputPath, decryptedData);
                Console.WriteLine($"[成功] {Path.GetFileName(inputPath)} -> {Path.GetFileName(outputPath)}");
                return 0;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[异常] 处理 {Path.GetFileName(inputPath)} 时发生错误: {ex.Message}");
                return 1;
            }
        }

        private static bool IsMatchSign(byte[] data, byte[] sign)
        {
            if (data.Length < sign.Length) return false;
            for (int i = 0; i < sign.Length; i++)
            {
                if (data[i] != sign[i]) return false;
            }
            return true;
        }
    }

    // ================= XXTEA 核心算法实现 =================
    public static class XXTEA
    {
        private const uint DELTA = 0x9e3779b9;

        public static byte[] Decrypt(byte[] data, byte[] key)
        {
            if (data == null || data.Length == 0) return data;
            uint[] v = ToUInt32Array(data, false);
            uint[] k = ToUInt32Array(FixKey(key), false);
            v = Decrypt(v, k);
            return ToByteArray(v, true);
        }

        private static uint[] Decrypt(uint[] v, uint[] k)
        {
            int n = v.Length - 1;
            if (n < 1) return v;
            uint z = v[n], y = v[0], sum, e;
            int p, q = 6 + 52 / (n + 1);
            unchecked
            {
                sum = (uint)(q * DELTA);
                while (sum != 0)
                {
                    e = (sum >> 2) & 3;
                    for (p = n; p > 0; p--)
                    {
                        z = v[p - 1];
                        y = v[p] -= ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z));
                    }
                    z = v[n];
                    y = v[0] -= ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z));
                    sum -= DELTA;
                }
            }
            return v;
        }

        private static byte[] FixKey(byte[] key)
        {
            if (key.Length == 16) return key;
            byte[] fixedKey = new byte[16];
            Array.Copy(key, 0, fixedKey, 0, Math.Min(key.Length, 16));
            return fixedKey;
        }

        private static uint[] ToUInt32Array(byte[] data, bool includeLength)
        {
            int length = data.Length;
            int n = (((length & 3) == 0) ? (length >> 2) : ((length >> 2) + 1));
            uint[] result;
            if (includeLength)
            {
                result = new uint[n + 1];
                result[n] = (uint)length;
            }
            else
            {
                result = new uint[n];
            }
            for (int i = 0; i < length; i++)
            {
                result[i >> 2] |= (uint)data[i] << ((i & 3) << 3);
            }
            return result;
        }

        private static byte[] ToByteArray(uint[] data, bool includeLength)
        {
            int n = data.Length << 2;
            if (includeLength)
            {
                int m = (int)data[data.Length - 1];
                n -= 4;
                if (m < n - 3 || m > n) return null;
                n = m;
            }
            byte[] result = new byte[n];
            for (int i = 0; i < n; i++)
            {
                result[i] = (byte)(data[i >> 2] >> ((i & 3) << 3));
            }
            return result;
        }
    }
}

加强版

csharp 复制代码
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Collections.Generic;

namespace XXTEATools
{
    class XXTEADecryptor
    {
        // ================= 核心配置区域 =================
        // SIGN: 加密文件的文件头标识(签名)
        // KEY:  XXTEA 加密的密钥
        private static string SIGN = "4meJnPyl"; 
        private static string KEY = "你的密钥"; 
        // ================================================

        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;

            string inputPath = null;
            string outputPath = null;
            HashSet<string> filters = null;

            // --- 命令行参数解析逻辑 ---
            for (int i = 0; i < args.Length; i++)
            {
                switch (args[i].ToLower())
                {
                    case "-i":
                        if (i + 1 < args.Length) inputPath = args[++i];
                        break;
                    case "-o":
                        if (i + 1 < args.Length) outputPath = args[++i];
                        break;
                    case "-f":
                        filters = new HashSet<string>();
                        while (i + 1 < args.Length && !args[i + 1].StartsWith("-"))
                        {
                            string ext = args[++i].ToLower();
                            filters.Add(ext.StartsWith(".") ? ext : "." + ext);
                        }
                        break;
                    case "-h":
                    case "--help":
                        PrintUsage();
                        return;
                }
            }

            // 兼容性处理:如果没有开关且有参数,默认第一个为输入路径
            if (string.IsNullOrEmpty(inputPath) && args.Length > 0 && !args[0].StartsWith("-"))
            {
                inputPath = args[0];
            }

            if (string.IsNullOrEmpty(inputPath))
            {
                PrintUsage();
                return;
            }

            Execute(inputPath, outputPath, filters);
        }

        static void PrintUsage()
        {
            Console.WriteLine("\n==================================================");
            Console.WriteLine("           XXTEA 全自动递归解密工具               ");
            Console.WriteLine("==================================================\n");
            Console.WriteLine("参数选项:");
            Console.WriteLine("  -i <路径>    必需。指定要处理的文件或文件夹路径。");
            Console.WriteLine("  -o <路径>    可选。指定输出根目录。若不带此参数,则直接覆盖原文件。");
            Console.WriteLine("  -f <扩展名>  可选。指定后缀过滤,空格分隔。示例: -f png lua json");
            Console.WriteLine("  -h           显示此帮助信息。");
            Console.WriteLine("\n使用示例:");
            Console.WriteLine("  1. 原地还原当前目录所有文件:");
            Console.WriteLine("     XXTEADecryptor.exe -i .");
            Console.WriteLine("\n  2. 还原指定格式并输出到新文件夹 (保持子目录结构):");
            Console.WriteLine("     XXTEADecryptor.exe -i D:\\Res -o D:\\Out -f png lua");
            Console.WriteLine("\n  3. 处理单个文件并重命名输出:");
            Console.WriteLine("     XXTEADecryptor.exe -i old.png -o new.png");
            Console.WriteLine("--------------------------------------------------\n");
        }

        static void Execute(string inputPath, string outputPath, HashSet<string> filters)
        {
            bool isDirectory = Directory.Exists(inputPath);
            bool isFile = File.Exists(inputPath);

            if (!isDirectory && !isFile)
            {
                Console.WriteLine($"[错误] 路径不存在: {inputPath}");
                return;
            }

            if (isDirectory)
            {
                Console.WriteLine($"[开始扫描] 目录: {Path.GetFullPath(inputPath)}");
                var files = Directory.EnumerateFiles(inputPath, "*.*", SearchOption.AllDirectories);
                foreach (var file in files)
                {
                    string targetFile = file;
                    if (!string.IsNullOrEmpty(outputPath))
                    {
                        // 计算相对路径,以便在输出目录重建结构
                        string relativePath = Path.GetRelativePath(inputPath, file);
                        targetFile = Path.Combine(outputPath, relativePath);
                    }
                    ProcessFile(file, targetFile, filters);
                }
            }
            else
            {
                string targetFile = outputPath ?? inputPath;
                // 如果 -o 指向一个已存在的目录,则把文件放进去
                if (!string.IsNullOrEmpty(outputPath) && Directory.Exists(outputPath))
                {
                    targetFile = Path.Combine(outputPath, Path.GetFileName(inputPath));
                }
                ProcessFile(inputPath, targetFile, filters);
            }
            Console.WriteLine("\n[完成] 任务处理结束。");
        }

        static void ProcessFile(string sourceFile, string targetFile, HashSet<string> filters)
        {
            // 扩展名过滤
            if (filters != null && !filters.Contains(Path.GetExtension(sourceFile).ToLower())) return;

            try
            {
                byte[] signBytes = Encoding.UTF8.GetBytes(SIGN);
                
                // 第一阶段:快速校验文件头(不读取全文,节省内存和IO)
                using (FileStream fs = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
                {
                    if (fs.Length < signBytes.Length) return;
                    byte[] head = new byte[signBytes.Length];
                    fs.Read(head, 0, head.Length);
                    for (int i = 0; i < signBytes.Length; i++)
                    {
                        if (head[i] != signBytes[i]) return; // 签名不匹配则跳过
                    }
                }

                // 第二阶段:读取并解密
                byte[] fullData = File.ReadAllBytes(sourceFile);
                byte[] encrypted = new byte[fullData.Length - signBytes.Length];
                Buffer.BlockCopy(fullData, signBytes.Length, encrypted, 0, encrypted.Length);
                
                byte[] decrypted = XXTEA.Decrypt(encrypted, Encoding.UTF8.GetBytes(KEY));
                if (decrypted == null)
                {
                    Console.WriteLine($"[异常] 解密失败 (Key可能不对): {Path.GetFileName(sourceFile)}");
                    return;
                }

                // 确保目标路径的父目录存在
                string dir = Path.GetDirectoryName(targetFile);
                if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);

                File.WriteAllBytes(targetFile, decrypted);
                Console.WriteLine($"[OK] {Path.GetFileName(sourceFile)}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[跳过] {Path.GetFileName(sourceFile)}: {ex.Message}");
            }
        }
    }

    // ================= XXTEA 核心算法实现 =================
    public static class XXTEA
    {
        private const uint DELTA = 0x9e3779b9;

        public static byte[] Decrypt(byte[] data, byte[] key)
        {
            if (data == null || data.Length == 0) return data;
            uint[] v = ToUInt32Array(data, false);
            uint[] k = ToUInt32Array(FixKey(key), false);
            v = Decrypt(v, k);
            return ToByteArray(v, true);
        }

        private static uint[] Decrypt(uint[] v, uint[] k)
        {
            int n = v.Length - 1;
            if (n < 1) return v;
            uint z = v[n], y = v[0], sum, e;
            int p, q = 6 + 52 / (n + 1);
            unchecked
            {
                sum = (uint)(q * DELTA);
                while (sum != 0)
                {
                    e = (sum >> 2) & 3;
                    for (p = n; p > 0; p--)
                    {
                        z = v[p - 1];
                        y = v[p] -= ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z));
                    }
                    z = v[n];
                    y = v[0] -= ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z));
                    sum -= DELTA;
                }
            }
            return v;
        }

        private static byte[] FixKey(byte[] key)
        {
            if (key.Length == 16) return key;
            byte[] fixedKey = new byte[16];
            Array.Copy(key, 0, fixedKey, 0, Math.Min(key.Length, 16));
            return fixedKey;
        }

        private static uint[] ToUInt32Array(byte[] data, bool includeLength)
        {
            int length = data.Length;
            int n = (((length & 3) == 0) ? (length >> 2) : ((length >> 2) + 1));
            uint[] result = includeLength ? new uint[n + 1] : new uint[n];
            if (includeLength) result[n] = (uint)length;
            for (int i = 0; i < length; i++) result[i >> 2] |= (uint)data[i] << ((i & 3) << 3);
            return result;
        }

        private static byte[] ToByteArray(uint[] data, bool includeLength)
        {
            int n = data.Length << 2;
            if (includeLength)
            {
                int m = (int)data[data.Length - 1];
                n -= 4;
                if (m < n - 3 || m > n) return null;
                n = m;
            }
            byte[] result = new byte[n];
            for (int i = 0; i < n; i++) result[i] = (byte)(data[i >> 2] >> ((i & 3) << 3));
            return result;
        }
    }
}

发布为单文件 EXE

AssemblyName=program 可以控制输出的 exe 文件名

bash 复制代码
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:AssemblyName=program -o ./dist
bash 复制代码
F:\program>dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:AssemblyName=program -o ./dist
  正在确定要还原的项目...
  已还原 F:\program\program.csproj (用时 2.59 秒)。
  program -> F:\program\bin\Release\net8.0\win-x64\program.dll
  program -> F:\program\dist\

得到文件:

测试

bash 复制代码
F:\program\dist>program.exe 0.png 01.png
[成功] 0.png -> 0_decrypted.png

参考资料

DotNet 命令行开发 + VSCode 调试

相关推荐
龙佚1 小时前
噪声抑制技术:让语音更清晰
算法·架构
兰令水1 小时前
topcode【随机算法题】【2026.5.14打卡-java版本】
java·算法·leetcode
故事和你911 小时前
洛谷-【图论2-1】树2
开发语言·数据结构·c++·算法·动态规划·图论
MicroTech20251 小时前
变分量子算法再升级:MLGO微算法科技滤波变分量子本征求解器推动量子计算落地
科技·算法·量子计算
gihigo19981 小时前
竞争性自适应重加权算法(CARS)
算法
foundbug9992 小时前
LSSVM(最小二乘支持向量机)状态分类与预测
算法
z200509302 小时前
今日算法:617,合并二叉树
算法·leetcode
ZHW_AI课题组2 小时前
基于逻辑回归的乳腺癌预测分类
算法·分类·逻辑回归
胡志辉2 小时前
贪心算法最坑的地方:每一步都看起来很对,最后还是错了
算法