|| 您现在的位置: 天下无挂网 >> 外挂文章 >> 游戏外挂制作 >> 外挂文章正文
:: 用户登录 ::

 
:: 专 题 栏 目 ::
:: 最新热门 ::
  • 没有热门外挂文章
  • :: 相关文章 ::
    没有相关外挂文章

    APIHOOK实例剖析
    作者:不详 文章来源:不详 点击数: 更新时间:2005-8-19

        关于APIHOOK的基础知识有很多,如dll的相关知识、Hook的相关知识、系统进程与线程之间的联系等。具体可以看我的另两篇文章:"我的Dll(动态链接库)学习笔记" 和 "我的Hook学习笔记"。:)下面进入这篇文章的重点,根据APIHook源码进行APIHook的剖析。
     
    一、APIHOOK之dll部分
     
    //////////////////////////////// APIHook_Dll.cpp ////////////////////////////////////////
    //                             rivershan写于2002.9.23                                //
    /////////////////////////////////////////////////////////////////////////////////////////

    #include "stdafx.h"
    #include "APIHook_Dll.h"

    #include <ImageHlp.h>
    #include <tlhelp32.h>

    #pragma comment(lib,"ImageHlp") //定义全局共享数据段

    #pragma data_seg("Shared")
    HMODULE hmodDll=NULL;
    HHOOK hHook=NULL;

    #pragma data_seg()

    #pragma comment(linker,"/Section:Shared,rws") //设置全局共享数据段的属性

    ///////////////////////////////////// DllMain 函数 /////////////////////////////////////////
    //dll的入口点
    BOOL APIENTRY DllMain( HMODULE hModule, 
                           DWORD  ul_reason_for_call, 
                           LPVOID lpReserved
          )
    {
     switch(ul_reason_for_call)
     {
     case DLL_PROCESS_ATTACH:
      //if(sHook)  
      
     case DLL_PROCESS_DETACH:
      UnInstallHook();
      break;
     }
     hmodDll=hModule;
        return TRUE;
    }

    ///////////////////////////////////// HookOneAPI 函数 /////////////////////////////////////////
    //进行IAT转换的关键函数,其参数含义:
    //pszCalleeModuleName:需要hook的模块名
    //pfnOriginApiAddress:要替换的自己API函数的地址
    //pfnDummyFuncAddress:需要hook的模块名的地址
    //hModCallerModule:我们要查找的模块名称,如果没有被赋值,
    //     将会被赋值为枚举的程序所有调用的模块

    void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress, 
            PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
    {
     ULONG size;

     //获取指向PE文件中的Import中IMAGE_DIRECTORY_DESCRIPTOR数组的指针

     PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
      ImageDirectoryEntryToData(hModCallerModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);

     if (pImportDesc == NULL)
      return;

     //查找记录,看看有没有我们想要的DLL

     for (;pImportDesc->Name;pImportDesc++)
     {
      LPSTR pszDllName = (LPSTR)((PBYTE)hModCallerModule+pImportDesc->Name);
      if (lstrcmpiA(pszDllName,pszCalleeModuleName) == 0)
       break;
     }

     if (pImportDesc->Name == NULL)
     {
      return;
     }

     //寻找我们想要的函数

     PIMAGE_THUNK_DATA pThunk = 
      (PIMAGE_THUNK_DATA)((PBYTE)hModCallerModule+pImportDesc->FirstThunk);//IAT
     for (;pThunk->u1.Function;pThunk++)
     {
      //ppfn记录了与IAT表项相应的函数的地址

      PROC * ppfn= (PROC *)&pThunk->u1.Function;  
      if (*ppfn == pfnOriginApiAddress) 
      {
       //如果地址相同,也就是找到了我们想要的函数,进行改写,将其指向我们所定义的函数

       WriteProcessMemory(GetCurrentProcess(),ppfn,&(pfnDummyFuncAddress),
        sizeof(pfnDummyFuncAddress),NULL);
       return;
      }
     }
    }

    //查找所挂钩的进程所应用的dll模块的

    BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
            PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
    {
     if (pszCalleeModuleName == NULL)
     {
      return FALSE;
     }
     if (pfnOriginApiAddress == NULL)
     {
      return FALSE;
     }
     //如果没传进来要挂钩的模块名称,枚举被挂钩进程的所有引用的模块,
     //并对这些模块进行传进来的相应函数名称的查找
     
     if (hModCallerModule == NULL)
     {
      MEMORY_BASIC_INFORMATION mInfo;
      HMODULE hModHookDLL;
      HANDLE hSnapshot;
      MODULEENTRY32 me = {sizeof(MODULEENTRY32)};
      //MODULEENTRY32:描述了一个被指定进程所应用的模块的struct

      VirtualQuery(HookOneAPI,&mInfo,sizeof(mInfo));
      hModHookDLL=(HMODULE)mInfo.AllocationBase;
      
      hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);
      BOOL bOk = Module32First(hSnapshot,&me);
      while (bOk)
      {
       if (me.hModule != hModHookDLL)
       {
        hModCallerModule = me.hModule;//赋值
        //me.hModule:指向当前被挂钩进程的每一个模块 
        HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,
         pfnDummyFuncAddress,hModCallerModule);
       }
       bOk = Module32Next(hSnapshot,&me);
      }
      return TRUE;  
     }
     //如果传进来了,进行查找
     else
     {
      HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,
        pfnDummyFuncAddress,hModCallerModule);
      return TRUE;
     }
     return FALSE;
    }

    //////////////////////////////////// UnhookAllAPIHooks 函数 /////////////////////////////////////
    //通过使pfnDummyFuncAddress与pfnOriginApiAddress相等的方法,取消对IAT的修改
    BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
             PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
    {
     PROC temp;
     temp = pfnOriginApiAddress;
     pfnOriginApiAddress = pfnDummyFuncAddress;
     pfnDummyFuncAddress = temp;
     return HookAllAPI(pszCalleeModuleName,pfnOriginApiAddress,
      pfnDummyFuncAddress,hModCallerModule);
    }

    ////////////////////////////////// GetMsgProc 函数 ////////////////////////////////////////
    //钩子子程。与其它钩子子程不大相同,没做什么有意义的事情,继续调用下一个钩子子程,形成循环
    LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam)
    {
     return CallNextHookEx(hHook,code,wParam,lParam);
    }

    //////////////////////////////////// InstallHook 函数 /////////////////////////////////////
    //安装或卸载钩子,BOOL IsHook参数是标志位
    //对要钩哪个API函数进行初始化
    //我们这里装的钩子类型是WH_GETMESSAGE
    void __declspec(dllexport) WINAPI InstallHook(BOOL IsHook,DWORD dwThreadId)
    {
     if(IsHook)
     {
     hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgProc,hmodDll,dwThreadId);
     
     //GetProcAddress(GetModuleHandle("GDI32.dll"),"ExtTextOutA"):取得要钩的函数在所在dll中的地址
     
     HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
      "TextOutW"),(PROC)&H_TextOutW,NULL);
     HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
      "TextOutA"),(PROC)&H_TextOutA,NULL);
     }
     else
     {
      UnInstallHook();
      UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
       "TextOutW"),(PROC)&H_TextOutW,NULL);
      UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
       "TextOutA"),(PROC)&H_TextOutA,NULL);
     }
    }

    ///////////////////////////////////// UnInstallHook 函数 ////////////////////////////////////
    //卸载钩子
    BOOL WINAPI UnInstallHook()
    {
     UnhookWindowsHookEx(hHook);
     return TRUE;
    }

    ///////////////////////////////////// H_TextOutA 函数 /////////////////////////////////////////
    //我们的替换函数,可以在里面实现我们所要做的功能
    //这里我做的是显示一个对话框,指明是替换了哪个函数
    BOOL WINAPI H_TextOutA(HDC hdc,int nXStart,int nYStart,LPCSTR lpString,int cbString)
    {
     MessageBox(NULL,"TextOutA","APIHook_Dll ---rivershan",MB_OK);
     TextOutA(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数,以显示字符
     return TRUE;
    }

    ///////////////////////////////////// H_TextOutW 函数 /////////////////////////////////////////
    //同上
    BOOL WINAPI H_TextOutW(HDC hdc,int nXStart,int nYStart,LPCWSTR lpString,int cbString)
    {
     MessageBox(NULL,"TextOutW","APIHook_Dll ---rivershan",MB_OK);
     TextOutW(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数,以显示字符
     return TRUE;
    }

    **********************************************************************************************
    **********************************************************************************************

    //////////////////////////////// APIHook_Dll.h ////////////////////////////////////////
    //                             rivershan写于2002.9.23                                  //
    /////////////////////////////////////////////////////////////////////////////////////////

    //dll头文件,用于声明函数

    void __declspec(dllexport) WINAPI InstallHook(BOOL,DWORD);
    BOOL WINAPI UnInstallHook();
    LRESULT CALLBACK GetMsgProC(int code,WPARAM wParam,LPARAM lParam);

    void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
            PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
    BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
            PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
    BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
             PROC pfnDummyFuncAddress,HMODULE hModCallerModule);

    BOOL WINAPI H_TextOutA(HDC, int, int, LPCSTR, int);
    BOOL WINAPI H_TextOutW(HDC, int, int, LPCWSTR, int);
    BOOL WINAPI H_ExtTextOutA(HDC, int, int, UINT, CONST RECT *,LPCSTR, UINT, CONST INT *);
    BOOL WINAPI H_ExtTextOutW(HDC, int, int, UINT, CONST RECT *,LPCWSTR, UINT, CONST INT *);

    **********************************************************************************************
    **********************************************************************************************

    ;APIHook_Dll之def文件
    LIBRARY APIHook_Dll.dll
    EXPORT
     InstallHook
     
    二、APIHOOK之exe部分

    //////////////////////////// APIHook_EXEDlg.cpp /////////////////////////////////////////
    //                             rivershan写于2002.9.23                                  //
    /////////////////////////////////////////////////////////////////////////////////////////


    #include "stdafx.h"
    #include "APIHook_EXE.h"
    #include "APIHook_EXEDlg.h"
    #include "APIHook_Dll.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif

    /////////////////////////////////////////////////////////////////////////////
    // CAPIHook_EXEDlg dialog

    CAPIHook_EXEDlg::CAPIHook_EXEDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CAPIHook_EXEDlg::IDD, pParent)
    {
     //{{AFX_DATA_INIT(CAPIHook_EXEDlg)
     // NOTE: the ClassWizard will add member initialization here
     //}}AFX_DATA_INIT
     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }

    void CAPIHook_EXEDlg::DoDataExchange(CDataExchange* pDX)
    {
     CDialog::DoDataExchange(pDX);
     //{{AFX_DATA_MAP(CAPIHook_EXEDlg)
     // DDX_Control(pDX, IDC_EDIT1, m_Edit);
     //}}AFX_DATA_MAP
    }

    BEGIN_MESSAGE_MAP(CAPIHook_EXEDlg, CDialog)
    //{{AFX_MSG_MAP(CAPIHook_EXEDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
     ON_BN_CLICKED(IDC_BUTTON_OUT, OnButtonOut)
     ON_BN_CLICKED(IDC_BUTTON_BEGIN, OnButtonBegin)
     ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
     //}}AFX_MSG_MAP
    END_MESSAGE_MAP()

    /////////////////////////////////////////////////////////////////////////////
    // CAPIHook_EXEDlg message handlers

    BOOL CAPIHook_EXEDlg::OnInitDialog()
    {
     CDialog::OnInitDialog();
     
     // Set the icon for this dialog.  The framework does this automatically
     // when the application's main window is not a dialog
     SetIcon(m_hIcon, TRUE);   // Set big icon
     SetIcon(m_hIcon, FALSE);  // Set small icon
     
     // TODO: Add extra initialization here
     
     return TRUE;  // return TRUE  unless you set the focus to a control
    }

    // If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework.

    void CAPIHook_EXEDlg::OnPaint() 
    {
     if (IsIconic())
     {
      CPaintDC dc(this); // device context for painting
      
      SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
      
      // Center icon in client rectangle
      int cxIcon = GetSystemMetrics(SM_CXICON);
      int cyIcon = GetSystemMetrics(SM_CYICON);
      CRect rect;
      GetClientRect(&rect);
      int x = (rect.Width() - cxIcon + 1) / 2;
      int y = (rect.Height() - cyIcon + 1) / 2;
      
      // Draw the icon
      dc.DrawIcon(x, y, m_hIcon);
     }
     else
     {
      CDialog::OnPaint();
     }
    }

    // The system calls this to obtain the cursor to display while the user drags
    //  the minimized window.
    HCURSOR CAPIHook_EXEDlg::OnQueryDragIcon()
    {
     return (HCURSOR) m_hIcon;
    }
    ///////////////////////////////////// OnButtonOut 函数 //////////////////////////////////////
    //使用TextOut函数
    void CAPIHook_EXEDlg::OnButtonOut() 
    {
     // TODO: Add your control notification handler code here
     HDC hdc = ::GetDC(GetSafeHwnd());
     ::TextOutA(hdc,0,0,"APIHOOK_EXE ---rivershan",30);
     UpdateWindow();
    }

    ///////////////////////////////////// OnButtonBegin 函数 ////////////////////////////////////
    //开始挂钩,这里我们挂的是自身这个APIHook_EXE这个程序
    void CAPIHook_EXEDlg::OnButtonBegin()
    {
     DWORD dwThreadId = GetWindowThreadProcessId(m_hWnd,NULL);//获得自身进程ID
     InstallHook(TRUE,dwThreadId);
    }

    ///////////////////////////////////// OnButtonStop 函数 ////////////////////////////////////
    //取消挂钩
    void CAPIHook_EXEDlg::OnButtonStop()
    {
     InstallHook(FALSE,0);
    }

    三、APIHOOK之集成

    1. 用 VC++新建一个 Win32 Dynamic-Link Library 程序,命名为 APIHook_Dll。接下来选择第二项 A Simple DLL
    Project;
    2. 新建一头文件,命名为 APIHook_Dll.h。删除工程中 APIHook_Dll.cpp文件中原来的内容,然后把上面的
    APIHook_Dll.cpp 和 APIHook_Dll.h文件的内容全部复制到新建的这个工程的 .cpp及 .h文件中来;
    3. 新建一 Text文件,命名为 APIHook_Dll.def。复制上面的def文件内容。
    4. 编译;
    5. 新建一 MFC APPWizard(exe)程序,命名为 APIHook_EXE。接着选择第三项,基于对话框的程序,其它默认;
    6. 删除原来对话框上的控件,然后新建三个按钮ID分别为:IDC_BUTTON_BEGIN、IDC_BUTTON_STOP、IDC_BUTTON_OUT,
    Caption分别为:Bigin Hook、Stop Hook、Text Out。不要让这三个按钮出于对话框客户区的最上面就行;
    7. 拷贝 APIHook_Dll.h文件到 APIHook_EXE程序目录下,然后加到 APIHook_EXE的头文件夹中。
    8. 删除工程中 APIHook_EXEDlg.cpp文件中原来的内容,然后把上面的 APIHook_EXEDlg.cpp文件的内容全部复制到新建
    的这个工程的 .cpp文件中来;
    9. 打开 Project->Setting菜单,选择第四项link,在 Object/library moduls里添加我们的dll的lib文件的路径:..
    \APIHook_Dll\Debug\APIHook_Dll.lib;
    10. 编译;
    11. 把 APIHook_Dll.dll文件放在 APIHook_Dll.exe程序的同一个文件夹内;
    12. 运行程序,点击 Bigin Hook按钮,开始挂钩。再点击 Text Out按钮会跳出对话框并且会在程序中显示所要显示的
    字。点击 Stop Hook然后在点击 Text Out按钮就没有对话框出现了。

    四、一些说明

    1、我这个 HookAPI是使用了 Jeffrey Richter的改写程序的 IAT来实现的,也可以用跳转函数入口点的方法来实现,这
    个我没做研究。:)

    2、我的一些心得:

     所谓 HookAPI,就是改写程序的 IAT,再调用我自己写的用于替换原API函数的函数。在我们自己写的API函数中,我们可以进行我们想要的工作。之后呢,可以把原来的函数传回去,也可以不传回去,只要你设计好了就行。

     而所谓调用自己的函数,就是把原函数参数都传给我的替换函数。我们就可以利用这些参数去干我们想做的事。而系统呢,我想由于微软设置的这个钩子的目的(我这么认为的),所以不会去检查替换函数是否就是原函数,只要参数、返回值符合条件就行,要不会出错。替换函数的返回值最好是原函数,否则有可能会出错 HookAPI时,exe程序起到的作用就是进行Hook,把dll注入到要Hook的程序,并且传回要挂接的进程的ID或者全局钩子,以便查询所要挂接的模块的IAT。如果不注入进去,系统不会让你去查询IAT的。DLL做的事情是确定要挂接哪个函数和这个函数在哪个DLL中等。

     
    GoldenSword 

    我把大侠的代码增加一点,让它能够Hook MessageBoxA和MessageBoxW函数发现有下面的问题我在原来的APIHook_Dll.h中
    增加了下面两个申明
    BOOL WINAPI H_MessageBoxA(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType );
    BOOL WINAPI H_MessageBoxW(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uTypeK);
    cpp也作了相应的修改
     void __declspec(dllexport) WINAPI InstallHook(BOOL IsHook,DWORD dwThreadId) { if(IsHook) {
    hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgProc,hmodDll,dwThreadId); //GetProcAddress
    (GetModuleHandle("GDI32.dll"),"ExtTextOutA")£oè?μ?òa13μ?oˉêy?ú?ù?údll?Dμ?μ??· /* HookAllAPI(
    "GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"), "TextOutW"),(PROC)&H_TextOutW,NULL ); HookAllAPI
    ( "GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"), "TextOutA"),(PROC)&H_TextOutA,NULL ); */
    HookAllAPI( "user32.dll",GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxW"),(PROC)
    &H_MessageBoxW,NULL ); HookAllAPI( "user32.dll",GetProcAddress(GetModuleHandle("user32.dll"),
    "MessageBoxA"),(PROC)&H_MessageBoxA,NULL ); } else { UnInstallHook(); /* UnhookAllAPIHooks
    ("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"), "TextOutW"),(PROC)&H_TextOutW,NULL );
    UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"), "TextOutA"),(PROC)
    &H_TextOutA,NULL ); */ UnhookAllAPIHooks("user32.dll",GetProcAddress(GetModuleHandle("user32.dll"),
    "MessageBoxW"),(PROC)&H_MessageBoxW,NULL ); UnhookAllAPIHooks("user32.dll",GetProcAddress(GetModuleHandle
    ("user32.dll"), "MessageBoxA"),(PROC)&H_MessageBoxA,NULL ); } } BOOL WINAPI H_MessageBoxA(HWND
    hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType) { MessageBox(NULL,"MessageBoxA","APIHook_Dll ---
    rivershan",MB_OK); return TRUE; } BOOL WINAPI H_MessageBoxW(HWND hWnd,LPCTSTR lpText,LPCTSTR
    lpCaption,UINT uType) { MessageBox(NULL,"MessageBoxW","APIHook_Dll ---rivershan",MB_OK); return TRUE; } 这
    时候把测试的exe文件也增加了一个按钮,点击之后调用MessageBox函数,发现非得调用和DLL中一样的格式才行 void
    CAPIHook_EXEDlg::OnButtonMessage() { ::MessageBox(this->m_hWnd,"test","APIHook Test",MB_OK); //MessageBox
    ("test"); } 上面就可以钩住,下面的不行,其实MFC的源代码里面调用的还是上面一种,为什么就不行呢?

    外挂文章录入:admin    责任编辑:admin 
  • 上一篇外挂文章:

  • 下一篇外挂文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口

    点击申请点击申请点击申请点击申请点击申请点击申请
    点击申请点击申请点击申请点击申请点击申请点击申请点击申请

    版权所有 Copyright? 2004-2008 天下无挂科技网 网站维护:GHOST
    网站域名:http://www.watxwg.com
    客服邮箱:txwgwa@163.com
    客服电话:13810978321
    客服 Q Q:12439470