我是靠谱客的博主 冷酷招牌,最近开发中收集的这篇文章主要介绍内核对象HOOK内核对象HOOK,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

内核对象HOOK

内核对象的结构

首先我们来了解一下内核对象的基本结构,每一个内核对象都是由对象头和对象体组成,对象头都是一样的,对象体 不同的内核对象是不一样的。该结构体请参考内核结构体。

//0x20 bytes (sizeof)
struct _OBJECT_HEADER
{
    LONG PointerCount;                                                      //0x0           //对象的指针计数
    union
    {
        LONG HandleCount;                                                   //0x4           //对象的引用计数
        VOID* NextToFree;                                                   //0x4
    };
    struct _EX_PUSH_LOCK Lock;                                              //0x8
    UCHAR TypeIndex;                                                        //0xc           //对象类型
    UCHAR TraceFlags;                                                       //0xd
    UCHAR InfoMask;                                                         //0xe
    UCHAR Flags;                                                            //0xf
    union
    {
        struct _OBJECT_CREATE_INFORMATION* ObjectCreateInfo;                //0x10
        VOID* QuotaBlockCharged;                                            //0x10
    };
    VOID* SecurityDescriptor;                                               //0x14
    struct _QUAD Body;                                                      //0x18           //对象ti
}; 

内核对象的获取

获取ObTypeIndexTable首地址, 地址在ObGetObjectType函数内部中出现,因此, 取函数首地址, 加上一定偏移就能得到该表的首地址.在win7 32系统下, 该表在函数中的0xF偏移处。

kd> u ObGetObjectType
	nt!ObGetObjectType:
	84291a72 8bff            mov     edi,edi
	84291a74 55              push    ebp
	84291a75 8bec            mov     ebp,esp
	84291a77 8b4508          mov     eax,dword ptr [ebp+8]
	84291a7a 0fb640f4        movzx   eax,byte ptr [eax-0Ch]
	84291a7e 8b0485c0801784  mov     eax,dword ptr nt!ObTypeIndexTable (841780c0)[eax*4]
	84291a85 5d              pop     ebp
	84291a86 c20400          ret     4

内核对象HOOK

     测试环境:
                          > windows7 32位
       HOOK步骤:
                          >找到内核对象原型数组
                          >遍历数组,得到指定类型的原型对象
                          >修改原型对象中的函数指针
       首先构造进程内核对象和函数原型。这里以Hook进程内核对象的OpenProcessDure函数为例,以打开记事本展开实验。
//内核对象
//0x88 bytes (sizeof)
struct _OBJECT_TYPE
{
    struct _LIST_ENTRY TypeList;                                            //0x0
    struct _UNICODE_STRING Name;                                            //0x8
    VOID* DefaultObject;                                                    //0x10
    UCHAR Index;                                                            //0x14
    ULONG TotalNumberOfObjects;                                             //0x18
    ULONG TotalNumberOfHandles;                                             //0x1c
    ULONG HighWaterNumberOfObjects;                                         //0x20
    ULONG HighWaterNumberOfHandles;                                         //0x24
    struct _OBJECT_TYPE_INITIALIZER TypeInfo;                               //0x28
    struct _EX_PUSH_LOCK TypeLock;                                          //0x78
    ULONG Key;                                                              //0x7c
    struct _LIST_ENTRY CallbackList;                                        //0x80
}; 

//0x50 bytes (sizeof)
//内核对象的操作函数结构体
struct _OBJECT_TYPE_INITIALIZER
{
    USHORT Length;                                                          //0x0
    union
    {
        UCHAR ObjectTypeFlags;                                              //0x2
        struct
        {
            UCHAR CaseInsensitive:1;                                        //0x2
            UCHAR UnnamedObjectsOnly:1;                                     //0x2
            UCHAR UseDefaultObject:1;                                       //0x2
            UCHAR SecurityRequired:1;                                       //0x2
            UCHAR MaintainHandleCount:1;                                    //0x2
            UCHAR MaintainTypeList:1;                                       //0x2
            UCHAR SupportsObjectCallbacks:1;                                //0x2
        };
    };
    ULONG ObjectTypeCode;                                                   //0x4
    ULONG InvalidAttributes;                                                //0x8
    struct _GENERIC_MAPPING GenericMapping;                                 //0xc
    ULONG ValidAccessMask;                                                  //0x1c
    ULONG RetainAccess;                                                     //0x20
    enum _POOL_TYPE PoolType;                                               //0x24
    ULONG DefaultPagedPoolCharge;                                           //0x28
    ULONG DefaultNonPagedPoolCharge;                                        //0x2c
    VOID (*DumpProcedure)(VOID* arg1, struct _OBJECT_DUMP_CONTROL* arg2);   //0x30
    LONG (*OpenProcedure)(enum _OB_OPEN_REASON arg1, CHAR arg2, struct _EPROCESS* arg3, VOID* arg4, ULONG* arg5, ULONG arg6); //0x34
    VOID (*CloseProcedure)(struct _EPROCESS* arg1, VOID* arg2, ULONG arg3, ULONG arg4); //0x38
    VOID (*DeleteProcedure)(VOID* arg1);                                    //0x3c
    LONG (*ParseProcedure)(VOID* arg1, VOID* arg2, struct _ACCESS_STATE* arg3, CHAR arg4, ULONG arg5, struct _UNICODE_STRING* arg6, struct _UNICODE_STRING* arg7, VOID* arg8, struct _SECURITY_QUALITY_OF_SERVICE* arg9, VOID** arg10); //0x40
    LONG (*SecurityProcedure)(VOID* arg1, enum _SECURITY_OPERATION_CODE arg2, ULONG* arg3, VOID* arg4, ULONG* arg5, VOID** arg6, enum _POOL_TYPE arg7, struct _GENERIC_MAPPING* arg8, CHAR arg9); //0x44
    LONG (*QueryNameProcedure)(VOID* arg1, UCHAR arg2, struct _OBJECT_NAME_INFORMATION* arg3, ULONG arg4, ULONG* arg5, CHAR arg6); //0x48
    UCHAR (*OkayToCloseProcedure)(struct _EPROCESS* arg1, VOID* arg2, VOID* arg3, CHAR arg4); //0x4c
}; 

//函数原型需用到该枚举变量
typedef enum _OB_OPEN_REASON { 
	ObCreateHandle,
	ObOpenHandle,
	ObDuplicateHandle,
	ObInheritHandle,
	ObMaxOpenReason
} OB_OPEN_REASON;


//OpenProcessDure函数原型
typedef NTSTATUS(*OB_OPEN_METHOD)(
	IN ULONG Unknown,
	IN OB_OPEN_REASON OpenReason,
	IN PEPROCESS Process OPTIONAL,
	IN PVOID Object,
	IN ACCESS_MASK GrantedAccess,
	IN ULONG HandleCount
	);

// 声明函数 获取内核对象表地址
PULONG _declspec(dllimport) ObGetObjectType(PVOID);

//用来保存系统进程对象地址
POBJECT_TYPE g_pFileObjTypeProcess;

//用来保存原来系统打开进程内核对象的函数
OB_OPEN_METHOD g_oldObjectParseProcess;

//定义自己的打开进程内核对象函数
NTSTATUS MyIopParseProcess(
	IN ULONG Unknown,
	IN OB_OPEN_REASON OpenReason,
	IN PEPROCESS Process OPTIONAL,
	IN PVOID Object,
	IN ACCESS_MASK GrantedAccess,
	IN ULONG HandleCount)
{
         //打开进程的名称保存的Object的偏移位0x16c位置,比较进程名
	if (
		RtlCompareMemory(((char*)Object + 0x16c), "notepad.exe", 12) == 12
		)
	{
               //当打开记事本程序时返回失败

		return STATUS_UNSUCCESSFUL;
	}
                //不是则调用系统打开进程的函数
	return ((OB_OPEN_METHOD)g_oldObjectParseProcess)(0, OpenReason, Process, Object, GrantedAccess, HandleCount);

}

//进程内核对象HOOK
NTSTATUS OnDeviceCtrlObjProcessHook(DEVICE_OBJECT* pDevice, IRP* pIrp)
{
	//获取typeIndexTable表的位置
	ULONG addr = ObGetObjectType;
	OBJECT_TYPE** typeIndexTable = (OBJECT_TYPE*)*(ULONG*)(addr + 0xF);
	//在表中找到文件内核对象
	ULONG i = 2;
	UNICODE_STRING fileTypeName;
	RtlInitUnicodeString(&fileTypeName, L"Process");
	POBJECT_TYPE fileObjType = NULL;

	// 遍历TypeIndex表,找到File对象的原型
	while (typeIndexTable[i])
	{
		// 判断类型名是否一致
		if (0 == RtlCompareUnicodeString(&typeIndexTable[i]->Name, &fileTypeName, TRUE))
		{
                        //保存内核对象的di'zhi
			g_pFileObjTypeProcess = typeIndexTable[i];
			break;
		}
		++i;
	}

	//替换函数地址
	if (g_pFileObjTypeProcess)
	{
		//保存老函数地址
		g_oldObjectParseProcess = (OB_OPEN_METHOD)g_pFileObjTypeProcess->TypeInfo.OpenProcedure;
		//替换新函数地址
		g_pFileObjTypeProcess->TypeInfo.OpenProcedure = (PVOID)MyIopParseProcess;
	}
}

//卸载进程内核对象HOOK
NTSTATUS OnDeviceCtrlUnloadProHook(DEVICE_OBJECT* pDevice, IRP* pIrp)
{
	if (g_pFileObjTypeProcess)
	{
		_asm sti; // 屏蔽中断
		// 将原始函数还原回去
		g_pFileObjTypeProcess->TypeInfo.OpenProcedure = g_oldObjectParseProcess;
		_asm cli; // 允许中断
	}
}

实验测试

      >新建文本文档,打开
      >Hook 进程内核对象
      >再次打开记事本失败

在这里插入图片描述
在这里插入图片描述

总结

此实验程序三环用MFC框架编写,利用设备IRP_MJ_DEVICE_CONTROL进行通讯,可以看成三环发送消息进内核,内核处理消息,这里就不多叙述了。
HOOK的关键在于找到内核对象原型数组,这里只介绍了32位win7环境下的方法。有兴趣的话可以查找其他方法。知道了以上过程,就可以对其他内核对象进行
HOOK了,方法大同小异。

最后

以上就是冷酷招牌为你收集整理的内核对象HOOK内核对象HOOK的全部内容,希望文章能够帮你解决内核对象HOOK内核对象HOOK所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部