Assets/Editor/Confusion.meta
New file @@ -0,0 +1,9 @@ fileFormatVersion: 2 guid: 70e2d34303c93fe40a5b82718604e51c folderAsset: yes timeCreated: 1535620874 licenseType: Free DefaultImporter: userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/ConfusionDirectoryInfo.cs
New file @@ -0,0 +1,6 @@ [System.Serializable] public class ConfusionDirectoryInfo { public string path; public bool includeChild; } Assets/Editor/Confusion/ConfusionDirectoryInfo.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: ffd621f5229090c41afeea6296d6b474 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/ConfusionFile.cs
New file @@ -0,0 +1,5 @@ [System.Serializable] public class ConfusionFile { public ConfusionRelation[] items; } Assets/Editor/Confusion/ConfusionFile.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: 1e739d5ecd1a9d7438a050010140c02d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/ConfusionRelation.cs
New file @@ -0,0 +1,8 @@ [System.Serializable] public class ConfusionRelation { public string typeName; public string path; public string[] keys; public string[] values; } Assets/Editor/Confusion/ConfusionRelation.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: 03b97e134be0ee042868c4477f81f18b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/ConfusionSetting.cs
New file @@ -0,0 +1,71 @@ [System.Serializable] public class ConfusionSetting { public ConfusionDirectoryInfo[] confusionDirectorys; private int BitPrivate = 1; private int BitProtected = 2; private int BitPublic = 4; public int confuseField = 1; public int confuseMethod = 1; public ConfusionSetting() { } public bool IsConfusePrivateField { get { return (confuseField & BitPrivate) == 1; } set { confuseField = value ? confuseField | BitPrivate : confuseField & ~BitPrivate; } } public bool IsConfuseProtectedField { get { return ((confuseField & BitProtected) >> 1) == 1; } set { confuseField = value ? confuseField | BitProtected : confuseField & ~BitProtected; } } public bool IsConfusePublicField { get { return ((confuseField & BitPublic) >> 2) == 1; } set { confuseField = value ? confuseField | BitPublic : confuseField & ~BitPublic; } } public bool IsConfusePrivateMethod { get { return (confuseMethod & BitPrivate) == 1; } set { confuseMethod = value ? confuseMethod | BitPrivate : confuseMethod & ~BitPrivate; } } public bool IsConfuseProtectedMethod { get { return ((confuseMethod & BitProtected) >> 1) == 1; } set { confuseMethod = value ? confuseMethod | BitProtected : confuseMethod & ~BitProtected; } } public bool IsConfusePublicMethod { get { return ((confuseMethod & BitPublic) >> 2) == 1; } set { confuseMethod = value ? confuseMethod | BitPublic : confuseMethod & ~BitPublic; } } } Assets/Editor/Confusion/ConfusionSetting.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: a855a92bec1c0434f92ff3ec3c48c5d5 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/Editor.meta
New file @@ -0,0 +1,8 @@ fileFormatVersion: 2 guid: 923f2e4e4875f754883e46f0ce553808 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/Editor/ConfusionConfig.cs
New file @@ -0,0 +1,14 @@ [System.Serializable] public class ConfusionConfig { // 存储变量默认的混淆方式 public int confusionField; // 存储方法默认的混淆方式 public int confusionMethod; // 需要被混淆的路径列表 public string[] confusionDirectorys; } Assets/Editor/Confusion/Editor/ConfusionConfig.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: 7e0a5afe7434f784cac664fbefed4fc1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/Editor/ConfusionContorller.cs
New file @@ -0,0 +1,533 @@ 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<Type> m_AssemblyTypes; public static List<Type> AssemblyTypes { get { if (m_AssemblyTypes == null) { m_AssemblyTypes = new List<Type>(); } 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<string, ConfusionDirectoryInfo> 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<string> _typeMemberList = new List<string>(); 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("<color=red>程序集中不包含方法所归属的类型: {0}</color>", mi.ReflectedType); return; } if(mi.IsSpecialName) { Debug.LogFormat("不处理set和get方法: {0}", mi.Name); return; } Debug.LogFormat(" |- 开始处理: {0} 的方法: {1} .", mi.ReflectedType, mi.Name); Dictionary<string, string> _replacePair = null; if (!DataModel.confusionDict.TryGetValue(mi.ReflectedType, out _replacePair)) { _replacePair = new Dictionary<string, string>(); 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<string, string> _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("<color=red>父类: {0} 没有为这个方法进行混淆逻辑处理: {1}</color>", 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<string, string> _replacePair = null; if (!DataModel.confusionDict.TryGetValue(fi.ReflectedType, out _replacePair)) { _replacePair = new Dictionary<string, string>(); DataModel.confusionDict.Add(fi.ReflectedType, _replacePair); } // 是否反射的类型与定义此变量的类型不相同, 代表这个类型是父类定义的 if (fi.DeclaringType != fi.ReflectedType) { // 所以要先处理父类 if (!DataModel.confusionTypeDict.ContainsKey(fi.DeclaringType)) { HandleClassType(fi.DeclaringType); } // 父类检测和处理完毕后, 这里获取父类的处理结果 Dictionary<string, string> _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<MonoScript>(_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<string, string>()); } 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<ConfusionFile>(_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; } } Assets/Editor/Confusion/Editor/ConfusionContorller.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: a942b945029314443b5fad3fc765c6c6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/Editor/ConfusionEditorWindow.cs
New file @@ -0,0 +1,279 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.Reflection; using System; using System.IO; using System.Text.RegularExpressions; using System.Linq; public class ConfusionEditorWindow : EditorWindow { [MenuItem("Tools/Confusion")] static void Init() { var _win = CreateInstance<ConfusionEditorWindow>(); _win.minSize = new Vector2(420, 400); _win.maxSize = _win.minSize; _win.Show(); } private string LS_KEY_CONFIG_PATH; private string m_MapFilePath = ""; private List<string> removePathList = new List<string>(); private Vector2 m_ScrollVec2; private Color m_LabelColor = new Color(.9f, .9f, .8f, 1); public static ConfusionSetting Setting { get; private set; } void OnEnable() { ConfusionController.Reset(); LS_KEY_CONFIG_PATH = Application.dataPath + "LS_KEY_CONFIG_PATH"; BuildConfig(); } private void BuildConfig() { // 确认配置位置 string _configPath = EditorPrefs.GetString(LS_KEY_CONFIG_PATH, ""); // 有配置地址,读取配置地址 if (string.IsNullOrEmpty(_configPath)) { var _files = Directory.GetFiles(Application.dataPath, "*.cs", SearchOption.AllDirectories); foreach (var _file in _files) { if (_file.Contains("ConfusionEditorWindow")) { _configPath = Path.GetDirectoryName(_file).Replace("\\", "/"); break; } } _configPath += "/config.json"; } // 判断配置地址下是否有配置文件 if (File.Exists(_configPath)) { string _json = null; using (StreamReader _sr = new StreamReader(_configPath)) { _json = _sr.ReadToEnd(); } if (!string.IsNullOrEmpty(_json)) { Setting = JsonUtility.FromJson<ConfusionSetting>(_json); } } if (Setting == null) { Setting = new ConfusionSetting(); EditorPrefs.SetString(LS_KEY_CONFIG_PATH, _configPath); File.Create(_configPath); } if (Setting.confusionDirectorys != null) { foreach (var _info in Setting.confusionDirectorys) { ConfusionController.SelectDirectory(_info.path, _info.includeChild); } } } private void SaveConfig() { ConfusionSetting _setting = new ConfusionSetting(); _setting.confuseField = Setting.confuseField; _setting.confuseMethod = Setting.confuseMethod; int _count = ConfusionController.SelectDirectoryCount(); _setting.confusionDirectorys = new ConfusionDirectoryInfo[_count]; int _index = 0; ConfusionController.ForeachSelectDirectory((_path, _info) => { _setting.confusionDirectorys[_index] = new ConfusionDirectoryInfo(); _setting.confusionDirectorys[_index].path = _path; _setting.confusionDirectorys[_index].includeChild = _info.includeChild; _index++; }); string _json = JsonUtility.ToJson(_setting); Debug.Log(_json); string _configPath = EditorPrefs.GetString(LS_KEY_CONFIG_PATH, ""); if (string.IsNullOrEmpty(_configPath)) { Debug.LogErrorFormat("找不到配置地址!"); return; } using (StreamWriter _sw = new StreamWriter(_configPath)) { _sw.Write(_json); } } void OnGUI() { Color _defaultColor = GUI.color; EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); GUI.color = m_LabelColor; GUILayout.Label("ConfusionDiretory", EditorStyles.toolbarButton, GUILayout.Width(110)); GUI.color = _defaultColor; if (GUILayout.Button("ADD +", EditorStyles.toolbarButton, GUILayout.ExpandWidth(true))) { var _path = EditorUtility.OpenFolderPanel("选择要被混淆的脚本文件夹", Application.dataPath, ""); if (!string.IsNullOrEmpty(_path)) { ConfusionController.SelectDirectory(_path); } } EditorGUILayout.EndHorizontal(); if (ConfusionController.SelectDirectoryCount() == 0) { EditorGUILayout.HelpBox("点击[ADD+]按钮添加一个想要被混淆的脚本文件夹,可以多次添加\r\n" + "添加完毕以后点击Confusion按钮进行混淆\r\n" + "混淆后会生成一个混淆列表文件,可以将混淆的文件恢复回来.", MessageType.Info); } removePathList.Clear(); m_ScrollVec2 = EditorGUILayout.BeginScrollView(m_ScrollVec2); int _i = 1; ConfusionController.ForeachSelectDirectory((key, info) => { EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); GUILayout.Label("└", GUILayout.Width(18)); GUILayout.Label(_i.ToString(), EditorStyles.toolbarButton, GUILayout.Width(20)); GUILayout.Label(key, EditorStyles.textField, GUILayout.ExpandWidth(true)); info.includeChild = GUILayout.Toggle(info.includeChild, "IncludeChild", EditorStyles.toolbarButton, GUILayout.Width(80)); if (GUILayout.Button("DEL -", EditorStyles.toolbarButton, GUILayout.Width(70))) { removePathList.Add(key); } EditorGUILayout.EndHorizontal(); _i++; }); EditorGUILayout.EndScrollView(); for (int i = 0; i < removePathList.Count; ++i) { ConfusionController.RemoveSelectDirectory(removePathList[i]); } EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); GUI.color = m_LabelColor; GUILayout.Label("Confuse Field", EditorStyles.toolbarButton); GUI.color = _defaultColor; bool _toggle = Setting.IsConfusePrivateField; var _newToggle = GUILayout.Toggle(_toggle, "Private", EditorStyles.toolbarButton, GUILayout.Width(100)); if (_toggle != _newToggle) { Setting.IsConfusePrivateField = _newToggle; } _toggle = Setting.IsConfuseProtectedField; _newToggle = GUILayout.Toggle(_toggle, "Protected", EditorStyles.toolbarButton, GUILayout.Width(100)); if (_toggle != _newToggle) { Setting.IsConfuseProtectedField = _newToggle; } _toggle = Setting.IsConfusePublicField; _toggle = GUILayout.Toggle(_toggle, "Public", EditorStyles.toolbarButton, GUILayout.Width(100)); Setting.IsConfusePublicField = _toggle; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); GUI.color = m_LabelColor; GUILayout.Label("Confuse Method", EditorStyles.toolbarButton); GUI.color = _defaultColor; _toggle = Setting.IsConfusePrivateMethod; _toggle = GUILayout.Toggle(_toggle, "Private", EditorStyles.toolbarButton, GUILayout.Width(100)); Setting.IsConfusePrivateMethod = _toggle; _toggle = Setting.IsConfuseProtectedMethod; _toggle = GUILayout.Toggle(_toggle, "Protected", EditorStyles.toolbarButton, GUILayout.Width(100)); Setting.IsConfuseProtectedMethod = _toggle; _toggle = Setting.IsConfusePublicMethod; _toggle = GUILayout.Toggle(_toggle, "Public", EditorStyles.toolbarButton, GUILayout.Width(100)); Setting.IsConfusePublicMethod = _toggle; EditorGUILayout.EndHorizontal(); if (GUILayout.Button("Confusion", GUILayout.Height(100))) { SaveConfig(); Confusion(); } EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); GUI.color = m_LabelColor; GUILayout.Label("MapFileSavePath", EditorStyles.toolbarButton, GUILayout.Width(110)); GUI.color = _defaultColor; GUILayout.TextField(ConfusionController.DataModel.ReConfuseMapFileDir, EditorStyles.toolbarTextField, GUILayout.Width(222)); if (GUILayout.Button("SELECT", EditorStyles.toolbarButton, GUILayout.Width(70))) { var _path = EditorUtility.OpenFolderPanel("选择混淆替换对应文件存放路径", Application.dataPath, ""); if (!string.IsNullOrEmpty(_path)) { ConfusionController.DataModel.ReConfuseMapFileDir = _path.Replace("\\", "/"); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); GUI.color = m_LabelColor; GUILayout.Label("ReConfusionMapFile", EditorStyles.toolbarButton, GUILayout.Width(110)); GUI.color = _defaultColor; GUILayout.TextField(m_MapFilePath, EditorStyles.toolbarTextField, GUILayout.Width(222)); if (GUILayout.Button("SELECT", EditorStyles.toolbarButton, GUILayout.Width(70))) { m_MapFilePath = EditorUtility.OpenFilePanel("选择要反混淆的文件", ConfusionController.DataModel.ReConfuseMapFileDir, "json"); } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); if (GUILayout.Button("ReConfusion", GUILayout.Height(100))) { ConfusionController.ReConfusion(m_MapFilePath); } } private void Confusion() { if (ConfusionController.SelectDirectoryCount() == 0) { EditorUtility.DisplayDialog("警告", "未指定要混淆的文件夹\r\n请点击 [ADD +] 按钮进行添加", "返回"); return; } ConfusionController.CollectConfusionDirectory(); ConfusionController.DecideClassType(); ConfusionController.BuildAssembleRelation(); //ConfusionController.ReplaceFieldAndMethod(); //ConfusionController.BuildConfusionRelation(); EditorUtility.ClearProgressBar(); } } Assets/Editor/Confusion/Editor/ConfusionEditorWindow.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: a4c42e02d3fcf7943b06a77a1a059ab9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/Editor/ConfusionModel.cs
New file @@ -0,0 +1,64 @@ using System.Collections.Generic; using UnityEngine; using UnityEditor; using System; public class ConfusionModel { private string LS_KEY_RECONFUSION_MAP_FILE = Application.dataPath + "ReConfuseMapFile"; // 通过Assembly找到需要被混淆的ClassType // 对这些ClassType的Field和Method根据配置建立索引 private const string PREV_FIX = "_"; private static int m_Seed = 0; public string NewContent { get { return string.Format("{0}{1}", PREV_FIX, m_Seed++); } } // 想要被混淆的文件夹路径 public Dictionary<string, ConfusionDirectoryInfo> confuseFileSourcePathDict = new Dictionary<string, ConfusionDirectoryInfo>(); // 类型对应的文件路径 public Dictionary<Type, string> typeToPathDict = new Dictionary<Type, string>(); // 类型里需要被混淆的变量或者方法名称对应列表 public Dictionary<Type, List<string>> confusionTypeDict = new Dictionary<Type, List<string>>(); // 记录类型里最终被混淆成了什么内容, 用于反混淆的时候替换 public Dictionary<Type, Dictionary<string, string>> confusionDict = new Dictionary<Type, Dictionary<string, string>>(); // 记录类型里最终被混淆成了什么内容, 用于反混淆的时候替换 public Dictionary<Type, Dictionary<string, string>> reConfusionDict = new Dictionary<Type, Dictionary<string, string>>(); // 通过反射搜集到的文件路径 public List<string> confusionScriptFilePath = new List<string>(); // 替换表生成路径 public string ReConfuseMapFileDir { get { return EditorPrefs.GetString(LS_KEY_RECONFUSION_MAP_FILE, Application.dataPath + "/ReConfusionMapFiles"); } set { EditorPrefs.SetString(LS_KEY_RECONFUSION_MAP_FILE, value); } } public ConfusionModel() { Reset(); } public void Reset() { m_Seed = 0; typeToPathDict.Clear(); confuseFileSourcePathDict.Clear(); confusionTypeDict.Clear(); confusionDict.Clear(); } } Assets/Editor/Confusion/Editor/ConfusionModel.cs.meta
New file @@ -0,0 +1,11 @@ fileFormatVersion: 2 guid: 70a2051eca557674b84aa32f391390c8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: Assets/Editor/Confusion/Editor/config.json
New file @@ -0,0 +1 @@ {"confusionDirectorys":[{"path":"Assets/Scripts/Fight/GameActor","includeChild":false}],"confuseField":3,"confuseMethod":3} Assets/Editor/Confusion/Editor/config.json.meta
New file @@ -0,0 +1,7 @@ fileFormatVersion: 2 guid: 6a436ca306c67d94b9aa5a9a1af2ddd3 TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: