精华内容
下载资源
问答
  • HOOK

    千次阅读 2016-02-17 10:14:30
    HOOK是一种通过更改程序的数据结构或代码结构从而改变程序运行路线的一种方法。其中包括用户模式的HOOK和内核模式的HOOK(Windows 64bit 系统有SG保护,有些HOOK不能这样简单的实现,此处仅仅记录方法)。 用户层...

    HOOK是一种通过更改程序的数据结构或代码结构从而改变程序运行路线的一种方法。其中包括用户模式的HOOK和内核模式的HOOK(Windows 64bit 系统有SG保护,有些HOOK不能这样简单的实现,此处仅仅记录方法)。


    用户层的HOOK:IAT-HOOK,  远程线程DLL注入,远程线程代码注入,内联HOOK(可用mHOOK库)

    其中IAT-HOOK主要是修改程序PE文件中的IAT表,改变函数的调用位置,但用的比较多的还是DLL注入的方法。DLL注入的方法主要是通过创建远程线程的方法将自定义的DLL文件通过系统函数LoadLibrary加载到目标进程,然后可以通过使用热键的方式,启动和关闭目标进程的HOOK。


    内核层的HOOK:SSDT-HOOK, IDT-HOOK,INLINE-HOOK

    SSDT--- 系统服务描述符表

    IDT--- 中断描述符表

    INLINE--- 内联

    其实HOOK的思想都是差不多的,基本上都是

    1、先保存要HOOK位置原来的数据。

    2、修改内存访问属性。

    3、写入HOOK数据到要HOOK的位置。

    其实HOOK就是跟二进制的机器码打交道,所以还需要懂得一些机器码的基本知识。E8---call E9----jmp 等等。。


    其实学习内核HOOK主要是为了学习使用windbg的内核调试,在驱动编写时难免会出现这样那样的问题,windbag可谓是驱动调试的一把利剑。同时也学习一些hook的基本思路和方法。(内核HOOK在xp系统下)

    首先内核HOOK必须在内核模式下,所以用驱动来实现HOOK。此处采用NT模式驱动,实现OpenProcess的SSDT-HOOK 。

    一、驱动编写的框架

    #pragma code_seg("INIT")
    extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryPath)
    {
    //	__asm int 3
    	NTSTATUS status = STATUS_SUCCESS;
    
    	//注册驱动函数及其他入口
    	pDriverObj->DriverUnload = UnloadDriver;
    
    	pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchRoutine;
    	pDriverObj->MajorFunction[IRP_MJ_READ]	 = DispatchRoutine;
    	pDriverObj->MajorFunction[IRP_MJ_WRITE] = DispatchRoutine;
    	pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchRoutine;
    
    	pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControlRoutine;
    	//nt 式的驱动中需要在DriverEntry中创建设备对象
    
    	status = CreateDevice(pDriverObj);
    
    	//HookNtOpenProcess();//此处实现HOOK
    	KdPrint(("Driver Load Success! +++++++\n"));
    	return status;
    }

    此处为驱动的入口函数,类似于main函数,加载驱动的时候首先会调用此函数。然后注册相应的IRP对应的函数调用例程,类似于回调函数或者消息相应的函数更为贴切。其中IRP_MJ_DEVICE_CONTROL是通过IOCTROL的方式来与应用层进行通信。所以HOOK函数最简单的实现方式就是写在这个函数里面。

    二、HOOK函数

    1、通过OD跟踪或者KD或者xuetr等工具都可以查找到OpenProcess在SSDT表的index为257,所以就直接用了

    2、KeServiceDescriptorTable是xp系统已经导出的结构

    3、UserOpenProcess是我自己定义的HOOK函数

    4、NtOpenProcessAddr是保存原先函数地址的全局变量

    void HookNtOpenProcess()
    {
    	ULONG index = 257;
    	PULONG SSDTOpenProcessAddr;
    
    	ULONG UserOpenProcessAddr = (ULONG)UserOpenProcess;
    	__asm
    	{
    		push eax
    			push ebx
    			mov eax, KeServiceDescriptorTable
    			mov ebx, [eax]
    			mov eax, index
    			lea eax, [ebx + 4*eax]
    			mov SSDTOpenProcessAddr, eax
    			pop ebx
    			pop eax
    	}
    
    	//去掉页面保护
    	__asm 
    	{
    		cli
    			mov eax, cr0
    			and eax, not 10000h //and eax,0FFFEFFFFh
    			mov cr0, eax
    	}
    	NtOpenProcessAddr = *SSDTOpenProcessAddr;
    	*SSDTOpenProcessAddr = UserOpenProcessAddr;
    	//恢复页面保护
    	__asm
    	{
    		mov     eax, cr0
    			or     eax, 10000h
    			mov     cr0, eax
    			sti
    	}
    	KdPrint(("Hook NtOpenProcess\n"));
    }
    到此出已经实现了一个简单的SSDT-HOOK,要想UNHOOK只需要把原先的地址再写入到相应的SSDT中即可。


    三、思考 怎样就可以知道SSDT是否被HOOK呢
    有一个内核函数MmGetSystemRoutineAddress可以得到原先函数的地址,与SSDT中得到的函数地址比较,一致则表示没有被SSDT-HOOK,有了这些知识,那么INLINE-HOOK的实现就简单许多了。








    展开全文
  • Hook

    万次阅读 2016-11-17 23:59:47
    Hook 钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许...

    Hook

    钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

             可以输入监控、API拦截、消息捕获等方面。

             DOS时代的HOOK技术就是修改中断向量表中的中断地址。

             HOOK技术会涉及到DLL相关知识。

    展开全文
  • hook

    2015-10-19 19:20:00
    我们hook的就是第18行(0042EC7B)那句代码,setHookBytes构建了一个5字节的call语句,0xe8为CALL指令的机器码,后面4个字节是CALL的偏移量(目标地址 - 当前地址 - CALL指令占用的5个字节)。 ...

    我们hook的就是第18行(0042EC7B)那句代码,setHookBytes构建了一个5字节的call语句,0xe8为CALL指令的机器码,后面4个字节是CALL的偏移量(目标地址 - 当前地址 - CALL指令占用的5个字节)。






     

    Inline Hook 之(监视任意函数)

    分类: 汇编语言 C/C++ inline汇编语言 18721人阅读 评论(23) 收藏 举报

    前面已经写过两次inline hook的博文了,第一篇为:《C/C++ HOOK API(原理深入剖析之-LoadLibraryA)》,这篇博文的方法是通过修改任意函数的前面N个字节,实现跳转并进入到我们自定义的hook函数里,执行完毕我们的hook函数之后,再直接调用被hook的函数。第一篇的方法没有考虑多线程的情况,所以在多线程环境下会有问题。第二篇为:《 Inline HOOK API 改进版(hot-patching)》,这篇的初衷是为了解决多线程的问题,因为这种方式是一直hook的,直到程序结束。因此在多线程情况下,并不会在hook与unhook期间执行被hook的函数。不过,第二种方式有局限性,它主要针对windows的很多API而设计,在函数头部必须有空闲的两个字节和函数首地址之前的5个空闲字节(一般为5个nop指令),这样能够实现一个short jmp和一个long jmp。从而实现了hook,在此就不再累述了。

     

    好了,本文已经是第三次写hook相关的东西了。前两种hook有个共同点就是他们都是直接hook掉某个函数,也就是说,当执行完我们自定义的hook函数之后,又从被hook函数的首部开始执行,被hook函数一进入就被跳转了。而本文,则要实现在某个函数体内部任意地方进行hook并跳转,执行完我们的函数之后,再回到原来的位置继续向下执行完未执行的逻辑。那么,初看这种方式似乎与前面写的两篇hook没有什么差别,都是hook,都是跳转然后回到被hook的函数。但仔细一想,你会发现本文要实现的方式要比前面两种hook复杂,因为hook的地方是函数体内任意地方,那么回来的时候就不是直接调用被hook的函数了,而是要回到之前hook的地方去。这期间就涉及到hook函数的返回地址问题和被hook函数的返回地址问题。

     

    说了这么多,可能还是有点晕,先不管为什么要这么做,也不管这种hook方式能有什么用途(在本文最后会说明用途),下面我们先写一些代码,在实践中来想一想这种方式有什么用途,并且与之前的两篇hook进行比较。

     

    首先,我们需要一个自定义的hook函数,这个函数也就是被hook函数被hook后跳转到的地方,这个hook函数负责hook与unhook,还可以监视寄存器,监视内存,也可以管理hook的次数,以供我们灵活的hook需求。直接贴代码吧:

    1. #include <iostream>  
    2. #include <windows.h>  
    3.   
    4. #pragma warning( disable : 4311 )  
    5. #pragma warning( disable : 4312 )  
    6.   
    7. #define HOOK_BYTES 5  
    8. typedef unsigned int uint;  
    9.   
    10. uint  hookAddr = 0;  
    11. char  old_code[ HOOK_BYTES ];  
    12. char  new_code[ HOOK_BYTES ];  
    13.   
    14. void printRegisters( void );  
    15.   
    16. bool hook( void )  
    17. {  
    18.     DWORD dwFlag;  
    19.     if ( VirtualProtect( ( void* )hookAddr, HOOK_BYTES, PAGE_EXECUTE_READWRITE, &dwFlag ) )  
    20.     {  
    21.         memcpy( old_code, ( void* )hookAddr, HOOK_BYTES );  
    22.         memcpy( ( void* )hookAddr, new_code, HOOK_BYTES );  
    23.         VirtualProtect( ( void* )hookAddr, HOOK_BYTES, dwFlag, &dwFlag );  
    24.         return true;  
    25.     }  
    26.     return false;  
    27. }  
    28.   
    29. void unhook( void )  
    30. {  
    31.     DWORD dwFlag;  
    32.     if ( VirtualProtect( ( void* )hookAddr, HOOK_BYTES, PAGE_EXECUTE_READWRITE, &dwFlag ) )  
    33.     {  
    34.         memcpy( ( void* )hookAddr, old_code, HOOK_BYTES );  
    35.         VirtualProtect( ( void* )hookAddr, HOOK_BYTES, dwFlag, &dwFlag );  
    36.     }  
    37. }  
    38.   
    39. namespace global  
    40. {  
    41.     uint gEAX = 0;  
    42.     uint gEBX = 0;  
    43.     uint gECX = 0;  
    44.     uint gEDX = 0;  
    45.     uint gESP = 0;  
    46.     uint gEBP = 0;  
    47.     uint gESI = 0;  
    48.     uint gEDI = 0;  
    49.   
    50.     uint gRet = 0;  // 临时的返回地址  
    51.     uint gTmp = 0;  // 一些临时的值保存  
    52.     uint gPar = 0;  // 被hook函数的正常返回地址  
    53.     uint gCnt = 1;  // 当前hook的次数  
    54.     uint gMax = 0;  // 最大hook次数,为0表示一直hook  
    55.     bool bEnt = 0;  // 是否为第一次进入hook函数  
    56. }  
    57.   
    58. void __declspecnaked ) hook_jmp( void )  
    59. {  
    60.     __asm  
    61.     {  
    62. __entry:  
    63.         pushad  
    64.         {  
    65.             cmp global::bEnt, 0   // 如果没有进入则表示需要unhook  
    66.             je  __first  
    67.   
    68.             cmp global::gMax, 0   // 如果为0,则一直启用hook逻辑  
    69.             je  __second  
    70.   
    71.             mov eax, global::gCnt  
    72.             cmp eax, global::gMax // 如果当前hook次数没有达到最大次数,则继续  
    73.             jl  __second  
    74.   
    75.             mov global::gCnt, 1   // reset state  
    76.             mov global::bEnt, 0   // reset state  
    77.             mov global::gMax, 0   // reset state  
    78.   
    79.             mov eax, global::gPar // 被hook函数的正常返回地址  
    80.             mov global::gRet, eax // 准备跳转到被hook函数的上层调用,结束hook  
    81.             popad  
    82.             jmp __ret  
    83.         }  
    84.   
    85. __first:  
    86.         // 保存相关重要寄存器值  
    87.         {  
    88.             popad  
    89.             mov global::gEAX, eax    
    90.             mov global::gEBX, ebx  
    91.             mov global::gECX, ecx  
    92.             mov global::gEDX, edx  
    93.             mov global::gESP, esp  
    94.             mov global::gEBP, ebp  
    95.             mov global::gESI, esi  
    96.             mov global::gEDI, edi  
    97.         }  
    98.   
    99.         // 第一次进入,unhook并监视相关状态  
    100.         pushad  
    101.         {  
    102.             mov global::bEnt, 1    // 记录状态  
    103.   
    104.             mov edi, global::gEBP  // 被hook函数的ebp  
    105.             mov eax, [ edi + 4 ]   // 被hook函数的返回地址(其上层调用地址)  
    106.             mov global::gPar, eax  // 保存返回地址  
    107.             mov esi, __entry       // 将被hook函数的返回地址修改为  
    108.             mov [ edi + 4 ], esi   // 本函数的首地址,以便执行完被hook函数的  
    109.                                    // 剩余逻辑之后能够返回到本函数,决定是否  
    110.                                    // 还需要hook。  
    111.   
    112.             call printRegisters    // 打印寄存器值[测试],或者其他  
    113.             call unhook            // unhook  
    114.   
    115.             mov  eax, hookAddr     // 获得被hook的内存地址  
    116.             mov  global::gRet, eax  
    117.         }  
    118.         popad  
    119.   
    120.         pop  global::gTmp          // 移除本函数的返回地址,并将hook的地址设置  
    121.         jmp __ret                  // 为本函数的返回地址,从而实现跳转  
    122.   
    123. __second:  
    124.         // 第二次进入, 继续hook, 这次进入是被hook函数ret返回的,没有新的ret地址被压栈  
    125.         {  
    126.             mov global::bEnt, 0    // 设置状态  
    127.             add global::gCnt, 1    // 增加hook计数  
    128.   
    129.             call hook              // hook  
    130.   
    131.             mov  eax, global::gPar // 将被hook函数的返回地址设置为本函数的  
    132.             mov  global::gRet, eax // 返回地址,从而实现正常的函数流程  
    133.         }  
    134.         popad  
    135.   
    136. __ret:  
    137.         push global::gRet                   // 修改本函数的返回地址  
    138.         ret  
    139.     }  
    140. }  
    141.   
    142. void setHookBytes( uint addr )  
    143. {  
    144.     hookAddr = addr;  
    145.     new_code[ 0 ] = ( char )0xe8; // call 指令机器码  
    146.     ( uint& )new_code[ 1 ] = ( uint )hook_jmp - addr - 5; // 计算跳转偏移  
    147. }  
    148.   
    149. void printRegisters( void )  
    150. {  
    151.     printf( "EAX = 0x%08x/n", global::gEAX );  
    152.     printf( "EBX = 0x%08x/n", global::gEBX );  
    153.     printf( "ECX = 0x%08x/n", global::gECX );  
    154.     printf( "EDX = 0x%08x/n", global::gEDX );  
    155.     printf( "ESP = 0x%08x/n", global::gESP );  
    156.     printf( "EBP = 0x%08x/n", global::gEBP );  
    157.     printf( "ESI = 0x%08x/n", global::gESI );  
    158.     printf( "EDI = 0x%08x/n", global::gEDI );  
    159. }  

    如上,hook_jmp函数即为我们自定义的hook函数,当被hook函数被hook之后,就会跳转到这个函数里,执行相关逻辑,上面我加了很详细的注释。应该很容易看懂。还是先看怎么使用这套方法,再来细说,代码如下:

    1. void testHook( void )  
    2. {  
    3.     printf( "This is a hook test 1./n" );  
    4.     printf( "This is a hook test 2./n" );  
    5.     printf( "This is a hook test 3./n" );  
    6.     printf( "This is a hook test 4./n" );  
    7.     printf( "______________________/n" );  
    8. }  
    9.   
    10. int main( void )  
    11. {  
    12.     uint hook_addr = 0x0042ec7b;  
    13.     setHookBytes( hook_addr );  
    14.       
    15.     global::gMax = 2;  
    16.     if ( hook() )  
    17.     {  
    18.         testHook();  
    19.         testHook();  
    20.         testHook();  
    21.     }  
    22.     system( "pause" );  
    23.     return 0;  
    24. }  

    如上,testHook函数即为被hook的函数,在main函数中,0x0042ec7b则为testHook函数里的第二个printf调用的地址,在你的机器上可能不一样。这里只是测试之用。testHook函数具体反汇编代码如下:

    1. void testHook( void )  
    2. {  
    3. 0042EC50  push        ebp    
    4. 0042EC51  mov         ebp,esp   
    5. 0042EC53  sub         esp,0C0h   
    6. 0042EC59  push        ebx    
    7. 0042EC5A  push        esi    
    8. 0042EC5B  push        edi    
    9. 0042EC5C  lea         edi,[ebp-0C0h]   
    10. 0042EC62  mov         ecx,30h   
    11. 0042EC67  mov         eax,0CCCCCCCCh   
    12. 0042EC6C  rep stos    dword ptr es:[edi]   
    13.     printf( "This is a hook test 1./n" );  
    14. 0042EC6E  push        offset string "This is a hook test 1./n" (487E24h)   
    15. 0042EC73  call        @ILT+4550(_printf) (42D1CBh)   
    16. 0042EC78  add         esp,4   
    17.     printf( "This is a hook test 2./n" );  
    18. 0042EC7B  push        offset string "This is a hook test 2./n" (487E08h)   
    19. 0042EC80  call        @ILT+4550(_printf) (42D1CBh)   
    20. 0042EC85  add         esp,4   
    21.     printf( "This is a hook test 3./n" );  
    22. 0042EC88  push        offset string "This is a hook test 3./n" (487DECh)   
    23. 0042EC8D  call        @ILT+4550(_printf) (42D1CBh)   
    24. 0042EC92  add         esp,4   
    25.     printf( "This is a hook test 4./n" );  
    26. 0042EC95  push        offset string "This is a hook test 4./n" (487DD0h)   
    27. 0042EC9A  call        @ILT+4550(_printf) (42D1CBh)   
    28. 0042EC9F  add         esp,4   
    29.     printf( "______________________/n" );  
    30. 0042ECA2  push        offset string "_____________________./n" (487DB4h)   
    31. 0042ECA7  call        @ILT+4550(_printf) (42D1CBh)   
    32. 0042ECAC  add         esp,4   
    33. }  
    34. 0042ECAF  pop         edi    
    35. 0042ECB0  pop         esi    
    36. 0042ECB1  pop         ebx    
    37. 0042ECB2  add         esp,0C0h   
    38. 0042ECB8  cmp         ebp,esp   
    39. 0042ECBA  call        @ILT+3570(__RTC_CheckEsp) (42CDF7h)   
    40. 0042ECBF  mov         esp,ebp   
    41. 0042ECC1  pop         ebp    
    42. 0042ECC2  ret   

    我们hook的就是第18行(0042EC7B)那句代码,setHookBytes构建了一个5字节的call语句,0xe8为CALL指令的机器码,后面4个字节是CALL的偏移量(目标地址 - 当前地址 - CALL指令占用的5个字节)。

     

    在main函数中,构建了hook的5个字节之后,设置了hook次数,如main函数那段代码的第15行:global::gMax = 2,则会hook两次。然后是main函数那段代码的第16行,调用hook函数,将5个字节的call指令写入0042EC7B中,并保存了0042EC7B中原来的代码到old_code中。之后,我们便可以调用testHook函数进行测试hook的流程了。最终输出结果为:

    This is a hook test 1.
    EAX = 0x00000017
    EBX = 0x7ffdc000
    ECX = 0x8df97741
    EDX = 0x00499148
    ESP = 0x0012fd84
    EBP = 0x0012fe54
    ESI = 0x00000000
    EDI = 0x0012fe54
    This is a hook test 2.
    This is a hook test 3.
    This is a hook test 4.
    ______________________
    This is a hook test 1.
    EAX = 0x00000017
    EBX = 0x7ffdc000
    ECX = 0x8df97741
    EDX = 0x00499148
    ESP = 0x0012fd84
    EBP = 0x0012fe54
    ESI = 0x00000000
    EDI = 0x0012fe54
    This is a hook test 2.
    This is a hook test 3.
    This is a hook test 4.
    ______________________
    This is a hook test 1.
    This is a hook test 2.
    This is a hook test 3.
    This is a hook test 4.
    ______________________

     

    可以看出,前面两次调用testHook函数时,都执行了hook_jmp函数,并调用了printRegisters函数将寄存器打印了出来,之后又回到testHook中,继续输出后面的3句字符串。当两次hook之后,第三次调用testHook时,就不会再输出寄存器了,也没有被hook了。

     

    我们来看几个比较hook_jmp中比较关键的几个地方:

    第104到110行:这段汇编代码,主要用于保存testHook函数(被hook函数)的正常的返回地址(main函数里调用testHook的下一句指令的地址)到global::gPar变量中,并将hook_jmp的首地址(也就是__entry标签指示的地址)写入testHook函数的返回地址所在的内存里。这样当unhook并执行完testHook之后又能回到hook_jmp中,进一步判断是否需要下一次hook。如果不需要再hook(已经达到最大hook次数)时,则会执行第79到80行的两句汇编代码,这两句汇编代码的作用是将hook_jmp函数的返回地址设置为testHook函数正常的返回地址,也就是main函数里调用testHook函数的下一句汇编代码的地址(ret指令的原理如果不清楚,请看前两篇hook文章或查阅相关资料)。这样一来,当不再需要hook时,就能顺利的从hook_jmp函数返回后直接跳转到main函数的作用域里。这样整个调用流程就符合原本的调用流程了。

     

    第113行:这句代码是在调用了printRegister函数之后进行unhook操作,将原本的5个字节的代码重新拷贝到testHook函数的相应代码地址的内存里,本例中为testHook函数中第二句printf函数调用的地址。unhook之后,第115到116行的两句代码与第79到80行的两句汇编代码类似,只不过这时是将被hook的内存地址设置为hook_jmp的返回地址,这样就能在第一次进入testHook函数并执行完毕返回时,能够跳转到被hook的地址(hookTest函数里第2句printf调用的地址)继续向下执行剩余的逻辑。

     

    第131到132行:这两句汇编代码与第79到80行的两句汇编代码一致,都是将main函数里相应的代码地址设置为hook_jmp函数的ret返回地址,这样就能直接从hook_jmp跳转到main函数里继续向下执行,这样也就代表testHook被顺利的调用完成。

     

    所以,总结下来,hook_jmp函数会进入两次,第一次用于监视一些数据,本例只监视了相关寄存器,还可以增加监视指定内存地址等等。第一次进入时,会保存被hook函数(testHook函数)的返回地址,并将其修改为hook_jmp函数的首地址,这样做是为了执行完testHook函数之后能够第二次进入hook_jmp函数。那么,第二次进入后,首先是判断是否还需要hook,不需要则直接返回到main函数里,如果还要继续hook,则再次调用hook函数,然后跳转到main函数里。这样就构成了一个严密的调用流程,一切都看起来很和谐的调用,有点类似缓冲区溢出攻击的原理。

     

    hook_jmp函数中需要注意寄存器的保存,否则输出的寄存器值并不是testHook函数执行到hook位置时的寄存器状态,这样就丧失了监视的意义。

     

    原理上其实比较简单,构建稍微细致了一些,与前两篇hook最大的不同就是需要手动修改ret的返回地址,从而达到hook的目的,不像之前的两篇hook,在进入hook函数之后,要回到被hook的函数时,只需要直接call就可以了,并不需要维护ret指令的返回地址。另外,由于本文的hook方式与第一篇的hook方式类似,所以本文的方式并没有支持多线程环境。

     

    再者,本文的方式还有另外一些局限性:

    1. 不能hook函数大括号以外的代码,也就是反汇编代码中大括号之前和之后的代码,因为本文的hook方式是需要通过被hook函数的ebp获取ret地址的,如果设置ebp的相关代码被hook,就得不到正确的ret返回地址等。而且hook大括号之外的代码意义并不大。

    2. 被hook的函数的栈帧不能被编译器优化掉,否则得不到ret地址和ebp。

    3. hook的代码地址必须为某条汇编指令机器码序列的首地址,本文并没有兼容任意代码地址hook,当然任意代码地址是可以实现的,不过在实际中要监视一些状态,这样做并没有太大的意义。所以你需要明确的知道你hook的代码地址是合法的,并且不会破坏原有的代码逻辑。

     

    好了,整个hook的逻辑和原理就介绍得差不多了,再附上一张流程图:

    如图所示,testHook函数如果被hook了,它是不会直接返回到main函数的,而是要先进入hook_jmp函数,再由hook_jmp函数返回到main函数,知道不再hook的时候,testHook才有“权利”直接返回到main函数里。

     

    好了差不多就介绍完了,最后说说这套hook的用途,其实最初我是想用于反外挂检测上,于是写了这么一套hook逻辑,方便在不用调试客户端程序的情况下,监视在运行有外挂的客户端的一些关键的反外挂检测点,例如某个反外挂检测逻辑是否被执行,某些检测结果值的监视等。外挂一般加了比较强悍的保护壳,这些壳具有反调试等功能。典型的就是VMP壳和UPX壳。当然在这之前尝试了脱壳等方式调试跟踪有外挂的客户端,但是脱壳和绕过反调试机制的工作量都相对较大一些,我们的一贯思想又是以最少的工作量去做到好的反外挂效果。于是我便写了这套hook规则,用于检测当前反外挂系统是否被破解,是否被绕开。通过这套规则,就可以很方便的设立观测点,监视相关逻辑和数据,当然还可以有更多用途,此处不再一一说明,另外为此还写了一个可视化工具,方便工作中使用,并成功检测了多个外挂的破解机制,如图:

     

    左边为hook逻辑的界面,右边tool页面为调用任意函数的功能,同时支持查看模块和查看并修改内存。基本上已经够用了。- -

     

    好了,本文到此结束,由于水平有限,可能存在bug,还望指教,衷心感谢!


    展开全文
  • React Hook之Effect Hook

    万次阅读 2019-06-11 09:02:49
    Effect Hook概念性内容介绍: Effect Hook可以让你在函数组件中执行副作用操作。 PS:副作用操作包括: 数据获取 设置定义 手动更改React组件中的DOM 。。。 Effect Hook可以把它当作是componentDidMount,...

    Effect Hook概念性内容介绍:

    • Effect Hook可以让你在函数组件中执行副作用操作。
      PS:副作用操作包括:
      1. 数据获取
      2. 设置定义
      3. 手动更改React组件中的DOM
      4. 。。。
    • Effect Hook可以把它当作是componentDidMount,componentDidUpdate和componentWillUnmount这三个生命周期的组合。(组件渲染,更新,销毁)
    • 在组件内部我们可以在useEffect中直接访问state变量或是props。我们不需要特殊的API来读取它 – 它已经保存在函数作用域中。Hook使用了JavaScript的闭包机制,而不用在JavaScript已经提供了解决方案的情况下,还引入特定的React API。

    PS:React组件中有俩种常见的副作用操作:一种是需要清除的,一种是不需要清除的。
    无需清除的effect:
    比如我们只想在React更新DOM之后运行一些额外的代码。比如发送网络请求,手动变更DOM,记录日志,这些都是常见的无需清除的操作。因为在执行完这些操作之后,就可以忽略它们了。
    需要清除的effect:
    比如订阅外部数据源。这种情况清除工作是非常重要的,可以防止引起内存泄漏!

    如果朋友们想在里面进行异步操作的话请这样用【或者你可以把这个方法放到外面在这里调用即可】:

    useEffect(() => {
    	async function asyncRequest() {
    		//请自己将getData换成你自己的异步请求
    		const res = await getData();
    		console.log(res)
    	}
    	asyncRequest();
    }, [])
    

    我们可以监听某个状态的变化来进行一些操作

    function Test() {
    	const [count, setCount] = useState(0);
    	useEffect(() => {
    		console.log('count变化了,我们可以在这里做些什么')
    	}, [count])
    	return (
    		<button onClick={() => setCount(count+1)}>
    			{count}
    			更改count
    		</button>
    	)
    }
    

    useEffect vs useLayoutEffect

    下面是何时使用它们的简单规则。

    这两种方法都可以用来做基本相同的事情,但是它们的用例稍有不同。这里有一些规则供您在决定使用哪个React Hook时参考。


    useEffect
    99%的情况下,这是你想要使用的。当hooks是稳定的,并且如果您重构任何类组件来使用钩子,那么您可能会将任何代码从componentDidMount、componentDidUpdate和componentWillUnmount移到useEffect。

    有一个问题是,它在react呈现组件之后运行,并确保您的效果回调不会阻塞浏览器绘图。这与类组件中的行为不同,在类组件中,componentDidMount和componentDidUpdate在呈现后同步运行。这样更有性能,大多数时候这就是你想要的。

    但是,如果您的效果正在改变DOM(通过一个DOM节点ref),并且DOM变化将在呈现DOM节点和您的效果改变它之间改变它的外观,那么您不希望使用useEffect。你需要使用useLayoutEffect。否则,当DOM变化生效时,用户可能会看到闪烁。这是你唯一想要避免使用效果而使用useLayoutEffect的时候。


    useLayoutEffect
    在React执行完所有DOM突变后,它立即同步运行。如果您需要进行DOM度量(比如获取元素的滚动位置或其他样式),然后进行DOM更改或通过更新状态触发同步重新呈现,那么这将非常有用。

    就调度而言,这与componentDidMount和componentDidUpdate的工作方式相同。您的代码在DOM更新后立即运行,但在浏览器有机会“绘制”这些更改之前(用户实际上直到浏览器重新绘制后才会看到更新)。

    总结
    useLayoutEffect:如果需要修改DOM和/或确实需要执行度量
    useEffect:如果您根本不需要与DOM交互,或者您的DOM更改是不可观察的(说真的,大多数时候您应该使用这个)。

    展开全文
  • 了解react-hook以及State Hook

    万次阅读 2019-05-18 23:28:00
    react更新到16.8版本后最主要的内容就是增加了hook这个特性,它的主要作用可以理解为对react的函数组件进行了一次升级,使react的函数组件拥有了和react类组件一样的功能(关于以前版本react的组件的介绍可以移步到...
  • Hook 实战之 Hook AMS

    千次阅读 2020-10-09 20:15:39
    我们知道新建一个 Activity 之后我们需要在 manifest 中注册,否则启动的时候就会崩溃,现在使用 Hook 的方法绕过检查来启动一个没有注册的 Activity。 如果我们不注册的话就会报下面的错误: Caused by: android....
  • Hook原理

    千次阅读 2018-06-22 22:00:00
    Hook原理对于会Hook的人来说,Hook其实也就那么回事。对于没有Hook过的人来说,会感觉Hook很高大上(其实也没毛病)。 那么今天我们就来探讨一些Hook的原理...
  • IAT HOOK、EAT HOOK和Inline Hook

    千次阅读 2017-01-12 13:41:07
    导入表hook原理是修改导入表中某函数的地址到自己的补丁函数,具体步骤如下: 1. 通过GetProcAddress获取目标函数地址 2. 在程序内存中找到所在dll的导入表 3. 查找目标函数地址保存的位置 4. 把地址修改为自己...
  • Android Hook 机制之简单实战

    万次阅读 多人点赞 2019-08-06 10:11:44
    Hook 又叫“钩子”,它可以在事件传送的过程中截获并监控事件的传输,将自身的代码与系统方法进行融入。这样当这些方法被调用时,也就可以执行我们自己的代码,这也是面向切面编程的思想(AOP)。 Hook 分类 1....
  • Android HookHook CloseGuard

    千次阅读 2019-01-03 19:55:26
    APP端可以利用Hook REPORTER 在来实现客制化的上报提示信息 本章通过代码来学一下怎样Hook这个REPORTER来定制上报信息功能。 二、案例分析 直接上代码: package com.peterzhang.androidhookdemo; impor...
  • PLT hook与Inline hook

    2020-03-07 17:25:34
    在目前的安卓APP测试中对于Native Hook的需求越来越大,越来越多的APP开始逐渐使用NDK来开发核心或者敏感代码逻辑。 个人认为原因如下: 安全的考虑。各大APP越来越注重安全性,NDK所编译出来的so库逆向难度明显...
  • IAT hook 导入表hook原理:修改导入表中某函数的地址到自己的补丁函数。IATHook 通过GetProcAddress获取目标函数地址 在程序内存中找到所在dll的导入表 查找目标函数地址保存的位置 把地址修改为自己补丁函数...
  • HOOK API入门之Hook

    2017-01-13 10:09:13
    HOOK API入门之Hook自己程序的MessageBoxW http://blog.csdn.net/friendan/article/details/12222651 HOOK所有程序的MessageBox http://blog.csdn.net/friendan/article/details/12224481 低级...
  • hook入门 实现本地hook

    2017-03-22 14:17:46
    工作中有个程序需要做一些改变,但又没有源代码 那么只能通过hook来解决了. 学习中. 第一步是写一个简单的测试hook 参考了这里的 http://bbs.pediy.com/thread-193729.htm然后写了几个简单的工程测试成功 hook前...
  • Hook 技术初探

    千次阅读 2020-08-31 09:00:04
    最近在研究插件化技术,插件化的中经常会使用到 Hook 技术,查阅了很多资料这里总结下讲的比较好的,希望对大家有所帮助。 Hook 技术 Hook 是钩子的意思,在 Android 操作系统中系统维护着自己的一套事件分发机制。...
  • 而是在程序界流传的强大秘技-Hook函数,Hook原意是指钩子,它表示的就是在某个函数的上下文做自定义的处理来实现我们想要的黑科技。   在很多技术领域都存在的这种Hook技术,比如下面这些: 在...
  • Hook与Socket Hook

    千次阅读 2014-01-11 10:45:30
    本文主要介绍了如何实现替换Windows上的API函数,实现Windows API Hook(当然,对于socket的Hook只是其中的一种特例)。这种Hook API技术被广泛的采用在一些领域中,如屏幕取词,个人防火墙等。 这种API Hook技术并...
  • Android Hook

    2018-04-21 18:50:44
    什么是Hook 拦截事件并监控事件的传输。 常用的Hook框架 要root权限,直接Hook系统,可以干掉所有的App 免root权限,但是只能Hook自身,对系统其他App无能为力 常见Hook方案 Xposed 通过替换/system/...
  • HOOK汇总

    2017-07-10 16:59:01
    HOOK技术主要分为两大类,一是内核层HOOK,一是用户层HOOK. 用户层HOOK也就是在ring3环境下hook kenerl32.dll、 User3.dll、Gui32.dll、Advapi.dll等导出的函数。而内核层HOOK就是HOOK只有ring0级别环境下才能操作...
  • 文章目录I、问题分析II、使用方法交换,全局修改see also ... I、问题分析 ...cell.addSubView(tempView1) 这种方式添加的,通过试图分析发现被系统自带的UITableViewCellContentView遮挡在底部了,所以需要改规范的做法...
  • Android Native Hook

    2019-11-17 20:43:18
    Hook 直译过来就是“钩子”的意思,是指截获进程对某个 API 函数的调用,使得 API 的执行流程转向我们实现的代码片段,从而实现我们所需要得功能,这里的功能可以是监控、修复系统漏洞,也可以是劫持或者其他恶意...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 71,055
精华内容 28,422
热门标签
关键字:

hook