API hook 原理与Windows hook 应用

Hook原理--逆向开发 fishhook的源码地址为fishhook的主要方法有两个还有一个结构体查看代码结构为,将红色圈起来部分移入到代码中,即可使用fishhook来hook代码。上面讲述了Hook的几种技术方式以及fishhook的原理探究,以及如何让别人的app实现自己的代码。下面我们对此总结一下,写了一个本篇博客的整个过程便于大家整理,希望对大家有所帮助加深理解。这就是今天的全部内容,喜欢的或者有想法的朋友可以私信我。 阅读详情

API hook 原理与Windows hook 应用

分类: 系统程序   3679人阅读  评论(3)  收藏  举报

目录(?)[+]


优快云 上图片很麻烦,请到百度文库直接看Word 文档,图片比这个全http://wenku.baidu.com/view/0946ce1155270722192ef74f.html

Hook 字面的意思是钩子,但是实际上更像提供一种过滤,或者说修改消息处理,或者API的机制。

API hook 

什么是API的hook呢,其实就是将API调用的地方进行了转移,或者重新实现的一种技术。这种技术不仅仅可以用在windows 上,其他OS上一样可以使用,我曾经在brew mp 上的手机开发上测试过API hook。所以这里主要只讲windows 下的API hook。 API的hook 基本思路都是想办法替换原来的API,使函数的调用关系,直接进行转换, 典型的如下




可以看到client 端要调用的FunctionA,在A进入之后,就调用了FunctionB , 在Function B 中回到FunctionA 做具体A应该做的事情,从A返回之后,FunctionB 然后在返回给Client,那么在FunctionB 中使用FunctionA的前后,它自己都可以干自己想要干的事情,这样就是一个API的hook, 下面我们主要讨论Windows 上最常用的两种API hook 策略。

A)IAT 替换API hook 

所谓的IAT (import  address table ) 这个是PE文件中一个重要的部分,这里我们不详细讨论PE文件的构成,因为这个本来就可以写一张内容。我们主要了解的是PE如何在一个已经加载在内存中的PE文件如何找到它的IAT。

(1) 为什么要找IAT?

          一个模块,可能依赖别的API,也可能提供API,供别的模块调用,MS为了在PE文件中,分别用导入表和导出表进行描述两种关系。导入表IAT 主要是描述了这个模块依赖那些其他模块提供的API。 而导出表EAT 是描述这个模块中都提供那些函数供别的模块调用。如果我们在某个模块的导入表中替换它所依赖的函数,那么这样就可以实现API hook.

(2) 如何找IAT?

 要找IAT 要稍微了解一下PE文件的结构,

 


 

一个PE 文件的大概长相就是这样,我们要找的IAT,就是要先找到PE文件可选头,在这个数据结构中,描述了IAT 描述的位置在那里,然后给距IAT descriptor 就可以找到IAT了。

[cpp]  view plain copy
  1. BOOL TestFunctionInIAT( HMODULE hModule, ULONG FunctionAddress )  
  2. {  
  3.     BOOL bReturn = FALSE;  
  4.     unsigned char *pBaseAddr = reinterpret_cast<unsigned char *>(hModule);  
  5.   
  6.     // 获取DOS header 的位置  
  7.     PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(pBaseAddr);  
  8.   
  9.     // 获取NTImage header 的位置  
  10.     PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(  
  11.         pBaseAddr + pDosHeader->e_lfanew );  
  12.   
  13.     // 获取 PE option header的位置  
  14.     PIMAGE_OPTIONAL_HEADER pPEOptionHeader = &pNtHeader->OptionalHeader;  
  15.   
  16.     // 获取导入表的目录结构  
  17.     PIMAGE_DATA_DIRECTORY pIATDataDirectory = &(pPEOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);  
  18.   
  19.     // 获取导入表 descriptor  
  20.     PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(  
  21.         pBaseAddr + pIATDataDirectory->VirtualAddress );  
  22.   
  23.     // 从pImportDescriptor 开始是一堆导入表,一张接着一张,直到  
  24.     // 导入表的名字为空为止,其实就是对应Windows 的一个dll,有几张表,就表示  
  25.     // 该模块依赖几个dll 的导出函数, Name 字段是dll的名称的相对虚拟地址  
  26.     while ( pImportDescriptor->Name != 0 )  
  27.     {  
  28.         // thunk data 就是表示导入dll 中函数描述  
  29.         PIMAGE_THUNK_DATA pThunkData = reinterpret_cast<PIMAGE_THUNK_DATA>(  
  30.             pBaseAddr + pImportDescriptor->FirstThunk);  
  31.         while( pThunkData->u1.Function != 0 )  
  32.         {  
  33.              ULONG *ppfn = ( ULONG *)&pThunkData->u1.Function;   
  34.              if ( *ppfn == FunctionAddress )  
  35.              {  
  36.               
  37.                  bReturn = TRUE;  
  38.                  break;  
  39.              }  
  40.              ++pThunkData;  
  41.         }  
  42.         ++pImportDescriptor;  
  43.     }  
  44.   
  45.     return bReturn;  
  46. }  
  47.   
  48. PROC g_CreateFunc = NULL;  
  49.   
  50. typedef BOOL (WINAPI *PCreateProcessW)(  
  51.                                        __in_opt    LPCWSTR lpApplicationName,  
  52.                                        __inout_opt LPWSTR lpCommandLine,  
  53.                                        __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,  
  54.                                        __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,  
  55.                                        __in        BOOL bInheritHandles,  
  56.                                        __in        DWORD dwCreationFlags,  
  57.                                        __in_opt    LPVOID lpEnvironment,  
  58.                                        __in_opt    LPCWSTR lpCurrentDirectory,  
  59.                                        __in        LPSTARTUPINFOW lpStartupInfo,  
  60.                                        __out       LPPROCESS_INFORMATION lpProcessInformation);  
  61.   
  62. BOOL WINAPI MyCreateProcessW(  
  63.                              __in_opt    LPCWSTR lpApplicationName,  
  64.                              __inout_opt LPWSTR lpCommandLine,  
  65.                              __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,  
  66.                              __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,  
  67.                              __in        BOOL bInheritHandles,  
  68.                              __in        DWORD dwCreationFlags,  
  69.                              __in_opt    LPVOID lpEnvironment,  
  70.                              __in_opt    LPCWSTR lpCurrentDirectory,  
  71.                              __in        LPSTARTUPINFOW lpStartupInfo,  
  72.                              __out       LPPROCESS_INFORMATION lpProcessInformation)  
  73. {  
  74.   
  75.     MessageBoxW(NULL, lpCommandLine, L"CreateProcessW", MB_OK);  
  76.   
  77.     return ((PCreateProcessW)g_CreateFunc)(  
  78.         lpApplicationName,   
  79.         lpCommandLine,  
  80.         lpProcessAttributes,  
  81.         lpThreadAttributes,  
  82.         bInheritHandles,  
  83.         dwCreationFlags,  
  84.         lpEnvironment,  
  85.         lpCurrentDirectory,  
  86.         lpStartupInfo,  
  87.         lpProcessInformation);  
  88. }  
  89.   
  90. int _tmain(int argc, _TCHAR* argv[])  
  91. {  
  92.     HMODULE hModule = NULL;  
  93.     GetModuleHandleEx(  
  94.         GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,  
  95.         (LPCTSTR)TestFunctionInIAT,  
  96.         &hModule);  
  97.     BOOL bReturn = TestFunctionInIAT( hModule , (ULONG_PTR)CreateProcessW );  
  98.     if ( bReturn )  
  99.     {  
  100.         printf("Found address CreateProcessW!\n");  
  101.     }  
  102.     else  
  103.     {  
  104.         printf("found failed!\n");  
  105.     }  
  106.   
  107.     g_CreateFunc = install_api_hook(hModule, "kernel32.dll", (PROC)CreateProcessW, (PROC)MyCreateProcessW);  
  108.       
  109.     wchar_t szProcessName[] = L"notepad.exe";  
  110.     STARTUPINFO si = {sizeof(si)};  
  111.     PROCESS_INFORMATION pi;   
  112.     CreateProcessW(NULL,  
  113.         szProcessName,  
  114.         NULL,  
  115.         NULL,  
  116.         FALSE,  
  117.         0,  
  118.         NULL,  
  119.         NULL,  
  120.         &si,  
  121.         &pi);  
  122.   
  123.     return 0;  
  124. }  
  125.   
  126. PROC install_api_hook(  
  127.                       HMODULE hHookModule,  
  128.                       const char * szDllName,   
  129.                       PROC pfnHookFunAddr,  
  130.                       PROC pfnNewFundAddr  
  131.                       )  
  132. {  
  133.     PROC pOrigFunc = NULL;  
  134.   
  135.     unsigned char *pBaseAddr =   
  136.         reinterpret_cast<unsigned char *>(hHookModule);  
  137.   
  138.     PIMAGE_DOS_HEADER pDosHeader =  
  139.         reinterpret_cast<PIMAGE_DOS_HEADER>(pBaseAddr);  
  140.   
  141.     PIMAGE_NT_HEADERS pNtHeader =   
  142.         reinterpret_cast<PIMAGE_NT_HEADERS>(  
  143.         pBaseAddr + pDosHeader->e_lfanew );  
  144.   
  145.     PIMAGE_OPTIONAL_HEADER pPEOptionHeader =   
  146.         &pNtHeader->OptionalHeader;  
  147.   
  148.     PIMAGE_DATA_DIRECTORY pIATDataDirectory =   
  149.         &(pPEOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);  
  150.   
  151.     PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor =   
  152.         reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(  
  153.         pBaseAddr + pIATDataDirectory->VirtualAddress );  
  154.   
  155.     for ( ; pImportDescriptor->Name; pImportDescriptor++ )    
  156.     {    
  157.         const char* pszModName =  
  158.             reinterpret_cast<const char*>(  
  159.             pBaseAddr + pImportDescriptor->Name);    
  160.         if ( 0 == lstrcmpiA( pszModName, szDllName ) )    
  161.         {  
  162.             break;    
  163.         }  
  164.     }    
  165.   
  166.     if ( 0 == pImportDescriptor->Name )  
  167.     {  
  168.         return pOrigFunc;  
  169.     }  
  170.   
  171.     PIMAGE_THUNK_DATA pThunkData =   
  172.         reinterpret_cast<PIMAGE_THUNK_DATA>(  
  173.         pBaseAddr + pImportDescriptor->FirstThunk);  
  174.     while( pThunkData->u1.Function != 0 )  
  175.     {  
  176.         PROC *ppFunc = reinterpret_cast<PROC*>(  
  177.             &pThunkData->u1.Function);  
  178.         if ( *ppFunc == pfnHookFunAddr )  
  179.         {  
  180.             DWORD dwOldProtect = 0;    
  181.             VirtualProtect( ppFunc, sizeof(PROC), PAGE_READWRITE, &dwOldProtect );    
  182.               
  183.             pOrigFunc = *ppFunc;  
  184.             CopyMemory(ppFunc, &pfnNewFundAddr, sizeof(PROC));  
  185. //          SIZE_T stMemorySize = 0;  
  186. //          WriteProcessMemory(   
  187. //              GetCurrentProcess(),  
  188. //              ppFunc,  
  189. //              &uNewFundAddr,  
  190. //              sizeof(*ppFunc),  
  191. //              &stMemorySize);  
  192.             VirtualProtect( ppFunc, sizeof(PROC), dwOldProtect, 0 );    
  193.             break;  
  194.         }  
  195.     }  
  196.   
  197.     return pOrigFunc;     
  198. }  

另外要获得导入表描述符,只要使用这个API ImageDirectoryEntryToData 就可以了,

但是这个API是有依赖的。我们使用Dumpbin,或者TC 都可以看到这个exe 确实使用kernel32 dll, 所以,我们下一步要替换我们的自己MyCreateProcessW. 将上面函数稍微优化一下,修改一下,就可以了,



然后在看这样的使用,那么一定会在CreateProcess 的时候,先弹出一个对话框,这样,就是我们的效果。

B)JMP 指令替换

现在你在网上搜索一下,说JMP指令替换的,一般都说保存函数入口处5个字节,其实这是相对地址跳转,当然了,如果使用了绝对跳转,那么就不至5个字节了,如果使用相对短地址跳转,当然少于5个字节,这个部分可以参看80x86 汇编instruction set, operator code.

这里我们也采用相对地址跳转,但是最后会说明如何用短跳转实现API hook, 因为这个很有用。至于是什么跳转,主要是他们跳转地址范围不同。相对地址跳转-2G到2G。

跳转的hook 的原理

第一种, 就是进入FunctionA 就跳转到FunctionB,做完B应该做的事情之后,将FunctionA的入口处的JMP去掉,回复到FunctionA原来的样子。 然后在Function B 中调用FunctionA,

当然这个地方你也可以不调用,根据你的功能决定, 然后再在FunctionA的入口布置JMP指令。 最后就是返回Caller。

我们看看如何实现,  这里补充一下,如何计算JMP指令后的operand. 就是跳转的相对地址。

Label1:

     Mov EAX, EAX

     Mov Edi, edi

...............................

Label2:

     JMP Label1

Label3:

     XOR EcX, EcX

那么如果是相对地址跳转JMP label1 汇编机器指令的以后,label1 这个位置的值是多少呢,因为只有知道这个如何计算,那么我们就知道怎么hardcode JMP 指令。因为计算机当执行

JMP Label1 的时候,地址译码机构已经完成了这条指令的译码,并将其送到了可执行单元,在可执行单元还没有开始执行的时候,地址译码机构不能闲着,已经将地址Label3已经装载到EIP中,当可执行单元进行执行JMP Label1的时候,其实是将EIP + JMP 指令operand 合成出来的,那么就有了下面的等式:

Label1 = EIP + operand;

EIP 等于label3 那么 

label1= Lebel3+ operand, 

那么

operand = Label1 - Label3.

这个是关键。

通常我们是不知道label3 的地址的,但是我们一定能知道lable2 的地址,这个地方就是我们要放JMP 指令的位置,如果我们放相对跳转的JMP 指令,该指令占用5个byte. 那么label3 就可以通过lable2 + JMP 指令的长度 计算出来。


[cpp]  view plain copy
  1. // JmpHook.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include <windows.h>  
  6.   
  7. unsigned char g_StubCode[6] = {0x0};  
  8. PROC g_CreateFunc = 0;  
  9. void restore_hook(PROC pfnOrigAddr);  
  10. void set_hook(PROC pfnOrigAddr, PROC pfnNewAddr );  
  11.   
  12. typedef BOOL (WINAPI *PCreateProcessW)(  
  13.                                        __in_opt    LPCWSTR lpApplicationName,  
  14.                                        __inout_opt LPWSTR lpCommandLine,  
  15.                                        __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,  
  16.                                        __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,  
  17.                                        __in        BOOL bInheritHandles,  
  18.                                        __in        DWORD dwCreationFlags,  
  19.                                        __in_opt    LPVOID lpEnvironment,  
  20.                                        __in_opt    LPCWSTR lpCurrentDirectory,  
  21.                                        __in        LPSTARTUPINFOW lpStartupInfo,  
  22.                                        __out       LPPROCESS_INFORMATION lpProcessInformation);  
  23.   
  24. BOOL WINAPI MyCreateProcessW1(  
  25.                              __in_opt    LPCWSTR lpApplicationName,  
  26.                              __inout_opt LPWSTR lpCommandLine,  
  27.                              __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,  
  28.                              __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,  
  29.                              __in        BOOL bInheritHandles,  
  30.                              __in        DWORD dwCreationFlags,  
  31.                              __in_opt    LPVOID lpEnvironment,  
  32.                              __in_opt    LPCWSTR lpCurrentDirectory,  
  33.                              __in        LPSTARTUPINFOW lpStartupInfo,  
  34.                              __out       LPPROCESS_INFORMATION lpProcessInformation)  
  35. {  
  36.   
  37.     restore_hook(g_CreateFunc);  
  38.   
  39.     MessageBoxW(NULL, lpCommandLine, L"CreateProcessW", MB_OK);  
  40.   
  41.     BOOL bRetCode = ((PCreateProcessW)g_CreateFunc)(  
  42.         lpApplicationName,   
  43.         lpCommandLine,  
  44.         lpProcessAttributes,  
  45.         lpThreadAttributes,  
  46.         bInheritHandles,  
  47.         dwCreationFlags,  
  48.         lpEnvironment,  
  49.         lpCurrentDirectory,  
  50.         lpStartupInfo,  
  51.         lpProcessInformation);  
  52.   
  53.     set_hook(g_CreateFunc, (PROC)MyCreateProcessW1);  
  54.   
  55.     return bRetCode;  
  56. }  
  57.   
  58.   
  59. void set_hook(PROC pfnOrigAddr, PROC pfnNewAddr )  
  60. {  
  61.     unsigned char *pSrcAddr =   
  62.         reinterpret_cast<unsigned char *>( pfnOrigAddr );  
  63.   
  64.     unsigned char *pDestAddr =   
  65.         reinterpret_cast<unsigned char *>( pfnNewAddr );  
  66.   
  67.     ULONG uOperand = static_cast<ULONG>  
  68.         ( pDestAddr - (pSrcAddr + 5) );  
  69.   
  70.     CopyMemory(g_StubCode, pSrcAddr, 5);  
  71.   
  72.     DWORD dwOldProtect = 0;    
  73.     VirtualProtect( pSrcAddr, 5, PAGE_READWRITE, &dwOldProtect );   
  74.   
  75.     unsigned char szJMPCode[5] = {0xE9};  
  76.     CopyMemory(&szJMPCode[1], &uOperand, 4);  
  77.     CopyMemory(pSrcAddr, szJMPCode, 5 );  
  78.   
  79.     VirtualProtect( pSrcAddr, 5, dwOldProtect, NULL );   
  80. }  
  81.   
  82. void restore_hook(PROC pfnOrigAddr)  
  83. {  
  84.     unsigned char *pSrcAddr =   
  85.         reinterpret_cast<unsigned char *>( pfnOrigAddr );  
  86.     DWORD dwOldProtect = 0;    
  87.     VirtualProtect( pSrcAddr, 5, PAGE_READWRITE, &dwOldProtect );   
  88.     CopyMemory(pSrcAddr, g_StubCode, 5);  
  89.     VirtualProtect( pSrcAddr, 5, dwOldProtect, NULL );   
  90. }  
  91.   
  92. int _tmain(int argc, _TCHAR* argv[])  
  93. {  
  94.     g_CreateFunc = GetProcAddress(GetModuleHandle(L"kernel32.dll"),"CreateProcessW");  
  95.       
  96.     set_hook(g_CreateFunc, (PROC)MyCreateProcessW1);  
  97.     wchar_t szProcessName[] = L"notepad.exe";  
  98.     STARTUPINFO si = {sizeof(si)};  
  99.     PROCESS_INFORMATION pi;   
  100.     CreateProcessW(NULL,  
  101.         szProcessName,  
  102.         NULL,  
  103.         NULL,  
  104.         FALSE,  
  105.         0,  
  106.         NULL,  
  107.         NULL,  
  108.         &si,  
  109.         &pi);  
  110.   
  111.     return 0;  
  112. }  

基本上就是这个样子了,但是这个有一个致命的缺点,就是如果是多线程,那么可能hook 不到,怎么回事呢?我淫荡的笑,哈哈.........................

那么第二种JMP hook 技术就出来。

首先和第一种一样都有一个g_StubCode,而这个大小已经变大了,不再是5个Byte, 为什么呢,就是hook 完毕之后,就不但算在恢复原来函数的入口的字节了,等跳转到我们自己函数中,做完要做的事情,然后通过stubCode 在返回原来的函数,这样说明了一个问题,就是这样hook 只能在原来函数之前做事,之后,就不能做事了,只能直接返回,当然有没有可能还能做事情呢,能,怎么办,有点复杂。 这里我们先讨论,简单这种。

1. 替换原来函数如果处若干个字节,但是必须大于要放JMP指令字节数,那么这个若干是多少呢?因为相对地址JMP,是5个字节,原函数入口处5个字节正好是完整指令,那么没有问题,如果5个自己不是完整指令,那么这样将一个指令劈成两半的做法是不是很不道德呢。所以这里应该使用反汇编的手法识别出完成指令,且这些指令的长度是大于JMP指令长度的最小值。

2. 将识别出的完整指令备份到stubCode, 然后将原来函数入口处写入JMP指令。

3. 在stubcode 尾部也加入JMP指令,这个JmP指令跳转到原来函数备份到stubCode 中的下一条指令,这样就可以无缝连接在一起了,哈哈,我淫荡的笑啊,我淫荡的笑。。。。。

4. 在新函数的结束的地方将stubCode 强转为该类型的函数指针,调用返回。

上代码:

[cpp]  view plain copy
  1. #include "sethook.h"  
  2. #include "disasm.h"  
  3. BOOL InstallHook (HOOK_DATA *pHook)   
  4. {  
  5.     ULONG dwJmpDst = 0;  
  6.     int nInstSize = 0;  
  7.     int nInstSizeIfMoved = 0;  
  8.     int nLoop = 0;  
  9.     BOOLEAN bRetCode = FALSE;     
  10.   
  11.     pHook->nHeadSize = 0;  
  12.     pHook->nStubSize = 5; // == sizeof(JMP rel32)  
  13.   
  14.     while (pHook->nHeadSize < 5) // need at least 5 char to path  
  15.     {  
  16.         bRetCode = Dasm_GetInstructionSize(pHook->pTargetFunc + pHook->nHeadSize, &nInstSize, &nInstSizeIfMoved);  
  17.         if (bRetCode == FALSE)  
  18.         {  
  19.             return FALSE;  
  20.         }  
  21.   
  22.         pHook->nHeadSize += nInstSize;  
  23.         pHook->nStubSize += nInstSizeIfMoved;  
  24.   
  25.         if (pHook->nStubSize >= MAX_STUB_SIZE)   
  26.         {  
  27.             return FALSE;  
  28.         }        
  29.     }  
  30.   
  31.     memcpy(pHook->pHead, pHook->pTargetFunc, pHook->nHeadSize);  
  32.   
  33.     // create stub  
  34.     bRetCode = Dasm_MoveProgram(pHook->pTargetFunc, pHook->nHeadSize, pHook->pStub, &pHook->nStubSize, MAX_STUB_SIZE);  
  35.     if (bRetCode == FALSE)  
  36.     {  
  37.         return FALSE;  
  38.     }  
  39.   
  40.     if ( (UCHAR)pHook->pTargetFunc[0] == 0xE9)  
  41.     {  
  42.         ULONG ulDstAddr = (ULONG)pHook->pTargetFunc + 5 + *(PULONG)(pHook->pTargetFunc + 1);  
  43.         ULONG ulSrcAddr = (ULONG)pHook->pStub + 5;  
  44.         dwJmpDst = ulDstAddr - ulSrcAddr;         
  45.         pHook->pStub[0] = 0xE9;  
  46.         memcpy(&pHook->pStub[1], &dwJmpDst, 4);  
  47.     }  
  48.   
  49.     // add jmp at the end of the stub  
  50.     dwJmpDst = (ULONG)pHook->pTargetFunc - (ULONG)pHook->pStub - pHook->nStubSize;  
  51.     pHook->pStub[pHook->nStubSize] = 0xE9; // JMP rel32  
  52.     memcpy(&pHook->pStub[pHook->nStubSize+1], &dwJmpDst, 4);  
  53.     pHook->nStubSize += 5;  
  54.   
  55.     DWORD dwOldProtect = 0;  
  56.     VirtualProtect(pHook->pTargetFunc, pHook->nHeadSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);  
  57.     pHook->pTargetFunc[0] = 0xE9; // JMP rel32  
  58.     dwJmpDst = (ULONG)pHook->pHookFunc - (ULONG)pHook->pTargetFunc - 5; // 5==sizeof(JMP rel32)  
  59.     memcpy(pHook->pTargetFunc + 1, &dwJmpDst, 4);  
  60.   
  61.     for (nLoop = 5; nLoop < pHook->nHeadSize; nLoop ++)  
  62.         pHook->pTargetFunc[nLoop] = 0x90; // NOP  
  63.   
  64.   
  65.   
  66.     return TRUE;  
  67. }  

[cpp]  view plain copy
  1. int  WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uiType)  
  2. {  
  3.   
  4.     return ((pMessageBoxW)&g_pData->pStub)(  
  5.         hWnd,  
  6.         lpText,  
  7.         lpCaption,  
  8.         uiType);  
  9.   
  10.     return 0;  
  11. }  
  12.   
  13. BOOL WINAPI MyCreateProcessW( __in_opt LPCWSTR lpApplicationName,  
  14.                       __inout_opt LPWSTR lpCommandLine,  
  15.                       __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,  
  16.                       __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,  
  17.                       __in BOOL bInheritHandles,  
  18.                       __in DWORD dwCreationFlags,  
  19.                       __in_opt LPVOID lpEnvironment,  
  20.                       __in_opt LPCWSTR lpCurrentDirectory,  
  21.                       __in LPSTARTUPINFOW lpStartupInfo,  
  22.                       __out LPPROCESS_INFORMATION lpProcessInformation )  
  23. {  
  24.     return ((PCreateProcessW)(&g_pData->pStub))( lpApplicationName,  
  25.         lpCommandLine,  
  26.         lpProcessAttributes,  
  27.         lpThreadAttributes,  
  28.         bInheritHandles,  
  29.         dwCreationFlags,  
  30.         lpEnvironment,  
  31.         lpCurrentDirectory,  
  32.         lpStartupInfo,  
  33.         lpProcessInformation);  
  34. }  
  35.   
  36.   
  37.   
  38. int _tmain(int argc, _TCHAR* argv[])  
  39. {  
  40.   
  41.     PCreateProcessW pOrigMBAddress = (PCreateProcessW)GetProcAddress( GetModuleHandle(_T("kernelbase.dll")), "CreateProcessW" );  
  42.       
  43.     //BeginRedirect(MyMessageBoxW);  
  44.   
  45.     HOOK_DATA *pData = new HOOK_DATA;  
  46.     g_pData = pData;  
  47.     pData->pTargetFunc = (PUCHAR)pOrigMBAddress;  
  48.     pData->pHookFunc = (PUCHAR)MyCreateProcessW;  
  49.   
  50.     //InstallHook( pData );  
  51.   
  52.     TCHAR szProcessNAme[60] = L"notepad.exe";  
  53.       
  54.     STARTUPINFOW info = { sizeof(info)};  
  55.     PROCESS_INFORMATION Pi = {0};  
  56.     CreateProcessW( NULL,  
  57.         szProcessNAme,  
  58.         NULL,  
  59.         NULL,  
  60.         FALSE,  
  61.         0,  
  62.         NULL,  
  63.         NULL,  
  64.         &info,  
  65.         &Pi);  
  66.   
  67.     return 0;  
  68. }  

可以明显的看到,这样hook 的优势所在. API hook 基本就是这样了,JMP short 的这种怎么实现的,一般我们要看看windows API 的函数汇编,


0x74cd43AB 是CreateProcessW 的地址,这个函数进来的第一件事,就是mov edi, edi 这条指令看起来很蛋疼,但是这个蛋疼的指令,却有着很牛叉的意义,另外MS的所有API都是这样的,这个是一个公开的秘密,在这里放一个JmP short , 那么这个JMP short 跳转的是-127 ~ 127 那么我们怎么可能将函数放到MS API的位置呢,看到函数上面的5个nop 了,

这个5个字节,怎么这么适合放相对地址JMP far,  我淫荡的笑啊.... 剩下的和我们刚才的一样啦,这个技术就是MS在放补丁时候,hot fix 就是这样的。MS都在用,你就放心的用吧,要死大家一起死。

API hook 在本进程中,无非就是兀自手淫,没有什么大意义,那么如何才能将API hook 放到别人的进程中,我们这里讨论两种技术,第一种CreateRomoteThread, 第二种Windows hook,.

1 CreateRomoteThread 

用法很简单,

1. 准备一个dll, 在DllMain中的 DLL_PROCESS_ATTACH 中,进行sethook 调用,那么就是可以hook 本进程了。

2. 将这个dll 放到要hook 的进程中去

[cpp]  view plain copy
  1. void Inject(LPCTSTR lpszDllPath, DWORD dwProcessID )  
  2. {  
  3.     HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwProcessID );  
  4.     if ( hProcess != NULL )  
  5.     {  
  6.         LPVOID pAddr = VirtualAllocEx(  
  7.             hProcess,  
  8.             NULL,   
  9.             (_tcslen(lpszDllPath) + 1) * sizeof(*lpszDllPath),   
  10.             MEM_COMMIT | MEM_RESERVE,  
  11.             PAGE_EXECUTE_READWRITE);  
  12.   
  13.         if ( pAddr != NULL )  
  14.         {  
  15.             SIZE_T uSize = 0;  
  16.             WriteProcessMemory(  
  17.                 hProcess,  
  18.                 pAddr,  
  19.                 lpszDllPath,  
  20.                 (_tcslen(lpszDllPath) + 1) * sizeof(*lpszDllPath),  
  21.                 &uSize);  
  22.   
  23.            HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, pAddr, 0, 0 );  
  24.            CloseHandle( hThread );  
  25.         }  
  26.     }  
  27. }  

但是常常因为你没有足够的权限而失败,那么Windows hook 技术就可以帮助到我们了。

Windows hook 技术

大家可以看看http://en.wikipedia.org/wiki/Hooking  对hook 的一种通用解释,

Windows 上主要使用SetWindowsHookEx 或者不带EX的函数,首先我们看看

HHOOK WINAPI SetWindowsHookEx(

  __in  int idHook,

  __in  HOOKPROC lpfn,

  __in  HINSTANCE hMod,

  __in  DWORD dwThreadId

);

这个API的用法,idHook 表示你要hook 那种事件,如键盘,消息,等,

Lpfn 表示hook 处理函数

Hmod 模块句柄,这个就是dll 的句柄

dwThreadId 表示要hook 那个线程的,如果是0, the hook procedure is associated with all existing threads running in the same desktop as the calling thread.  就是说当前桌面的所有线程都会加载到这个dll. 厉害了吧,我淫荡的笑。。。。。。。。。。。。。

SetWindowsHookEx 一般成功了返回了hook 的句柄,但是这个句柄要在hook 的处理函数中使用,我们不是说,将hook 处理函数写在dll 中,那么dll 的在A进程调用了SetWindowsHookEx ,那么dll 映射到B进程中,可是hook 句柄在A进程中,那么B中的hook 处理函数,如何才能使用这个hook 句柄呢?当然进程通信的方式很多,这里使用一种比较简单的策略,就是dll 中增加一个共享数据段。这个共享数据段,就是当dll 映射到不同进程中,每个进程都可以看到这里数据,而且其中一个进程改变这个区域的数据,其他进程也就看到了。


[cpp]  view plain copy
  1. #pragma comment(linker, "/SECTION:.myseg,RWS")   
  2. #pragma data_seg (".myseg")  
  3. HWND g_Hwnd = NULL;  
  4. HHOOK g_HookHandle = NULL;  
  5. #pragma data_seg()  

做个简单解释,dll 中在不同进程可能相同的内容,映射的地址不同,因为不同进程空间,各自不能直接地址访问,dll 的可读部分,进程中其实大家共享一份,只是映射的在virtual address 不同而已,但是将A进程要去写dll 中的数据,那么对不起,这个时候,OS就会重新分一块空间给A就写,A写进去的,就是A的,不会影响到B进程,但是共享数据段,就是所有进程的将使用同一份物理内存,虽然这个空间在不同进程中的地址不同,但是却是同一块物理内存,这样A写了进去,B就可以看到。

哈哈, 有了这样的技术,大家想干什么就干什么了, 你说是不是呢

http://download.youkuaiyun.com/detail/zwh37333/4225393

http://download.youkuaiyun.com/detail/zwh37333/4225395

上面的位置,是源码。

hook原理介绍与简单实例 一、HOOK介绍 1、什么是HOOK(钩子) HOOK技术即钩子函数,钩子函数是Windows消息处理机制的一部分,通过设置“钩子”,应用程序可以在系统级对所有消息、事件进行过滤,访问在正常情况下无法访问的消息。 钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。 ... 阅读详情

相关推荐

Windows C++ Hook技术实战:Detour框架原理与API拦截应用

Hook技术是系统编程和软件安全领域的核心概念,它通过在程序执行流程中插入自定义代码来拦截、监控或修改原有函数行为。其实现原理主要基于二进制代码修改,常见方式包括Inline Hook、IAT Hook等,通过在目标函数入口处插入跳转指令实现控制流重定向。这项技术的工程价值在于能够在不修改源码的情况下扩展第三方程序功能、进行API监控调试、实现性能分析或安全防护。在实际应用场景中,Hook技术广泛用于软件调试、游戏修改、安全研究和系统监控等领域。本文以微软Detour框架为例,深入解析其基于Trampoli

weixin_31858171的博客 267

API 与 Webhook,其实并没有那么难懂

API 和 Webhook 都允许不同的软件系统同步和共享信息,随着软件应用程序变得越来越相互关联,开发人员必须了解这两种共享数据方式之间的区别,并选择最能满足手头任务需求的工具。

meiqia888的博客 2168

Windows API Hook实战:从Inline Hook原理到C++实现与Detours应用

在Windows系统编程与软件安全领域,API拦截(Hook)是一项核心技术,它允许开发者在函数调用过程中插入自定义代码,实现对系统行为的监控与修改。其原理主要分为修改导入地址表的IAT Hook和直接覆盖函数机器码的Inline Hook两种方式。这项技术的核心价值在于为调试分析、安全监控、性能优化等场景提供了底层解决方案。通过理解内存保护、指令备份、蹦床函数等关键机制,开发者能够构建稳定的拦截系统。在实际工程中,微软Detours库封装了线程安全、指令修复等复杂细节,是生产环境的首选工具。本文以C++实

weixin_33725515的博客 362

hook API 详解

来源:http://cisco.chinaitlab.com/safety/366596.html详谈HOOK API的技术HOOK API是一个永恒的话题,如果没有HOOK,许多技术将很难实现,也许根本不能实现。这里所说的API,是广义上的API,它包括DOS下的中断,WINDOWS里的API、中断服务、IFS和NDIS过滤等。比如大家熟悉的即时翻译软件,就是靠HOOK TextOut()或Ex

jsl8998620的专栏 1878

Windows API拦截实战:Detours Hook原理、配置与监控应用

API拦截(Hook)是Windows系统编程中的一项关键技术,它允许开发者在运行时动态修改或监控函数行为,而无需修改原始二进制代码。其核心原理通常涉及修改目标函数入口指令,将执行流重定向到自定义函数,再通过“蹦床”(Trampoline)机制安全地调用原函数。这项技术在软件调试、性能分析、安全监控和功能扩展等场景中具有重要价值。例如,在遗留系统分析、第三方组件行为监控或运行时诊断等场景,无侵入式的API拦截能有效解决源码缺失或服务不可中断的难题。本文以微软开源的Detours库为例,深入解析其通过指令修改

weixin_33691817的博客 448

API hook原理和实例快速入门(inline hook),以dll线程注入方式使用(win7-64bit)

一个完整的hook,如果hook程序是以dll形式生成的,是分两步:1.完成dll本身的设计和生成,2.完成dll注入程序的设计和生成 本文完成第一步。 第二步在http://blog.youkuaiyun.com/arvon2012/article/details/7767437有详细讲解。   最近在64位win7上hook文件复制,拖拽和剪切的hook(这个要通过hook IFileOperat

扣的CODE 1万+

Windows API Hook技术原理与实战应用

Hook技术是系统编程中的核心拦截机制,通过修改函数调用链实现行为监控与功能扩展。其原理基于内存指令重定向,关键技术包括DLL注入、调试API和异常处理。在Windows平台下,API Hook广泛应用于安全审计、性能分析和遗留系统改造等场景。现代框架如Detours和Frida通过封装底层细节,显著降低了Hook技术的实现门槛。特别是在自动化测试和逆向工程领域,结合热词中的DLL注入和异常处理技术,开发者可以构建强大的运行时分析工具。

weixin_32705179的博客 117

掌握API Hook技术:以Detours为案例

API Hook技术是编程中一种高级技术,通过在运行时拦截对API函数的调用来修改或扩展其原始行为。在软件开发、安全分析和性能调优等领域,API Hook技术被广泛使用。它允许开发者在不修改原始代码的情况下,控制和监督API函数的调用过程和结果。Detours是微软研究院发布的一个用于拦截Win32 API调用的库,其核心功能是允许开发者在不修改原始DLL文件的情况下,拦截和修改API调用。

weixin_35762258的博客 561

深入探索Windows Hook技术:原理、内核级实现与高级应用

Hook(钩子)是Windows系统中用于监视和拦截特定事件的核心机制,通过注入自定义代码到目标进程的消息处理流程中,开发者能够捕获并处理键盘输入、鼠标操作、窗口消息等系统事件。

@ 2373

C++实现API Hook拦截MessageBox窗口系统项目

MFC的消息机制是Windows事件驱动模型的抽象体现,通过消息队列、消息循环以及消息映射三大核心组件构建起整个框架的响应体系。理解这一机制是实现MFC消息拦截与处理的前提。消息过滤是指根据预设规则判断是否允许某条消息继续传递。可以通过在钩子回调或窗口过程中添加判断逻辑实现。// 自定义过滤规则// 屏蔽鼠标移动消息return 1;// 返回非零值表示已处理,消息不再传递过滤规则逻辑说明:若返回值为非零,则系统认为消息已被处理,不再传递给窗口过程。

weixin_42462474的博客 933

( WindowsAPI HOOK以及Rootkits资料大全.part18.rar )

( WindowsAPI HOOK以及Rootkits资料大全.part18.rar )

Windows API学习-Hook学习

最近在参加ISCC,里面有一道与驱动Dll注入有关的题目,

RickGray 1247

Mac电脑用Latex论文排版3天速成5天实战de笔记

我后悔了,这五天竞赛搞得我视力都下降了...一个冲动的决定后成为数模竞赛论文写手,3天速成+5天时间=点亮攻克latex写论文技能💡关于Overleaf我是Mac,曾经按照大部分推荐的方式用TEXshop+vs code,但是把模板导入就开始报错。跟着少之又少的适配mac的教程(此时我已知道大概是走错路了)改了配置也无效。海鲜市场找佬改了半天,佬问我:一定要用VC吗?我说,那倒也不是。于是佬推荐我overleaf,三下五除二帮我挑配了环境,美汁汁收了我30块钱。

luwanjoyce的博客 2251

基于HOOK的应用层进程隐藏

基于HOOK的应用层进程隐藏 要求:开发一个可以将指定的用户进程进行隐藏工具,要求在“任务管理器”无法检测的该用户进程,也无法终止该进程。 一、HOOK原理 对于 Hook 技术,可以分为两块,第一块是在 Ring3 层的 Hook,俗称应用层 Hook 技术,而另外一块自然是在 Ring0 层得 Hook,俗称为内核层 Hook 技术,而在 Ring3 层的 Hook 基本上可以分为两种大的类型,第一类即是 Windows 消息的 Hook,第二类则是 Windows API 的 Hook。每个调用的 A

weixin_40921670的博客 1864

说一下Intel Fortran 编译器经典版ifort和新一代ifx

摘要:ifort是Intel开发的传统Fortran编译器,以稳定性和遗留代码兼容性著称,现已进入维护模式。ifx则是基于LLVM架构的新一代Fortran编译器,具有更好的性能优化、更快的编译速度,并支持最新Fortran标准和GPU加速。英特尔计划逐步用ifx取代ifort,前者将成为未来主力发展的产品线。两者的核心区别在于技术基础(传统vs.现代化LLVM)和功能支持(维护状态vs.持续更新)。

luohaitao的专栏 1347

Dify工作流自动化:如何用Trae AI助手10倍提升你的开发效率(含避坑指南)

本文详细介绍了如何利用Trae AI助手自动化生成Dify工作流,实现开发效率的10倍提升。通过构建DSL示例库、精准需求描述和四步实战法,开发者可将重复的配置工作交给AI,快速生成可运行的工作流,并提供了关键的避坑指南。

weixin_29062865的博客 371

API Hook基本原理和实现

[size=large][color=red][b]hook是什么?[/b][/color][/size]   [color=green][size=medium]windows系统下的编程,消息message的传递是贯穿其始终的。这个消息我们可以简单理解为一个有特定意义的整数,正如我们看过的老故事片中的“长江长江,我是黄河”一个含义。windows中定义的消息给初学者的印象似乎是“不计其数”的...

iteye_6510的博客 128

光模块封装工艺简介

光模块按照部件可以分为芯片、光器件、光模块三个层级;按照应用领域大概可分为电信应用、数通应用两个领域;按照内部器件的封装工艺可分为TO、Box、COB三大类。 但是,无论是哪种类型的光模块,其生产工艺基本上可以分为封装、测试两大块。   那什么叫做器件封装呢?我的理解器件封装就是利用胶水、焊料、机械、热量等手段把器件按照一定的先后次序结合形成一个整体的过程,就好像早上吃的煎饼,把面粉、鸡蛋、脆饼、烤肠、葱花等这些“器件”,按照一定的顺序,通过食用油、甜面酱、加热、卷起来等手段结合到一起,形成了美味的

qq_33253182的博客 2832

HOOK API技术

HOOk API技术 HOOK学习笔记与心得 奇技淫巧之调试被远程线程注入的DLL windows核心编程_系统消息与自定义钩子hook使用 [Windows Dll Injection、Process Injection、API Hook、DLL后门/恶意程序入侵技术] Hook :Microsoft Detours 2.1简介 detours3.0文档 Hook简单实用 detours ...

【黑键】 4583

工业缺陷检测深度学习方法综述

异常:点异常、 上下文异常和集群异常。点异常:又称为离群值 (outliers)[9], 描述数值上偏离正 常样本的独立数据。与异常相近的概念还包括新颖点(novelty)和分布外数据。上下文异常:同样描述数据点,其数值属于正常范围,但不符合局部上下文规律。集群异常:描述一系列相关数据的集合,集合中的每一个实例的数值在单独考察时都处于正常值域,但集 合整体的相关性特征不服从正常模式。一般的图像异常检测往往仅需区分正常与异常样本,而工业缺陷检测更关注于检测 图像中的异常像素.

2301_80355452的博客 1844

SpringCloud最新最全面试题

在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心存放服务地址相关信息(接口地址)。

qq_38196449的博客 4329

Hook基本知识

一、什么是HOOK(钩子) Windows系统,建立在事件驱动机制上,就是整个系统都是通过消息传递实现的。hook(钩子)是一种特殊的消息处理机制,它可以监视系统或者进程中的各种事件消息,截获发往目标窗口的消息并进行处理。 钩子的种类很多,每种钩子可以截获相应的消息,如键盘钩子可以截获键盘消息,外壳钩子可以截取、启动和关闭应用程序的消息等。钩子可以分...

weixin_30616969的博客 2600

试读源码在这里下载

试读文章的源码在这里下载。源码不做任何修改,重点重点重点:为了代码运行不报错,安装matlab 版本为 2021 及以上版本。matlab安装教程大家可以参考这个教程:手把手教你安装matlab软件。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 4306
上一篇: zigbee中有几个不同的频率,是啥意思?有啥联系和区别
下一篇: 函数开始处的MOV EDI, EDI的作用收藏
linuxheik
博客等级 码龄15年 865粉丝 135原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值