| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 | 
							- #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] <void, byte, uint> 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);
 
-             }
 
-         }
 
-         /// <summary>
 
-         /// set flags of address to `read write execute`
 
-         /// </summary>
 
-         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<long, long> GetPageAlignedAddr(long code, int size)
 
-         {
 
-             long pagesize   = _Pagesize;
 
-             long startPage  = (code) & ~(pagesize - 1);
 
-             long endPage    = (code + size + pagesize - 1) & ~(pagesize - 1);
 
-             return new KeyValuePair<long, long>(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<IntPtr, string> 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.ToLowerInvariant();
 
-             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<DelegateFlushICache>(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<DelegateFlushICache>(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
 
 
  |