利用hook截获进程的API调用

原创 2003年04月01日 09:03:00

截获API是个很有用的东西,比如你想分析一下别人的程序是怎样工作的。这里我介绍一下一种我自己试验通过的方法。
首先,我们必须设法把自己的代码放到目标程序的进程空间里去。Windows Hook可以帮我们实现这一点。SetWindowsHookEx的声明如下:
HHOOK SetWindowsHookEx(
  int idHook,        // hook type
  HOOKPROC lpfn,     // hook procedure
  HINSTANCE hMod,    // handle to application instance
  DWORD dwThreadId   // thread identifier
);
具体的参数含义可以翻阅msdn,没有msdn可谓寸步难行。
这里Hook本身的功能并不重要,我们使用它的目的仅仅只是为了能够让Windows把我们的代码植入别的进程里去。hook Type我们任选一种即可,只要保证是目标程序肯定会调用到就行,这里我用的是WH_CALLWNDPROC。lpfn和hMod分别指向我们的钩子代码及其所在的dll,dwThreadId设为0,表示对所有系统内的线程都挂上这样一个hook,这样我们才能把代码放到别的进程里去。

之后,我们的代码就已经进入了系统内的所有进程空间了。必须注意的是,我们只需要截获我们所关心的目标程序的调用,因此还必须区分一下进程号。我们自己的钩子函数中,第一次运行将进行最重要的API重定向的工作。也就是通过将所需要截获的API的开头几个字节改为一个跳转指令,使其跳转到我们的API中来。这是最关键的部分。这里我想截三个调用,ws2_32.dll中的send和recv、user32.dll中的GetMessageA。

DWORD dwCurrentPID = 0;
HHOOK hOldHook = NULL;
DWORD pSend = 0;
DWORD pRecv = 0;
GETMESSAGE pGetMessage = NULL;

BYTE btNewBytes[8] = { 0x0B8, 0x0, 0x0, 0x40, 0x0, 0x0FF, 0x0E0, 0 };
DWORD dwOldBytes[3][2];

HANDLE hDebug = INVALID_HANDLE_VALUE;

LRESULT CALLBACK CallWndProc( int nCode, WPARAM wParam, LPARAM lParam )
{
 DWORD dwSize;
 DWORD dwPIDWatched;
 HMODULE hLib;

    if( dwCurrentPID == 0 )
    {
        dwCurrentPID = GetCurrentProcessId();
        HWND hwndMainHook;
        hwndMainHook = ::FindWindow( 0, "MainHook" );
        dwPIDWatched = ::SendMessage( hwndMainHook, (WM_USER+100), 0, 0 );
        hOldHook = (HHOOK)::SendMessage( hwndMainHook, (WM_USER+101), 0, 0 );

        if( dwCurrentPID == dwPIDWatched )
        {
            hLib = LoadLibrary( "ws2_32.dll" );
            pSend = (DWORD)GetProcAddress( hLib, "send" );
            pRecv = (DWORD)GetProcAddress( hLib, "recv" );

            ::ReadProcessMemory( INVALID_HANDLE_VALUE, (void *)pSend, (void *)dwOldBytes[0], sizeof(DWORD)*2, &dwSize );
            *(DWORD *)( btNewBytes + 1 ) = (DWORD)new_send;
            ::WriteProcessMemory( INVALID_HANDLE_VALUE, (void *)pSend, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );

            ::ReadProcessMemory( INVALID_HANDLE_VALUE, (void *)pRecv, (void *)dwOldBytes[1], sizeof(DWORD)*2, &dwSize );
            *(DWORD *)( btNewBytes + 1 ) = (DWORD)new_recv;
            ::WriteProcessMemory( INVALID_HANDLE_VALUE, (void *)pRecv, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );

            hLib = LoadLibrary( "user32.dll" );
            pGetMessage = (GETMESSAGE)GetProcAddress( hLib, "GetMessageA" );
            ::ReadProcessMemory( INVALID_HANDLE_VALUE, (void *)pGetMessage, (void *)dwOldBytes[2], sizeof(DWORD)*2, &dwSize );
            *(DWORD *)( btNewBytes + 1 ) = (DWORD)new_GetMessage;
            ::WriteProcessMemory( INVALID_HANDLE_VALUE, (void *)pGetMessage, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );

            hDebug = ::CreateFile( "C://Trace.log", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 );
        }
    }

 if( hOldHook != NULL )
 {
  return CallNextHookEx( hOldHook, nCode, wParam, lParam );
 }

 return 0;
}

上面的钩子函数,只有第一次运行时有用,就是把三个函数的首8字节修改一下(实际上只需要7个)。btNewBytes中的指令实际就是
mov  eax, 0x400000
jmp   eax
这里的0x400000就是新的函数的地址,比如new_recv/new_send/new_GetMessage,此时,偷梁换柱已经完成。再看看我们的函数中都干了些什么。以GetMessageA为例:

BOOL _stdcall new_GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax )
{
 DWORD dwSize;
 char szTemp[256];
 BOOL r = false;

 //Watch here before it's executed.
 sprintf( szTemp, "Before GetMessage : HWND 0x%8.8X, msgMin 0x%8.8X, msgMax 0x%8.8x /r/n", hWnd, wMsgFilterMin, wMsgFilterMax );
 ::WriteFile( hDebug, szTemp, strlen(szTemp), &dwSize, 0 );
 //Watch over

 // restore it at first
 ::WriteProcessMemory( INVALID_HANDLE_VALUE, (void *)pGetMessage, (void *)dwOldBytes[2], sizeof(DWORD)*2, &dwSize );

 // execute it
 r = pGetMessage( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax );

 // hook it again
 *(DWORD *)( btNewBytes + 1 ) = (DWORD)new_GetMessage;
 ::WriteProcessMemory( INVALID_HANDLE_VALUE, (void *)pGetMessage, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );

 //Watch here after it's executed
 sprintf( szTemp, "Result of GetMessage is %d./r/n", r );
 ::WriteFile( hDebug, szTemp, strlen( szTemp ), &dwSize, 0 );
 if( r )
 {
  sprintf( szTemp, "Msg : HWND 0x%8.8X, MSG 0x%8.8x, wParam 0x%8.8X, lParam 0x%8.8X/r/nTime 0x%8.8X, X %d, Y %d/r/n",
   lpMsg->hwnd, lpMsg->message,
   lpMsg->wParam, lpMsg->lParam, lpMsg->time,
   lpMsg->pt.x, lpMsg->pt.y );
  ::WriteFile( hDebug, szTemp, strlen( szTemp ), &dwSize, 0 );
 }
 strcpy( szTemp, "/r/n" );
 ::WriteFile( hDebug, szTemp, strlen( szTemp ), &dwSize, 0 ); 

 //Watch over

 return r;
}

先将截获下来的参数,写入到一个log文件中,以便分析。然后恢复原先保留下来的GetMessageA的首8字节,然后执行真正的GetMessageA调用,完毕后再将执行结果也写入log文件,然后将GetMessageA的执行结果返回给调用者。
整个截获的过程就是这样。你可以把其中的写log部分改成你自己想要的操作。这里有个不足的地方是,截获动作是不能够并发进行的,如果目标进程是多线程的,就会有问题。解决办法是,可以在每次new_GetMessage中加入一个CriticalSection的锁和解锁,以使调用变为串行进行,但这个我没有试验过。

代码下载, http://redspider.126.com/assault/APIHook.zip

使用APIHOOK实现进程隐藏

今天翻出一些今年前写的代码。其中一个是09年,我帮一个读研的同学写的一个“无公害恶意”程序。大致要求就是要实现自启动和自我隐藏。我使用的都是些简单的技术,只是实现自我隐藏稍微让我花费了点时间写算法。其...
  • breaksoftware
  • breaksoftware
  • 2011年12月27日 18:57
  • 5099

Windows 平台下 Api的拦截(hook)

   Api拦截并不是一种新技术,在许多的商业软件中也使用了这一技术。主要使用的方法有两种:一种就是《windows核心编程》中介绍的修改PE文件的输入节,这种方法很安全,不过有些麻烦,还有个缺点就是...
  • raul_qu
  • raul_qu
  • 2007年12月18日 06:55
  • 1368

PE文件格式与API HOOK

对于windows低层编程来说,进行API拦截始终是一件让人激动的事,用自己的代码来改变其它程序的行为,还有比这个更有趣吗?而且,在实现API拦截的过程中我们还有机会去熟悉许多在RAD编程环境中很少接...
  • wltg2001
  • wltg2001
  • 2008年04月23日 10:22
  • 4735

API勾取实现进程隐藏

Windows中,任务管理器、Procexp等软件都是通过遍历进程信息结构体链表来获取进程名的,所以我们只要获取进程信息结构体链表然后删除指定进程信息块就能实现进程的隐藏,这种隐藏其实不是真正的隐藏而...
  • qq_20977145
  • qq_20977145
  • 2016年07月26日 18:19
  • 3105

关于HOOK,如何通过钩子截获指定窗口的所有消息 SetWindowsHookEx demo

SetWindowsHookEx   第三个参数为HINSTANCE,通过FindWindow找到指定窗口句柄后如何      得到该进程的HINSTANCE呢? 这个参数应该是你调用SetWind...
  • q610098308
  • q610098308
  • 2017年09月11日 21:11
  • 858

Hook api! 如何拦截系统api, 让它做你想做的事!

正文:   拦截api的技术有很多种,大体分为用户层和内核层的拦截.这里只说说用户层的拦截.而用户层也分为许多种:修改PE文件导入表,直接修改要拦截的api的内存(从开始到最后,使程序跳转到指定的地...
  • lonelyrains
  • lonelyrains
  • 2014年05月05日 20:35
  • 6718

使用hook 拦截消息

钩子(Hook),是Windows消息处理机制的一个平台,用用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的(我始终认为用hook去钩当前自己的进程没多大意义,...
  • zp373860147
  • zp373860147
  • 2012年03月23日 11:07
  • 5452

Windows 7 64位 HookApi例子

转载请注明来源:http://www.cnblogs.com/xuesongshu/   本程序HOOK的API是DispatchMessageA和DispatchMessageW。在HOOK的方法内...
  • caoshiying
  • caoshiying
  • 2016年07月11日 16:20
  • 2273

Android利用ptrace实现Hook API

Hook API的技术由来已久,在操作系统未能提供所需功能的情况下,利用Hook API的手段来实现某种必需的功能也算是一种不得已的办法。 笔者了解Hook API技术最早是在十几年前,当时是...
  • u013234805
  • u013234805
  • 2014年04月30日 15:46
  • 6571

API 通过HOOK OpenProcess() 实现进程防杀

在WINDOWS操作系统下,当我们无法结束或者不知道怎样结束一个程序的时候,或者是懒得去找“退出”按钮的时候,通常会按“CTRL+ALT+DEL”呼出任务管理器,找到想结束的程序,点一下“结束任务”就...
  • jiht594
  • jiht594
  • 2012年04月11日 16:09
  • 5072
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:利用hook截获进程的API调用
举报原因:
原因补充:

(最多只允许输入30个字)