写得很简单,也是看了看雪的牛们以后自己实践了一下下,虽然简单,但还是建议菜鸟们多练手(像我一样 嘿嘿),当你能自己写个出来并跑起来,才是入门~
不说废话了,上代码,还请各位指正!
代码:
NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString ) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING ustrLinkName; UNICODE_STRING ustrDevName; PDEVICE_OBJECT pDevObj; //HardCode For Searching…… ULONG Addr_KiInsertQueueApc=0; CHAR FindCode[1][5]={ {0xe8,0x4b,0x2b,0x00,0x00} }; KdPrint(("==>DriverEntry\n")); pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate; pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose; pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl; pDriverObj->DriverUnload = DriverUnload; RtlInitUnicodeString(&ustrDevName, DEVICE_NAME); status = IoCreateDevice(pDriverObj, 0, &ustrDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj); if(!NT_SUCCESS(status)) { return status; } RtlInitUnicodeString(&ustrLinkName, LINK_NAME); status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName); if(!NT_SUCCESS(status)) { IoDeleteDevice(pDevObj); return status; } // // 添加执行代码 // KdPrint(("Search ……\n")); OrigfnAddr.KiInsertQueueApc=GetTargetFnAddrFromExportedFn(FindCode[0],L"KeInsertQueueApc",100,0x2b4b); if (OrigfnAddr.KiInsertQueueApc!=0) { KdPrint(("We find it!Address of KiInsertQueueApc: 0x%08x\n",OrigfnAddr.KiInsertQueueApc)); } else { KdPrint(("Not Find~ \n")); return STATUS_UNSUCCESSFUL; } status=InlineHook(OrigfnAddr.KiInsertQueueApc,(ULONG)fake_KiInsertQueueApc,(ULONG)Proxy_KiInsertQueueApc,OrigHeadCode.KiInsertQueueApc); //进行inlineHook if (!NT_SUCCESS(status)) { return status; } KdPrint(("<==DriverEntry\n")); return status; } VOID DriverUnload( PDRIVER_OBJECT pDriverObj ) { UNICODE_STRING strLink; NTSTATUS status; RtlInitUnicodeString(&strLink, LINK_NAME); // // 添加卸载代码 // status=UnHook(OrigfnAddr.KiInsertQueueApc,OrigHeadCode.KiInsertQueueApc); if (!NT_SUCCESS(status)) { KdPrint(("DriverUnload!UnHook Failre~")); } IoDeleteSymbolicLink(&strLink); IoDeleteDevice(pDriverObj->DeviceObject); KdPrint(("==>DriverUnload\n")); } 下面是实现hook的代码: //WriteProtect OFF/ON By MDL! PVOID WPOFFByMdl(PVOID VirtualAddr,ULONG uLen,PMDL pMDL) { PVOID MVA=NULL; //system-base VA maps physical pages that MDL describes pMDL=IoAllocateMdl(VirtualAddr,uLen,FALSE,FALSE,NULL); if (pMDL==NULL) { KdPrint(("WPOFF!IoAllocateMdl FAILURE pMdl==NULL\n")); return NULL; } MmBuildMdlForNonPagedPool(pMDL); _try { MmProbeAndLockPages(pMDL,KernelMode,IoModifyAccess); } _except(EXCEPTION_EXECUTE_HANDLER) { return NULL; } pMDL->MdlFlags|=MDL_MAPPED_TO_SYSTEM_VA; MVA=MmGetSystemAddressForMdlSafe(pMDL,NormalPagePriority); if (MVA) { KdPrint(("MVA : %x",MVA)); } KdPrint(("WPOFFByMdl Successful")); return MVA; } VOID WPONByMdl(PMDL pMdl) { if (pMdl==NULL) { return ; } MmUnlockPages(pMdl); IoFreeMdl(pMdl); } //Write Protect OFF/ON By CR0! VOID WPOFFByCR0() { ULONG uAttr; _asm { push eax; mov eax, cr0; mov uAttr, eax; and eax, 0FFFEFFFFh; // CR0 16 BIT = 0 mov cr0, eax; pop eax; cli }; g_uCr0 = uAttr; //保存原有的 CRO 性 } VOID WPONByCR0() { _asm { sti push eax; mov eax, g_uCr0; //恢原有 CR0 性 mov cr0, eax; pop eax; }; } /////////////////////////////////////////////////////////////////////// //Get the exported function's address ULONG GetFunctionAddr(PCWSTR FunctionName) { UNICODE_STRING uFnName; RtlInitUnicodeString(&uFnName,FunctionName); return (ULONG)MmGetSystemRoutineAddress(&uFnName); } //Find address of the function that we want to hook // //Description:通过已知函数找我们的目标函数 // //ARGUMENTs: // //FindCode:寻找目标函数(即我们要HOOK的函数)的硬编码 //ExportedFnName:已知函数名 //SearchLen:在已知函数里面的搜索长度 //Offset:相对跳转值 // ULONG GetTargetFnAddrFromExportedFn(CHAR* FindCode,PCWSTR ExportedFnName,ULONG SearchLen,ULONG Offset) { ULONG i=0,j=0; CHAR * Addr_ExportedFn=NULL; ULONG TargetFnAddr=0; Addr_ExportedFn=(CHAR*)GetFunctionAddr(ExportedFnName); if (Addr_ExportedFn==NULL) { KdPrint(("GetTargetFnAddrFromExportedFn!GetFunctionAddr FAILURE\n")); return 0; } for (i=0;i<SearchLen;i++) //搜索用户指定长度的函数字节 { if (Addr_ExportedFn[i]==FindCode[0]) { for (j=1;j<sizeof(FindCode);j++) { if (Addr_ExportedFn[i+j]==FindCode[j]) { continue; } else { break; } } if (j==sizeof(FindCode)) { TargetFnAddr=(ULONG)&Addr_ExportedFn[i]+Offset+5; //由相对jmp的dword值得到 break; } } } return TargetFnAddr; } ////////////////////////////////////////////////////////////////////////////////////////////////////// // //Hook Function // NTSTATUS InlineHook(ULONG OrigFnAddr,ULONG FakeFnAddr,ULONG ProxyFnAddr,PVOID OrigHeadCode) { KIRQL oldIrql; BYTE HookCode[5]={0xe9,0x00,0x00,0x00,0x00}; BYTE jmpCode[7]={0xEA,0x00,0x00,0x00,0x00,0x08,0x00}; PVOID MVA=NULL; if (!OrigFnAddr||!FakeFnAddr||!ProxyFnAddr||!OrigHeadCode) { return STATUS_UNSUCCESSFUL; } RtlCopyMemory(OrigHeadCode,(BYTE*)OrigFnAddr,5); *(ULONG*)(HookCode+1)=(ULONG)FakeFnAddr-(ULONG)OrigFnAddr-5; *(ULONG*)(jmpCode+1)=(ULONG)((BYTE*)OrigFnAddr+0x05);// 不需要相对跳转,这里是长转移 RtlCopyMemory((BYTE*)ProxyFnAddr,(BYTE*)OrigHeadCode,5); RtlCopyMemory((BYTE*)ProxyFnAddr+5,(BYTE*)jmpCode,7); /*WPOFFByCR0();*/ //这里是去掉内存写保护,两种方法,我们选择MDL的方法 MVA=WPOFFByMdl((PVOID)OrigFnAddr,10,MDLs.KiInsertQueueApc); if (!MVA) { KdPrint(("WPOFFByMdl FAILURE~")); return STATUS_UNSUCCESSFUL; } oldIrql=KeRaiseIrqlToDpcLevel(); /*RtlCopyMemory((BYTE*)OrigFnAddr,(BYTE*)HookCode,5);*/ //将要HOOK的函数的函数头前5个字节改写 跳到我们的fake函数里面 RtlCopyMemory((BYTE*)MVA,(BYTE*)HookCode,5); KeLowerIrql(oldIrql); /*WPONByCR0();*/ WPONByMdl(MDLs.KiInsertQueueApc); //恢复写保护 return STATUS_SUCCESS; } // // 停止inline hook // NTSTATUS UnHook(ULONG OrigFnAddr,PVOID OrigHeadCode) { KIRQL oldIrql; PVOID MVA=NULL; if (!OrigFnAddr||!OrigHeadCode) { return STATUS_UNSUCCESSFUL; } /*WPOFFByCR0();*/ MVA=WPOFFByMdl((PVOID)OrigFnAddr,10,MDLs.KiInsertQueueApc); if (!MVA) { KdPrint(("WPOFFByMdl FAILURE~")); return STATUS_UNSUCCESSFUL; } oldIrql = KeRaiseIrqlToDpcLevel(); RtlCopyMemory ( (BYTE*)OrigFnAddr, OrigHeadCode, 5 ); KeLowerIrql(oldIrql); /*WPONByCR0();*/ WPONByMdl(MDLs.KiInsertQueueApc); return STATUS_SUCCESS; } 嘿嘿,大家应该能看出来,在提供的工程里面,用到了sudami同学的一些框架代码,感谢!(程序的最大价值就在于复用~:3: )