分享
 
 
 

【收藏】内核级利用通用Hook函数方法检测进程

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

来源:http://www.xfocus.net/articles/200505/798.html

创建时间:2005-05-10

文章属性:原创

文章提交:LionD8 (liond8_at_126.com)

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

作者: LionD8

QQ: 10415468

Email: LionD8@126.com

Blog: http://blog.csdn.net/LionD8 or http://liond8.126.com

介绍通用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大哥对小弟的指点及其鼓励

毕业在即将次愚作献给我的母校---重庆科技学院

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有