InlineHook 已导出函数
HookObReferenceObjectByHandle() { KIRQL Irql; KdPrint(("[ObReferenceObjectByHandle] :0x%x",ObReferenceObjectByHandle)); //地址验证 //保存函数前五个字节内容 RtlCopyMemory(OriginalBytes,(BYTE *)ObReferenceObjectByHandle,5); //保存新函数五个字节之后偏移地址 *(ULONG *)(JmpAddress+1)=(ULONG)DetourMyObReferenceObjectByHandle-((ULONG)ObReferenceObjectByHandle+5); _asm { push eax mov eax, cr0 mov CR0VALUE, eax and eax, 0fffeffffh mov cr0, eax pop eax } Irql=KeRaiseIrqlToDpcLevel(); //函数开头五个字节写JMP RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,JmpAddress,5); KeLowerIrql(Irql); __asm { push eax mov eax, CR0VALUE mov cr0, eax pop eax } } _declspec (naked) NTSTATUS OriginalObReferenceObjectByHandle( IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType OPTIONAL, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL ) { _asm { mov edi,edi // 手动写ObReferenceObjectByHandle函数开头的五个字节, 可用WinDbg查看 push ebp mov ebp,esp mov eax,ObReferenceObjectByHandle add eax,5 jmp eax } } NTSTATUS DetourMyObReferenceObjectByHandle( IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType OPTIONAL, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL ) { NTSTATUS status; //调用原函数 status=OriginalObReferenceObjectByHandle(Handle,DesiredAccess,ObjectType,AccessMode,Object,HandleInformation); if((status==STATUS_SUCCESS)&&(DesiredAccess==1)) // 如果是关闭软件, 从DesiredAccess == 1可知 { if(ObjectType== *PsProcessType) { if( _stricmp((char *)((ULONG)(*Object)+0x174),"notepad.exe")==0) { ObDereferenceObject(*Object); return STATUS_INVALID_HANDLE; } } } return status; } void UnHookObReferenceObjectByHandle() { KIRQL Irql; _asm { push eax mov eax, cr0 mov CR0VALUE, eax and eax, 0fffeffffh mov cr0, eax pop eax } Irql=KeRaiseIrqlToDpcLevel(); //还原开头的五个字节 RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,OriginalBytes,5); KeLowerIrql(Irql); __asm { push eax mov eax, CR0VALUE mov cr0, eax pop eax } } ![]() InlineHook 未已导出函数 ULONG GetFunctionAddr( IN PCWSTR FunctionName) //PCWSTR常量指针,指向16位UNICODE { UNICODE_STRING UniCodeFunctionName; RtlInitUnicodeString( &UniCodeFunctionName, FunctionName ); return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName ); } ULONG GetKiInsertQueueApcAddr() { /* 804fd4d3 894728 mov dword ptr [edi+28h],eax 804fd4d6 e8dd340000 call nt!KiInsertQueueApc (805009b8) 804fd4db 8ad8 mov bl,al */ ULONG sp_code1=0x28,sp_code2=0xe8,sp_code3=0xd88a; //特征码 ULONG address=0; PUCHAR addr; PUCHAR p; addr=(PUCHAR)GetFunctionAddr(L"KeInsertQueueApc"); for(p=addr;p<p+PAGE_SIZE;p++) { if((*(p-1)==sp_code1)&&(*p==sp_code2)&&(*(PUSHORT)(p+5)==sp_code3)) { // 地址换算 // 0x804fd4d6 + 0x000034dd + 0x5 = 0x805009b8 address=*(PULONG)(p+1)+(ULONG)(p+5); break; } } KdPrint(("[KeInsertQueueApc] addr %x\n",(ULONG)addr)); KdPrint(("[KiInsertQueueApc] address %x\n",address)); return address; } VOID HookKiInsertQueueApc() { KIRQL Irql; g_KiInsertQueueApc = GetKiInsertQueueApcAddr(); KdPrint(("[KiInsertQueueApc] KiInsertQueueApc %x\n",g_KiInsertQueueApc)); // 保存原函数的前5字节内容 RtlCopyMemory (OriginalBytes, (BYTE*)g_KiInsertQueueApc, 5); // 新函数对原函数的偏移地址 *( (ULONG*)(JmpAddress + 1) ) = (ULONG)DetourMyKiInsertQueueApc - ((ULONG)g_KiInsertQueueApc + 5); WPOFF(); Irql = KeRaiseIrqlToDpcLevel(); RtlCopyMemory ( (BYTE*)g_KiInsertQueueApc, JmpAddress, 5 ); KeLowerIrql(Irql); WPON(); } //原函数 _declspec (naked) VOID FASTCALL OriginalKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment) { _asm { //原函数前五个字节 mov edi,edi push ebp mov ebp,esp mov eax,g_KiInsertQueueApc add eax,5 jmp eax } } //处理函数 //apc--kthread--apc_state--eprocess VOID FASTCALL DetourMyKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment) { ULONG thread; ULONG process; if(MmIsAddressValid((PULONG)((ULONG)Apc+0x008))) //地址验证 KAPC结构+008--->kthread thread=*((PULONG)((ULONG)Apc+0x008)); else return ; if(MmIsAddressValid((PULONG)((ULONG)thread+0x044))) //kthread+34-->KAPC_STATE+10-->eprocess process=*((PULONG)((ULONG)thread+0x044)); else return ; if(MmIsAddressValid((PULONG)((ULONG)process+0x174))) //eprocess+174---->进程名字 { if((_stricmp((char *)((ULONG)process+0x174),"notepad.exe")==0)&&(Increment==2)) return ; else OriginalKiInsertQueueApc(Apc,Increment); } else return; } MJ大牛的猥琐InlineHook大法(加了点自己的注释和完善了下Unload) 先用WinDbg看下具体的函数
Hook示意图:
代码如下: NTSTATUS InlineHookFuncXP(IN PVOID FuncAddress, IN PVOID NewFuncAddress) { //FuncAddress:orignal function address //NewFuncAddress:new function address to hook //if function successed,the old function which the hook function will jump to //is the FuncAddress+2 KIRQL OldIrql ; NTSTATUS stat; KeAcquireSpinLock( &SDTSpinLock, &OldIrql ); WPOFF(); //保存原函数的头两个字节 RtlCopyMemory(OriginalBytes,(BYTE *)ObReferenceObjectByHandle,2); __asm { push eax push ecx lea eax,[FuncAddress] mov eax,[eax] cmp byte ptr[eax],0x8b jnz failtohook cmp byte ptr[eax+1],0xff ;判断函数开始头部是不是 "mov edi,edi" jnz failtohook mov ecx,0xffffffff ;-1 loopcheck: cmp byte ptr[eax+ecx],0x90 jnz failtohook dec ecx cmp ecx,0xfffffffa ;循环5次, 判断函数开始上面部分是不是"nop" jnz loopcheck mov byte ptr[eax],0xeb ; 短跳jmp mov byte ptr[eax+1],0xf9 ; 0-偏移量-指令长度 = 0x00-5-2 = f9 ;write the new function header:jmp short funcaddr-5(0x00-0x07) mov byte ptr[eax-5],0xe9 ;远跳jmp ;write 1 byte :jmp xxxxx mov ecx,[NewFuncAddress] sub ecx,eax ;得到跳转的相对偏移 mov dword ptr[eax-4],ecx jmp hookok failtohook: mov stat,0xc0000001 jmp end hookok: mov stat,0 end: pop ecx pop eax } WPON(); KeReleaseSpinLock( &SDTSpinLock, OldIrql ); return stat; } VOID UnInlineHookFuncXP(IN PVOID FuncAddress) { KIRQL OldIrql ; NTSTATUS stat; KeAcquireSpinLock( &SDTSpinLock, &OldIrql ); WPOFF(); // 恢复函数的前两个字节 RtlCopyMemory((BYTE *)FuncAddress, OriginalBytes, 2); // 恢复函数上面的5个nop __asm { push ecx push eax lea eax,[FuncAddress] mov eax,[eax] mov ecx,0xffffffff ;-1 loopcheck: mov byte ptr[eax+ecx],0x90 dec ecx cmp ecx,0xfffffffa jnz loopcheck pop eax pop ecx } WPON(); KeReleaseSpinLock( &SDTSpinLock, OldIrql ); }
|