APIHOOK实例剖析 |
2004-2-18加入 来自csdn 作者rivershan 0条评论 点击224次 |
关于APIHOOK的基础知识有很多,如dll的相关知识、Hook的相关知识、系统进程与线程之间的联系等。具体可以看我的另两篇文章:"我的Dll(动态链接库)学习笔记" 和 "我的Hook学习笔记"。:)下面进入这篇文章的重点,根据APIHook源码进行APIHook的剖析。 一、APIHOOK之dll部分 APIHook_Dll.cpp // rivershan写于2002.9.23 // / #include "stdafx.h" #include "APIHook_Dll.h" #include #include #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中等。 |
APIHOOK实例剖析
最新推荐文章于 2020-12-19 03:46:17 发布