首页 网络安全 安全学院 查看内容

API HOOK实例剖析

2009-7-14 12:12 1126 1

摘要:   关于APIHOOK的基础知识有很多,如dll的相关知识、Hook的相关知识、系统进程与线程之间的联系等。具体可以看我的另两篇文章:"我的Dll(动态链接库)学习笔记" 和 "我的Hook学习笔记"...
关键词: nbsp 函数 APIHOOK dll pfnDummyFuncAddr pfnOriginApiAddr hModCallerModule EXEDlg pszCalleeModuleN CAPIHook

  关于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中等。
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

返回顶部