Windows 平台下 Api的拦截(hook)

本文介绍了一种API拦截技术,通过修改系统代码实现对特定API的拦截和替换,详细讲解了使用jmp指令进行拦截的过程,并提供了VC6环境下的完整源代码。

   Api拦截并不是一种新技术,在许多的商业软件中也使用了这一技术。主要使用的方法有
两种:一种就是《windows核心编程》中介绍的修改PE文件的输入节,这种方法很安全,不过
有些麻烦,还有个缺点就是有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到
的情况。第二种方法就是古老而又实用的jmp XXXX技术。

    先讲一讲我们使用jmp的思路:
    1. 先找到系统代码在进程空间中的起始位置
    2. 然后我们写jmp "我们的代码" 的机器指令到系统代码的超始位置
    3. 这样系统在调用api之前,就会先执行我们的代码

    下来我们给出一些关键代码来具体说明一下:
    1. 得到系统代码的位置,保存原始的系统机器码:
        BYTE SysCode[5]; //机器指令占1B,32位指针(DWORD)占4B
        HMODULE hMod = GetModuleHandle( m_MoudleName );
        m_SysApi = (void*)GetProcAddress(hMod , m_SysApiName);
        memcpy( SysCode, m_SysApi, sizeof(SysCode) );
        
    2. 构造我们的jmp机器指令:
        BYTE JmpCode[5];
        /* 计算jmp指令的偏移地址: offset = userfun-sysfun-5 */
        JmpCode[0] = 0xE9; //jmp的机器指令
        *(DWORD*)(JmpCode+1) = (DWORD)((LONG)m_UserApi-(LONG)m_SysApi-5); //这儿是DWORD
        
    3. 写跳转指令
        bRet = WriteProcessMemory( GetCurrentProcess(), 
                (LPVOID)m_SysApi, (LPVOID)JmpCode, m_CodeLength ,NULL);
                
    4. ok,到这儿,我们就完成了拦截过程,有点要注意的是我们拦截函数的写法:
        首先,拦截函数的定义要和目标函数相同,最起码在数据类型上要兼容,主要是指参数的
        个数和参数类型的长度要一致!
        
        下面是个例子:
        int FAR PASCAL hook_recv(SOCKET s,char FAR * buf,int len,int flags)
        {
                int ret=0;
                if (ah3.isHooked)
                {
                        ah3.HookOff();  //先写回系统的代码,不然就是死循环!!!
                        ret = recv(s,buf,len,flags);
                        ah3.SetJumpCode();
        
                        WriteBufferToFile("c://hook_recv",buf,len);
                        return ret;
                }
                
                return 0;
        }

    5. 一点小问题:在win2k里面,系统在装载DLL时是同进程在同一个空间,所以这时的拦截
       只是拦截目标进程中的api,不影响系统的api;但在win9x中拦截的却是整个系统的api。
       
    6. ok,我们把我们的拦截函数写成一个DLL,再按照《远程线程技术(一)》中的方法,写一个
       挂接程序,把我们的DLL挂接到目标进程中去,就可以了!!

 =============================================================================

    下面给出完整的源代码(调试环境:VC6+W2k):

       //////////////////////////////////////////////////////////////////////
        // ApiHook.h: interface for the CApiHook class.
        // by ssssss24cn@hotmail.com    2003.07.24
        //////////////////////////////////////////////////////////////////////
        
        #if !defined(AFX_APIHOOK_H__F7B7A124_D1EA_407F_B199_8592E86D5FEC__INCLUDED_)
        #define AFX_APIHOOK_H__F7B7A124_D1EA_407F_B199_8592E86D5FEC__INCLUDED_
        
        #if _MSC_VER > 1000
        #pragma once
        #endif // _MSC_VER > 1000
        
        #include <windows.h>
        
        class CApiHook  
        {
        public:
                BOOL HookOff();
                BOOL HookOn(const char *szModName, const char *szFunName, void* userfun);
                BOOL SetJumpCode();
                CApiHook();
                virtual ~CApiHook();
        public:
                BOOL isHooked;
        
        private:
                BOOL SaveSysCode();
                void InitJmpCode();
        private:
                int m_CodeLength;
                void *m_UserApi;        //指向用户函数的指针
                void *m_SysApi;         //指向系统函数的指针
        
                char m_MoudleName[30];  //目标模块
                char m_SysApiName[80];  //目标函数
        
                BYTE SysCode[5];        //存放原来的系统机器码
                BYTE JmpCode[5];        //存放跳转指令的机器码
        };
        
        #endif // !defined(AFX_APIHOOK_H__F7B7A124_D1EA_407F_B199_8592E86D5FEC__INCLUDED_)
        

        //////////////////////////////////////////////////////////////////////
        // ApiHook.cpp: implementation of the CApiHook class.
        // by ssssss24cn@hotmail.com    2003.07.24
        //////////////////////////////////////////////////////////////////////
        
        #include "stdafx.h"
        #include "ApiHook.h"
        
        #ifdef _DEBUG
        #undef THIS_FILE
        static char THIS_FILE[]=__FILE__;
        #define new DEBUG_NEW
        #endif
        
        //////////////////////////////////////////////////////////////////////
        // Construction/Destruction
        //////////////////////////////////////////////////////////////////////
        
        CApiHook::CApiHook()
        {
                isHooked = FALSE;
        
                JmpCode[0]=0x00;
                SysCode[0]=0x00;
                m_CodeLength=sizeof(BYTE)*5;
                
                m_SysApi=NULL;
                m_UserApi=NULL;
        }
        
        CApiHook::~CApiHook()
        {
        
        }
        
        BOOL CApiHook::HookOn(const char *szModName, const char *szFunName, void *userfun)
        {
                if (!szModName) return FALSE;
                if (!szFunName) return FALSE;
        
                /////////////////
                memcpy(m_MoudleName,szModName,strlen(szModName)+1);
                memcpy(m_SysApiName,szFunName,strlen(szFunName)+1);
                m_UserApi = userfun;
                /////////////////
        
                //保存系统原始机器码
                if (!SaveSysCode())             return FALSE;
        
                //写跳转指令机器码
                InitJmpCode();
                
                //写目标代码
                return SetJumpCode();
        }
        
        BOOL CApiHook::HookOff()
        {       
                BOOL bRet;
                bRet = WriteProcessMemory(GetCurrentProcess(), m_SysApi, 
                        (LPVOID)SysCode, m_CodeLength,NULL);
                if(!bRet)
                {
                        return FALSE;
                }
        
                isHooked = FALSE;
                return TRUE;
        }
        
        void CApiHook::InitJmpCode()
        {
                /* 计算jmp指令的偏移地址: offset = userfun-sysfun-5 */
                JmpCode[0] = 0xE9; //jmp的机器指令
                *(DWORD*)(JmpCode+1) = (DWORD)((LONG)m_UserApi-(LONG)m_SysApi-5);
        }
        
        BOOL CApiHook::SaveSysCode()
        {
                HMODULE hMod = GetModuleHandle( m_MoudleName );
                if ( hMod == NULL )
                {
                        return FALSE;
                }
        
                m_SysApi = (void*)GetProcAddress(hMod , m_SysApiName);
                if (m_SysApi == NULL )
                {
                        return FALSE;
                }
        
                //save  
                memcpy( SysCode, m_SysApi, sizeof(SysCode) );
                
                return TRUE;
        }
        
        
        BOOL CApiHook::SetJumpCode()
        {
                //写目标地址
                BOOL bRet;
                bRet = WriteProcessMemory( GetCurrentProcess(),
                        (LPVOID)m_SysApi, (LPVOID)JmpCode, m_CodeLength ,NULL);
                if(!bRet)
                {
                        return FALSE;
                }
        
                isHooked = TRUE;
                return TRUE;
        }
        
        /////////////////////////////////////////////////////////////
        // dll.cpp : Defines the entry point for the DLL application.
        // by ssssss24cn@hotmail.com    2003.07.24
        /////////////////////////////////////////////////////////////
        #include "stdafx.h"
        #include <windows.h>
        #include <ImageHlp.h>
        #include <winsock2.h>
        #include "ApiHook.h"
        /*========================================================*/
        #pragma comment(lib, "ImageHlp")
        #pragma comment(lib, "ws2_32")
        /*========================================================*/
        int FAR PASCAL hook_send(SOCKET s,const char FAR * buf,int len,int flags);
        int FAR PASCAL hook_recv(SOCKET s,char FAR * buf,int len,int flags);
        /*========================================================*/
        void WINAPI HookOn();
        int WINAPI WriteBufferToFile(const char *fn, const char *bp, const unsigned long blen);
        /*========================================================*/
        HANDLE hDllSelf=NULL;
        CApiHook ah1,ah2,ah3,ah4;
        /*========================================================*/
        BOOL APIENTRY DllMain( HANDLE hModule, 
                                                  DWORD  ul_reason_for_call, 
                                                  LPVOID lpReserved
                                                  )
        {
                if (ul_reason_for_call==DLL_PROCESS_ATTACH)
                {
                        hDllSelf = hModule;
                        HookOn();
                }
                
            return TRUE;
        }
        
        //------------------------------------------------------------------//
        void WINAPI HookOn()
        {
                PROC new_fun=NULL;
        
                //ws2_32.dll
                new_fun = (PROC)hook_send;
                if (!ah1.HookOn("ws2_32.dll","send",new_fun))
                        MessageBox(NULL,"hook ws2_32.dll failed.","提示",16);
        
                //wsock32.dll
                if (!ah2.HookOn("wsock32.dll","send",new_fun))
                        MessageBox(NULL,"hook wsock32.dll failed.","提示",16);
        
                ////////////
        
                //ws2_32.dll
                new_fun = (PROC)hook_recv;
                if (!ah3.HookOn("ws2_32.dll","recv",new_fun))
                        MessageBox(NULL,"hook ws2_32.dll failed.","提示",16);
        
                //wsock32.dll
                if (!ah4.HookOn("wsock32.dll","recv",new_fun))
                        MessageBox(NULL,"hook wsock32.dll failed.","提示",16);
        
        }
        //------------------------------------------------------------------//
        int FAR PASCAL hook_send(SOCKET s,const char FAR * buf,int len,int flags)
        {
                int ret=0;
                if (ah1.isHooked)
                {
                        WriteBufferToFile("c://hook_send",buf,len);
        
                        ah1.HookOff();
                        ret = send(s,buf,len,flags);
                        ah1.SetJumpCode();
        
                        return ret;     
                }
        
                if (ah2.isHooked)
                {
                        WriteBufferToFile("c://hook_send",buf,len);
        
                        ah2.HookOff();
                        ret = send(s,buf,len,flags);
                        ah2.SetJumpCode();
        
                        return ret;     
                }
        
                return 0;
        }
        //------------------------------------------------------------------//
        int FAR PASCAL hook_recv(SOCKET s,char FAR * buf,int len,int flags)
        {
                int ret=0;
                if (ah3.isHooked)
                {
                        ah3.HookOff();
                        ret = recv(s,buf,len,flags);
                        ah3.SetJumpCode();
        
                        WriteBufferToFile("c://hook_recv",buf,len);
                        return ret;
                }
        
                if (ah4.isHooked)
                {
                        ah4.HookOff();
                        ret = recv(s,buf,len,flags);
                        ah4.SetJumpCode();
        
                        WriteBufferToFile("c://hook_recv",buf,len);
                        return ret;
                }
        
                return 0;
        }
        //------------------------------------------------------------------//
        int WINAPI WriteBufferToFile(const char *fn, const char *bp, const unsigned long blen)
        {
                FILE *fp;
                int wlen=-1;
                
                fp = fopen(fn,"wb+");
                if (fp)
                {
                        fseek(fp,0L,SEEK_END);
                        wlen = fwrite(bp,sizeof(char),blen,fp);
                        fclose(fp);
                }
                
                return wlen;
        }
        //------------------------------------------------------------------//

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值