diff --git a/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Mac.dll.bytes b/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Mac.dll.bytes
deleted file mode 100644
index 0eb3f38..0000000
Binary files a/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Mac.dll.bytes and /dev/null differ
diff --git a/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Win.dll.bytes b/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Win.dll.bytes
deleted file mode 100644
index 926857d..0000000
Binary files a/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Win.dll.bytes and /dev/null differ
diff --git a/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Mac.dll.bytes.meta b/Editor/3rds/UnityHook.meta
similarity index 57%
rename from Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Mac.dll.bytes.meta
rename to Editor/3rds/UnityHook.meta
index 625dd7a..4fab614 100644
--- a/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Mac.dll.bytes.meta
+++ b/Editor/3rds/UnityHook.meta
@@ -1,6 +1,7 @@
fileFormatVersion: 2
-guid: a96a2c46326d2a84984c2820bd4bfc91
-TextScriptImporter:
+guid: 13fe0cab0b357464d889de45c8d98850
+folderAsset: yes
+DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
diff --git a/Editor/3rds/UnityHook/CodePatcher.cs b/Editor/3rds/UnityHook/CodePatcher.cs
new file mode 100644
index 0000000..6ec2fa7
--- /dev/null
+++ b/Editor/3rds/UnityHook/CodePatcher.cs
@@ -0,0 +1,320 @@
+using DotNetDetour;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.Linq;
+
+namespace MonoHook
+{
+ public unsafe abstract class CodePatcher
+ {
+ public bool isValid { get; protected set; }
+
+ protected void* _pTarget, _pReplace, _pProxy;
+ protected int _jmpCodeSize;
+ protected byte[] _targetHeaderBackup;
+
+ public CodePatcher(IntPtr target, IntPtr replace, IntPtr proxy, int jmpCodeSize)
+ {
+ _pTarget = target.ToPointer();
+ _pReplace = replace.ToPointer();
+ _pProxy = proxy.ToPointer();
+ _jmpCodeSize = jmpCodeSize;
+ }
+
+ public void ApplyPatch()
+ {
+ BackupHeader();
+ EnableAddrModifiable();
+ PatchTargetMethod();
+ PatchProxyMethod();
+ FlushICache();
+ }
+
+ public void RemovePatch()
+ {
+ if (_targetHeaderBackup == null)
+ return;
+
+ EnableAddrModifiable();
+ RestoreHeader();
+ FlushICache();
+ }
+
+ protected void BackupHeader()
+ {
+ if (_targetHeaderBackup != null)
+ return;
+
+ uint requireSize = LDasm.SizeofMinNumByte(_pTarget, _jmpCodeSize);
+ _targetHeaderBackup = new byte[requireSize];
+
+ fixed (void* ptr = _targetHeaderBackup)
+ HookUtils.MemCpy(ptr, _pTarget, _targetHeaderBackup.Length);
+ }
+
+ protected void RestoreHeader()
+ {
+ if (_targetHeaderBackup == null)
+ return;
+
+ HookUtils.MemCpy_Jit(_pTarget, _targetHeaderBackup);
+ }
+
+ protected void PatchTargetMethod()
+ {
+ byte[] buff = GenJmpCode(_pTarget, _pReplace);
+ HookUtils.MemCpy_Jit(_pTarget, buff);
+ }
+ protected void PatchProxyMethod()
+ {
+ if (_pProxy == null)
+ return;
+
+ // copy target's code to proxy
+ HookUtils.MemCpy_Jit(_pProxy, _targetHeaderBackup);
+
+ // jmp to target's new position
+ long jmpFrom = (long)_pProxy + _targetHeaderBackup.Length;
+ long jmpTo = (long)_pTarget + _targetHeaderBackup.Length;
+
+ byte[] buff = GenJmpCode((void*)jmpFrom, (void*)jmpTo);
+ HookUtils.MemCpy_Jit((void*)jmpFrom, buff);
+ }
+
+ protected void FlushICache()
+ {
+ HookUtils.FlushICache(_pTarget, _targetHeaderBackup.Length);
+ HookUtils.FlushICache(_pProxy, _targetHeaderBackup.Length * 2);
+ }
+ protected abstract byte[] GenJmpCode(void* jmpFrom, void* jmpTo);
+
+#if ENABLE_HOOK_DEBUG
+ protected string PrintAddrs()
+ {
+ if (IntPtr.Size == 4)
+ return $"target:0x{(uint)_pTarget:x}, replace:0x{(uint)_pReplace:x}, proxy:0x{(uint)_pProxy:x}";
+ else
+ return $"target:0x{(ulong)_pTarget:x}, replace:0x{(ulong)_pReplace:x}, proxy:0x{(ulong)_pProxy:x}";
+ }
+#endif
+
+ private void EnableAddrModifiable()
+ {
+ HookUtils.SetAddrFlagsToRWX(new IntPtr(_pTarget), _targetHeaderBackup.Length);
+ HookUtils.SetAddrFlagsToRWX(new IntPtr(_pProxy), _targetHeaderBackup.Length + _jmpCodeSize);
+ }
+ }
+
+ public unsafe class CodePatcher_x86 : CodePatcher
+ {
+ protected static readonly byte[] s_jmpCode = new byte[] // 5 bytes
+ {
+ 0xE9, 0x00, 0x00, 0x00, 0x00, // jmp $val ; $val = $dst - $src - 5
+ };
+
+ public CodePatcher_x86(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) { }
+
+ protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
+ {
+ byte[] ret = new byte[s_jmpCode.Length];
+ int val = (int)jmpTo - (int)jmpFrom - 5;
+
+ fixed(void * p = &ret[0])
+ {
+ byte* ptr = (byte*)p;
+ *ptr = 0xE9;
+ int* pOffset = (int*)(ptr + 1);
+ *pOffset = val;
+ }
+ return ret;
+ }
+ }
+
+ ///
+ /// x64下2G 内的跳转
+ ///
+ public unsafe class CodePatcher_x64_near : CodePatcher_x86 // x64_near pathcer code is same to x86
+ {
+ public CodePatcher_x64_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy) { }
+ }
+
+ ///
+ /// x64下距离超过2G的跳转
+ ///
+ public unsafe class CodePatcher_x64_far : CodePatcher
+ {
+ protected static readonly byte[] s_jmpCode = new byte[] // 12 bytes
+ {
+ // 由于 rax 会被函数作为返回值修改,并且不会被做为参数使用,因此修改是安全的
+ 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax,
+ 0x50, // push rax
+ 0xC3 // ret
+ };
+
+ //protected static readonly byte[] s_jmpCode2 = new byte[] // 14 bytes
+ //{
+ // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ // 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF // jmp [rip - 0xe]
+ //};
+
+ public CodePatcher_x64_far(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) { }
+ protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
+ {
+ byte[] ret = new byte[s_jmpCode.Length];
+
+ fixed (void* p = &ret[0])
+ {
+ byte* ptr = (byte*)p;
+ *ptr++ = 0x48;
+ *ptr++ = 0xB8;
+ *(long*)ptr = (long)jmpTo;
+ ptr += 8;
+ *ptr++ = 0x50;
+ *ptr++ = 0xC3;
+ }
+ return ret;
+ }
+ }
+
+ public unsafe class CodePatcher_arm32_near : CodePatcher
+ {
+ private static readonly byte[] s_jmpCode = new byte[] // 4 bytes
+ {
+ 0x00, 0x00, 0x00, 0xEA, // B $val ; $val = (($dst - $src) / 4 - 2) & 0x1FFFFFF
+ };
+
+ public CodePatcher_arm32_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
+ {
+ if (Math.Abs((long)target - (long)replace) >= ((1 << 25) - 1))
+ throw new ArgumentException("address offset of target and replace must less than ((1 << 25) - 1)");
+
+#if ENABLE_HOOK_DEBUG
+ Debug.Log($"CodePatcher_arm32_near: {PrintAddrs()}");
+#endif
+ }
+
+ protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
+ {
+ byte[] ret = new byte[s_jmpCode.Length];
+ int val = ((int)jmpTo - (int)jmpFrom) / 4 - 2;
+
+ fixed (void* p = &ret[0])
+ {
+ byte* ptr = (byte*)p;
+ *ptr++ = (byte)val;
+ *ptr++ = (byte)(val >> 8);
+ *ptr++ = (byte)(val >> 16);
+ *ptr++ = 0xEA;
+ }
+ return ret;
+ }
+ }
+
+ public unsafe class CodePatcher_arm32_far : CodePatcher
+ {
+ private static readonly byte[] s_jmpCode = new byte[] // 8 bytes
+ {
+ 0x04, 0xF0, 0x1F, 0xE5, // LDR PC, [PC, #-4]
+ 0x00, 0x00, 0x00, 0x00, // $val
+ };
+
+ public CodePatcher_arm32_far(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
+ {
+ if (Math.Abs((long)target - (long)replace) < ((1 << 25) - 1))
+ throw new ArgumentException("address offset of target and replace must larger than ((1 << 25) - 1), please use InstructionModifier_arm32_near instead");
+
+#if ENABLE_HOOK_DEBUG
+ Debug.Log($"CodePatcher_arm32_far: {PrintAddrs()}");
+#endif
+ }
+
+ protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
+ {
+ byte[] ret = new byte[s_jmpCode.Length];
+
+ fixed (void* p = &ret[0])
+ {
+ uint* ptr = (uint*)p;
+ *ptr++ = 0xE51FF004;
+ *ptr = (uint)jmpTo;
+ }
+ return ret;
+ }
+ }
+
+ ///
+ /// arm64 下 ±128MB 范围内的跳转
+ ///
+ public unsafe class CodePatcher_arm64_near : CodePatcher
+ {
+ private static readonly byte[] s_jmpCode = new byte[] // 4 bytes
+ {
+ /*
+ * from 0x14 to 0x17 is B opcode
+ * offset bits is 26
+ * https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/B--Branch-
+ */
+ 0x00, 0x00, 0x00, 0x14, // B $val ; $val = (($dst - $src)/4) & 7FFFFFF
+ };
+
+ public CodePatcher_arm64_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
+ {
+ if (Math.Abs((long)target - (long)replace) >= ((1 << 26) - 1) * 4)
+ throw new ArgumentException("address offset of target and replace must less than (1 << 26) - 1) * 4");
+
+#if ENABLE_HOOK_DEBUG
+ Debug.Log($"CodePatcher_arm64: {PrintAddrs()}");
+#endif
+ }
+
+ protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
+ {
+ byte[] ret = new byte[s_jmpCode.Length];
+ int val = (int)((long)jmpTo - (long)jmpFrom) / 4;
+
+ fixed (void* p = &ret[0])
+ {
+ byte* ptr = (byte*)p;
+ *ptr++ = (byte)val;
+ *ptr++ = (byte)(val >> 8);
+ *ptr++ = (byte)(val >> 16);
+
+ byte last = (byte)(val >> 24);
+ last &= 0b11;
+ last |= 0x14;
+
+ *ptr = last;
+ }
+ return ret;
+ }
+ }
+
+ ///
+ /// arm64 远距离跳转
+ ///
+ public unsafe class CodePatcher_arm64_far : CodePatcher
+ {
+ private static readonly byte[] s_jmpCode = new byte[] // 20 bytes(字节数过多,太危险了,不建议使用)
+ {
+ /*
+ * ADR: https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/ADR--Form-PC-relative-address-
+ * BR: https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/BR--Branch-to-Register-
+ */
+ 0x6A, 0x00, 0x00, 0x10, // ADR X10, #C
+ 0x4A, 0x01, 0x40, 0xF9, // LDR X10, [X10,#0]
+ 0x40, 0x01, 0x1F, 0xD6, // BR X10
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // $dst
+ };
+
+ public CodePatcher_arm64_far(IntPtr target, IntPtr replace, IntPtr proxy, int jmpCodeSize) : base(target, replace, proxy, jmpCodeSize)
+ {
+ }
+
+ protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Editor/3rds/UnityHook/CodePatcher.cs.meta b/Editor/3rds/UnityHook/CodePatcher.cs.meta
new file mode 100644
index 0000000..f745350
--- /dev/null
+++ b/Editor/3rds/UnityHook/CodePatcher.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 97cc0d26f72fc4148b8370b2252d1585
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/3rds/UnityHook/HookPool.cs b/Editor/3rds/UnityHook/HookPool.cs
new file mode 100644
index 0000000..34a0599
--- /dev/null
+++ b/Editor/3rds/UnityHook/HookPool.cs
@@ -0,0 +1,74 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEngine;
+using System.Linq;
+using System.IO;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+namespace MonoHook
+{
+ ///
+ /// Hook 池,防止重复 Hook
+ ///
+ public static class HookPool
+ {
+ private static Dictionary _hooks = new Dictionary();
+
+ public static void AddHook(MethodBase method, MethodHook hook)
+ {
+ MethodHook preHook;
+ if (_hooks.TryGetValue(method, out preHook))
+ {
+ preHook.Uninstall();
+ _hooks[method] = hook;
+ }
+ else
+ _hooks.Add(method, hook);
+ }
+
+ public static MethodHook GetHook(MethodBase method)
+ {
+ if (method == null) return null;
+
+ MethodHook hook;
+ if (_hooks.TryGetValue(method, out hook))
+ return hook;
+ return null;
+ }
+
+ public static void RemoveHooker(MethodBase method)
+ {
+ if (method == null) return;
+
+ _hooks.Remove(method);
+ }
+
+ public static void UninstallAll()
+ {
+ var list = _hooks.Values.ToList();
+ foreach (var hook in list)
+ hook.Uninstall();
+
+ _hooks.Clear();
+ }
+
+ public static void UninstallByTag(string tag)
+ {
+ var list = _hooks.Values.ToList();
+ foreach (var hook in list)
+ {
+ if(hook.tag == tag)
+ hook.Uninstall();
+ }
+ }
+
+ public static List GetAllHooks()
+ {
+ return _hooks.Values.ToList();
+ }
+ }
+
+}
diff --git a/Editor/3rds/UnityHook/HookPool.cs.meta b/Editor/3rds/UnityHook/HookPool.cs.meta
new file mode 100644
index 0000000..7503859
--- /dev/null
+++ b/Editor/3rds/UnityHook/HookPool.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6b7421e47f0ae1e4ebb72bf18d1d7d48
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/3rds/UnityHook/HookUtils.cs b/Editor/3rds/UnityHook/HookUtils.cs
new file mode 100644
index 0000000..7acd8c9
--- /dev/null
+++ b/Editor/3rds/UnityHook/HookUtils.cs
@@ -0,0 +1,272 @@
+#if !(UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX)
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using UnityEngine;
+
+namespace MonoHook
+{
+ public static unsafe class HookUtils
+ {
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate void DelegateFlushICache(void* code, int size); // delegate * unmanaged[Cdecl] native_flush_cache_fun_ptr; // unsupported at C# 8.0
+
+ static DelegateFlushICache flush_icache;
+ private static readonly long _Pagesize;
+
+ static HookUtils()
+ {
+ PropertyInfo p_SystemPageSize = typeof(Environment).GetProperty("SystemPageSize");
+ if (p_SystemPageSize == null)
+ throw new NotSupportedException("Unsupported runtime");
+ _Pagesize = (int)p_SystemPageSize.GetValue(null, new object[0]);
+ SetupFlushICacheFunc();
+ }
+
+ public static void MemCpy(void* pDst, void* pSrc, int len)
+ {
+ byte* pDst_ = (byte*)pDst;
+ byte* pSrc_ = (byte*)pSrc;
+
+ for (int i = 0; i < len; i++)
+ *pDst_++ = *pSrc_++;
+ }
+
+ public static void MemCpy_Jit(void* pDst, byte[] src)
+ {
+ fixed (void* p = &src[0])
+ {
+ MemCpy(pDst, p, src.Length);
+ }
+ }
+
+ ///
+ /// set flags of address to `read write execute`
+ ///
+ public static void SetAddrFlagsToRWX(IntPtr ptr, int size)
+ {
+ if (ptr == IntPtr.Zero)
+ return;
+
+#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
+ uint oldProtect;
+ bool ret = VirtualProtect(ptr, (uint)size, Protection.PAGE_EXECUTE_READWRITE, out oldProtect);
+ UnityEngine.Debug.Assert(ret);
+#else
+ SetMemPerms(ptr,(ulong)size,MmapProts.PROT_READ | MmapProts.PROT_WRITE | MmapProts.PROT_EXEC);
+#endif
+ }
+
+ public static void FlushICache(void* code, int size)
+ {
+ if (code == null)
+ return;
+
+ flush_icache?.Invoke(code, size);
+
+#if ENABLE_HOOK_DEBUG
+ Debug.Log($"flush icache at 0x{(IntPtr.Size == 4 ? (uint)code : (ulong)code):x}, size:{size}");
+#endif
+ }
+
+ public static KeyValuePair GetPageAlignedAddr(long code, int size)
+ {
+ long pagesize = _Pagesize;
+ long startPage = (code) & ~(pagesize - 1);
+ long endPage = (code + size + pagesize - 1) & ~(pagesize - 1);
+ return new KeyValuePair(startPage, endPage);
+ }
+
+
+ const int PRINT_SPLIT = 4;
+ const int PRINT_COL_SIZE = PRINT_SPLIT * 4;
+ public static string HexToString(void* ptr, int size, int offset = 0)
+ {
+ Func formatAddr = (IntPtr addr__) => IntPtr.Size == 4 ? $"0x{(uint)addr__:x}" : $"0x{(ulong)addr__:x}";
+
+ byte* addr = (byte*)ptr;
+
+ StringBuilder sb = new StringBuilder(1024);
+ sb.AppendLine($"addr:{formatAddr(new IntPtr(addr))}");
+
+ addr += offset;
+ size += Math.Abs(offset);
+
+ int count = 0;
+ while (true)
+ {
+ sb.Append($"\r\n{formatAddr(new IntPtr(addr + count))}: ");
+ for (int i = 1; i < PRINT_COL_SIZE + 1; i++)
+ {
+ if (count >= size)
+ goto END;
+
+ sb.Append($"{*(addr + count):x2}");
+ if (i % PRINT_SPLIT == 0)
+ sb.Append(" ");
+
+ count++;
+ }
+ }
+ END:;
+ return sb.ToString();
+ }
+
+ static void SetupFlushICacheFunc()
+ {
+ string processorType = SystemInfo.processorType;
+ if (processorType.Contains("Intel") || processorType.Contains("AMD"))
+ return;
+
+ if (IntPtr.Size == 4)
+ {
+ // never release, so save GCHandle is unnecessary
+ s_ptr_flush_icache_arm32 = GCHandle.Alloc(s_flush_icache_arm32, GCHandleType.Pinned).AddrOfPinnedObject().ToPointer();
+ SetAddrFlagsToRWX(new IntPtr(s_ptr_flush_icache_arm32), s_flush_icache_arm32.Length);
+ flush_icache = Marshal.GetDelegateForFunctionPointer(new IntPtr(s_ptr_flush_icache_arm32));
+ }
+ else
+ {
+ s_ptr_flush_icache_arm64 = GCHandle.Alloc(s_flush_icache_arm64, GCHandleType.Pinned).AddrOfPinnedObject().ToPointer();
+ SetAddrFlagsToRWX(new IntPtr(s_ptr_flush_icache_arm64), s_flush_icache_arm64.Length);
+ flush_icache = Marshal.GetDelegateForFunctionPointer(new IntPtr(s_ptr_flush_icache_arm64));
+ }
+
+#if ENABLE_HOOK_DEBUG
+ Debug.Log($"flush_icache delegate is {((flush_icache != null) ? "not " : "")}null");
+#endif
+ }
+
+
+ static void* s_ptr_flush_icache_arm32, s_ptr_flush_icache_arm64;
+ private static byte[] s_flush_icache_arm32 = new byte[]
+ {
+ // void cdecl mono_arch_flush_icache (guint8 *code, gint size)
+ 0x00, 0x48, 0x2D, 0xE9, // PUSH {R11,LR}
+ 0x0D, 0xB0, 0xA0, 0xE1, // MOV R11, SP
+ 0x08, 0xD0, 0x4D, 0xE2, // SUB SP, SP, #8
+ 0x04, 0x00, 0x8D, 0xE5, // STR R0, [SP,#8+var_4]
+ 0x00, 0x10, 0x8D, 0xE5, // STR R1, [SP,#8+var_8]
+ 0x04, 0x00, 0x9D, 0xE5, // LDR R0, [SP,#8+var_4]
+ 0x04, 0x10, 0x9D, 0xE5, // LDR R1, [SP,#8+var_4]
+ 0x00, 0x20, 0x9D, 0xE5, // LDR R2, [SP,#8+var_8]
+ 0x02, 0x10, 0x81, 0xE0, // ADD R1, R1, R2
+ 0x01, 0x00, 0x00, 0xEB, // BL __clear_cache
+ 0x0B, 0xD0, 0xA0, 0xE1, // MOV SP, R11
+ 0x00, 0x88, 0xBD, 0xE8, // POP {R11,PC}
+
+ // __clear_cache ; CODE XREF: j___clear_cache+8↑j
+ 0x80, 0x00, 0x2D, 0xE9, // PUSH { R7 }
+ 0x02, 0x70, 0x00, 0xE3, 0x0F, 0x70, 0x40, 0xE3, // MOV R7, #0xF0002
+ 0x00, 0x20, 0xA0, 0xE3, // MOV R2, #0
+ 0x00, 0x00, 0x00, 0xEF, // SVC 0
+ 0x80, 0x00, 0xBD, 0xE8, // POP {R7}
+ 0x1E, 0xFF, 0x2F, 0xE1, // BX LR
+ };
+
+ private static byte[] s_flush_icache_arm64 = new byte[] // X0: code, W1: size
+ {
+ // void cdecl mono_arch_flush_icache (guint8 *code, gint size)
+ 0xFF, 0xC3, 0x00, 0xD1, // SUB SP, SP, #0x30
+ 0xE8, 0x03, 0x7E, 0xB2, // MOV X8, #4
+ 0xE0, 0x17, 0x00, 0xF9, // STR X0, [SP,#0x30+var_8]
+ 0xE1, 0x27, 0x00, 0xB9, // STR W1, [SP,#0x30+var_C]
+ 0xE0, 0x17, 0x40, 0xF9, // LDR X0, [SP,#0x30+var_8]
+ 0xE9, 0x27, 0x80, 0xB9, // LDRSW X9, [SP,#0x30+var_C]
+ 0x09, 0x00, 0x09, 0x8B, // ADD X9, X0, X9
+ 0xE9, 0x0F, 0x00, 0xF9, // STR X9, [SP,#0x30+var_18]
+ 0xE8, 0x07, 0x00, 0xF9, // STR X8, [SP,#0x30+var_28]
+ 0xE8, 0x03, 0x00, 0xF9, // STR X8, [SP,#0x30+var_30]
+ 0xE8, 0x17, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_8]
+ 0x08, 0xF5, 0x7E, 0x92, // AND X8, X8, #0xFFFFFFFFFFFFFFFC
+ 0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
+
+ // loc_590 ; CODE XREF: mono_arch_flush_icache(uchar*, int)+58↓j
+ 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
+ 0xE9, 0x0F, 0x40, 0xF9, // LDR X9, [SP,#0x30+var_18]
+ 0x1F, 0x01, 0x09, 0xEB, // CMP X8, X9
+ 0xE2, 0x00, 0x00, 0x54, // B.CS loc_5B8
+ 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
+ 0x28, 0x7E, 0x0B, 0xD5, // SYS #3, c7, c14, #1, X8
+ 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
+ 0x08, 0x11, 0x00, 0x91, // ADD X8, X8, #4
+ 0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
+ 0xF7, 0xFF, 0xFF, 0x17, // B loc_590
+ // ; ---------------------------------------------------------------------------
+
+ // loc_5B8 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+40↑j
+ 0x9F, 0x3B, 0x03, 0xD5, // DSB ISH
+ 0xE8, 0x17, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_8]
+ 0x08, 0xF5, 0x7E, 0x92, // AND X8, X8, #0xFFFFFFFFFFFFFFFC
+ 0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
+
+ // loc_5C8 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+90↓j
+ 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
+ 0xE9, 0x0F, 0x40, 0xF9, // LDR X9, [SP,#0x30+var_18]
+ 0x1F, 0x01, 0x09, 0xEB, // CMP X8, X9
+ 0xE2, 0x00, 0x00, 0x54, // B.CS loc_5F0
+ 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
+ 0x28, 0x75, 0x0B, 0xD5, // SYS #3, c7, c5, #1, X8
+ 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
+ 0x08, 0x11, 0x00, 0x91, // ADD X8, X8, #4
+ 0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
+ 0xF7, 0xFF, 0xFF, 0x17, // B loc_5C8
+ // ; ---------------------------------------------------------------------------
+
+ // loc_5F0 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+78↑j
+ 0x9F, 0x3B, 0x03, 0xD5, // DSB ISH
+ 0xDF, 0x3F, 0x03, 0xD5, // ISB
+ 0xFF, 0xC3, 0x00, 0x91, // ADD SP, SP, #0x30 ; '0'
+ 0xC0, 0x03, 0x5F, 0xD6, // RET
+ };
+
+
+#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
+ [Flags]
+ public enum Protection
+ {
+ PAGE_NOACCESS = 0x01,
+ PAGE_READONLY = 0x02,
+ PAGE_READWRITE = 0x04,
+ PAGE_WRITECOPY = 0x08,
+ PAGE_EXECUTE = 0x10,
+ PAGE_EXECUTE_READ = 0x20,
+ PAGE_EXECUTE_READWRITE = 0x40,
+ PAGE_EXECUTE_WRITECOPY = 0x80,
+ PAGE_GUARD = 0x100,
+ PAGE_NOCACHE = 0x200,
+ PAGE_WRITECOMBINE = 0x400
+ }
+
+ [DllImport("kernel32")]
+ public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, Protection flNewProtect, out uint lpflOldProtect);
+
+#else
+ [Flags]
+ public enum MmapProts : int {
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ PROT_NONE = 0x0,
+ PROT_GROWSDOWN = 0x01000000,
+ PROT_GROWSUP = 0x02000000,
+ }
+
+ [DllImport("libc", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
+ private static extern int mprotect(IntPtr start, IntPtr len, MmapProts prot);
+
+ public static unsafe void SetMemPerms(IntPtr start, ulong len, MmapProts prot) {
+ var requiredAddr = GetPageAlignedAddr(start.ToInt64(), (int)len);
+ long startPage = requiredAddr.Key;
+ long endPage = requiredAddr.Value;
+
+ if (mprotect((IntPtr) startPage, (IntPtr) (endPage - startPage), prot) != 0)
+ throw new Exception($"mprotect with prot:{prot} fail!");
+ }
+#endif
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Editor/3rds/UnityHook/HookUtils.cs.meta b/Editor/3rds/UnityHook/HookUtils.cs.meta
new file mode 100644
index 0000000..8ec4cb3
--- /dev/null
+++ b/Editor/3rds/UnityHook/HookUtils.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e84139b42a6164e4c93ce4df1be6dcfb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/3rds/UnityHook/HookUtils_OSX.cs b/Editor/3rds/UnityHook/HookUtils_OSX.cs
new file mode 100644
index 0000000..8e4a126
--- /dev/null
+++ b/Editor/3rds/UnityHook/HookUtils_OSX.cs
@@ -0,0 +1,102 @@
+#if (UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX)
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using UnityEngine;
+
+namespace MonoHook
+{
+ public static unsafe class HookUtils
+ {
+ static bool jit_write_protect_supported;
+ private static readonly long _Pagesize;
+
+
+ static HookUtils()
+ {
+ jit_write_protect_supported = pthread_jit_write_protect_supported_np() != 0;
+
+ PropertyInfo p_SystemPageSize = typeof(Environment).GetProperty("SystemPageSize");
+ if (p_SystemPageSize == null)
+ throw new NotSupportedException("Unsupported runtime");
+ _Pagesize = (int)p_SystemPageSize.GetValue(null, new object[0]);
+ }
+
+ public static void MemCpy(void* pDst, void* pSrc, int len)
+ {
+ byte* pDst_ = (byte*)pDst;
+ byte* pSrc_ = (byte*)pSrc;
+
+ for (int i = 0; i < len; i++)
+ *pDst_++ = *pSrc_++;
+ }
+
+ public static void MemCpy_Jit(void* pDst, byte[] src)
+ {
+ fixed(void * p = &src[0])
+ {
+ memcpy_jit(new IntPtr(pDst), new IntPtr(p), src.Length);
+ }
+ }
+
+ ///
+ /// set flags of address to `read write execute`
+ ///
+ public static void SetAddrFlagsToRWX(IntPtr ptr, int size) { }
+
+ public static void FlushICache(void* code, int size) { }
+
+ public static KeyValuePair GetPageAlignedAddr(long code, int size)
+ {
+ long pagesize = _Pagesize;
+ long startPage = (code) & ~(pagesize - 1);
+ long endPage = (code + size + pagesize - 1) & ~(pagesize - 1);
+ return new KeyValuePair(startPage, endPage);
+ }
+
+
+ const int PRINT_SPLIT = 4;
+ const int PRINT_COL_SIZE = PRINT_SPLIT * 4;
+ public static string HexToString(void* ptr, int size, int offset = 0)
+ {
+ Func formatAddr = (IntPtr addr__) => IntPtr.Size == 4 ? $"0x{(uint)addr__:x}" : $"0x{(ulong)addr__:x}";
+
+ byte* addr = (byte*)ptr;
+
+ StringBuilder sb = new StringBuilder(1024);
+ sb.AppendLine($"addr:{formatAddr(new IntPtr(addr))}");
+
+ addr += offset;
+ size += Math.Abs(offset);
+
+ int count = 0;
+ while (true)
+ {
+ sb.Append($"\r\n{formatAddr(new IntPtr(addr + count))}: ");
+ for (int i = 1; i < PRINT_COL_SIZE + 1; i++)
+ {
+ if (count >= size)
+ goto END;
+
+ sb.Append($"{*(addr + count):x2}");
+ if (i % PRINT_SPLIT == 0)
+ sb.Append(" ");
+
+ count++;
+ }
+ }
+ END:;
+ return sb.ToString();
+ }
+
+ [DllImport("pthread", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
+ private static extern int pthread_jit_write_protect_supported_np();
+
+ [DllImport("libMonoHookUtils_OSX", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr memcpy_jit(IntPtr dst, IntPtr src, int len);
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta b/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta
new file mode 100644
index 0000000..6ecee49
--- /dev/null
+++ b/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: efda6e010e5c6594081c4a62861d469f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Win.dll.bytes.meta b/Editor/3rds/UnityHook/HybridCLRHooks.meta
similarity index 57%
rename from Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Win.dll.bytes.meta
rename to Editor/3rds/UnityHook/HybridCLRHooks.meta
index 939b185..8169f8d 100644
--- a/Data~/ModifiedUnityAssemblies/2021.3.1/UnityEditor.CoreModule-Win.dll.bytes.meta
+++ b/Editor/3rds/UnityHook/HybridCLRHooks.meta
@@ -1,6 +1,7 @@
fileFormatVersion: 2
-guid: 33c064b00b452284f93cd6e89de8a06d
-TextScriptImporter:
+guid: d796fc01daee1964586621890988a5ae
+folderAsset: yes
+DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
diff --git a/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs b/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs
new file mode 100644
index 0000000..d78848f
--- /dev/null
+++ b/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs
@@ -0,0 +1,67 @@
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEngine;
+using UnityEditor;
+using System.Runtime.CompilerServices;
+using MonoHook;
+using HybridCLR.Editor.BuildProcessors;
+using System.IO;
+
+namespace HybridCLR.MonoHook
+{
+#if UNITY_2021_1_OR_NEWER && UNITY_IOS
+ [InitializeOnLoad]
+ public class CopyStrippedAOTAssembliesHook
+ {
+ private static MethodHook _hook;
+
+ static CopyStrippedAOTAssembliesHook()
+ {
+ if (_hook == null)
+ {
+ Type type = typeof(UnityEditor.EditorApplication).Assembly.GetType("UnityEditorInternal.AssemblyStripper");
+ MethodInfo miTarget = type.GetMethod("StripAssembliesTo", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
+
+ MethodInfo miReplacement = new StripAssembliesDel(OverrideStripAssembliesTo).Method;
+ MethodInfo miProxy = new StripAssembliesDel(StripAssembliesToProxy).Method;
+
+ _hook = new MethodHook(miTarget, miReplacement, miProxy);
+ _hook.Install();
+ }
+ }
+
+ private delegate bool StripAssembliesDel(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, object runInformation);
+
+ private static bool OverrideStripAssembliesTo(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, object runInformation)
+ {
+ bool result = StripAssembliesToProxy(outputFolder, out output, out error, linkXmlFiles, runInformation);
+ if (!result)
+ {
+ return false;
+ }
+ UnityEngine.Debug.Log($"== StripAssembliesTo outputDir:{outputFolder}");
+ string outputStrippedDir = HybridCLR.Editor.SettingsUtil.GetAssembliesPostIl2CppStripDir(EditorUserBuildSettings.activeBuildTarget);
+ Directory.CreateDirectory(outputStrippedDir);
+ foreach (var aotDll in Directory.GetFiles(outputFolder, "*.dll"))
+ {
+ string dstFile = $"{outputStrippedDir}/{Path.GetFileName(aotDll)}";
+ Debug.Log($"[RunAssemblyStripper] copy aot dll {aotDll} -> {dstFile}");
+ File.Copy(aotDll, dstFile, true);
+ }
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.NoOptimization)]
+ private static bool StripAssembliesToProxy(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, object runInformation)
+ {
+ Debug.LogError("== StripAssembliesToProxy ==");
+ output = "";
+ error = "";
+ return true;
+ }
+ }
+#endif
+}
diff --git a/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta b/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta
new file mode 100644
index 0000000..18542c3
--- /dev/null
+++ b/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cf42c4f20b8a1b94baa04a1a5c6b8beb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/3rds/UnityHook/LDasm.cs b/Editor/3rds/UnityHook/LDasm.cs
new file mode 100644
index 0000000..d87ab91
--- /dev/null
+++ b/Editor/3rds/UnityHook/LDasm.cs
@@ -0,0 +1,903 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace DotNetDetour
+{
+ ///
+ /// 用于计算汇编指令长度,使用的是BlackBone的LDasm.c中的算法,我把他翻译成C#了
+ ///
+ public unsafe class LDasm
+ {
+ const int F_INVALID = 0x01;
+ const int F_PREFIX = 0x02;
+ const int F_REX = 0x04;
+ const int F_MODRM = 0x08;
+ const int F_SIB = 0x10;
+ const int F_DISP = 0x20;
+ const int F_IMM = 0x40;
+ const int F_RELATIVE = 0x80;
+
+ const int OP_NONE = 0x00;
+ const int OP_INVALID = 0x80;
+
+ const int OP_DATA_I8 = 0x01;
+ const int OP_DATA_I16 = 0x02;
+ const int OP_DATA_I16_I32 = 0x04;
+ const int OP_DATA_I16_I32_I64 = 0x08;
+ const int OP_EXTENDED = 0x10;
+ const int OP_RELATIVE = 0x20;
+ const int OP_MODRM = 0x40;
+ const int OP_PREFIX = 0x80;
+
+ struct ldasm_data
+ {
+ public byte flags;
+ public byte rex;
+ public byte modrm;
+ public byte sib;
+ public byte opcd_offset;
+ public byte opcd_size;
+ public byte disp_offset;
+ public byte disp_size;
+ public byte imm_offset;
+ public byte imm_size;
+ }
+
+ static byte[] flags_table =
+ {
+ /* 00 */ OP_MODRM,
+ /* 01 */ OP_MODRM,
+ /* 02 */ OP_MODRM,
+ /* 03 */ OP_MODRM,
+ /* 04 */ OP_DATA_I8,
+ /* 05 */ OP_DATA_I16_I32,
+ /* 06 */ OP_NONE,
+ /* 07 */ OP_NONE,
+ /* 08 */ OP_MODRM,
+ /* 09 */ OP_MODRM,
+ /* 0A */ OP_MODRM,
+ /* 0B */ OP_MODRM,
+ /* 0C */ OP_DATA_I8,
+ /* 0D */ OP_DATA_I16_I32,
+ /* 0E */ OP_NONE,
+ /* 0F */ OP_NONE,
+
+ /* 10 */ OP_MODRM,
+ /* 11 */ OP_MODRM,
+ /* 12 */ OP_MODRM,
+ /* 13 */ OP_MODRM,
+ /* 14 */ OP_DATA_I8,
+ /* 15 */ OP_DATA_I16_I32,
+ /* 16 */ OP_NONE,
+ /* 17 */ OP_NONE,
+ /* 18 */ OP_MODRM,
+ /* 19 */ OP_MODRM,
+ /* 1A */ OP_MODRM,
+ /* 1B */ OP_MODRM,
+ /* 1C */ OP_DATA_I8,
+ /* 1D */ OP_DATA_I16_I32,
+ /* 1E */ OP_NONE,
+ /* 1F */ OP_NONE,
+
+ /* 20 */ OP_MODRM,
+ /* 21 */ OP_MODRM,
+ /* 22 */ OP_MODRM,
+ /* 23 */ OP_MODRM,
+ /* 24 */ OP_DATA_I8,
+ /* 25 */ OP_DATA_I16_I32,
+ /* 26 */ OP_PREFIX,
+ /* 27 */ OP_NONE,
+ /* 28 */ OP_MODRM,
+ /* 29 */ OP_MODRM,
+ /* 2A */ OP_MODRM,
+ /* 2B */ OP_MODRM,
+ /* 2C */ OP_DATA_I8,
+ /* 2D */ OP_DATA_I16_I32,
+ /* 2E */ OP_PREFIX,
+ /* 2F */ OP_NONE,
+
+ /* 30 */ OP_MODRM,
+ /* 31 */ OP_MODRM,
+ /* 32 */ OP_MODRM,
+ /* 33 */ OP_MODRM,
+ /* 34 */ OP_DATA_I8,
+ /* 35 */ OP_DATA_I16_I32,
+ /* 36 */ OP_PREFIX,
+ /* 37 */ OP_NONE,
+ /* 38 */ OP_MODRM,
+ /* 39 */ OP_MODRM,
+ /* 3A */ OP_MODRM,
+ /* 3B */ OP_MODRM,
+ /* 3C */ OP_DATA_I8,
+ /* 3D */ OP_DATA_I16_I32,
+ /* 3E */ OP_PREFIX,
+ /* 3F */ OP_NONE,
+
+ /* 40 */ OP_NONE,
+ /* 41 */ OP_NONE,
+ /* 42 */ OP_NONE,
+ /* 43 */ OP_NONE,
+ /* 44 */ OP_NONE,
+ /* 45 */ OP_NONE,
+ /* 46 */ OP_NONE,
+ /* 47 */ OP_NONE,
+ /* 48 */ OP_NONE,
+ /* 49 */ OP_NONE,
+ /* 4A */ OP_NONE,
+ /* 4B */ OP_NONE,
+ /* 4C */ OP_NONE,
+ /* 4D */ OP_NONE,
+ /* 4E */ OP_NONE,
+ /* 4F */ OP_NONE,
+
+ /* 50 */ OP_NONE,
+ /* 51 */ OP_NONE,
+ /* 52 */ OP_NONE,
+ /* 53 */ OP_NONE,
+ /* 54 */ OP_NONE,
+ /* 55 */ OP_NONE,
+ /* 56 */ OP_NONE,
+ /* 57 */ OP_NONE,
+ /* 58 */ OP_NONE,
+ /* 59 */ OP_NONE,
+ /* 5A */ OP_NONE,
+ /* 5B */ OP_NONE,
+ /* 5C */ OP_NONE,
+ /* 5D */ OP_NONE,
+ /* 5E */ OP_NONE,
+ /* 5F */ OP_NONE,
+ /* 60 */ OP_NONE,
+
+ /* 61 */ OP_NONE,
+ /* 62 */ OP_MODRM,
+ /* 63 */ OP_MODRM,
+ /* 64 */ OP_PREFIX,
+ /* 65 */ OP_PREFIX,
+ /* 66 */ OP_PREFIX,
+ /* 67 */ OP_PREFIX,
+ /* 68 */ OP_DATA_I16_I32,
+ /* 69 */ OP_MODRM | OP_DATA_I16_I32,
+ /* 6A */ OP_DATA_I8,
+ /* 6B */ OP_MODRM | OP_DATA_I8,
+ /* 6C */ OP_NONE,
+ /* 6D */ OP_NONE,
+ /* 6E */ OP_NONE,
+ /* 6F */ OP_NONE,
+
+ /* 70 */ OP_RELATIVE | OP_DATA_I8,
+ /* 71 */ OP_RELATIVE | OP_DATA_I8,
+ /* 72 */ OP_RELATIVE | OP_DATA_I8,
+ /* 73 */ OP_RELATIVE | OP_DATA_I8,
+ /* 74 */ OP_RELATIVE | OP_DATA_I8,
+ /* 75 */ OP_RELATIVE | OP_DATA_I8,
+ /* 76 */ OP_RELATIVE | OP_DATA_I8,
+ /* 77 */ OP_RELATIVE | OP_DATA_I8,
+ /* 78 */ OP_RELATIVE | OP_DATA_I8,
+ /* 79 */ OP_RELATIVE | OP_DATA_I8,
+ /* 7A */ OP_RELATIVE | OP_DATA_I8,
+ /* 7B */ OP_RELATIVE | OP_DATA_I8,
+ /* 7C */ OP_RELATIVE | OP_DATA_I8,
+ /* 7D */ OP_RELATIVE | OP_DATA_I8,
+ /* 7E */ OP_RELATIVE | OP_DATA_I8,
+ /* 7F */ OP_RELATIVE | OP_DATA_I8,
+
+ /* 80 */ OP_MODRM | OP_DATA_I8,
+ /* 81 */ OP_MODRM | OP_DATA_I16_I32,
+ /* 82 */ OP_MODRM | OP_DATA_I8,
+ /* 83 */ OP_MODRM | OP_DATA_I8,
+ /* 84 */ OP_MODRM,
+ /* 85 */ OP_MODRM,
+ /* 86 */ OP_MODRM,
+ /* 87 */ OP_MODRM,
+ /* 88 */ OP_MODRM,
+ /* 89 */ OP_MODRM,
+ /* 8A */ OP_MODRM,
+ /* 8B */ OP_MODRM,
+ /* 8C */ OP_MODRM,
+ /* 8D */ OP_MODRM,
+ /* 8E */ OP_MODRM,
+ /* 8F */ OP_MODRM,
+
+ /* 90 */ OP_NONE,
+ /* 91 */ OP_NONE,
+ /* 92 */ OP_NONE,
+ /* 93 */ OP_NONE,
+ /* 94 */ OP_NONE,
+ /* 95 */ OP_NONE,
+ /* 96 */ OP_NONE,
+ /* 97 */ OP_NONE,
+ /* 98 */ OP_NONE,
+ /* 99 */ OP_NONE,
+ /* 9A */ OP_DATA_I16 | OP_DATA_I16_I32,
+ /* 9B */ OP_NONE,
+ /* 9C */ OP_NONE,
+ /* 9D */ OP_NONE,
+ /* 9E */ OP_NONE,
+ /* 9F */ OP_NONE,
+
+ /* A0 */ OP_DATA_I8,
+ /* A1 */ OP_DATA_I16_I32_I64,
+ /* A2 */ OP_DATA_I8,
+ /* A3 */ OP_DATA_I16_I32_I64,
+ /* A4 */ OP_NONE,
+ /* A5 */ OP_NONE,
+ /* A6 */ OP_NONE,
+ /* A7 */ OP_NONE,
+ /* A8 */ OP_DATA_I8,
+ /* A9 */ OP_DATA_I16_I32,
+ /* AA */ OP_NONE,
+ /* AB */ OP_NONE,
+ /* AC */ OP_NONE,
+ /* AD */ OP_NONE,
+ /* AE */ OP_NONE,
+ /* AF */ OP_NONE,
+
+ /* B0 */ OP_DATA_I8,
+ /* B1 */ OP_DATA_I8,
+ /* B2 */ OP_DATA_I8,
+ /* B3 */ OP_DATA_I8,
+ /* B4 */ OP_DATA_I8,
+ /* B5 */ OP_DATA_I8,
+ /* B6 */ OP_DATA_I8,
+ /* B7 */ OP_DATA_I8,
+ /* B8 */ OP_DATA_I16_I32_I64,
+ /* B9 */ OP_DATA_I16_I32_I64,
+ /* BA */ OP_DATA_I16_I32_I64,
+ /* BB */ OP_DATA_I16_I32_I64,
+ /* BC */ OP_DATA_I16_I32_I64,
+ /* BD */ OP_DATA_I16_I32_I64,
+ /* BE */ OP_DATA_I16_I32_I64,
+ /* BF */ OP_DATA_I16_I32_I64,
+
+ /* C0 */ OP_MODRM | OP_DATA_I8,
+ /* C1 */ OP_MODRM | OP_DATA_I8,
+ /* C2 */ OP_DATA_I16,
+ /* C3 */ OP_NONE,
+ /* C4 */ OP_MODRM,
+ /* C5 */ OP_MODRM,
+ /* C6 */ OP_MODRM | OP_DATA_I8,
+ /* C7 */ OP_MODRM | OP_DATA_I16_I32,
+ /* C8 */ OP_DATA_I8 | OP_DATA_I16,
+ /* C9 */ OP_NONE,
+ /* CA */ OP_DATA_I16,
+ /* CB */ OP_NONE,
+ /* CC */ OP_NONE,
+ /* CD */ OP_DATA_I8,
+ /* CE */ OP_NONE,
+ /* CF */ OP_NONE,
+
+ /* D0 */ OP_MODRM,
+ /* D1 */ OP_MODRM,
+ /* D2 */ OP_MODRM,
+ /* D3 */ OP_MODRM,
+ /* D4 */ OP_DATA_I8,
+ /* D5 */ OP_DATA_I8,
+ /* D6 */ OP_NONE,
+ /* D7 */ OP_NONE,
+ /* D8 */ OP_MODRM,
+ /* D9 */ OP_MODRM,
+ /* DA */ OP_MODRM,
+ /* DB */ OP_MODRM,
+ /* DC */ OP_MODRM,
+ /* DD */ OP_MODRM,
+ /* DE */ OP_MODRM,
+ /* DF */ OP_MODRM,
+
+ /* E0 */ OP_RELATIVE | OP_DATA_I8,
+ /* E1 */ OP_RELATIVE | OP_DATA_I8,
+ /* E2 */ OP_RELATIVE | OP_DATA_I8,
+ /* E3 */ OP_RELATIVE | OP_DATA_I8,
+ /* E4 */ OP_DATA_I8,
+ /* E5 */ OP_DATA_I8,
+ /* E6 */ OP_DATA_I8,
+ /* E7 */ OP_DATA_I8,
+ /* E8 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* E9 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* EA */ OP_DATA_I16 | OP_DATA_I16_I32,
+ /* EB */ OP_RELATIVE | OP_DATA_I8,
+ /* EC */ OP_NONE,
+ /* ED */ OP_NONE,
+ /* EE */ OP_NONE,
+ /* EF */ OP_NONE,
+
+ /* F0 */ OP_PREFIX,
+ /* F1 */ OP_NONE,
+ /* F2 */ OP_PREFIX,
+ /* F3 */ OP_PREFIX,
+ /* F4 */ OP_NONE,
+ /* F5 */ OP_NONE,
+ /* F6 */ OP_MODRM,
+ /* F7 */ OP_MODRM,
+ /* F8 */ OP_NONE,
+ /* F9 */ OP_NONE,
+ /* FA */ OP_NONE,
+ /* FB */ OP_NONE,
+ /* FC */ OP_NONE,
+ /* FD */ OP_NONE,
+ /* FE */ OP_MODRM,
+ /* FF */ OP_MODRM
+ };
+
+ static byte[] flags_table_ex =
+ {
+ /* 0F00 */ OP_MODRM,
+ /* 0F01 */ OP_MODRM,
+ /* 0F02 */ OP_MODRM,
+ /* 0F03 */ OP_MODRM,
+ /* 0F04 */ OP_INVALID,
+ /* 0F05 */ OP_NONE,
+ /* 0F06 */ OP_NONE,
+ /* 0F07 */ OP_NONE,
+ /* 0F08 */ OP_NONE,
+ /* 0F09 */ OP_NONE,
+ /* 0F0A */ OP_INVALID,
+ /* 0F0B */ OP_NONE,
+ /* 0F0C */ OP_INVALID,
+ /* 0F0D */ OP_MODRM,
+ /* 0F0E */ OP_INVALID,
+ /* 0F0F */ OP_MODRM | OP_DATA_I8, //3Dnow
+
+ /* 0F10 */ OP_MODRM,
+ /* 0F11 */ OP_MODRM,
+ /* 0F12 */ OP_MODRM,
+ /* 0F13 */ OP_MODRM,
+ /* 0F14 */ OP_MODRM,
+ /* 0F15 */ OP_MODRM,
+ /* 0F16 */ OP_MODRM,
+ /* 0F17 */ OP_MODRM,
+ /* 0F18 */ OP_MODRM,
+ /* 0F19 */ OP_INVALID,
+ /* 0F1A */ OP_INVALID,
+ /* 0F1B */ OP_INVALID,
+ /* 0F1C */ OP_INVALID,
+ /* 0F1D */ OP_INVALID,
+ /* 0F1E */ OP_INVALID,
+ /* 0F1F */ OP_NONE,
+
+ /* 0F20 */ OP_MODRM,
+ /* 0F21 */ OP_MODRM,
+ /* 0F22 */ OP_MODRM,
+ /* 0F23 */ OP_MODRM,
+ /* 0F24 */ OP_MODRM | OP_EXTENDED, //SSE5
+ /* 0F25 */ OP_INVALID,
+ /* 0F26 */ OP_MODRM,
+ /* 0F27 */ OP_INVALID,
+ /* 0F28 */ OP_MODRM,
+ /* 0F29 */ OP_MODRM,
+ /* 0F2A */ OP_MODRM,
+ /* 0F2B */ OP_MODRM,
+ /* 0F2C */ OP_MODRM,
+ /* 0F2D */ OP_MODRM,
+ /* 0F2E */ OP_MODRM,
+ /* 0F2F */ OP_MODRM,
+
+ /* 0F30 */ OP_NONE,
+ /* 0F31 */ OP_NONE,
+ /* 0F32 */ OP_NONE,
+ /* 0F33 */ OP_NONE,
+ /* 0F34 */ OP_NONE,
+ /* 0F35 */ OP_NONE,
+ /* 0F36 */ OP_INVALID,
+ /* 0F37 */ OP_NONE,
+ /* 0F38 */ OP_MODRM | OP_EXTENDED,
+ /* 0F39 */ OP_INVALID,
+ /* 0F3A */ OP_MODRM | OP_EXTENDED | OP_DATA_I8,
+ /* 0F3B */ OP_INVALID,
+ /* 0F3C */ OP_INVALID,
+ /* 0F3D */ OP_INVALID,
+ /* 0F3E */ OP_INVALID,
+ /* 0F3F */ OP_INVALID,
+
+ /* 0F40 */ OP_MODRM,
+ /* 0F41 */ OP_MODRM,
+ /* 0F42 */ OP_MODRM,
+ /* 0F43 */ OP_MODRM,
+ /* 0F44 */ OP_MODRM,
+ /* 0F45 */ OP_MODRM,
+ /* 0F46 */ OP_MODRM,
+ /* 0F47 */ OP_MODRM,
+ /* 0F48 */ OP_MODRM,
+ /* 0F49 */ OP_MODRM,
+ /* 0F4A */ OP_MODRM,
+ /* 0F4B */ OP_MODRM,
+ /* 0F4C */ OP_MODRM,
+ /* 0F4D */ OP_MODRM,
+ /* 0F4E */ OP_MODRM,
+ /* 0F4F */ OP_MODRM,
+
+ /* 0F50 */ OP_MODRM,
+ /* 0F51 */ OP_MODRM,
+ /* 0F52 */ OP_MODRM,
+ /* 0F53 */ OP_MODRM,
+ /* 0F54 */ OP_MODRM,
+ /* 0F55 */ OP_MODRM,
+ /* 0F56 */ OP_MODRM,
+ /* 0F57 */ OP_MODRM,
+ /* 0F58 */ OP_MODRM,
+ /* 0F59 */ OP_MODRM,
+ /* 0F5A */ OP_MODRM,
+ /* 0F5B */ OP_MODRM,
+ /* 0F5C */ OP_MODRM,
+ /* 0F5D */ OP_MODRM,
+ /* 0F5E */ OP_MODRM,
+ /* 0F5F */ OP_MODRM,
+
+ /* 0F60 */ OP_MODRM,
+ /* 0F61 */ OP_MODRM,
+ /* 0F62 */ OP_MODRM,
+ /* 0F63 */ OP_MODRM,
+ /* 0F64 */ OP_MODRM,
+ /* 0F65 */ OP_MODRM,
+ /* 0F66 */ OP_MODRM,
+ /* 0F67 */ OP_MODRM,
+ /* 0F68 */ OP_MODRM,
+ /* 0F69 */ OP_MODRM,
+ /* 0F6A */ OP_MODRM,
+ /* 0F6B */ OP_MODRM,
+ /* 0F6C */ OP_MODRM,
+ /* 0F6D */ OP_MODRM,
+ /* 0F6E */ OP_MODRM,
+ /* 0F6F */ OP_MODRM,
+
+ /* 0F70 */ OP_MODRM | OP_DATA_I8,
+ /* 0F71 */ OP_MODRM | OP_DATA_I8,
+ /* 0F72 */ OP_MODRM | OP_DATA_I8,
+ /* 0F73 */ OP_MODRM | OP_DATA_I8,
+ /* 0F74 */ OP_MODRM,
+ /* 0F75 */ OP_MODRM,
+ /* 0F76 */ OP_MODRM,
+ /* 0F77 */ OP_NONE,
+ /* 0F78 */ OP_MODRM,
+ /* 0F79 */ OP_MODRM,
+ /* 0F7A */ OP_INVALID,
+ /* 0F7B */ OP_INVALID,
+ /* 0F7C */ OP_MODRM,
+ /* 0F7D */ OP_MODRM,
+ /* 0F7E */ OP_MODRM,
+ /* 0F7F */ OP_MODRM,
+
+ /* 0F80 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F81 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F82 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F83 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F84 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F85 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F86 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F87 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F88 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F89 */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F8A */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F8B */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F8C */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F8D */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F8E */ OP_RELATIVE | OP_DATA_I16_I32,
+ /* 0F8F */ OP_RELATIVE | OP_DATA_I16_I32,
+
+ /* 0F90 */ OP_MODRM,
+ /* 0F91 */ OP_MODRM,
+ /* 0F92 */ OP_MODRM,
+ /* 0F93 */ OP_MODRM,
+ /* 0F94 */ OP_MODRM,
+ /* 0F95 */ OP_MODRM,
+ /* 0F96 */ OP_MODRM,
+ /* 0F97 */ OP_MODRM,
+ /* 0F98 */ OP_MODRM,
+ /* 0F99 */ OP_MODRM,
+ /* 0F9A */ OP_MODRM,
+ /* 0F9B */ OP_MODRM,
+ /* 0F9C */ OP_MODRM,
+ /* 0F9D */ OP_MODRM,
+ /* 0F9E */ OP_MODRM,
+ /* 0F9F */ OP_MODRM,
+
+ /* 0FA0 */ OP_NONE,
+ /* 0FA1 */ OP_NONE,
+ /* 0FA2 */ OP_NONE,
+ /* 0FA3 */ OP_MODRM,
+ /* 0FA4 */ OP_MODRM | OP_DATA_I8,
+ /* 0FA5 */ OP_MODRM,
+ /* 0FA6 */ OP_INVALID,
+ /* 0FA7 */ OP_INVALID,
+ /* 0FA8 */ OP_NONE,
+ /* 0FA9 */ OP_NONE,
+ /* 0FAA */ OP_NONE,
+ /* 0FAB */ OP_MODRM,
+ /* 0FAC */ OP_MODRM | OP_DATA_I8,
+ /* 0FAD */ OP_MODRM,
+ /* 0FAE */ OP_MODRM,
+ /* 0FAF */ OP_MODRM,
+
+ /* 0FB0 */ OP_MODRM,
+ /* 0FB1 */ OP_MODRM,
+ /* 0FB2 */ OP_MODRM,
+ /* 0FB3 */ OP_MODRM,
+ /* 0FB4 */ OP_MODRM,
+ /* 0FB5 */ OP_MODRM,
+ /* 0FB6 */ OP_MODRM,
+ /* 0FB7 */ OP_MODRM,
+ /* 0FB8 */ OP_MODRM,
+ /* 0FB9 */ OP_MODRM,
+ /* 0FBA */ OP_MODRM | OP_DATA_I8,
+ /* 0FBB */ OP_MODRM,
+ /* 0FBC */ OP_MODRM,
+ /* 0FBD */ OP_MODRM,
+ /* 0FBE */ OP_MODRM,
+ /* 0FBF */ OP_MODRM,
+
+ /* 0FC0 */ OP_MODRM,
+ /* 0FC1 */ OP_MODRM,
+ /* 0FC2 */ OP_MODRM | OP_DATA_I8,
+ /* 0FC3 */ OP_MODRM,
+ /* 0FC4 */ OP_MODRM | OP_DATA_I8,
+ /* 0FC5 */ OP_MODRM | OP_DATA_I8,
+ /* 0FC6 */ OP_MODRM | OP_DATA_I8,
+ /* 0FC7 */ OP_MODRM,
+ /* 0FC8 */ OP_NONE,
+ /* 0FC9 */ OP_NONE,
+ /* 0FCA */ OP_NONE,
+ /* 0FCB */ OP_NONE,
+ /* 0FCC */ OP_NONE,
+ /* 0FCD */ OP_NONE,
+ /* 0FCE */ OP_NONE,
+ /* 0FCF */ OP_NONE,
+
+ /* 0FD0 */ OP_MODRM,
+ /* 0FD1 */ OP_MODRM,
+ /* 0FD2 */ OP_MODRM,
+ /* 0FD3 */ OP_MODRM,
+ /* 0FD4 */ OP_MODRM,
+ /* 0FD5 */ OP_MODRM,
+ /* 0FD6 */ OP_MODRM,
+ /* 0FD7 */ OP_MODRM,
+ /* 0FD8 */ OP_MODRM,
+ /* 0FD9 */ OP_MODRM,
+ /* 0FDA */ OP_MODRM,
+ /* 0FDB */ OP_MODRM,
+ /* 0FDC */ OP_MODRM,
+ /* 0FDD */ OP_MODRM,
+ /* 0FDE */ OP_MODRM,
+ /* 0FDF */ OP_MODRM,
+
+ /* 0FE0 */ OP_MODRM,
+ /* 0FE1 */ OP_MODRM,
+ /* 0FE2 */ OP_MODRM,
+ /* 0FE3 */ OP_MODRM,
+ /* 0FE4 */ OP_MODRM,
+ /* 0FE5 */ OP_MODRM,
+ /* 0FE6 */ OP_MODRM,
+ /* 0FE7 */ OP_MODRM,
+ /* 0FE8 */ OP_MODRM,
+ /* 0FE9 */ OP_MODRM,
+ /* 0FEA */ OP_MODRM,
+ /* 0FEB */ OP_MODRM,
+ /* 0FEC */ OP_MODRM,
+ /* 0FED */ OP_MODRM,
+ /* 0FEE */ OP_MODRM,
+ /* 0FEF */ OP_MODRM,
+
+ /* 0FF0 */ OP_MODRM,
+ /* 0FF1 */ OP_MODRM,
+ /* 0FF2 */ OP_MODRM,
+ /* 0FF3 */ OP_MODRM,
+ /* 0FF4 */ OP_MODRM,
+ /* 0FF5 */ OP_MODRM,
+ /* 0FF6 */ OP_MODRM,
+ /* 0FF7 */ OP_MODRM,
+ /* 0FF8 */ OP_MODRM,
+ /* 0FF9 */ OP_MODRM,
+ /* 0FFA */ OP_MODRM,
+ /* 0FFB */ OP_MODRM,
+ /* 0FFC */ OP_MODRM,
+ /* 0FFD */ OP_MODRM,
+ /* 0FFE */ OP_MODRM,
+ /* 0FFF */ OP_INVALID,
+ };
+
+ static byte cflags(byte op)
+ {
+ return flags_table[op];
+ }
+
+ static byte cflags_ex(byte op)
+ {
+ return flags_table_ex[op];
+ }
+
+ ///
+ /// 计算大于等于 size 字节的最少指令的长度
+ ///
+ ///
+ ///
+ public static uint SizeofMinNumByte(void* code, int size)
+ {
+ if (IsARM())
+ return (uint)((size + 3) / 4) * 4; // 此为 jit 模式下的长度,不再支持 thumb
+
+ uint Length;
+ byte* pOpcode;
+ uint Result = 0;
+ ldasm_data data = new ldasm_data();
+ bool is64 = IntPtr.Size == 8;
+ do
+ {
+ Length = ldasm(code, data, is64);
+
+ pOpcode = (byte*)code + data.opcd_offset;
+ Result += Length;
+ if (Result >= size)
+ break;
+ if ((Length == 1) && (*pOpcode == 0xCC))
+ break;
+
+ code = (void*)((ulong)code + Length);
+
+ } while (Length>0);
+
+ return Result;
+ }
+
+ static bool? s_isArm;
+ public static bool IsARM()
+ {
+ if(s_isArm.HasValue)
+ return s_isArm.Value;
+
+ var arch = RuntimeInformation.ProcessArchitecture;
+ s_isArm = arch == Architecture.Arm || arch == Architecture.Arm64;
+
+ return s_isArm.Value;
+ }
+
+ public static bool IsArm32()
+ {
+ return IsARM() && IntPtr.Size == 4;
+ }
+
+ public static bool IsArm64()
+ {
+ return IsARM() && IntPtr.Size == 8;
+ }
+
+ static bool? s_isiOS;
+ public static bool IsiOS()
+ {
+ if(s_isiOS.HasValue)
+ return s_isiOS.Value;
+
+ s_isiOS = UnityEngine.SystemInfo.operatingSystem.ToLower().Contains("ios");
+ return s_isiOS.Value;
+ }
+
+ static bool? s_isIL2CPP;
+ public static bool IsIL2CPP()
+ {
+ if (s_isIL2CPP.HasValue)
+ return s_isIL2CPP.Value;
+
+ try
+ {
+ byte[] ilBody = typeof(LDasm).GetMethod("IsIL2CPP").GetMethodBody().GetILAsByteArray();
+ if (ilBody == null || ilBody.Length == 0)
+ s_isIL2CPP = true;
+ else
+ s_isIL2CPP = false;
+ }
+ catch
+ {
+ s_isIL2CPP = true;
+ }
+
+ return s_isIL2CPP.Value;
+ }
+
+ public static bool IsThumb(IntPtr code)
+ {
+ return IsArm32() && ((long)code & 0x1) == 0x1;
+ }
+
+ ///
+ /// 计算 thumb 指令长度
+ ///
+ ///
+ ///
+ ///
+ public static uint CalcARMThumbMinLen(void* code, int size)
+ {
+ uint len = 0;
+
+ ushort* ins = (ushort*)code;
+ while (true)
+ {
+ if (len >= size)
+ return len;
+
+ if (((*ins >> 13) & 3) == 3)
+ {
+ ins += 2;
+ len += 4;
+ }
+ else
+ {
+ ins++;
+ len += 2;
+ }
+ }
+ }
+
+ static uint ldasm(void* code, ldasm_data ld, bool is64)
+ {
+ byte* p = (byte*)code;
+ byte s, op, f;
+ byte rexw, pr_66, pr_67;
+
+ s = rexw = pr_66 = pr_67 = 0;
+
+ /* dummy check */
+ if ((int)code==0)
+ return 0;
+
+ /* init output data */
+ //memset(ld, 0, sizeof(ldasm_data));
+
+ /* phase 1: parse prefixies */
+ while ((cflags(*p) & OP_PREFIX)!=0)
+ {
+ if (*p == 0x66)
+ pr_66 = 1;
+ if (*p == 0x67)
+ pr_67 = 1;
+ p++; s++;
+ ld.flags |= F_PREFIX;
+ if (s == 15)
+ {
+ ld.flags |= F_INVALID;
+ return s;
+ }
+ }
+
+ /* parse REX prefix */
+ if (is64 && *p >> 4 == 4)
+ {
+ ld.rex = *p;
+ rexw = (byte)((ld.rex >> 3) & 1);
+ ld.flags |= F_REX;
+ p++; s++;
+ }
+
+ /* can be only one REX prefix */
+ if (is64 && *p >> 4 == 4)
+ {
+ ld.flags |= F_INVALID;
+ s++;
+ return s;
+ }
+
+ /* phase 2: parse opcode */
+ ld.opcd_offset = (byte)(p - (byte*)code);
+ ld.opcd_size = 1;
+ op = *p++; s++;
+
+ /* is 2 byte opcode? */
+ if (op == 0x0F)
+ {
+ op = *p++; s++;
+ ld.opcd_size++;
+ f = cflags_ex(op);
+ if ((f & OP_INVALID)!=0)
+ {
+ ld.flags |= F_INVALID;
+ return s;
+ }
+ /* for SSE instructions */
+ if ((f & OP_EXTENDED)!=0)
+ {
+ op = *p++; s++;
+ ld.opcd_size++;
+ }
+ }
+ else {
+ f = cflags(op);
+ /* pr_66 = pr_67 for opcodes A0-A3 */
+ if (op >= 0xA0 && op <= 0xA3)
+ pr_66 = pr_67;
+ }
+
+ /* phase 3: parse ModR/M, SIB and DISP */
+ if ((f & OP_MODRM)!=0)
+ {
+ byte mod = (byte)(*p >> 6);
+ byte ro = (byte)((*p & 0x38) >> 3);
+ byte rm = (byte)(*p & 7);
+
+ ld.modrm = *p++; s++;
+ ld.flags |= F_MODRM;
+
+ /* in F6,F7 opcodes immediate data present if R/O == 0 */
+ if (op == 0xF6 && (ro == 0 || ro == 1))
+ f |= OP_DATA_I8;
+ if (op == 0xF7 && (ro == 0 || ro == 1))
+ f |= OP_DATA_I16_I32_I64;
+
+ /* is SIB byte exist? */
+ if (mod != 3 && rm == 4 && !(!is64 && pr_67!=0))
+ {
+ ld.sib = *p++; s++;
+ ld.flags |= F_SIB;
+
+ /* if base == 5 and mod == 0 */
+ if ((ld.sib & 7) == 5 && mod == 0)
+ {
+ ld.disp_size = 4;
+ }
+ }
+
+ switch (mod)
+ {
+ case 0:
+ if (is64)
+ {
+ if (rm == 5)
+ {
+ ld.disp_size = 4;
+ if (is64)
+ ld.flags |= F_RELATIVE;
+ }
+ }
+ else if (pr_67!=0)
+ {
+ if (rm == 6)
+ ld.disp_size = 2;
+ }
+ else {
+ if (rm == 5)
+ ld.disp_size = 4;
+ }
+ break;
+ case 1:
+ ld.disp_size = 1;
+ break;
+ case 2:
+ if (is64)
+ ld.disp_size = 4;
+ else if (pr_67!=0)
+ ld.disp_size = 2;
+ else
+ ld.disp_size = 4;
+ break;
+ }
+
+ if (ld.disp_size>0)
+ {
+ ld.disp_offset = (byte)(p - (byte*)code);
+ p += ld.disp_size;
+ s += ld.disp_size;
+ ld.flags |= F_DISP;
+ }
+ }
+
+ /* phase 4: parse immediate data */
+ if (rexw!=0 && (f & OP_DATA_I16_I32_I64)!=0)
+ ld.imm_size = 8;
+ else if ((f & OP_DATA_I16_I32)!=0 || (f & OP_DATA_I16_I32_I64)!=0)
+ ld.imm_size = (byte)(4 - (pr_66 << 1));
+
+ /* if exist, add OP_DATA_I16 and OP_DATA_I8 size */
+ ld.imm_size += (byte)(f & 3);
+
+ if ((ld.imm_size)!=0)
+ {
+ s += ld.imm_size;
+ ld.imm_offset = (byte)(p - (byte*)code);
+ ld.flags |= F_IMM;
+ if ((f & OP_RELATIVE)!=0)
+ ld.flags |= F_RELATIVE;
+ }
+
+ /* instruction is too long */
+ if (s > 15)
+ ld.flags |= F_INVALID;
+
+ return s;
+ }
+ }
+}
diff --git a/Editor/3rds/UnityHook/LDasm.cs.meta b/Editor/3rds/UnityHook/LDasm.cs.meta
new file mode 100644
index 0000000..969a5a1
--- /dev/null
+++ b/Editor/3rds/UnityHook/LDasm.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3c561c9729c367e4fbef63f4ec56f268
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/3rds/UnityHook/MethodHook.cs b/Editor/3rds/UnityHook/MethodHook.cs
new file mode 100644
index 0000000..e7acd0a
--- /dev/null
+++ b/Editor/3rds/UnityHook/MethodHook.cs
@@ -0,0 +1,381 @@
+/*
+ Desc: 一个可以运行时 Hook Mono 方法的工具,让你可以无需修改 UnityEditor.dll 等文件就可以重写其函数功能
+ Author: Misaka Mikoto
+ Github: https://github.com/Misaka-Mikoto-Tech/MonoHook
+ */
+
+using DotNetDetour;
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Unity.Collections.LowLevel.Unsafe;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+using UnityEngine;
+using System.Runtime.CompilerServices;
+
+
+/*
+>>>>>>> 原始 UnityEditor.LogEntries.Clear 一型(.net 4.x)
+0000000000403A00 < | 55 | push rbp |
+0000000000403A01 | 48 8B EC | mov rbp,rsp |
+0000000000403A04 | 48 81 EC 80 00 00 00 | sub rsp,80 |
+0000000000403A0B | 48 89 65 B0 | mov qword ptr ss:[rbp-50],rsp |
+0000000000403A0F | 48 89 6D A8 | mov qword ptr ss:[rbp-58],rbp |
+0000000000403A13 | 48 89 5D C8 | mov qword ptr ss:[rbp-38],rbx | <<
+0000000000403A17 | 48 89 75 D0 | mov qword ptr ss:[rbp-30],rsi |
+0000000000403A1B | 48 89 7D D8 | mov qword ptr ss:[rbp-28],rdi |
+0000000000403A1F | 4C 89 65 E0 | mov qword ptr ss:[rbp-20],r12 |
+0000000000403A23 | 4C 89 6D E8 | mov qword ptr ss:[rbp-18],r13 |
+0000000000403A27 | 4C 89 75 F0 | mov qword ptr ss:[rbp-10],r14 |
+0000000000403A2B | 4C 89 7D F8 | mov qword ptr ss:[rbp-8],r15 |
+0000000000403A2F | 49 BB 00 2D 1E 1A FE 7F 00 00 | mov r11,7FFE1A1E2D00 |
+0000000000403A39 | 4C 89 5D B8 | mov qword ptr ss:[rbp-48],r11 |
+0000000000403A3D | 49 BB 08 2D 1E 1A FE 7F 00 00 | mov r11,7FFE1A1E2D08 |
+
+
+>>>>>>> 二型(.net 2.x)
+0000000000403E8F | 55 | push rbp |
+0000000000403E90 | 48 8B EC | mov rbp,rsp |
+0000000000403E93 | 48 83 EC 70 | sub rsp,70 |
+0000000000403E97 | 48 89 65 C8 | mov qword ptr ss:[rbp-38],rsp |
+0000000000403E9B | 48 89 5D B8 | mov qword ptr ss:[rbp-48],rbx |
+0000000000403E9F | 48 89 6D C0 | mov qword ptr ss:[rbp-40],rbp | <<(16)
+0000000000403EA3 | 48 89 75 F8 | mov qword ptr ss:[rbp-8],rsi |
+0000000000403EA7 | 48 89 7D F0 | mov qword ptr ss:[rbp-10],rdi |
+0000000000403EAB | 4C 89 65 D0 | mov qword ptr ss:[rbp-30],r12 |
+0000000000403EAF | 4C 89 6D D8 | mov qword ptr ss:[rbp-28],r13 |
+0000000000403EB3 | 4C 89 75 E0 | mov qword ptr ss:[rbp-20],r14 |
+0000000000403EB7 | 4C 89 7D E8 | mov qword ptr ss:[rbp-18],r15 |
+0000000000403EBB | 48 83 EC 20 | sub rsp,20 |
+0000000000403EBF | 49 BB 18 3F 15 13 FE 7F 00 00 | mov r11,7FFE13153F18 |
+0000000000403EC9 | 41 FF D3 | call r11 |
+0000000000403ECC | 48 83 C4 20 | add rsp,20 |
+
+>>>>>>>>> arm64
+il2cpp:00000000003DE714 F5 0F 1D F8 STR X21, [SP,#-0x10+var_20]! | << absolute safe
+il2cpp:00000000003DE718 F4 4F 01 A9 STP X20, X19, [SP,#0x20+var_10] | << may be safe
+il2cpp:00000000003DE71C FD 7B 02 A9 STP X29, X30, [SP,#0x20+var_s0] |
+il2cpp:00000000003DE720 FD 83 00 91 ADD X29, SP, #0x20 |
+il2cpp:00000000003DE724 B5 30 00 B0 ADRP X21, #_ZZ62GameObject_SetActive_mCF1EEF2A314F3AE | << dangerous: relative instruction, can not be overwritten
+il2cpp:00000000003DE728 A2 56 47 F9 LDR method, [X21,#_ZZ62GameObject_SetActive_mCF] ; |
+il2cpp:00000000003DE72C F3 03 01 2A MOV W19, W1 |
+ */
+
+namespace MonoHook
+{
+ ///
+ /// Hook 类,用来 Hook 某个 C# 方法
+ ///
+ public unsafe class MethodHook
+ {
+ public string tag;
+ public bool isHooked { get; private set; }
+ public bool isPlayModeHook { get; private set; }
+
+ public MethodBase targetMethod { get; private set; } // 需要被hook的目标方法
+ public MethodBase replacementMethod { get; private set; } // 被hook后的替代方法
+ public MethodBase proxyMethod { get; private set; } // 目标方法的代理方法(可以通过此方法调用被hook后的原方法)
+
+ private IntPtr _targetPtr; // 目标方法被 jit 后的地址指针
+ private IntPtr _replacementPtr;
+ private IntPtr _proxyPtr;
+
+ private CodePatcher _codePatcher;
+
+#if UNITY_EDITOR
+ ///
+ /// call `MethodInfo.MethodHandle.GetFunctionPointer()`
+ /// will visit static class `UnityEditor.IMGUI.Controls.TreeViewGUI.Styles` and invoke its static constructor,
+ /// and init static filed `foldout`, but `GUISKin.current` is null now,
+ /// so we should wait until `GUISKin.current` has a valid value
+ ///
+ private static FieldInfo s_fi_GUISkin_current;
+#endif
+
+ static MethodHook()
+ {
+#if UNITY_EDITOR
+ s_fi_GUISkin_current = typeof(GUISkin).GetField("current", BindingFlags.Static | BindingFlags.NonPublic);
+#endif
+ }
+
+ ///
+ /// 创建一个 Hook
+ ///
+ /// 需要替换的目标方法
+ /// 准备好的替换方法
+ /// 如果还需要调用原始目标方法,可以通过此参数的方法调用,如果不需要可以填 null
+ public MethodHook(MethodBase targetMethod, MethodBase replacementMethod, MethodBase proxyMethod, string data = "")
+ {
+ this.targetMethod = targetMethod;
+ this.replacementMethod = replacementMethod;
+ this.proxyMethod = proxyMethod;
+ this.tag = data;
+
+ CheckMethod();
+ }
+
+ public void Install()
+ {
+ if (LDasm.IsiOS()) // iOS 不支持修改 code 所在区域 page
+ return;
+
+ if (isHooked)
+ return;
+
+#if UNITY_EDITOR
+ if (s_fi_GUISkin_current.GetValue(null) != null)
+ DoInstall();
+ else
+ EditorApplication.update += OnEditorUpdate;
+#else
+ DoInstall();
+#endif
+ isPlayModeHook = Application.isPlaying;
+ }
+
+ public void Uninstall()
+ {
+ if (!isHooked)
+ return;
+
+ _codePatcher.RemovePatch();
+
+ isHooked = false;
+ HookPool.RemoveHooker(targetMethod);
+ }
+
+ #region private
+ private void DoInstall()
+ {
+ if (targetMethod == null || replacementMethod == null)
+ throw new Exception("none of methods targetMethod or replacementMethod can be null");
+
+ HookPool.AddHook(targetMethod, this);
+
+ if (_codePatcher == null)
+ {
+ if (GetFunctionAddr())
+ {
+#if ENABLE_HOOK_DEBUG
+ UnityEngine.Debug.Log($"Original [{targetMethod.DeclaringType.Name}.{targetMethod.Name}]: {HookUtils.HexToString(_targetPtr.ToPointer(), 64, -16)}");
+ UnityEngine.Debug.Log($"Original [{replacementMethod.DeclaringType.Name}.{replacementMethod.Name}]: {HookUtils.HexToString(_replacementPtr.ToPointer(), 64, -16)}");
+ if(proxyMethod != null)
+ UnityEngine.Debug.Log($"Original [{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}]: {HookUtils.HexToString(_proxyPtr.ToPointer(), 64, -16)}");
+#endif
+
+ CreateCodePatcher();
+ _codePatcher.ApplyPatch();
+
+#if ENABLE_HOOK_DEBUG
+ UnityEngine.Debug.Log($"New [{targetMethod.DeclaringType.Name}.{targetMethod.Name}]: {HookUtils.HexToString(_targetPtr.ToPointer(), 64, -16)}");
+ UnityEngine.Debug.Log($"New [{replacementMethod.DeclaringType.Name}.{replacementMethod.Name}]: {HookUtils.HexToString(_replacementPtr.ToPointer(), 64, -16)}");
+ if(proxyMethod != null)
+ UnityEngine.Debug.Log($"New [{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}]: {HookUtils.HexToString(_proxyPtr.ToPointer(), 64, -16)}");
+#endif
+ }
+ }
+
+ isHooked = true;
+ }
+
+ private void CheckMethod()
+ {
+ if (targetMethod == null || replacementMethod == null)
+ throw new Exception("MethodHook:targetMethod and replacementMethod and proxyMethod can not be null");
+
+ string methodName = $"{targetMethod.DeclaringType.Name}.{targetMethod.Name}";
+ if (targetMethod.IsAbstract)
+ throw new Exception($"WRANING: you can not hook abstract method [{methodName}]");
+
+#if UNITY_EDITOR
+ int minMethodBodySize = 10;
+
+ {
+ if ((targetMethod.MethodImplementationFlags & MethodImplAttributes.InternalCall) != MethodImplAttributes.InternalCall)
+ {
+ int codeSize = targetMethod.GetMethodBody().GetILAsByteArray().Length; // GetMethodBody can not call on il2cpp
+ if (codeSize < minMethodBodySize)
+ UnityEngine.Debug.LogWarning($"WRANING: you can not hook method [{methodName}], cause its method body is too short({codeSize}), will random crash on IL2CPP release mode");
+ }
+ }
+
+ if(proxyMethod != null)
+ {
+ methodName = $"{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}";
+ int codeSize = proxyMethod.GetMethodBody().GetILAsByteArray().Length;
+ if (codeSize < minMethodBodySize)
+ UnityEngine.Debug.LogWarning($"WRANING: size of method body[{methodName}] is too short({codeSize}), will random crash on IL2CPP release mode, please fill some dummy code inside");
+
+ if ((proxyMethod.MethodImplementationFlags & MethodImplAttributes.NoOptimization) != MethodImplAttributes.NoOptimization)
+ throw new Exception($"WRANING: method [{methodName}] must has a Attribute `MethodImpl(MethodImplOptions.NoOptimization)` to prevent code call to this optimized by compiler(pass args by shared stack)");
+ }
+#endif
+ }
+
+ private void CreateCodePatcher()
+ {
+ long addrOffset = Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64());
+
+ if(_proxyPtr != IntPtr.Zero)
+ addrOffset = Math.Max(addrOffset, Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64()));
+
+ if (LDasm.IsARM())
+ {
+ if (IntPtr.Size == 8)
+ _codePatcher = new CodePatcher_arm64_near(_targetPtr, _replacementPtr, _proxyPtr);
+ else if (addrOffset < ((1 << 25) - 1))
+ _codePatcher = new CodePatcher_arm32_near(_targetPtr, _replacementPtr, _proxyPtr);
+ else if (addrOffset < ((1 << 27) - 1))
+ _codePatcher = new CodePatcher_arm32_far(_targetPtr, _replacementPtr, _proxyPtr);
+ else
+ throw new Exception("address of target method and replacement method are too far, can not hook");
+ }
+ else
+ {
+ if (IntPtr.Size == 8)
+ {
+ if(addrOffset < 0x7fffffff) // 2G
+ _codePatcher = new CodePatcher_x64_near(_targetPtr, _replacementPtr, _proxyPtr);
+ else
+ _codePatcher = new CodePatcher_x64_far(_targetPtr, _replacementPtr, _proxyPtr);
+ }
+ else
+ _codePatcher = new CodePatcher_x86(_targetPtr, _replacementPtr, _proxyPtr);
+ }
+ }
+
+ ///
+ /// 获取对应函数jit后的native code的地址
+ ///
+ private bool GetFunctionAddr()
+ {
+ _targetPtr = GetFunctionAddr(targetMethod);
+ _replacementPtr = GetFunctionAddr(replacementMethod);
+ _proxyPtr = GetFunctionAddr(proxyMethod);
+
+ if (_targetPtr == IntPtr.Zero || _replacementPtr == IntPtr.Zero)
+ return false;
+
+ if (proxyMethod != null && _proxyPtr == null)
+ return false;
+
+ if(_replacementPtr == _targetPtr)
+ {
+ throw new Exception($"the addresses of target method {targetMethod.Name} and replacement method {replacementMethod.Name} can not be same");
+ }
+
+ if (LDasm.IsThumb(_targetPtr) || LDasm.IsThumb(_replacementPtr))
+ {
+ throw new Exception("does not support thumb arch");
+ }
+
+ return true;
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)] // 好像在 IL2CPP 里无效
+ private struct __ForCopy
+ {
+ public long __dummy;
+ public MethodBase method;
+ }
+ ///
+ /// 获取方法指令地址
+ ///
+ ///
+ ///
+ private IntPtr GetFunctionAddr(MethodBase method)
+ {
+ if (method == null)
+ return IntPtr.Zero;
+
+ if (!LDasm.IsIL2CPP())
+ return method.MethodHandle.GetFunctionPointer();
+ else
+ {
+ /*
+ // System.Reflection.MonoMethod
+ typedef struct Il2CppReflectionMethod
+ {
+ Il2CppObject object;
+ const MethodInfo *method;
+ Il2CppString *name;
+ Il2CppReflectionType *reftype;
+ } Il2CppReflectionMethod;
+
+ typedef Il2CppClass Il2CppVTable;
+ typedef struct Il2CppObject
+ {
+ union
+ {
+ Il2CppClass *klass;
+ Il2CppVTable *vtable;
+ };
+ MonitorData *monitor;
+ } Il2CppObject;
+
+ typedef struct MethodInfo
+ {
+ Il2CppMethodPointer methodPointer; // this is the pointer to native code of method
+ InvokerMethod invoker_method;
+ const char* name;
+ Il2CppClass *klass;
+ const Il2CppType *return_type;
+ const ParameterInfo* parameters;
+ // ...
+ }
+ */
+
+ __ForCopy __forCopy = new __ForCopy() { method = method };
+
+ long* ptr = &__forCopy.__dummy;
+ ptr++; // addr of _forCopy.method
+
+ IntPtr methodAddr = IntPtr.Zero;
+ if (sizeof(IntPtr) == 8)
+ {
+ long methodDataAddr = *(long*)ptr;
+ byte* ptrData = (byte*)methodDataAddr + sizeof(IntPtr) * 2; // offset of Il2CppReflectionMethod::const MethodInfo *method;
+
+ long methodPtr = 0;
+ methodPtr = *(long*)ptrData;
+ methodAddr = new IntPtr(*(long*)methodPtr); // MethodInfo::Il2CppMethodPointer methodPointer;
+ }
+ else
+ {
+ int methodDataAddr = *(int*)ptr;
+ byte* ptrData = (byte*)methodDataAddr + sizeof(IntPtr) * 2; // offset of Il2CppReflectionMethod::const MethodInfo *method;
+
+ int methodPtr = 0;
+ methodPtr = *(int*)ptrData;
+ methodAddr = new IntPtr(*(int*)methodPtr);
+ }
+ return methodAddr;
+ }
+ }
+
+#if UNITY_EDITOR
+ private void OnEditorUpdate()
+ {
+ if (s_fi_GUISkin_current.GetValue(null) != null)
+ {
+ try
+ {
+ DoInstall();
+ }
+ finally
+ {
+ EditorApplication.update -= OnEditorUpdate;
+ }
+ }
+ }
+#endif
+
+ #endregion
+ }
+
+}
diff --git a/Editor/3rds/UnityHook/MethodHook.cs.meta b/Editor/3rds/UnityHook/MethodHook.cs.meta
new file mode 100644
index 0000000..007e62c
--- /dev/null
+++ b/Editor/3rds/UnityHook/MethodHook.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bd0b8071cf434d6498160259e3829980
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/3rds/UnityHook/Plugins.meta b/Editor/3rds/UnityHook/Plugins.meta
new file mode 100644
index 0000000..f6f9520
--- /dev/null
+++ b/Editor/3rds/UnityHook/Plugins.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 82346623158bae349a8347ae74662b12
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/3rds/UnityHook/Plugins/Utils.cpp b/Editor/3rds/UnityHook/Plugins/Utils.cpp
new file mode 100644
index 0000000..106d990
--- /dev/null
+++ b/Editor/3rds/UnityHook/Plugins/Utils.cpp
@@ -0,0 +1,23 @@
+//
+// Utils.cpp
+// MonoHookUtils_OSX
+//
+// Created by Misaka-Mikoto on 2022/8/31.
+//
+#include
+#include
+#include
+#include
+#include
+
+extern "C"{
+
+void* memcpy_jit(void* dst, void* src, int32_t size)
+{
+ pthread_jit_write_protect_np(0);
+ void* ret = memcpy(dst, src, size);
+ pthread_jit_write_protect_np(1);
+ sys_icache_invalidate (dst, size);
+ return ret;
+}
+}
diff --git a/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta b/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta
new file mode 100644
index 0000000..447c3db
--- /dev/null
+++ b/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta
@@ -0,0 +1,81 @@
+fileFormatVersion: 2
+guid: 56b28b5583a184c669dcb968d175544c
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ : Any
+ second:
+ enabled: 0
+ settings:
+ Exclude Android: 1
+ Exclude Editor: 0
+ Exclude Linux64: 1
+ Exclude OSXUniversal: 1
+ Exclude WebGL: 1
+ Exclude Win: 1
+ Exclude Win64: 1
+ Exclude iOS: 1
+ - first:
+ Android: Android
+ second:
+ enabled: 0
+ settings:
+ CPU: ARMv7
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ DefaultValueInitialized: true
+ OS: OSX
+ - first:
+ Standalone: Linux64
+ second:
+ enabled: 0
+ settings:
+ CPU: None
+ - first:
+ Standalone: OSXUniversal
+ second:
+ enabled: 0
+ settings:
+ CPU: ARM64
+ - first:
+ Standalone: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: None
+ - first:
+ Standalone: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: None
+ - first:
+ iPhone: iOS
+ second:
+ enabled: 0
+ settings:
+ AddToEmbeddedBinaries: false
+ CPU: AnyCPU
+ CompileFlags:
+ FrameworkDependencies:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/3rds/UnityHook/Plugins/libMonoHookUtils_OSX.dylib b/Editor/3rds/UnityHook/Plugins/libMonoHookUtils_OSX.dylib
new file mode 100644
index 0000000..07f9063
Binary files /dev/null and b/Editor/3rds/UnityHook/Plugins/libMonoHookUtils_OSX.dylib differ
diff --git a/Editor/3rds/UnityHook/Plugins/libMonoHookUtils_OSX.dylib.meta b/Editor/3rds/UnityHook/Plugins/libMonoHookUtils_OSX.dylib.meta
new file mode 100644
index 0000000..48e28e3
--- /dev/null
+++ b/Editor/3rds/UnityHook/Plugins/libMonoHookUtils_OSX.dylib.meta
@@ -0,0 +1,81 @@
+fileFormatVersion: 2
+guid: 4adb23596911347faa69537b900c9f5e
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ : Any
+ second:
+ enabled: 0
+ settings:
+ Exclude Android: 1
+ Exclude Editor: 0
+ Exclude Linux64: 1
+ Exclude OSXUniversal: 1
+ Exclude WebGL: 1
+ Exclude Win: 1
+ Exclude Win64: 1
+ Exclude iOS: 1
+ - first:
+ Android: Android
+ second:
+ enabled: 0
+ settings:
+ CPU: ARMv7
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ DefaultValueInitialized: true
+ OS: OSX
+ - first:
+ Standalone: Linux64
+ second:
+ enabled: 0
+ settings:
+ CPU: None
+ - first:
+ Standalone: OSXUniversal
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: None
+ - first:
+ Standalone: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: None
+ - first:
+ iPhone: iOS
+ second:
+ enabled: 0
+ settings:
+ AddToEmbeddedBinaries: false
+ CPU: AnyCPU
+ CompileFlags:
+ FrameworkDependencies:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/Installer/InstallerController.cs b/Editor/Installer/InstallerController.cs
index a163e88..f867357 100644
--- a/Editor/Installer/InstallerController.cs
+++ b/Editor/Installer/InstallerController.cs
@@ -266,10 +266,6 @@ namespace HybridCLR.Editor.Installer
Debug.LogError($"未找到当前版本:{curVersionStr} 对应的改造过的 Unity.IL2CPP.dll,打包出的程序将会崩溃");
}
}
- if (version.major >= 2021)
- {
- Debug.LogError($"如果需要打包iOS,必须手动替换UnityEditor.CoreModule.dll为修改后的版本,否则无法获得AOT dlls。详见 https://focus-creative-games.github.io/hybridclr/modify_unity_dll/#unityeditor-coremodule-dll");
- }
if (HasInstalledHybridCLR())
{
Debug.Log("安装成功");
diff --git a/package.json b/package.json
index e2ce069..6561291 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "com.focus-creative-games.hybridclr_unity",
- "version": "2.0.0",
+ "version": "2.0.1",
"displayName": "HybridCLR",
"description": "Unity package for HybridCLR. It includes editor and runtime scripts and assets for HybridCLR",
"category": "Runtime",