CPP | ALLHOOK proj

2017年2月12日 0 条评论 298 次阅读 0 人点赞

 

前言

AllHook项目是一个windows Hook学习项目,旨在熟悉各类Hook功能的实现及测试工作。

 

钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

简单的说,就是在程序执行特定事件的过程中“中断”,执行自己的子程以完成审计监控、修改等目的。特定事件包括指定的windows消息、指定API函数等等。


项目

实现windows消息钩子、APIHook等(暂实现这么多,后续继续更新如comHook)。

鼠标键盘钩子

鼠标键盘钩子属于消息钩子,消息钩子作为Hook的一个分类,是通过在dll中使用SetWindowsHookEx函数对指定的消息事件(如鼠标键盘消息事件)进行挂钩,系统会将其加载入使用user32的进程中,在捕获到对应类型消息事件后执行预先设定好的程序段。

实现

在界面进程启动时,加载KeyBoardAndMouse.dll模块,在“加载键盘钩子”按钮被按下后,通过KeyBoardAndMouse模块的导出函数sethook完成hook设置,在捕获到对应键盘或鼠标动作后KeyBoardAndMouse.dll模块将具体内容通过SendMessage发回界面进程显示(当然也可以直接阻断)。

下面是sethook设置的鼠标键盘被hook的回调函数:

CPP | ALLHOOK proj

实现效果如下图:

CPP | ALLHOOK proj

在记事本(或其他输入界面)写的东西会被我的界面进程显示出来。试想,如果界面进程隐藏,所有键盘输入被写入文档并通过邮件外发,那计算机上的输入信息将被他人得知。

CPP | ALLHOOK proj

鼠标点击事件被捕获后,所有点击失效,需要使用键盘选定释放钩子按钮完成释放。

说明

鼠标键盘钩子只是消息钩子的两种,还有其他的消息钩子会在后续添加。

APIHook

不同于消息钩子,APIHook是针对windows API函数的“中断”。

我们可以通过api hook,改变一个系统api的原有功能。基本的方法就是通过hook“接触”到需要修改的api函数入口点,改变它的地址指向新的自定义的函数。

APIHook就是通过修改指定API函数的函数地址,使得在执行该API函数时jump到我们自定义的函数,以实现对原API函数功能修改或丰富等功能。

实现

实现APIHOOK主要有两个重要环节,一是如何把代码注入到目标地址空间,二是如何让自己的代码被调用。

第一个环节,我们的代码段要进入目标进程,我使用远线程注入的办法,在指定进程中加载我们自己的模块。

/*****************************  *函数名:DllInject  *功  能:将dll注入到指定的进程中  *入  参:const char*ProcessName,进程名          const char *pDllName,dll名  *出  参:无  *返回值:成功返回0,失败返回-1  *****************************/   int DllInject(const wchar_t *pProcessName, const wchar_t *pDllName)   {     int iRet = 0;     DWORD dwProcessID=0;       HANDLE hProcessHandle=NULL;       LPVOID pAddrStart=NULL;       HANDLE hThreadHandle=NULL;      BOOL bSuccess = FALSE;     DWORD dwSize = 0;     //根据进程名获取进程ID       dwProcessID = GetProcessIdByName(pProcessName);       if(dwProcessID == -1)       {           OutputDebugString(stringformat(L"%s未运行", pProcessName).c_str());         iRet = -1;         goto _DllInject_End;     }     OutputDebugString(stringformat(L"%s进程ID为%d", pProcessName,dwProcessID).c_str());      //根据进程ID获取进程句柄       hProcessHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessID);       if(hProcessHandle == NULL)       {           OutputDebugString(L"OpenProcess获取进程句柄失败n");           iRet = -1;         goto _DllInject_End;     }  #ifdef UNICODE     dwSize = (lstrlen(pDllName) + 1) * 2; //宽字符占用2个字节 #else     dwSize = lstrlen(pDllName) + 1; #endif      //用VirtualAllocEx在进程内申请内存       pAddrStart = VirtualAllocEx(hProcessHandle,NULL,dwSize,MEM_COMMIT,PAGE_READWRITE);       if (pAddrStart == NULL)       {         OutputDebugString(L"进程内存申请失败!n");           iRet = -1;         goto _DllInject_End;      }      //将需要运行的dll名写入申请的内存地址       bSuccess = WriteProcessMemory(hProcessHandle,pAddrStart,pDllName,dwSize,0);       if(!bSuccess)       {           OutputDebugString(L"WriteProcessMemory失败!n");           iRet = -1;         goto _DllInject_End;     }       //printf("memory of pAddrStart is:%s",pAddrStart);        //注入,即"LoadLibraryW"函数加载dll       hThreadHandle = CreateRemoteThread(hProcessHandle,                                          0,                                          0,                                          (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"LoadLibraryW"),//函数LoadLibraryW的地址                                          pAddrStart,//dll                                        0,                                          0);       if(hThreadHandle == NULL)       {         OutputDebugString(stringformat(L"在进程%s中注入%s失败 Getlasterror:%d",pProcessName,pDllName,GetLastError()).c_str());         iRet = -1;         goto _DllInject_End;     }       WaitForSingleObject(hThreadHandle,INFINITE);       //到这里已经完成dll的加载即注入了,通过dll函数执行我们要完成的任务     _DllInject_End:      //释放      if (pAddrStart != NULL)     {         VirtualFreeEx(hProcessHandle,pAddrStart,0,MEM_RELEASE);         pAddrStart = NULL;     }     if (hThreadHandle != NULL)     {          CloseHandle(hThreadHandle);     }    if (hProcessHandle != NULL)    {        CloseHandle(hProcessHandle);      }      return iRet;   }

第二个环节,要让我们的代码先一步被程序调用,需要在被hook的API函数的函数地址前加入jump指令,这部分我使用微软提供的detours.dll来实现,

Detours是微软开发的一个函数库,可用于捕获系统API。

但微软仅仅提供了免费的x86的detours,x64的需要收费使用,我在实现这部分时,x64使用的是开源的minhook.dll,在github上搜索minhook可以看到源码。

在实现上述逻辑后,我尝试写了个对messagebox的函数hook。

CPP | ALLHOOK proj

实现效果如下:

没有挂钩的进程和按钮弹窗:

CPP | ALLHOOK proj

挂钩以后的弹窗如下:

CPP | ALLHOOK proj

这样,这个框架就搭起来了,后续需要hook的其他API函数直接仿照messagebox实现即可。比如hook相关时间函数破解收费软件试用时间限制、hook网络编程中的connect等函数,实现对网络通信的重定向等等。

说明

暂无。

 

项目在github上开源,搜索AllHookProj可得。


 

        非经过本人同意,严禁转载。

        如有问题,请关注公众号留言,我看到会及时回复的。

CPP | ALLHOOK proj

 

admin

这个人太懒什么东西都没留下

文章评论(0)