예제 #1
0
 public SocketHookHosting(HookOptions options, IHookLifetimeService hookLifetime, ISocketHookService hookService, IHostEnvironment env)
 {
     _isProduction      = env.IsProduction();
     _socketHookService = hookService;
     _hookLifetime      = hookLifetime;
     _options           = options;
 }
예제 #2
0
 public HookDelegateEmitter(string name, IEnumerable <ParameterDefinition> parameters, TypeDefinition returnType, HookOptions flags, ModuleDefinition module)
 {
     this._name       = name;
     this._parameters = parameters;
     this._flags      = flags;
     this._module     = module;
     this._returnType = returnType;
 }
예제 #3
0
 public HookDelegateEmitter(string prefix, MethodDefinition method, HookOptions flags)
 {
     this._name       = prefix + method.GetSafeName();
     this._flags      = flags;
     this._parameters = method.Parameters;
     this._module     = method.Module;
     this._returnType = method.ReturnType;
 }
예제 #4
0
 public static string DisplayValue(HookOptions opts)
 {
     switch (opts)
     {
         case HookOptions.IgnoreInjected: return "Ignore Injected Events";
         case HookOptions.All: return "All";
         default: return "None";
     }
 }
예제 #5
0
        public static string DisplayValue(HookOptions opts)
        {
            switch (opts)
            {
            case HookOptions.IgnoreInjected: return("Ignore Injected Events");

            case HookOptions.All: return("All");

            default: return("None");
            }
        }
        /// <summary>
        /// Generates a hook that is called before any native code
        /// </summary>
        /// <param name="method">Method to generate the hook in</param>
        /// <param name="options">Configurable hook options</param>
        /// <returns>A <see cref="MergableMethod"/> instance</returns>
        public static MergableMethod GenerateBeginHook
        (
            this MethodDefinition method,

            HookOptions options = HookOptions.Default,
            VariableDefinition result_variable = null
        )
        {
            // emit call at offset 0

            // add or get the types where we are storing out auto generated hooks & their delegates
            var hooks_type           = method.DeclaringType.GetHooksType();
            var hooks_delegates_type = method.DeclaringType.GetHooksDelegateType();

            // generate the hook handler delegate
            var hook_delegate_emitter = new HookDelegateEmitter("OnPre", method, options);
            var hook_handler          = hook_delegate_emitter.Emit();

            hooks_delegates_type.NestedTypes.Add(hook_handler);

            // generate the api hook external modules can attach to
            var hook_field = new FieldDefinition("Pre" + method.GetSafeName(), FieldAttributes.Public | FieldAttributes.Static, hook_handler);

            hooks_type.Fields.Add(hook_field);

            // generate the call to the delegate
            var hook_emitter = new HookEmitter(hook_field, method,
                                               (options & HookOptions.Cancellable) != 0,
                                               (options & HookOptions.ReferenceParameters) != 0,
                                               result_variable
                                               );
            var result = hook_emitter.Emit();
            //instructions.MergeInto(method, 0);

            // end of method

            var invoke_method = hook_handler.Resolve().Method("Invoke");

            if (invoke_method.ReturnType.FullName != "System.Void")
            {
                result.Instructions = result.Instructions.Concat(new[]
                {
                    Instruction.Create(OpCodes.Brtrue_S, method.Body.Instructions.First()),
                    Instruction.Create(OpCodes.Br_S, method.Body.Instructions.Last())
                });
            }

            return(result);
        }
예제 #7
0
        /// <summary>
        /// Start the engine at your project startup.
        /// It's could be OwinStartup class or Global.asax or WebApiConfig.cs for web projects
        /// or
        /// Could be Program.cs for Desktop projects
        /// </summary>
        /// <param name="_Options"></param>
        /// <param name="_MainAssembly"></param>
        public static void Start(HookOptions _Options, Assembly _MainAssembly)
        {
            Options = _Options;
            try
            {
                Assembly currentAssembly = _MainAssembly;
                var      findedActions   = currentAssembly.GetTypes()
                                           .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static))
                                           .Where(m =>
                                                  !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any()
                                                  &&
                                                  m.IsDefined(typeof(HookEngineAppStartupMethod), true)
                                                  )
                                           .Select(x =>
                                                   new
                {
                    Type   = x.DeclaringType,
                    Class  = x.DeclaringType.Name,
                    Action = x.Name
                })
                                           .OrderBy(x => x.Class).ThenBy(x => x.Action).ToList();

                foreach (var findedAction in findedActions)
                {
                    findedAction.Type.InvokeMember(findedAction.Action, BindingFlags.InvokeMethod | BindingFlags.Public |
                                                   BindingFlags.Static,
                                                   null,
                                                   null,
                                                   null);
                }
            }
            catch (Exception e)
            {
                if (Options.ThrowErrors)
                {
                    throw e;
                }
            }
        }
        /// <summary>
        /// Generates a hook that is called after native code
        /// </summary>
        /// <param name="method">Method to generate the hook in</param>
        /// <param name="options">Configurable hook options</param>
        /// <returns>A <see cref="MergableMethod"/> instance</returns>
        public static MergableMethod GenerateHook
        (
            this IEnumerable <ParameterDefinition> parameters,

            string name,
            TypeDefinition parentType,
            TypeDefinition returnType, HookOptions flags, ModuleDefinition module,

            HookOptions options = HookOptions.Post,
            VariableDefinition result_variable = null
        )
        {
            // emit call at each ret instruction

            // add or get the types where we are storing out auto generated hooks & their delegates
            var hooks_type           = parentType.GetHooksType();
            var hooks_delegates_type = parentType.GetHooksDelegateType();

            // generate the hook handler delegate
            var hook_delegate_emitter = new HookDelegateEmitter("On" + name, parameters, returnType, options, module);
            var hook_handler          = hook_delegate_emitter.Emit();

            hooks_delegates_type.NestedTypes.Add(hook_handler);

            // generate the api hook external modules can attach to
            var hook_field = new FieldDefinition(name, FieldAttributes.Public | FieldAttributes.Static, hook_handler);

            hooks_type.Fields.Add(hook_field);

            // generate the call to the delegate
            var hook_emitter = new HookEmitter(hook_field, parameters, false, false, result_variable);
            var result       = hook_emitter.Emit();


            // end of method

            return(result);
        }
        /// <summary>
        /// Generates a hook that is called after native code
        /// </summary>
        /// <param name="method">Method to generate the hook in</param>
        /// <param name="options">Configurable hook options</param>
        /// <returns>A <see cref="MergableMethod"/> instance</returns>
        public static MergableMethod GenerateEndHook
        (
            this MethodDefinition method,

            HookOptions options = HookOptions.Default,
            VariableDefinition result_variable = null
        )
        {
            // emit call at each ret instruction

            // add or get the types where we are storing out auto generated hooks & their delegates
            var hooks_type           = method.DeclaringType.GetHooksType();
            var hooks_delegates_type = method.DeclaringType.GetHooksDelegateType();

            // generate the hook handler delegate
            var hook_delegate_emitter = new HookDelegateEmitter("OnPost", method, options & ~(
                                                                    HookOptions.ReferenceParameters |
                                                                    HookOptions.Cancellable
                                                                    ));
            var hook_handler = hook_delegate_emitter.Emit();

            hooks_delegates_type.NestedTypes.Add(hook_handler);

            // generate the api hook external modules can attach to
            var hook_field = new FieldDefinition("Post" + method.GetSafeName(), FieldAttributes.Public | FieldAttributes.Static, hook_handler);

            hooks_type.Fields.Add(hook_field);

            // generate the call to the delegate
            var hook_emitter = new HookEmitter(hook_field, method, false, false, result_variable);
            var result       = hook_emitter.Emit();

            // end of method

            return(result);
        }
예제 #10
0
        public WinEventHook(Process process, int?threadId, WinEvent minEvent, WinEvent maxEvent, HookOptions options = HookOptions.None, SynchronizationContext syncCtx = null)
        {
            if (!(syncCtx != null || !options.HasFlag(HookOptions.AsyncCallbacks)))
            {
                throw new ArgumentException("Contract assertion not met: syncCtx != null || !options.HasFlag(HookOptions.AsyncCallbacks)", nameof(syncCtx));
            }

            this.thCreated       = Thread.CurrentThread;
            this.Observers       = new List <IObserver <WinEventEventArgs> >();
            this.Process         = process;
            this.ThreadID        = threadId;
            this.MinEvent        = minEvent;
            this.MaxEvent        = maxEvent;
            this.SyncCtx         = syncCtx;
            this.CallbackContext = options.HasFlag(HookOptions.AsyncCallbacks)
                ? new Action <Action>(CallbackAsync) : new Action <Action>(CallbackSyncIfNeeded);

            // EventProcHandle is the callback to CLR code, and must be valid.  We take a new GCRoot
            // and only release once a successfull Unhook occurs
            this.EventProcHandle       = new NativeMethods.WinEventProc(Hook_EventProc);
            this.EventProcHandleGCRoot = GCHandle.Alloc(EventProcHandle);

            if (!options.HasFlag(HookOptions.StartDisabled))
            {
                StartInternal();
            }
        }
예제 #11
0
 public WinEventHook(Process process, int?threadId, WinEvent minEvent, WinEvent maxEvent, HookOptions options)
     : this(process, threadId, minEvent, maxEvent, options, null)
 {
 }
        /// <summary>
        /// Adds configurable hooks into each method of the query
        /// </summary>
        /// <param name="results">Methods to be hooked</param>
        /// <param name="options">Hook options</param>
        /// <returns>The existing <see cref="QueryResult"/> instance</returns>
        public static QueryResult Hook(this QueryResult results, HookOptions options = HookOptions.Default)
        {
            var context = results
                          .Select(x => x.Instance as MethodDefinition)
                          .Where(
                x => x != null &&
                x.HasBody &&
                !x.DeclaringType.IsInterface &&
                x.GenericParameters.Count == 0
                );

            foreach (var method in context)
            {
                var new_method = method.Clone();

                // rename method to be suffixed with Direct
                method.Name += "Direct";
                method.Name  = method.GetSafeName();
                method.DeclaringType.Methods.Add(new_method);
                method.Attributes &= ~MethodAttributes.Virtual;
                method.Attributes &= ~MethodAttributes.SpecialName;
                method.Attributes &= ~MethodAttributes.RTSpecialName;
                method.Overrides.Clear();
                method.CustomAttributes.Clear();
                method.SecurityDeclarations.Clear();
                method.ReplaceWith(new_method);

                var processor  = new_method.Body.GetILProcessor();
                var ins_return = Instruction.Create(OpCodes.Ret);
                processor.Append(ins_return);

                var call_emitter = new CallEmitter(method, new_method.Body.Instructions.First());

                var call = call_emitter.Emit();

                VariableDefinition return_variable = null;
                var nop = call.Instructions
                          .SingleOrDefault(x => x.OpCode == OpCodes.Pop);               // expect one here as the CallEmitter should only handle one. if it changes this needs to change
                if (nop != null)
                {
                    return_variable = new VariableDefinition(method.ReturnType);
                    new_method.Body.Variables.Add(return_variable);
                    nop.Operand = return_variable;
                    nop.OpCode  = OpCodes.Stloc_S;
                }
                call.MergeInto(new_method, 0);

                if ((options & HookOptions.Pre) != 0)
                {
                    var hook = new_method.GenerateBeginHook(options, return_variable);

                    if ((options & HookOptions.Cancellable) != 0 &&
                        (options & HookOptions.AlterResult) == 0 &&
                        method.ReturnType.FullName != "System.Void")
                    {
                        // TODO: this functionality will be desired - idea: just generate the "default(T)"
                        // what to do if you get here: add HookFlags.AlterResult to your flags or don't try cancelling
                        throw new NotSupportedException("Attempt to cancel a non-void method without allowing the callback to alter the result.");
                    }

                    hook.MergeInto(new_method, 0);
                }

                if ((options & HookOptions.Post) != 0)
                {
                    var hook = new_method.GenerateEndHook(options, return_variable);

                    //var last_ret = new_method.Body.Instructions.Last(x => x.OpCode == OpCodes.Ret);
                    //last_ret.ReplaceTransfer(hook.Instructions.First(), new_method);

                    hook.MergeInto(new_method, call.Instructions.Last().Next);
                }

                if (return_variable != null)
                {
                    var ins_return_variable = Instruction.Create(OpCodes.Ldloc, return_variable);
                    processor.InsertBefore(ins_return, ins_return_variable);
                    ins_return.ReplaceTransfer(ins_return_variable, new_method);
                }

                // for all classes (not structs) we need to move the base type constructor over to the new
                // method before any of our hook code is executed.
                if (new_method.IsConstructor && new_method.HasThis && !new_method.DeclaringType.IsValueType)
                {
                    var instructions = method.Body.Instructions.TakeWhile(
                        x => x.Previous == null ||
                        x.Previous.OpCode != OpCodes.Call ||
                        (x.Previous.Operand as MethodReference).FullName != method.DeclaringType.BaseType.Resolve().Method(".ctor").FullName
                        );

                    foreach (var instruction in instructions.Reverse())
                    {
                        method.Body.Instructions.Remove(instruction);
                        new_method.Body.Instructions.Insert(0, instruction);
                    }
                }
            }

            return(results);
        }