linux内核函数:内核级利用通用Hook函数思路方法检测进程

介绍通用Hook点思想: 在系统内核级中MS很多信息都没公开包括参数数目每个参数类型等在系统内核中访问了大量寄存器而很多寄存器是上层者提供如果值改变系统就会变得不稳定很可能出现不可想象后果另外有时候对需要Hook参数不了解所以不能随便就去改变它堆栈如果不小心也有可能导致蓝屏所以Hook最佳原则是在自己Hook中呼叫原时候所有寄存器值堆栈里面值和Hook前信息这样就能保证在原中不会出错般我们自己Hook都是写在C文件里面例如Hook目标KiReadyThread 那么般就自己实现个:
MyKiReadyThread(...) { ...... call KiReadyThread ...... }

但是用C编译器编译出来代码会出现个堆栈帧:
Push ebp mov ebp,esp

这就和我们初衷不改变寄存器数违背了所以我们可以自己用汇编来实现MyKiReadyThread
_func@0 proc pushad ;保存通用寄存器 call _cfunc@0 ;这里是在进入原来前进行些处理 popad ;恢复通用寄存器 push eax mov eax,[esp+4] ;得到系统在call 目标时入栈返回地址 mov ds:_OrgRet,eax ;保存在个临时变量中 pop eax mov [esp],retaddr ;把目标返回地址改成自己代码空间返回地址使其返回 后能接手继续处理 jmp _OrgDestFunction ;跳到原目标中 retaddr: pushad ;原处理完后保存寄存器 call _HookDestFunction@0 ;再处理 popad ;回复寄存器 jmp ds:_OrgRet ;跳到系统目标条指令 _func@0 endp

当我们要拦截目标API时候只要修改原头5个字节机器为个JMP_func就行了然后把原来5字节保存在跳入原恢复那5个字节即可 Hook KiReadyThread检测系统中进程: 在线程调度抢占时候会KiReadyThread原型为VOID FASTCALL KiReadyThread (IN PRKTHREAD Thread)在进入KiReadyThread时ecx指向Thread所以完全可以Hook KiReadyThread 然后用ecx值得到但前线程进程信息KiReadyThread没被ntosknrl.exe导出所以通过硬编码来在2000Sp4中地址为0x8043141f 具体实现:
//////////////////////////////// // 1.cpp //////////////////////////////// #def __cplusplus extern "C" { #end # "ntddk.h" # ".h" # "nts.h" # "stdio.h" # FILE_DEVICE_EVENT 0x8000 # IOCTL_PASSBUF \ CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) void DriverUnload (IN PDRIVER_OBJECT pDriverObject); NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath); void cfunc ; void HookDestFunction; NTSTATUS DeviceIoControlDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp); extern void func; void ResumeDestFunction; const WCHAR devLink = L"\\??\\MyEvent"; const WCHAR devName = L"\\Device\\MyEvent"; UNICODE_STRING devNameUnicd; UNICODE_STRING devLinkUnicd; ULONG OrgDestFunction = (ULONG)0x8043141f; //KiReadyThread char JmpMyCode = {0xE9,0x00,0x00,0x00,0x00}; char OrgCode [5]; char OutBuf[128][16]; Count = 0; ULONG orgcr0; #def __cplusplus } #end VOID DisableWriteProtect( PULONG pOldAttr) { ULONG uAttr; _asm { push eax; mov eax, cr0; mov uAttr, eax; and eax, 0FFFEFFFFh; // CR0 16 BIT = 0 mov cr0, eax; pop eax; }; *pOldAttr = uAttr; //保存原有 CRO 属性 } VOID EnableWriteProtect( ULONG uOldAttr ) { _asm { push eax; mov eax, uOldAttr; //恢复原有 CR0 属性 mov cr0, eax; pop eax; }; } NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath) { NTSTATUS Status; PDEVICE_OBJECT pDevice; DbgPr("DriverEntry called!\n"); RtlInitUnicodeString (&devNameUnicd, devName ); RtlInitUnicodeString (&devLinkUnicd, devLink ); Status = IoCreateDevice ( pDriverObject, 0, &devNameUnicd, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevice ); ( !NT_SUCCESS(Status)) { DbgPr(("Can not create device.\n")); Status; } Status = IoCreateSymbolicLink (&devLinkUnicd, &devNameUnicd); ( !NT_SUCCESS(Status)) { DbgPr(("Cannot create link.\n")); Status; } pDriverObject->DriverUnload = DriverUnload; pDriverObject->MajorFunction[IRP_MJ_CREATE] = pDriverObject->MajorFunction[IRP_MJ_CLOSE] = pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControlDispatch; pDriverObject->DriverUnload = DriverUnload; * ( (ULONG*) (JmpMyCode+1) ) = (ULONG)func - (ULONG)OrgDestFunction - 5; memcpy(OrgCode,(char*)OrgDestFunction,5); HookDestFunction; STATUS_SUCCESS; } void DriverUnload (IN PDRIVER_OBJECT pDriverObject) { NTSTATUS status; ResumeDestFunction; (pDriverObject->DeviceObject != NULL) { status=IoDeleteSymbolicLink( &devLinkUnicd ); ( !NT_SUCCESS( status ) ) { DbgPr(( "IoDeleteSymbolicLink failed\n" )); } IoDeleteDevice( pDriverObject->DeviceObject ); } } void DisplayName(PKTHREAD Thread) { PKPROCESS Process = Thread->ApcState.Process; PEPROCESS pEprocess = (PEPROCESS)Process; DbgPr("ImageFileName = %s \n",pEprocess->ImageFileName); sprf(OutBuf[Count],"%s",pEprocess->ImageFileName); } void cfunc (void) { ULONG PKHeader=0; __asm { mov PKHeader,ecx //ecx寄存器是KiReadyThread中PRKTHREAD参数 } ResumeDestFunction; ( PKHeader != 0 && Count < 128 ) { DisplayName((PKTHREAD)PKHeader); } } void HookDestFunction { DisableWriteProtect(&orgcr0); memcpy((char*)OrgDestFunction,JmpMyCode,5); EnableWriteProtect(orgcr0); } void ResumeDestFunction { DisableWriteProtect(&orgcr0); memcpy((char*)OrgDestFunction,OrgCode,5); EnableWriteProtect(orgcr0); } NTSTATUS DeviceIoControlDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp ) { PIO_STACK_LOCATION irpStack; NTSTATUS status; PVOID inputBuffer; ULONG inputLength; PVOID outputBuffer; ULONG outputLength; OBJECT_HANDLE_INFORMATION objHandleInfo; status = STATUS_SUCCESS; // 取出IOCTL请求代码 irpStack = IoGetCurrentIrpStackLocation(pIrp); switch (irpStack->MajorFunction) { IRP_MJ_CREATE : DbgPr("Call IRP_MJ_CREATE\n"); ; IRP_MJ_CLOSE: DbgPr("Call IRP_MJ_CLOSE\n"); ; IRP_MJ_DEVICE_CONTROL: DbgPr("IRP_MJ_DEVICE_CONTROL\n"); inputLength=irpStack->Parameters.DeviceIoControl.InputBufferLength; outputLength=irpStack->Parameters.DeviceIoControl.OutputBufferLength; switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { IOCTL_PASSBUF: { RtlCopyMemory(pIrp->UserBuffer, OutBuf, 20*16); mem(OutBuf,0,128*16); Count = 0; ; } default: ; } default: DbgPr("Call IRP_MJ_UNKNOWN\n"); ; } pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; IoCompleteRequest (pIrp, IO_NO_INCREMENT); status; } //////////////////////////////// // 1.asm //////////////////////////////// .386 .model small .data _OrgRet dd 0 .code public _func@0 extrn _cfunc@0:near extrn _HookDestFunction@0:near extrn _OrgDestFunction:DWORD _func@0 proc pushad call _cfunc@0 popad push eax mov eax,[esp+4] mov ds:_OrgRet,eax pop eax mov [esp],retaddr jmp _OrgDestFunction retaddr: pushad call _HookDestFunction@0 popad jmp ds:_OrgRet _func@0 endp END ////////////////////////////////////////// // app.cpp ////////////////////////////////////////// # <windows.h> # <stdio.h> # FILE_DEVICE_EVENT 0x8000 # CTL_CODE( DeviceType, Function, Method, Access ) ( \ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ ) # FILE_ANY_ACCESS 0 # METHOD_BUFFERED 0 # FILE_DEVICE_UNKNOWN 0x00000022 # IOCTL_PASSBUF \ CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) { HANDLE hDevice; bool status; ULONG dwReturn; char outbuf[129][16]; hDevice = NULL; m_hCommEvent = NULL; hDevice = CreateFile( "\\\\.\\MyEvent", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); (hDevice INVALID_HANDLE_VALUE) { prf("createfile wrong\n"); getchar; 0; } while(1) { mem(outbuf,0,129*16); status =DeviceIoControl(hDevice, IOCTL_PASSBUF, NULL, 0, &outbuf, 128*16, &dwReturn,NULL); ( !status) { prf("IO wrong+%d\n", GetLastError); getchar; 0; } c=0; while( *((char*)(&outbuf)+c*16) ) { //把csrss.exe和自身进程信息跳过会产生有大量信息 ( strcmp((char*)(&outbuf)+c*16,"app.exe") && \ strcmp((char*)(&outbuf)+c*16,"csrss.exe") ) prf("%s\n",(char*)(&outbuf)+c*16); c; } Sleep(1); } }

试验结果:
...... TTPlayer.exe TTPlayer.exe vrvmon.exe TTPlayer.exe Explorer.EXE Explorer.EXE Explorer.EXE ......

测试、编译环境Windows2000 Sp4、Windows2000 DDK没写出线程隐藏进程代码不过基本上实现得差不多了只需要把返回信息和Ring3级查询得到信息进行适时对比就能查出异常进程了



  • 篇文章: 种新穿透防火墙数据传输技术

  • 篇文章: 邮件蠕虫和垃圾邮件技术融合
  • Tags:  xpath通用函数 内核函数 hook函数 linux内核函数

    延伸阅读

    最新评论

    发表评论