内核级利用通用Hook函数方法检测进程

来源:互联网 发布:电商大米销售数据 编辑:程序博客网 时间:2024/04/28 22:17
内核级利用通用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
////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif

#include "ntddk.h"
#include "string.h"
#include "ntifs.h"
#include "stdio.h"

#define FILE_DEVICE_EVENT  0x8000

#define 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];

int Count = 0;

ULONG orgcr0;
#ifdef __cplusplus
}
#endif

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;

    DbgPrint("DriverEntry called!/n");
    RtlInitUnicodeString (&devNameUnicd, devName );
    RtlInitUnicodeString (&devLinkUnicd, devLink );
    Status = IoCreateDevice ( pDriverObject,
    0,
         &devNameUnicd,
    FILE_DEVICE_UNKNOWN,
       0,
       TRUE,
       &pDevice );
        if( !NT_SUCCESS(Status))
        {
        DbgPrint(("Can not create device./n"));
        return Status;
    }
       Status = IoCreateSymbolicLink (&devLinkUnicd, &devNameUnicd);
       if( !NT_SUCCESS(Status))
       {
           DbgPrint(("Cannot create link./n"));
           return 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();
    
    return STATUS_SUCCESS;
}

void DriverUnload (IN PDRIVER_OBJECT pDriverObject)
{
    NTSTATUS            status;
    ResumeDestFunction();
    if(pDriverObject->DeviceObject != NULL)
        {
           status=IoDeleteSymbolicLink( &devLinkUnicd );
        if ( !NT_SUCCESS( status ) )
            {
                    DbgPrint((  "IoDeleteSymbolicLink() failed/n" ));
            }
            IoDeleteDevice( pDriverObject->DeviceObject );
        }
}

void DisplayName(PKTHREAD Thread)
{
    PKPROCESS Process = Thread->ApcState.Process;
    PEPROCESS pEprocess = (PEPROCESS)Process;
    DbgPrint("ImageFileName = %s /n",pEprocess->ImageFileName);
    sprintf(OutBuf[Count++],"%s",pEprocess->ImageFileName);
}

void cfunc (void)
{
    ULONG PKHeader=0;
    __asm
    {
        mov PKHeader,ecx  //ecx寄存器是KiReadyThread中的PRKTHREAD参数
    }
    ResumeDestFunction();
    
    if ( 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)
    {
    case IRP_MJ_CREATE :
        DbgPrint("Call IRP_MJ_CREATE/n");
        break;
    case IRP_MJ_CLOSE:
        DbgPrint("Call IRP_MJ_CLOSE/n");
        break;
    case IRP_MJ_DEVICE_CONTROL:
        DbgPrint("IRP_MJ_DEVICE_CONTROL/n");
        inputLength=irpStack->Parameters.DeviceIoControl.InputBufferLength;
        outputLength=irpStack->Parameters.DeviceIoControl.OutputBufferLength;
        switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
        {
            case    IOCTL_PASSBUF:
            {
                RtlCopyMemory(pIrp->UserBuffer, OutBuf, 20*16);
                
                memset(OutBuf,0,128*16);
                Count = 0;
                break;
            }
            default:
                break;
        }

    default:
        DbgPrint("Call IRP_MJ_UNKNOWN/n");
        break;
    }
    pIrp->IoStatus.Status = status;
    pIrp->IoStatus.Information = 0;
    IoCompleteRequest (pIrp, IO_NO_INCREMENT);
    return 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
//////////////////////////////////////////

#include <windows.h>
#include <stdio.h>

#define FILE_DEVICE_EVENT  0x8000
#define CTL_CODE( DeviceType, Function, Method, Access ) (                 /
    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) /
)

#define FILE_ANY_ACCESS                 0
#define METHOD_BUFFERED                 0
#define FILE_DEVICE_UNKNOWN             0x00000022

#define IOCTL_PASSBUF /
    CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)

int main()
{
       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);
        if(hDevice == INVALID_HANDLE_VALUE)
        {
           printf("createfile wrong/n");
           getchar();
           return 0;
        }
    while(1)
    {
        memset(outbuf,0,129*16);
        status =DeviceIoControl(hDevice,
                    IOCTL_PASSBUF,
                    NULL,
                    0,
                    &outbuf,
                    128*16,
                    &dwReturn,NULL);
        if( !status)
        {
            printf("IO wrong+%d/n", GetLastError());
            getchar();
            return 0;
        }
        int c=0;
        while( *((char*)(&outbuf)+c*16) )
        {
            //把csrss.exe和自身进程信息跳过,因为会产生有大量的信息。
            if ( strcmp((char*)(&outbuf)+c*16,"app.exe") && /
                 strcmp((char*)(&outbuf)+c*16,"csrss.exe")  )
                printf("%s/n",(char*)(&outbuf)+c*16);
            c++;
        }
        Sleep(1);
    }
}

试验结果:
......
TTPlayer.exe
System
TTPlayer.exe
vrvmon.exe
TTPlayer.exe
System
System
Explorer.EXE
Explorer.EXE
Explorer.EXE
......
测试,编译环境 2000 Sp4 2000 DDK
没写出线程的隐藏进程代码。不过基本上实现得差不多了,只需要把返回的信息,和Ring3级查询得到的信息进行适时对比就能查出异常进程了。

本人水平有限,如哪里有错误,欢迎高手不吝赐教。
感谢:sinister大哥对小弟的指点及其鼓励
毕业在即将次愚作献给我的母校---重庆科技学院

本文引用通告地址: http://blog.csdn.net/i_like_cpp/services/trackbacks/405478.aspx
[点击此处收藏本文]
发表于 2005年06月28日 10:33 AM
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孕晚期感冒流鼻涕怎么办 孕晚期流鼻涕打喷嚏怎么办 孕晚期鼻塞流鼻涕怎么办 孕晚期流鼻涕怎么办呢 鼻子干燥有血痂怎么办 九个月宝宝鼻炎怎么办 两岁宝贝流鼻涕怎么办 咳嗽流清鼻涕怎么办 鼻塞咳嗽痰多怎么办 宝宝鼻涕流不止怎么办 咳嗽有痰鼻塞怎么办 舌头长水泡怎么办儿童 小孩淌清鼻涕怎么办 小孩淌清水鼻涕怎么办 闻到辣的流鼻涕怎么办 舌头上长囊肿怎么办 单侧鼻塞流清涕怎么办 鼻塞流清鼻涕怎么办 睡眠脑子总幻想怎么办 鼻塞流清水鼻涕怎么办 坐月子流清鼻涕怎么办 六岁宝宝牙疼怎么办 哺乳期感冒鼻塞流鼻涕怎么办 婴儿晚上睡觉晚怎么办 一个月孩子缺钙怎么办 七八岁睡眠不好怎么办 小孩溜黄鼻涕怎么办 孕妇鼻塞黄鼻涕怎么办 孕妇上火黄鼻涕怎么办 孕妇鼻涕很黄怎么办 孕妇鼻塞怎么办速效办法 孕妇流黄鼻涕怎么办 孕妇有脓鼻涕怎么办 孕妇感冒黄鼻涕怎么办 单侧鼻子流黄水 怎么办 怀孕感冒流鼻涕鼻塞怎么办 小孩鼻炎黄鼻涕怎么办 孕妇流浓鼻涕怎么办 孕妇感冒鼻塞流鼻涕怎么办 孕早期鼻塞流涕怎么办 流鼻涕半个月了怎么办