前言

  在说C#
Hook在此之前,大家先来说说什么样是Hook本领。相信我们都接触过外挂,不管是订正游戏顾客端的可不,盗取密码的也罢,它们都以怎么着落到实处的吧?

  实际上,Windows平台是基于事件驱动机制的,整个种类都以经过新闻的传递来兑现的。当进度有响适那个时候候(满含响应鼠标和键盘事件卡塔尔(قطر‎,则Windows会向应用程序发送一个音信给应用程序的消息队列,应用程序从而从音讯队列中抽出消息并发送给相应窗口进行拍卖。

  而Hook则是Windows新闻处理体制的贰个平台,应用程序能够在上边安装子程以监视钦赐窗口的某种消息,并且所监视的窗口能够是任何进度所创建的。当音讯达到后,在对象窗口管理函数早先管理它。钩子机制允许应用程序截获管理window音讯或特定事件。

  所以Hook就足以兑未来键盘/鼠标响应后,窗口管理音讯在此以前,就对此音信进行处理,比方监听键盘输入,鼠标点击坐标等等。某个盗号木马正是Hook了钦点的进度,进而监听键盘输入了什么样内容,进而偷取账户密码。

C#凯旋门074网址, Hook

  大家知道C#是运维在.NET平台之上,何况是基于CL纳瓦带动态运营的,所以只可以操作封装好的函数,且不恐怕直接操作内部存款和储蓄器数据。並且在C#常用的效劳中,并未有封装Hook相关的类与方法,所以若是用C#落到实处Hook,必需运用调用WindowsAPI的艺术展开贯彻。

澳门凯旋门游戏网址,  WindowsAPI函数归于非托管类型的函数,大家在调用时必须遵照以下几步:

  1、查找包含调用函数的DLL,如User32.dll,Kernel32.dll等。

  2、将该DLL加载到内部存款和储蓄器中,并注解入口

澳门凯旋门注册网址,  3、将所需参数转化为C#存在的品种,如指针对应Intptr,句柄对应int类型等等

  4、调用函数

  我们本篇要求采纳的函数有以下多少个:

  SetWindowsHookEx
    用于安装钩子

  UnhookWindowsHookEx
  用于卸载钩子

  CallNextHookEx      实行下多个钩子

  详细API介绍请参见MSDN官方注明

  接下去在C#  所以Hook就足以兑今后键盘/鼠标响应后。中供给首先注明此API函数:

[DllImport("user32.dll",CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn,IntPtr hInstance, int threadId);

[DllImport("user32.dll",CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);

[DllImport("user32.dll",CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode,IntPtr wParam, IntPtr lParam);

  表明后就可以兑现调用,SetWindowsHookEx(卡塔尔(قطر‎把三个应用程序定义的钩子程安装到钩子链表中,SetWindowsHookEx函数总是在Hook链的开始安装Hook子程。当内定项指标Hook监视的轩然大波产生时,系统就调用与那一个Hook关联的Hook链的上马的Hook子程。每三个Hook链中的Hook子程都调节是还是不是把这几个事件传递到下二个Hook子程。Hook子程传递事件到下二个Hook子程须要调用CallNextHookEx函数。
且钩子使用到位后须要调用UnhookWindowsHookEx进行卸载,不然轻便影响到此外钩子的施行,並且钩子太多会影响指标经过的正常化运维。

  关于实例详细操作过程不再赘言,请参见:
及 

EasyHook

  C#  所以Hook就足以兑今后键盘/鼠标响应后。自个儿调用WindowsAPI实行Hook作用受到一点都不小的范围,而C++则不受此节制,由此就有点精明能干的人想到了小聪明的艺术:使用C++将着力操作封装成库,由C#实行调用,由此诞生了伟大的EasyHook,它不唯有使用方便,而且开源无需付费,还帮助63个人版本。

  接下去我们一起使用C#操作EasyHook来贯彻三个Demo,实现对MessageBox的改写。

  首先大家建构八个WinForm项这段日子后相继,并加上叁个类库ClassLibrary1,再从官方网址

   澳门凯旋门注册网址 1

  此中WinForm程序用于获取指标经过,并对指标经过张开注入,相关手续如下:

  1、依照进度ID获取有关进度,并认清是否为六十几人;

  所以Hook就足以兑今后键盘/鼠标响应后。  2、将所需DLL注册到GAC(全局程序集缓存),注册到GAC的指标是索要在对象经过中调用EasyHook及大家所编写的DLL;

private bool RegGACAssembly()
 {
     var dllName = "EasyHook.dll";
     var dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dllName);
     if (!RuntimeEnvironment.FromGlobalAccessCache(Assembly.LoadFrom(dllPath)))
     {
         new System.EnterpriseServices.Internal.Publish().GacInstall(dllPath);
         Thread.Sleep(100);
     }
   dllName = "ClassLibrary1.dll";
     dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dllName);
     new System.EnterpriseServices.Internal.Publish().GacRemove(dllPath);
     if (!RuntimeEnvironment.FromGlobalAccessCache(Assembly.LoadFrom(dllPath)))
     {
           new System.EnterpriseServices.Internal.Publish().GacInstall(dllPath);
           Thread.Sleep(100);
     }
     return true;
  } 

  此处须要专心,要将本身编排的类库DLL参预GAC,需求对DLL实行强具名操作,操作方法请参照他事他说加以侦查:

  3、注入指标经过,此处需使用EasyHook的RemoteHooking.Inject(卡塔尔国方法开展注入:

private static bool InstallHookInternal(int processId)
{
  try
  {
     var parameter = new HookParameter
     {
         Msg = "已经成功注入目标进程",
         HostProcessId = RemoteHooking.GetCurrentProcessId()
      };
    RemoteHooking.Inject(
                    processId,
                    InjectionOptions.Default,
                    typeof(HookParameter).Assembly.Location,
                    typeof(HookParameter).Assembly.Location,
                    string.Empty,
                    parameter
                );
            }
            catch (Exception ex)
            {
                Debug.Print(ex.ToString());
                return false;
            }
            return true;
}

  HookParameter类为定义在ClassLibrary1中的一个类,包含消息与进程ID:

 [Serializable]
    public class HookParameter
    {
        public string Msg { get; set; }
        public int HostProcessId { get; set; }
    }

  到这一步大家就到位了对主窗体代码的编写,未来大家最初编写制定注入DLL的方法:

  1、先引入MessageBox相关的WindowsAPI:

#region MessageBoxW

        [DllImport("user32.dll", EntryPoint = "MessageBoxW", CharSet = CharSet.Unicode)]
        public static extern IntPtr MessageBoxW(int hWnd, string text, string caption, uint type);

        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
        delegate IntPtr DMessageBoxW(int hWnd, string text, string caption, uint type);

        static IntPtr MessageBoxW_Hooked(int hWnd, string text, string caption, uint type)
        {
            return MessageBoxW(hWnd, "已注入-" + text, "已注入-" + caption, type);
        }

        #endregion

        #region MessageBoxA

        [DllImport("user32.dll", EntryPoint = "MessageBoxA", CharSet = CharSet.Ansi)]
        public static extern IntPtr MessageBoxA(int hWnd, string text, string caption, uint type);

        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        delegate IntPtr DMessageBoxA(int hWnd, string text, string caption, uint type);

        static IntPtr MessageBoxA_Hooked(int hWnd, string text, string caption, uint type)
        {
            return MessageBoxA(hWnd, "已注入-" + text, "已注入-" + caption, type);
        }

        #endregion

  当中Message博克斯A与MessageBoxW是微软用于区分差异操作系统中的编码类型,早期的Windows并不归属真正的叁十四人操作系统,实践的API函数归属ANSI类型,而从Windows二〇〇〇方始,归属Unicode类型,Windows在实操中,调用的MessageBox会自动依据平台区分使用前者依旧前面一个,大家在那间就需求把二者都满含当中。

  而DMessageBoxA与DMessageBoxW归于IntPtr类型的委托,用于大家在Hook函数之后传出大家供给改善的艺术,此处我们改换了MessageBox的内容和标题,分别在前缀加上了”已注入-“的标识。

  2、达成定义之后大家就供给对函数进行Hook,此处使用LocalHook.GetProcAddress(“user32.dll”,
“MessageBoxW”卡塔尔函数,通过点名的DLL与函数名,获取函数在骨子里内存中的地址,获取到未来,传入LocalHook.Create(卡塔尔国方法,用于创立本地钩子:

public void Run(
            RemoteHooking.IContext context,
            string channelName
            , HookParameter parameter
            )
        {
            try
            {
                MessageBoxWHook = LocalHook.Create(
                    LocalHook.GetProcAddress("user32.dll", "MessageBoxW"),
                    new DMessageBoxW(MessageBoxW_Hooked),
                    this);
                MessageBoxWHook.ThreadACL.SetExclusiveACL(new int[1]);

                MessageBoxAHook = LocalHook.Create(
                    LocalHook.GetProcAddress("user32.dll", "MessageBoxA"),
                    new DMessageBoxW(MessageBoxA_Hooked),
                    this);
                MessageBoxAHook.ThreadACL.SetExclusiveACL(new int[1]);     
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }

            try
            {
                while (true)
                {
                    Thread.Sleep(10);
                }
            }
            catch
            {

            }
        }

  当中MessageBoxWHook与MessageBoxAHook均为LocalHook类型的变量,MessageBoxAHook.ThreadACL.SetExclusiveACL(new
int[1]卡塔尔(英语:State of Qatar); 那句代码用于将地点钩子参预当前线程中施行。

  运营之后大家来查阅Hook的成效,先开荒二个测量试验窗体,弹出MessageBox,那时候MessageBox未有标题,且内容是常规的:

    澳门凯旋门注册网址 2

 

  接着大家对指标经过张开注入,获取进度ID后点击注入,提醒已经打响注入指标经过:

 

    澳门凯旋门注册网址 3

 

  那时候点击指标经过MessageBox,能够窥见早就Hook成功,并改变了内容和标题:

 

    澳门凯旋门注册网址 4

 

  至此,C#调用EasyHook对指标经过Hook已经落实。

后记

  从此番推行中大家能够心获得,C#对程序开展Hook是一心可行的,固然不可能直接操作内存和地方,可是我们得以由此操作WindowsAPI与应用EasyHook的点子产生,非常是后人,大大减少了代码数量与利用难度。

  但是EasyHook这段日子中文资料少之又少,作者在利用的历程中也凌驾了比极大困难,Hook别的函数的法子也未能完全实现,希望能够博采众长,与我们一块儿考虑调换!

  自个儿刚钻探Hook时间不久,文中难免现身漏洞,恳请各位研究指正。

    源代码已经上传至百度网盘:链接:
密码: dv9b

 

 

 

相关文章