zoukankan      html  css  js  c++  java
  • HOOK API(三)—— HOOK 所有程序的 MessageBox

    HOOK API(三)

    —— HOOK 所有程序的 MessageBox

    原文出处:http://www.cnblogs.com/fanling999/p/4595035.html

    程序源代码:https://github.com/hfl15/windows_kernel_development/tree/master/demo_source_code/HoolAllMessageBox

    0x00 前言

    本实例要实现HOOK MessageBox,包括MessageBoxA和MessageBoxW,其实现细节与HOOK API(二)中介绍的基本类似,唯一不同的是,本实例要实现对所有程序的HOOK MessageBox,即无论系统中哪一个程序调用MessageBox都会被重定向到我们实现的新的API中。

    之前说过,在Windows中,每个进程都有自己的地址空间,进程不能调用别的进程中的函数。这里涉及到一个关键,如何让我们实现的新的API调用地址存在于所有进程的地址空间中呢?如果这无法实现的话,其他进程就无法调用到我们所实现的API。这里涉及到的关键就是,如何将我们的代码注入到别的进程中。

    这里有一个实现手段,就是将我们实现的代码随着系统钩子注入到目标进程中,我们在HOOK API (一)中讲过鼠标钩子,鼠标钩子一旦启动,就会存在于每个当前运行的进程中,实现对屏幕坐标的定位。还有一个关键就是,这样的钩子需要注入到多个目标进程中,那么这就要在动态链接库(DLL)中实现,然后启动某一主调进程将这样一个DLL注入到目标进程中,从而实现HOOK API。

    本实例介绍如何将实现了HOOK MessageBox的DLL注入到所有进程中的过程。

    0x01 HOOK DLL的实现

    建立一个MFC DLL工程

    由于被实例的DLL用于MFC框架,因此创建的是MFC DLL,需要的话,也可以建立其他类型的DLL工程。

    鼠标钩子回调函数

    我们的DLL要跟随鼠标钩子注入到目标进程中,而鼠标钩子是系统钩子,我们需要实现其钩子回调函数。

    /*
         鼠标钩子子过程,目的是加载本dll到使用鼠标的程序中。
         鼠标钩子的作用:当鼠标在某程序窗口中时,就会加载我们这个dll。
    */
    
    LRESULT CALLBACK MouseProc(
                            int nCode,     // hook code
                            WPARAM wParam,// message identifier
                            LPARAM lParam // mouse coordinates
                            )
    {
    return CallNextHookEx(hhk,nCode,wParam,lParam); }

    安装鼠标钩子

    调用SetWindowsHookEx() API可以安装鼠标钩子,其中SetWindowsHookEx() 原型如下:

    HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )

    参数:

    idHook表示钩子类型,它是和钩子函数类型一一对应的。比如,WH_KEYBOARD表示安装的是键盘钩子,WH_MOUSE表示是鼠标钩子等等。

      Lpfn是钩子函数的地址。

      HMod是钩子函数所在的实例的句柄。对于线程钩子,该参数为NULL;对于系统钩子,该参数为钩子函数所在的DLL句柄。

    dwThreadId 指定钩子所监视的线程的线程号。对于全局钩子,该参数为NULL。

    返回值:

      SetWindowsHookEx返回所安装的钩子句柄。

    //
    // 安装钩子
    //
    BOOL WINAPI StartHook(HWND hWnd){
    
        g_hWnd = hWnd;
        hhk = ::SetWindowsHookEx(WH_MOUSE,MouseProc,g_hInstance,0);
    
        if (hhk == NULL){
            return FALSE;
        }else{
            return TRUE;
        }
    }
     

    卸载鼠标钩子

    //
    // 卸载钩子
    //
    BOOL WINAPI StopHook()
    {    
    
        /*
            卸载钩子时,一定要记得恢复原API入口。
            这里恢复的只是主程序的原API入口,其它程序的API入口还没有被恢复。
            因此我们必须处理dll退出过程,即在函数ExitInstance()中,调用恢复
            API入口的函数HookOff(),只有这样,其它程序再次调用原API时,才不
            会发生错误。
            当我们HOOK所有程序的某个系统API时,千万要注意在ExitInstance()中
            调用HookOff()!!!!!
        */
    
        HookOff();
        if (hhk!=NULL){
            UnhookWindowsHookEx(hhk);
            FreeLibrary(g_hInstance);
        }
    
        return TRUE;
    } 

    导出我们的安装和卸载函数

    .def内容如下:

    将StarHook和StopHook函数导出,一遍主程序安装和卸载HOOK程序。

    ; HookDll.def : 声明 DLL 的模块参数。
    
    LIBRARY "HookMessageBox"
    
    EXPORTS
    
    ; 此处可以是显式导出
    
        StartHook
    
        StopHook

    MFC DLL的InitInstance()函数

     

    /*
        dll程序入口,当程序加载dll时,会执行InitInstance()
    */
    
    BOOL CHookDllApp::InitInstance(){
    
        CWinApp::InitInstance();
        g_hInstance = AfxGetInstanceHandle();//    获取当前DLL实例句柄
    
        AdjustPrivileges();    //    提高权限
        DWORD dwPid = ::GetCurrentProcessId();
        hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);
        if (hProcess == NULL){
            CString str;
            str.Format(_T("OpenProcess fail, and error code = %d"),GetLastError());
            AfxMessageBox(str);
            return FALSE;
        }
    
        Inject();    // 开始注入
        return TRUE;
    }

    MFC DLL的ExitInstance()函数

     

    int CHookDllApp::ExitInstance(){
    
        /*
            dll退出时,一定要记得恢复原API的入口!!!
            我们编写的dll会被注入到所有目标进程中,若dll退出时,没有恢复原API入口,
            那么被挂钩的程序再次调用该API时,会发生错误。
            因为我们的dll程序已经退出,但原API的入口仍为我们所定义的API的入口,这
            时被挂钩的程序无法找到我们实现的API,然而原API的地址又没有被恢复,也就
            调用不到原API,这时程序自然会发生崩溃了。
        */
    
        HookOff();
        return CWinApp::ExitInstance();
    }

    HOOK API实现

    1. 注入函数,保存新的,原来的API的入口

    该函数的主要功能是保存新的和原来的API入口,并且在最后启动HOOK。需要注意的是,这个函数只能被调用一次,即只能进行一次注入操作。

    /*
        注入
    */
    void Inject(){
    
        if ( TRUE == bIsInJected){
            return;
        }
    
        bIsInJected = TRUE;    // 保证只调用一次
    
        //
        // 获取函数
        //
        HMODULE hmodle = ::LoadLibrary(_T("User32.dll"));
        oldMsgBoxA = (TypeMsgBoxA) ::GetProcAddress(hmodle,"MessageBoxA");
        pfMsgBoxA = (FARPROC)oldMsgBoxA;
    
        oldMsgBoxW = (TypeMsgBoxW) ::GetProcAddress(hmodle,"MessageBoxW");
        pfMsgBoxW = (FARPROC)oldMsgBoxW;
    
        if (pfMsgBoxA == NULL){
            AfxMessageBox(_T("获取 MessageBoxA 函数失败"));
            return;
        }
    
        if ( pfMsgBoxW == NULL){
    
            AfxMessageBox(_T("获取 MessageBoxW 函数失败"));
            return;
        }
    
        // 保存原API地址
        _asm
        {
            lea edi,oldCodeA    // 取数组基地址
            mov esi,pfMsgBoxA    // API地址
            cld                    // 设置方向
            mov ecx,CODE_LENGTH
            rep movsb
        }
    
        _asm{
            lea edi,oldCodeW
            mov esi,pfMsgBoxW
            cld
            mov ecx,CODE_LENGTH
            rep movsb
        }
    
        // 将新地址复制到入口
        newCodeA[0] = newCodeW [0] = 0xe9;    // jmp 指定代码
        _asm
        {
            lea eax,MyMessageBoxA        // 新API地址
            mov ebx,pfMsgBoxA            // 原API地址
            sub eax,ebx                
            sub eax,CODE_LENGTH            // 跳转地址 = 新API地址 - 原API地址 - 指令长度
            mov dword ptr [newCodeA+1],eax // eax 32bit = 4 BYTE
        }
    
        _asm
        {
            lea eax,MyMessageBoxW
            mov ebx,pfMsgBoxW
            sub eax,ebx
            sub eax,CODE_LENGTH
            mov dword ptr [newCodeW + 1],eax
        }
    
        HookOn();    //    开始HOOK
     
    }
    写内存函数

    该函数主要完成向进程控制块写写指令的任务。供HookOn()和HookOff()调用,用来将原API入口,或新的API入口写入到进程的地址空间中。

    /*
        将长度为length的pcode写入到地址lpAddress中。
    */
    void WriteMemory(LPVOID lpAddress,BYTE* pcode,int length){
    
        //    保证本进程句柄不为NULL
        ASSERT(hProcess != NULL);
        DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
    
        // 修改API入口前length个字节为 jmp xxxx
        VirtualProtectEx(hProcess,lpAddress,length,PAGE_READWRITE,&dwOldProtect);
    
        dwRet = WriteProcessMemory(hProcess,lpAddress,pcode,length,&dwWrited);
        if ( 0 == dwRet || 0 == dwWrited){
            AfxMessageBox(_T("哭!!写入失败"));
        }
        VirtualProtectEx(hProcess,lpAddress,length,dwOldProtect,&dwTemp);
    }
    用新API地址替换原API地址
    /*
        用新API地址替换原API地址
    */
    void HookOn(){
    
        ASSERT(hProcess != NULL);
        DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
    
        WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH);
        WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH);
    }
    恢复原API地址
    /*  
        恢复原API地址
    */
    void HookOff(){
        ASSERT(hProcess != NULL);
        DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
        WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH);
        WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH);
    }
    新API定义
    /*
        自己用于替换的API
    */
    
    int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType){
    
        int nRet = 0;
        HookOff();
    
        nRet = ::MessageBoxA(hWnd,"哈哈 ^_^,MessageBoxA 被 HOOK 咯",lpCation,uType);
        nRet = ::MessageBoxA(hWnd,lpText,lpCation,uType);
    
        HookOn();
        return nRet;
    }
    
    
    int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType){
    
        int nRet = 0;
        HookOff();
    
        nRet = ::MessageBoxW(hWnd,_T("O(∩_∩)O哈哈~,MMessageBoxW 被 HOOK 咯"),lpCation,uType);
        nRet = ::MessageBoxW(hWnd,lpText,lpCation,uType);
    
        HookOn();
    
        return nRet;
    }
    提升权限函数

    这段代码并不是必须的,但有些时候会出现程序权限不足以获取进程句柄的情况,这个时候需要在代码执行前调用该函数来提高程序的权限。

    /*
         提升权限
    */
    bool AdjustPrivileges() {
        HANDLE hToken;
        TOKEN_PRIVILEGES tp;
        TOKEN_PRIVILEGES oldtp;
        DWORD dwSize=sizeof(TOKEN_PRIVILEGES);
        LUID luid;
    
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
            if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) return true;
            else return false;
        }
    
        if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
            CloseHandle(hToken);
            return false;
        }
    
        ZeroMemory(&tp, sizeof(tp));
        tp.PrivilegeCount=1;
        tp.Privileges[0].Luid=luid;
        tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
    
        /* Adjust Token Privileges */
        if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) {
            CloseHandle(hToken);
            return false;
        }
    
        // close handles
        CloseHandle(hToken);
    
        return true;
    }

    0x02 HOOK 窗体实现

    StartHook
    HINSTANCE g_hinstDll = NULL;
    
    // 开始 HOOK
    void CHookWindowDlg::OnBnClickedButtonStart(){
    
        // TODO: 在此添加控件通知处理程序代码
    
        g_hinstDll = LoadLibrary(_T("HookDll.dll"));
        if ( NULL == g_hinstDll){
            AfxMessageBox(_T("加载 HookDll.dll 失败"));
        }
    
        typedef BOOL (CALLBACK *HookStart)(HWND hwnd);
        HookStart hookStart = NULL;
        hookStart = (HookStart)::GetProcAddress(g_hinstDll,"StartHook");
        if ( NULL == hookStart){
            AfxMessageBox(_T("获取 StartHook 函数失败"));
            return;
        }
    
        bool ret = hookStart(m_hWnd);
        if (ret){
            m_list.InsertItem(m_list.GetItemCount(),_T("启动钩子成功"));
            m_list.EnsureVisible(m_list.GetItemCount()-1,FALSE);
        }else{
            m_list.InsertItem(m_list.GetItemCount(),_T("启动钩子失败"));
            m_list.EnsureVisible(m_list.GetItemCount()-1,FALSE);
        }
    }

     

    StopHook
    // 终止 HOOK
    void CHookWindowDlg::OnBnClickedButtonStop(){
    
        // TODO: 在此添加控件通知处理程序代码
        typedef BOOL (CALLBACK* HookStop)();
        HookStop hookStop = NULL;
        if (NULL == g_hinstDll) // 一定要加这个判断,若不为空的话就不需要在重新加载,否则会是不同的实例
        {
            g_hinstDll = LoadLibrary(_T("HookDll.dll"));
            if (g_hinstDll == NULL){
                AfxMessageBox(_T("加载 HookDll.dll 失败"));
                return;
            }
        }
    
        hookStop = ::GetProcAddress(g_hinstDll,"StopHook");
        if (hookStop == NULL){
            AfxMessageBox(_T("获取 StopHook 失败"));
            FreeLibrary(g_hinstDll);
            g_hinstDll=NULL;
            return;
        }
    
        hookStop();
        if (g_hinstDll!= NULL){
            ::FreeLibrary(g_hinstDll);
        }
    
        m_list.InsertItem(m_list.GetItemCount(),_T("终止HOOK成功"));
    
    }
    MessageBoxA
    // MessageBoxA
    void CHookWindowDlg::OnBnClickedButtonMsga(){
    
        // TODO: 在此添加控件通知处理程序代码
        MessageBoxA(m_hWnd,"这是正常的MessageBoxA...","哈哈",0);
    }
    MessageBoxW
    // MessageBoxW
    void CHookWindowDlg::OnBnClickedButtonMsgw(){
    
        // TODO: 在此添加控件通知处理程序代码
        MessageBoxW(_T("这是正常的MessageBoxW..."),_T("呵呵"),0);
    }

    0x03 测试

    本实例在自己实现的API中打印一句自己的话,然后再弹出原本的对话框。测试结果如下:

    启动钩子

    单击"MessageBoxA"按钮,调用MessageBoxA函数

    可以看到,先弹出了我们自己的对话框,然后才弹出真正的对话框。

    单击"MessageBoxW"按钮,调用MessageBoxW函数。

    可以看到,先弹出我们的对话框,然后才弹出真正的对话框。

    记事本的对话框也被HOOK了。

    打开技术本,打开查找对话框,然后输入一个字符串,"查找一下",这个时候同样先弹出我们的对话框,然后才弹出原来的,找不到对话框。

    0x04 附录——HOOK DLL关键源码

    // HookDll.cpp : 定义 DLL 的初始化例程。
    
    #include "stdafx.h"
    #include "HookDll.h"
    #include <Windows.h>
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    /*
         全局共享变量
    */
    #pragma data_seg("Share")
    HWND g_hWnd = NULL ;            // 主窗口句柄
    HINSTANCE g_hInstance = NULL;    // 本dll实例句柄
    HHOOK hhk = NULL;                // 鼠标钩子句柄
    #pragma data_seg()
    #pragma comment(linker,"/section:Share,rws")
    
    HANDLE hProcess = NULL;                //    当前进程
    BOOL bIsInJected = FALSE;            //    是否已注入标记
    TCHAR* msgToMain = new TCHAR[200];    //    发给主调程序的信息
    
    /*
        原函数定义
    */
    
    typedef int (WINAPI *TypeMsgBoxA)(HWND hWnd,LPCSTR lpText, LPCSTR lpCaption,UINT uType);
    
    typedef int (WINAPI *TypeMsgBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);
    
    TypeMsgBoxA oldMsgBoxA = NULL;    // 用于保存原函数地址
    TypeMsgBoxW oldMsgBoxW = NULL;    // 用于保存原楷书地址
    FARPROC pfMsgBoxA = NULL;        // 指向原函数地址的远指针
    FARPROC pfMsgBoxW = NULL;        // 指向原函数地址的远指针
    
    #define CODE_LENGTH 5
    BYTE oldCodeA[CODE_LENGTH];    // 保存原来API入口代码
    BYTE oldCodeW[CODE_LENGTH];    // 保存原来API入口代码
    BYTE newCodeA[CODE_LENGTH];    // 保存新API入口代码,jmp xxxx
    BYTE newCodeW[CODE_LENGTH];    // 保存新API入口代码,jmp xxxx
    
    /*
        自己编写的API
    */
    
    int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType);
    int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType);
    
    /*
        其它函数原型声明
    */
    
    void HookOn();            //    开始HOOK
    void HookOff();            //    关闭HOOK
    void Inject();            //    注入
    BOOL WINAPI StartHook(HWND hWnd);    // 加载钩子
    BOOL WINAPI StopHook();                // 卸载钩子
    bool AdjustPrivileges();            // 提升权限
    
     
    //
    //TODO: 如果此 DLL 相对于 MFC DLL 是动态链接的,
    //        则从此 DLL 导出的任何调入
    //        MFC 的函数必须将 AFX_MANAGE_STATE 宏添加到
    //        该函数的最前面。
    //
    //        例如:
    //
    //        extern "C" BOOL PASCAL EXPORT ExportedFunction()
    //        {
    //            AFX_MANAGE_STATE(AfxGetStaticModuleState());
    //            // 此处为普通函数体
    //        }
    //
    //        此宏先于任何 MFC 调用
    //        出现在每个函数中十分重要。这意味着
    //        它必须作为函数中的第一个语句
    //        出现,甚至先于所有对象变量声明,
    //        这是因为它们的构造函数可能生成 MFC
    //        DLL 调用。
    //
    //        有关其他详细信息,
    
    //        请参阅 MFC 技术说明 33 和 58。
    //
    
    // CHookDllApp
    
    BEGIN_MESSAGE_MAP(CHookDllApp, CWinApp)
    END_MESSAGE_MAP()
    
    // CHookDllApp 构造
    
    CHookDllApp::CHookDllApp(){
    
        // TODO: 在此处添加构造代码,
        // 将所有重要的初始化放置在 InitInstance 中
    }
    
    // 唯一的一个 CHookDllApp 对象
    CHookDllApp theApp;
    
    // CHookDllApp 初始化
    
    /*
        dll程序入口,当程序加载dll时,会执行InitInstance()
    */
    
    BOOL CHookDllApp::InitInstance(){
    
        CWinApp::InitInstance();
        g_hInstance = AfxGetInstanceHandle();//    获取当前DLL实例句柄
    
        AdjustPrivileges();    //    提高权限
        DWORD dwPid = ::GetCurrentProcessId();
        hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);
    
        if (hProcess == NULL){
            CString str;
            str.Format(_T("OpenProcess fail, and error code = %d"),GetLastError());
            AfxMessageBox(str);
            return FALSE;
        }
        Inject();    // 开始注入
        return TRUE;
    }
    
    int CHookDllApp::ExitInstance(){
    
        /*
            dll退出时,一定要记得恢复原API的入口!!!
            我们编写的dll会被注入到所有目标进程中,若dll退出时,没有恢复原API入口,
            那么被挂钩的程序再次调用该API时,会发生错误。
            因为我们的dll程序已经退出,但原API的入口仍为我们所定义的API的入口,这
            时被挂钩的程序无法找到我们实现的API,然而原API的地址又没有被恢复,也就
            调用不到原API,这时程序自然会发生崩溃了。
        */
    
        HookOff();
        return CWinApp::ExitInstance();
    }
    
    /*
         提升权限
    */
    bool AdjustPrivileges() {
        HANDLE hToken;
        TOKEN_PRIVILEGES tp;
        TOKEN_PRIVILEGES oldtp;
        DWORD dwSize=sizeof(TOKEN_PRIVILEGES);
        LUID luid;
    
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
            if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) return true;
            else return false;
        }
    
        if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
            CloseHandle(hToken);
            return false;
        }
    
        ZeroMemory(&tp, sizeof(tp));
        tp.PrivilegeCount=1;
        tp.Privileges[0].Luid=luid;
        tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
    
        /* Adjust Token Privileges */
        if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) {
            CloseHandle(hToken);
            return false;
        }
    
        // close handles
        CloseHandle(hToken);
        return true;
    }
    
    /*
         鼠标钩子子过程,目的是加载本dll到使用鼠标的程序中。
         鼠标钩子的作用:当鼠标在某程序窗口中时,就会加载我们这个dll。
    */
    LRESULT CALLBACK MouseProc(
                            int nCode,     // hook code
                            WPARAM wParam,// message identifier
                            LPARAM lParam // mouse coordinates
                            )
    {
        return CallNextHookEx(hhk,nCode,wParam,lParam);
    }
    
     
    /*
        将长度为length的pcode写入到地址lpAddress中。
    */
    void WriteMemory(LPVOID lpAddress,BYTE* pcode,int length){
    
        //    保证本进程句柄不为NULL
        ASSERT(hProcess != NULL);
        DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
    
        // 修改API入口前length个字节为 jmp xxxx
        VirtualProtectEx(hProcess,lpAddress,length,PAGE_READWRITE,&dwOldProtect);
        dwRet = WriteProcessMemory(hProcess,lpAddress,pcode,length,&dwWrited);
        if ( 0 == dwRet || 0 == dwWrited){
            AfxMessageBox(_T("哭!!写入失败"));
        }
        VirtualProtectEx(hProcess,lpAddress,length,dwOldProtect,&dwTemp);
    }
    
    /*
        用新API地址替换原API地址
    */
    void HookOn(){
        ASSERT(hProcess != NULL);
        DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
        WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH);
        WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH);
    }
    
     
    
    /*    
        恢复原API地址
    */
    void HookOff(){
    
        ASSERT(hProcess != NULL);
        DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
        WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH);
        WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH);
    
    }
     
    /*
        注入
    */
    void Inject(){
    
        if ( TRUE == bIsInJected){
            return;
        }
        bIsInJected = TRUE;    // 保证只调用一次
    
        //
        // 获取函数
        //
        HMODULE hmodle = ::LoadLibrary(_T("User32.dll"));
        oldMsgBoxA = (TypeMsgBoxA) ::GetProcAddress(hmodle,"MessageBoxA");
        pfMsgBoxA = (FARPROC)oldMsgBoxA;
    
        oldMsgBoxW = (TypeMsgBoxW) ::GetProcAddress(hmodle,"MessageBoxW");
        pfMsgBoxW = (FARPROC)oldMsgBoxW;
    
        if (pfMsgBoxA == NULL){
            AfxMessageBox(_T("获取 MessageBoxA 函数失败"));
            return;
        }
    
        if ( pfMsgBoxW == NULL){
            AfxMessageBox(_T("获取 MessageBoxW 函数失败"));
            return;
        }
    
        //
        // 保存原API地址
        //
        _asm
        {
            lea edi,oldCodeA    // 取数组基地址
            mov esi,pfMsgBoxA    // API地址
            cld                    // 设置方向
            mov ecx,CODE_LENGTH
            rep movsb
        }
    
        _asm
        {
            lea edi,oldCodeW
            mov esi,pfMsgBoxW
            cld
            mov ecx,CODE_LENGTH
            rep movsb
        }
    
        //
        // 将新地址复制到入口
        //
        newCodeA[0] = newCodeW [0] = 0xe9;    // jmp 指定代码
        _asm
        {
            lea eax,MyMessageBoxA        // 新API地址
            mov ebx,pfMsgBoxA            // 原API地址
            sub eax,ebx                
            sub eax,CODE_LENGTH            // 跳转地址 = 新API地址 - 原API地址 - 指令长度
            mov dword ptr [newCodeA+1],eax // eax 32bit = 4 BYTE
    
        }
    _asm { lea eax,MyMessageBoxW mov ebx,pfMsgBoxW sub eax,ebx sub eax,CODE_LENGTH mov dword ptr [newCodeW
    + 1],eax } HookOn(); // 开始HOOK } // // 安装钩子 // BOOL WINAPI StartHook(HWND hWnd){ g_hWnd = hWnd; hhk = ::SetWindowsHookEx(WH_MOUSE,MouseProc,g_hInstance,0); if (hhk == NULL){ return FALSE; } else{ return TRUE; } } // // 卸载钩子 // BOOL WINAPI StopHook(){ /* 卸载钩子时,一定要记得恢复原API入口。 这里恢复的只是主程序的原API入口,其它程序的API入口还没有被恢复。 因此我们必须处理dll退出过程,即在函数ExitInstance()中,调用恢复 API入口的函数HookOff(),只有这样,其它程序再次调用原API时,才不 会发生错误。 当我们HOOK所有程序的某个系统API时,千万要注意在ExitInstance()中 调用HookOff()!!!!! */ HookOff(); if (hhk!=NULL){ UnhookWindowsHookEx(hhk); FreeLibrary(g_hInstance); } return TRUE; } /* 自己用于替换的API */ int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType){ int nRet = 0; HookOff(); nRet = ::MessageBoxA(hWnd,"哈哈 ^_^,MessageBoxA 被 HOOK 咯",lpCation,uType); nRet = ::MessageBoxA(hWnd,lpText,lpCation,uType); HookOn(); return nRet; } int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType){ int nRet = 0; HookOff(); nRet = ::MessageBoxW(hWnd,_T("O(∩_∩)O哈哈~,MMessageBoxW 被 HOOK 咯"),lpCation,uType); nRet = ::MessageBoxW(hWnd,lpText,lpCation,uType); HookOn(); return nRet; }
     
  • 相关阅读:
    冲刺第五天个人博客
    冲刺第四天个人博客
    典型用户及场景
    冲刺第三天个人博客
    冲刺第二天个人博客
    冲刺第一天个人博客
    第三周学习进度表
    第二周学习进度表
    webServices
    vs开发工具使用问题
  • 原文地址:https://www.cnblogs.com/fanling999/p/4595035.html
Copyright © 2011-2022 走看看