public NativeDetour(MethodBase method, IntPtr from, IntPtr to) { Data = DetourManager.Native.Create(from, to); Method = method; // Backing up the original function only needs to happen once. if (Method != null && Method.GetMethodBody() != null) { _BackupMethod = method.CreateILCopy(); } // BackupNative is required even if BackupMethod is present to undo the detour. _BackupNative = DetourManager.Native.MemAlloc(Data.Size); DetourManager.Native.Copy(Data.Method, _BackupNative, Data.Size); Apply(); }
internal HookEndpoint(MethodBase method) { Method = method; // Add a "transparent" detour for IL manipulation. bool hasMethodBody; try { hasMethodBody = (method.GetMethodBody()?.GetILAsByteArray()?.Length ?? 0) != 0; } catch { hasMethodBody = false; } if (hasMethodBody) { // Note: This can but shouldn't fail, mainly if the user hasn't provided a Cecil ModuleDefinition generator. DMD = new DynamicMethodDefinition(method, HookEndpointManager.GenerateCecilModule); ILCopy = method.CreateILCopy(); ILDetour = new Detour(method, ILCopy); DetourILDetourTarget(); } }
public NativeDetour(MethodBase method, IntPtr from, IntPtr to) { Data = DetourManager.Native.Create(from, to); Method = method; // Backing up the original function only needs to happen once. MethodBody body; try { body = Method?.GetMethodBody(); } catch (InvalidOperationException) { body = null; } if (body != null) { _BackupMethod = method.CreateILCopy(); } // BackupNative is required even if BackupMethod is present to undo the detour. _BackupNative = DetourManager.Native.MemAlloc(Data.Size); DetourManager.Native.Copy(Data.Method, _BackupNative, Data.Size); Apply(); }
public Detour(MethodBase from, MethodBase to) { Method = from; Target = to; // TODO: Check target method arguments. if (!_BackupMethods.ContainsKey(Method)) { _BackupMethods[Method] = Method.CreateILCopy(); } // Generate a "chained trampoline" DynamicMethod. ParameterInfo[] args = Method.GetParameters(); Type[] argTypes; if (!Method.IsStatic) { argTypes = new Type[args.Length + 1]; argTypes[0] = Method.DeclaringType; for (int i = 0; i < args.Length; i++) { argTypes[i + 1] = args[i].ParameterType; } } else { argTypes = new Type[args.Length]; for (int i = 0; i < args.Length; i++) { argTypes[i] = args[i].ParameterType; } } _ChainedTrampoline = new DynamicMethod( $"chain_{Method.Name}_{GetHashCode()}", (Method as MethodInfo)?.ReturnType ?? typeof(void), argTypes, Method.DeclaringType, false // Otherwise just ret is invalid for whatever reason. ).StubCriticalDetour().Pin(); // Add the detour to the detour map. List <Detour> detours; lock (_DetourMap) { if (!_DetourMap.TryGetValue(Method, out detours)) { _DetourMap[Method] = detours = new List <Detour>(); } } lock (detours) { // New Detour instances are always on the top. if (detours.Count > 0) { detours[detours.Count - 1]._TopUndo(); } _TopApply(); // Do the initial "chained trampoline" setup. NativeDetourData link; if (detours.Count > 0) { // If a previous Detour exists in the chain, detour our "chained trampoline" to it, link = DetourManager.Native.Create( _ChainedTrampoline.GetNativeStart(), detours[detours.Count - 1].Target.GetNativeStart() ); } else { // If this is the first Detour in the chain, detour our "chained trampoline" to the original method. link = DetourManager.Native.Create( _ChainedTrampoline.GetNativeStart(), _BackupMethods[Method].GetNativeStart() ); } DetourManager.Native.MakeWritable(link); DetourManager.Native.Apply(link); DetourManager.Native.MakeExecutable(link); DetourManager.Native.Free(link); detours.Add(this); } }