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 (!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;
|
}
|
}
|