From d2fac1dab3fd8f09208be5b9f3897f1d84bcd466 Mon Sep 17 00:00:00 2001 From: walon Date: Sat, 17 May 2025 13:59:03 +0800 Subject: [PATCH] new: add DeobfuscateStackTrace project --- .../DeobfuscateStackTrace.csproj | 15 + .../DeobfuscateStackTrace.sln | 24 + DeobfuscateStackTrace/Program.cs | 57 + .../Properties/launchSettings.json | 8 + .../StackTraceDeObfuscator.cs | 49 + DeobfuscateStackTrace/SymbolMappingReader.cs | 204 + DeobfuscateStackTrace/mapping.xml | 3614 +++++++++++++++++ 7 files changed, 3971 insertions(+) create mode 100644 DeobfuscateStackTrace/DeobfuscateStackTrace.csproj create mode 100644 DeobfuscateStackTrace/DeobfuscateStackTrace.sln create mode 100644 DeobfuscateStackTrace/Program.cs create mode 100644 DeobfuscateStackTrace/Properties/launchSettings.json create mode 100644 DeobfuscateStackTrace/StackTraceDeObfuscator.cs create mode 100644 DeobfuscateStackTrace/SymbolMappingReader.cs create mode 100644 DeobfuscateStackTrace/mapping.xml diff --git a/DeobfuscateStackTrace/DeobfuscateStackTrace.csproj b/DeobfuscateStackTrace/DeobfuscateStackTrace.csproj new file mode 100644 index 0000000..c20cf7e --- /dev/null +++ b/DeobfuscateStackTrace/DeobfuscateStackTrace.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + disable + 1.0.0 + + + + + + + diff --git a/DeobfuscateStackTrace/DeobfuscateStackTrace.sln b/DeobfuscateStackTrace/DeobfuscateStackTrace.sln new file mode 100644 index 0000000..98fcbcc --- /dev/null +++ b/DeobfuscateStackTrace/DeobfuscateStackTrace.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35931.197 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeobfuscateStackTrace", "DeobfuscateStackTrace.csproj", "{B7192F39-1EEA-4F31-885B-B606D700FC79}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B7192F39-1EEA-4F31-885B-B606D700FC79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7192F39-1EEA-4F31-885B-B606D700FC79}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7192F39-1EEA-4F31-885B-B606D700FC79}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7192F39-1EEA-4F31-885B-B606D700FC79}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9F39E3ED-EF31-43DE-B085-0F7BF60844E8} + EndGlobalSection +EndGlobal diff --git a/DeobfuscateStackTrace/Program.cs b/DeobfuscateStackTrace/Program.cs new file mode 100644 index 0000000..9cda94b --- /dev/null +++ b/DeobfuscateStackTrace/Program.cs @@ -0,0 +1,57 @@ +using CommandLine; + +namespace DeobfuscateStackTrace +{ + internal class Program + { + private class CommandOptions + { + + [Option('m', "mappingFile", Required = true, HelpText = "mapping xml file")] + public string MappingFile { get; set; } + + [Option('i', "input", Required = true, HelpText = "input obfuscated log file")] + public string InputFile { get; set; } + + [Option('o', "output", Required = true, HelpText = "output deobfuscated log file")] + public string OutputFile { get; set; } + + } + + static void Main(string[] args) + { + CommandOptions opt = ParseArgs(args); + + if (!File.Exists(opt.MappingFile)) + { + Console.Error.WriteLine($"Mapping file {opt.MappingFile} not found"); + Environment.Exit(1); + } + if (!File.Exists(opt.InputFile)) + { + Console.Error.WriteLine($"Input file {opt.InputFile} not found"); + Environment.Exit(1); + } + var reader = new SymbolMappingReader(opt.MappingFile); + StackTraceDeObfuscator.Convert(reader, opt.InputFile, opt.OutputFile); + } + + private static CommandOptions ParseArgs(string[] args) + { + var helpWriter = new StringWriter(); + var parser = new Parser(settings => + { + settings.AllowMultiInstance = true; + settings.HelpWriter = helpWriter; + }); + + var result = parser.ParseArguments(args); + if (result.Tag == ParserResultType.NotParsed) + { + Console.Error.WriteLine(helpWriter.ToString()); + Environment.Exit(1); + } + return ((Parsed)result).Value; + } + } +} diff --git a/DeobfuscateStackTrace/Properties/launchSettings.json b/DeobfuscateStackTrace/Properties/launchSettings.json new file mode 100644 index 0000000..de0ffc0 --- /dev/null +++ b/DeobfuscateStackTrace/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "DeobfuscateStackTrace": { + "commandName": "Project", + "commandLineArgs": "-m ../../../mapping.xml -i ../../../obfuscated.log -o ../../../deobfuscated.log" + } + } +} \ No newline at end of file diff --git a/DeobfuscateStackTrace/StackTraceDeObfuscator.cs b/DeobfuscateStackTrace/StackTraceDeObfuscator.cs new file mode 100644 index 0000000..2a13ab0 --- /dev/null +++ b/DeobfuscateStackTrace/StackTraceDeObfuscator.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DeobfuscateStackTrace +{ + public class StackTraceDeObfuscator + { + public static void Convert(SymbolMappingReader reader, string oldLogFile, string newLogFile) + { + var obfuscatedLines = File.ReadAllLines(oldLogFile, Encoding.UTF8); + var deObfuscatedLines = new List(); + + bool logLineFound = false; + foreach (string line in obfuscatedLines) + { + if (TryConvertLine(line, reader, ref logLineFound, out var newLine)) + { + deObfuscatedLines.Add(newLine); + } + else + { + deObfuscatedLines.Add(line); + } + } + File.WriteAllLines(newLogFile, deObfuscatedLines, Encoding.UTF8); + } + + private static bool TryConvertLine(string line, SymbolMappingReader reader, ref bool logLineFound, out string deObfuscatedStackTrace) + { + deObfuscatedStackTrace = line; + if (string.IsNullOrEmpty(line)) + { + logLineFound = false; + return false; + } + if (!logLineFound) + { + logLineFound = line.StartsWith("UnityEngine.DebugLogHandler:Internal_Log") + || line.StartsWith("UnityEngine.DebugLogHandler:LogFormat") + || line.StartsWith("UnityEngine.Logger:Log"); + return false; + } + return reader.TryDeObfuscateStackTrace(line, out deObfuscatedStackTrace); + } + } +} diff --git a/DeobfuscateStackTrace/SymbolMappingReader.cs b/DeobfuscateStackTrace/SymbolMappingReader.cs new file mode 100644 index 0000000..5d103c4 --- /dev/null +++ b/DeobfuscateStackTrace/SymbolMappingReader.cs @@ -0,0 +1,204 @@ + +using System.Xml; + +namespace DeobfuscateStackTrace +{ + + public class SymbolMappingReader + { + + private readonly Dictionary> _fullSignatureMapper = new Dictionary>(); + private readonly Dictionary> _signatureWithParamsMapper = new Dictionary>(); + + + private enum RenameStatus + { + NotRenamed, + Renamed, + } + + private class RenameRecord + { + public RenameStatus status; + public string signature; + public string oldName; + public string newName; + public string oldStackTraceSignature; // only for MethodDef + public object renameMappingData; + } + + private class RenameMappingField + { + public RenameStatus status; + public string signature; + public string newName; + } + + private class RenameMappingMethod + { + public RenameStatus status; + public string signature; + public string newName; + + public List parameters = new List(); + } + + private class RenameMappingMethodParam + { + public RenameStatus status; + public int index; + public string newName; + } + + private class RenameMappingProperty + { + public RenameStatus status; + public string signature; + public string newName; + } + + private class RenameMappingEvent + { + public RenameStatus status; + public string signature; + public string newName; + } + + private class RenameMappingType + { + public RenameStatus status; + public string oldFullName; + public string newFullName; + + public Dictionary fields = new Dictionary(); + public Dictionary methods = new Dictionary(); + public Dictionary properties = new Dictionary(); + public Dictionary events = new Dictionary(); + } + + private class RenameMappingAssembly + { + public RenameStatus status; + public string oldAssName; + public string newAssName; + + public Dictionary types = new Dictionary(); + } + + + public SymbolMappingReader(string mappingFile) + { + LoadXmlMappingFile(mappingFile); + } + + private void LoadXmlMappingFile(string mappingFile) + { + var doc = new XmlDocument(); + doc.Load(mappingFile); + var root = doc.DocumentElement; + foreach (XmlNode node in root.ChildNodes) + { + if (!(node is XmlElement element)) + { + continue; + } + LoadAssemblyMapping(element); + } + } + + private void LoadAssemblyMapping(XmlElement ele) + { + if (ele.Name != "assembly") + { + throw new System.Exception($"Invalid node name: {ele.Name}. Expected 'assembly'."); + } + foreach (XmlNode node in ele.ChildNodes) + { + if (!(node is XmlElement element)) + { + continue; + } + if (element.Name == "type") + { + LoadTypeMapping(element); + } + } + } + + private void LoadTypeMapping(XmlElement ele) + { + foreach (XmlNode node in ele.ChildNodes) + { + if (!(node is XmlElement c)) + { + continue; + } + if (node.Name == "method") + { + LoadMethodMapping(c); + } + } + } + + + private string GetMethodSignatureWithoutParams(string signature) + { + int index = signature.IndexOf('('); + if (index < 0) + { + return signature; + } + return signature.Substring(0, index); + } + + private void LoadMethodMapping(XmlElement ele) + { + if (!ele.HasAttribute("oldStackTraceSignature")) + { + throw new System.Exception($"Invalid node name: {ele.Name}. attribute 'oldStackTraceSignature' missing."); + } + if (!ele.HasAttribute("newStackTraceSignature")) + { + throw new System.Exception($"Invalid node name: {ele.Name}. attribute 'newStackTraceSignature' missing."); + } + string oldStackTraceSignature = ele.Attributes["oldStackTraceSignature"].Value; + string newStackTraceSignature = ele.Attributes["newStackTraceSignature"].Value; + + if (!_fullSignatureMapper.TryGetValue(newStackTraceSignature, out var oldFullSignatures)) + { + oldFullSignatures = new List(); + _fullSignatureMapper[newStackTraceSignature] = oldFullSignatures; + } + oldFullSignatures.Add(oldStackTraceSignature); + + string oldStackTraceSignatureWithoutParams = GetMethodSignatureWithoutParams(oldStackTraceSignature); + string newStackTraceSignatureWithoutParams = GetMethodSignatureWithoutParams(newStackTraceSignature); + if (!_signatureWithParamsMapper.TryGetValue(newStackTraceSignatureWithoutParams, out var oldSignaturesWithoutParams)) + { + oldSignaturesWithoutParams = new List(); + _signatureWithParamsMapper[newStackTraceSignatureWithoutParams] = oldSignaturesWithoutParams; + } + oldSignaturesWithoutParams.Add(oldStackTraceSignatureWithoutParams); + } + + + public bool TryDeObfuscateStackTrace(string obfuscatedStackTraceLog, out string deObfuscatedStackTrace) + { + obfuscatedStackTraceLog = obfuscatedStackTraceLog.Trim(); + if (_fullSignatureMapper.TryGetValue(obfuscatedStackTraceLog, out var oldFullSignatures)) + { + deObfuscatedStackTrace = string.Join("|", oldFullSignatures); + return true; + } + + string obfuscatedStackTraceSignatureWithoutParams = GetMethodSignatureWithoutParams(obfuscatedStackTraceLog); + if (_signatureWithParamsMapper.TryGetValue(obfuscatedStackTraceSignatureWithoutParams, out var oldSignaturesWithoutParams)) + { + deObfuscatedStackTrace = obfuscatedStackTraceLog.Replace(obfuscatedStackTraceSignatureWithoutParams, string.Join("|", oldSignaturesWithoutParams)); + return true; + } + deObfuscatedStackTrace = null; + return false; + } + } +} diff --git a/DeobfuscateStackTrace/mapping.xml b/DeobfuscateStackTrace/mapping.xml new file mode 100644 index 0000000..06d298c --- /dev/null +++ b/DeobfuscateStackTrace/mapping.xml @@ -0,0 +1,3614 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file