using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.Reflection; using System; using System.IO; using System.Text.RegularExpressions; public static class ConfusionController { private static List m_AssemblyTypes; public static List AssemblyTypes { get { if (m_AssemblyTypes == null) { m_AssemblyTypes = new List(); } if (m_AssemblyTypes.Count == 0) { var _assembly = Assembly.Load("Assembly-CSharp"); m_AssemblyTypes.AddRange(_assembly.GetTypes()); } return m_AssemblyTypes; } } private static ConfusionModel m_Model; public static ConfusionModel DataModel { get { if (m_Model == null) { m_Model = new ConfusionModel(); } return m_Model; } } public static int SelectDirectoryCount() { return DataModel.confuseFileSourcePathDict.Count; } public static void SelectDirectory(string path, bool includeChild = false) { path = path.Replace("\\", "/"); path = path.Substring(path.IndexOf("Assets")); if (!DataModel.confuseFileSourcePathDict.ContainsKey(path)) { var _directoryInfo = new ConfusionDirectoryInfo(); _directoryInfo.path = path; _directoryInfo.includeChild = includeChild; DataModel.confuseFileSourcePathDict[path] = _directoryInfo; } } public static void ForeachSelectDirectory(Action callback) { foreach (var _key in DataModel.confuseFileSourcePathDict.Keys) { callback(_key, DataModel.confuseFileSourcePathDict[_key]); } } public static void RemoveSelectDirectory(string path) { if (DataModel.confuseFileSourcePathDict.ContainsKey(path)) { DataModel.confuseFileSourcePathDict.Remove(path); } } public static void BuildAssembleRelation() { DataModel.confusionTypeDict.Clear(); int _count = AssemblyTypes.Count; int _index = 0; foreach (var _type in AssemblyTypes) { EditorUtility.DisplayProgressBar("开始生成类型内的变量和方法替换逻辑", "当前处理类型: " + _type.ToString(), _index * 1f / _count); if (IsIgnore(_type)) { continue; } HandleClassType(_type); _index++; } } private static void HandleClassType(Type type) { if (DataModel.confusionTypeDict.ContainsKey(type)) { return; } Debug.LogFormat("开始处理类: {0}", type); List _typeMemberList = new List(); DataModel.confusionTypeDict.Add(type, _typeMemberList); var _memberInfos = type.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); foreach (var _memberinfo in _memberInfos) { if (!AssemblyTypes.Contains(_memberinfo.DeclaringType)) { continue; } if (_memberinfo.MemberType == MemberTypes.Field) { // HandleField((FieldInfo)_memberinfo); } else if (_memberinfo.MemberType == MemberTypes.Method) { HandleMethod((MethodInfo)_memberinfo); } } } private static void HandleMethod(MethodInfo mi) { if (mi.IsPrivate && !ConfusionEditorWindow.Setting.IsConfusePrivateMethod) { return; } if (mi.IsFamily && !ConfusionEditorWindow.Setting.IsConfuseProtectedMethod) { return; } // && !ConfusionEditorWindow.Setting.IsConfusePublicMethod if (mi.IsPublic) { return; } if(mi.Name.Contains("UpdateOffLinePlayer") && mi.ReflectedType == typeof(GAMgr)) { Debug.Log("aaaa"); } if(!AssemblyTypes.Contains(mi.ReflectedType)) { Debug.LogFormat("程序集中不包含方法所归属的类型: {0}", mi.ReflectedType); return; } if(mi.IsSpecialName) { Debug.LogFormat("不处理set和get方法: {0}", mi.Name); return; } Debug.LogFormat(" |- 开始处理: {0} 的方法: {1} .", mi.ReflectedType, mi.Name); Dictionary _replacePair = null; if (!DataModel.confusionDict.TryGetValue(mi.ReflectedType, out _replacePair)) { _replacePair = new Dictionary(); DataModel.confusionDict.Add(mi.ReflectedType, _replacePair); } // 检测这个方法是否是父类定义的, 是的话直接使用父类已经更改好的混淆逻辑 // 1. 非私有 // 2. 可能是虚方法 // 3. 可由派生类使用 if (!mi.IsPrivate && (mi.IsVirtual || mi.IsFamily) && AssemblyTypes.Contains(mi.ReflectedType.BaseType) && !mi.IsHideBySig) { Debug.LogFormat("这是一个父类定义的方法: {0} != {1} .", mi.DeclaringType, mi.ReflectedType.BaseType); // 所以要先处理父类 if (!DataModel.confusionTypeDict.ContainsKey(mi.ReflectedType.BaseType)) { Debug.LogFormat("未处理类型: {0} 的父类: {1}, 现在进行处理.", mi.ReflectedType, mi.ReflectedType.BaseType); HandleClassType(mi.ReflectedType.BaseType); } // 父类检测和处理完毕后, 这里获取父类的处理结果 Dictionary _parentReplacePair = null; if (DataModel.confusionDict.TryGetValue(mi.ReflectedType.BaseType, out _parentReplacePair)) { if(_parentReplacePair.ContainsKey(mi.Name)) { // 赋值为父类替换名 _replacePair[mi.Name] = _parentReplacePair[mi.Name]; Debug.LogFormat("遵循: {0} 类的内容: {1} => {2}", mi.ReflectedType.BaseType, mi.Name, _parentReplacePair[mi.Name]); } else { Debug.LogFormat("父类: {0} 没有为这个方法进行混淆逻辑处理: {1}", mi.ReflectedType.BaseType,mi.Name); } } } else { // 就是本类定义的则直接赋值替换内容 if (!_replacePair.ContainsKey(mi.Name)) { _replacePair[mi.Name] = DataModel.NewContent; Debug.LogFormat(" |- 处理Method的替换: {1} => {2}", mi.DeclaringType, mi.Name, _replacePair[mi.Name]); } } } private static void HandleField(FieldInfo fi) { if (fi.IsPrivate && !ConfusionEditorWindow.Setting.IsConfusePrivateField) { return; } if (fi.IsFamily && !ConfusionEditorWindow.Setting.IsConfuseProtectedField) { return; } // && !ConfusionEditorWindow.Setting.IsConfusePublicField if (fi.IsPublic) { return; } Dictionary _replacePair = null; if (!DataModel.confusionDict.TryGetValue(fi.ReflectedType, out _replacePair)) { _replacePair = new Dictionary(); DataModel.confusionDict.Add(fi.ReflectedType, _replacePair); } // 是否反射的类型与定义此变量的类型不相同, 代表这个类型是父类定义的 if (fi.DeclaringType != fi.ReflectedType) { // 所以要先处理父类 if (!DataModel.confusionTypeDict.ContainsKey(fi.DeclaringType)) { HandleClassType(fi.DeclaringType); } // 父类检测和处理完毕后, 这里获取父类的处理结果 Dictionary _parentReplacePair = null; if (DataModel.confusionDict.TryGetValue(fi.DeclaringType, out _parentReplacePair)) { // 赋值为父类替换名 _replacePair[fi.Name] = _parentReplacePair[fi.Name]; } } else { // 就是本类定义的则直接赋值替换内容 if (!_replacePair.ContainsKey(fi.Name)) { _replacePair[fi.Name] = DataModel.NewContent; } } } public static void DecideClassType() { var _index = 0; var _count = DataModel.confusionScriptFilePath.Count; foreach (var _path in DataModel.confusionScriptFilePath) { var _p = _path.Substring(_path.IndexOf("Assets")); var _script = AssetDatabase.LoadAssetAtPath(_p); var _type = _script.GetClass(); EditorUtility.DisplayProgressBar("开始处理选择文件夹的文件信息", "当前处理类型: " + _type.ToString(), _index * 1f / _count); DataModel.typeToPathDict[_type] = Path.GetFullPath(_path).Replace("\\", "/"); } } public static void ReplaceFieldAndMethod() { var _index = 0; var _count = DataModel.confusionScriptFilePath.Count; string _scriptContent = null; foreach (var _type in DataModel.typeToPathDict.Keys) { EditorUtility.DisplayProgressBar("开始执行替换逻辑", "当前处理类型: " + _type.ToString(), _index * 1f / _count); if (!DataModel.confusionTypeDict.ContainsKey(_type)) { Debug.LogWarningFormat("不存在将要混淆的类型: {0} 的混淆逻辑"); continue; } using (var _streamReader = new StreamReader(DataModel.typeToPathDict[_type])) { _scriptContent = _streamReader.ReadToEnd(); } // 文件存在且有内容 if (!string.IsNullOrEmpty(_scriptContent)) { // 读取替换内容 foreach (var _replaceContent in DataModel.confusionDict[_type].Keys) { var _newContent = DataModel.confusionDict[_type][_replaceContent]; // 进行替换 _scriptContent = ReplaceWholeWord(_scriptContent, _replaceContent, _newContent); // 存储替换逻辑 if (!DataModel.reConfusionDict.ContainsKey(_type)) { DataModel.reConfusionDict.Add(_type, new Dictionary()); } DataModel.reConfusionDict[_type][_newContent] = _replaceContent; } } using (var _streamWritter = new StreamWriter(DataModel.typeToPathDict[_type])) { _streamWritter.Write(_scriptContent); } _index++; } AssetDatabase.Refresh(); } public static void CollectConfusionDirectory() { DataModel.confusionScriptFilePath.Clear(); foreach (var _path in DataModel.confuseFileSourcePathDict.Keys) { DoCollectChildDirectory(_path, DataModel.confuseFileSourcePathDict[_path].includeChild); } } private static void DoCollectChildDirectory(string parent, bool includeChild = false) { EditorUtility.DisplayProgressBar("搜集所有脚本文件", "当前处理文件: " + parent, 1f); var _files = Directory.GetFiles(parent, "*.cs"); foreach (var _file in _files) { var _path = Path.GetFullPath(_file).Replace("\\", "/"); if (!DataModel.confusionScriptFilePath.Contains(_path)) { DataModel.confusionScriptFilePath.Add(_path); } } if (includeChild) { var _directoryInfo = new DirectoryInfo(parent); var _directories = _directoryInfo.GetDirectories(); foreach (var _directory in _directories) { DoCollectChildDirectory(_directory.FullName, includeChild); } } } public static void ReConfusion(string path) { if (string.IsNullOrEmpty(path)) { EditorUtility.DisplayDialog("警告", "请指定反混淆文件", "返回"); return; } string _confusionRelationFile = null; using (var _streamReader = new StreamReader(path)) { _confusionRelationFile = _streamReader.ReadToEnd(); } if (string.IsNullOrEmpty(_confusionRelationFile)) { return; } ConfusionFile _file = JsonUtility.FromJson(_confusionRelationFile); if (_file == null) { return; } if (_file.items == null || _file.items.Length == 0) { return; } foreach (var _item in _file.items) { if (string.IsNullOrEmpty(_item.path)) { UnityEngine.Debug.LogFormat("未定义脚本文件地址"); continue; } if (string.IsNullOrEmpty(_item.typeName)) { UnityEngine.Debug.LogFormat("未定义类型名称"); continue; } string _scriptContent = null; using (var _streamReader = new StreamReader(_item.path)) { _scriptContent = _streamReader.ReadToEnd(); } if (string.IsNullOrEmpty(_scriptContent)) { continue; } for (int i = 0; i < _item.keys.Length; ++i) { _scriptContent = ReplaceWholeWord(_scriptContent, _item.keys[i], _item.values[i]); } using (var _streamReader = new StreamWriter(_item.path)) { _streamReader.Write(_scriptContent); } } AssetDatabase.Refresh(); } public static void BuildConfusionRelation() { var _file = new ConfusionFile(); _file.items = new ConfusionRelation[DataModel.reConfusionDict.Count]; int _index = 0; int _jndex = 0; foreach (var _type in DataModel.reConfusionDict.Keys) { _file.items[_index] = new ConfusionRelation(); _file.items[_index].typeName = _type.ToString(); _file.items[_index].path = DataModel.typeToPathDict[_type]; _file.items[_index].keys = new string[DataModel.reConfusionDict[_type].Count]; _file.items[_index].values = new string[DataModel.reConfusionDict[_type].Count]; _jndex = 0; foreach (var _key in DataModel.reConfusionDict[_type].Keys) { _file.items[_index].keys[_jndex] = _key; _file.items[_index].values[_jndex] = DataModel.reConfusionDict[_type][_key]; _jndex++; } _index++; } string _json = JsonUtility.ToJson(_file); if (!Directory.Exists(DataModel.ReConfuseMapFileDir)) { Directory.CreateDirectory(DataModel.ReConfuseMapFileDir); } using (var _streamWriter = new StreamWriter(DataModel.ReConfuseMapFileDir + "/Map_" + DateTime.Now.ToString("yyyy_MM_dd_HH_MM_ss") + ".json")) { _streamWriter.Write(_json); } } public static void Reset() { if (m_AssemblyTypes != null) { m_AssemblyTypes.Clear(); } DataModel.Reset(); } private static bool IsIgnore(Type type) { if (!DataModel.typeToPathDict.ContainsKey(type)) { return true; } if (type.BaseType == typeof(Editor) || type.BaseType == typeof(EditorWindow) || type.BaseType == typeof(ScriptableObject) || type.BaseType == typeof(MonoBehaviour) || type.IsSerializable) { return true; } return false; } private static string ReplaceWholeWord(string original, string wordToFind, string replacement, RegexOptions regexOptions = RegexOptions.None) { string pattern = String.Format(@"[^\.]\b{0}\b", wordToFind); string ret = Regex.Replace(original, pattern, " " + replacement, regexOptions); return ret; } }