首页
社区
课程
招聘
[原创] 续上篇,Win7 32位下遍历目录对象的方法探究
发表于: 2018-3-29 11:29 4580

[原创] 续上篇,Win7 32位下遍历目录对象的方法探究

2018-3-29 11:29
4580
1.原因,不多说。
2.说明,本文算不得教学资料,如有侵犯大佬版权,望告知即刻删除。此方法您可以参考后嵌入到商业用途,只为共享的大白兔声明。
3.思路来源同上篇类似,不能明白要参考此文的同仁请跳转上篇。
4.下面开启我的探究之路:
同对象实现,Win7 32位下果然和XP发什么了过渡,结构上就做了一些微妙的调整。
kd> !object \device\video0
Object: 882cbc48(对象地址)  Type: (86ee6f78) Device(对象的类型)
    ObjectHeader: 882cbc30 (new version)(和XP比较,算是新版本了吧,hah)
    HandleCount: 0  PointerCount: 3
    Directory Object: 8dc0f760(目录对象的地址,表示上一级 (\device) 对象的地址)  Name: Video0(此对象的名字)




看完这些,我们可以获取到对象的地址,对象的类型,对象的名字,那么,我相信,遍历对象目录的方案又是可行的,接着往下走,分析他们的结构。


对于此结构,请参考XP版本的过渡,我分析出来的对象头,对象类型结构如下(请注意,命名的时候我为了兼容,所以加了后缀_WIN7_32):
typedef struct _OBJECT_CREATE_INFORMATION_WIN7_32 
{
   ULONG Attributes;
   PVOID RootDirectory;
   PVOID ParseContext;
   CHAR ProbeMode;
   ULONG PagedPoolCharge;
   ULONG NonPagedPoolCharge;
   ULONG SecurityDescriptorCharge;
   PVOID SecurityDescriptor;
   PSECURITY_QUALITY_OF_SERVICE SecurityQos;
   SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
}OBJECT_CREATE_INFORMATION_WIN7_32,* POBJECT_CREATE_INFORMATION_WIN7_32;

typedef struct _OBJECT_HEADER_WIN7_32
{
    ULONG PointerCount;
    union
    {
        ULONG HandleCount;
        PVOID NextToFree;
    };
    EX_PUSH_LOCK Lock;
    UCHAR TypeIndex;
    UCHAR TraceFlags;
    UCHAR InfoMask;
    UCHAR Flags;
    union
    {
        POBJECT_CREATE_INFORMATION_WIN7_32 ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };

    PVOID SecurityDescriptor;
    QUAD Body;
} OBJECT_HEADER_WIN7_32, * POBJECT_HEADER_WIN7_32;

typedef struct _OBJECT_TYPE_FlAGS_WIN7_32
{  
    UCHAR CaseInsensitive : 1;  
    UCHAR UnnamedObjectsOnly : 1;  
    UCHAR UseDefaultObject : 1;  
    UCHAR SecurityRequired : 1;  
    UCHAR MaintainHandleCount : 1;  
    UCHAR MaintainTypeList : 1;  
    UCHAR SupportsObjectCallbacks : 1;  
    UCHAR CacheAligned : 1;  
}OBJECT_TYPE_FlAGS_WIN7_32, *POBJECT_TYPE_FlAGS_WIN7_32; 

typedef struct _OBJECT_TYPE_INITIALIZER_WIN7_32 
{
   USHORT Length       ;
   _OBJECT_TYPE_FlAGS_WIN7_32 ObjectTypeFlags; 
   ULONG  ObjectTypeCode      ;
   ULONG  InvalidAttributes   ;
   GENERIC_MAPPING   GenericMapping;
   ULONG ValidAccessMask      ;
   ULONG RetainAccess       ;
   POOL_TYPE PoolType               ;
   ULONG DefaultPagedPoolCharge      ;
   ULONG DefaultNonPagedPoolCharge   ;
   PVOID DumpProcedure     ;
   PLONG OpenProcedure     ;
   PVOID CloseProcedure    ;
   PVOID DeleteProcedure   ; 
   PLONG ParseProcedure    ; 
   PLONG SecurityProcedure ;
   PLONG QueryNameProcedure     ;
   PUCHAR OkayToCloseProcedure  ;
} OBJECT_TYPE_INITIALIZER_WIN7_32, *POBJECT_TYPE_INITIALIZER_WIN7_32;

typedef struct _OBJECT_TYPE_WIN7_32 
{
   LIST_ENTRY TypeList        ; 
   UNICODE_STRING Name        ;  
   PVOID DefaultObject       ;
   ULONG Index         ;
   ULONG TotalNumberOfObjects ;
   ULONG TotalNumberOfHandles ;
   ULONG HighWaterNumberOfObjects ;
   ULONG HighWaterNumberOfHandles ;
   OBJECT_TYPE_INITIALIZER_WIN7_32 TypeInfo ;
   EX_PUSH_LOCK TypeLock;       
   ULONG Key             ;
   LIST_ENTRY CallbackList;
 } OBJECT_TYPE_WIN7_32, *POBJECT_TYPE_WIN7_32;
首先,是获取对象的类型,由思路我们想到,通过对象头 的 TypeIndex 可能可以找到我们的对象的类型,那么从字面意义上查看,为什么是类型索引呢?
这点我们应该可以想到,这可能是链接到某一个存类型的列表或者数组中去,而这个就代表的是索引值。为了加快进度,网上有前辈们整理的相关知识,我这里就不多加赘述,确实和我猜想的一般模样。对于类型对象来说,它是固定的,表征的是各个对象的类型,在XP版本上是直接将Type地址存放在对象头的结构中,而Win7则做了改进,将各种类型对象的地址存放入一个表中,然后以他们的下标作为他们的索引,什么类型的对象就存放它对应的 TypeIndex。对于我的测试表来说,我的 \device\video0的类型对象地址位 86ee6f78,上图中也看到类型的名称为Device ,查看头对象中的索引值,0x19 = 25 。
请注意,大佬可以不管,这里面的第一列什么也不是,(不要算入到索引中) ,至于是什么?我来猜一下。第一列看它数据都是0x84192-- 第二列第一个数减去第一列的第一个数,发现其他几行也一样都是0X10 = 16 这什么意思呢?32位的机器上存放地址指针就是32位的也就是十六进制数的8位,连续存了4个32位的地址,然后就不存了么?会不会是这个样子呢?那这个问腿怎么验证呢?当然有办法,很明显的一个思路,我来遍历出类型对象的列表,把它存放的地址和列表下标的地址(也就是地址的地址)都显示出来,不就可以验证我的猜想了么?大佬切莫怪罪,小生无显摆之意,遇到这个问腿思考一下,验证一下,共享一下。
我得猜想就是Windbg 将他们的某一个地址打印了出来,就像反汇编看函数一样也会出现地址列,而不是指定数组值。

很高兴,能继续把问题思考清楚,根据  Alone_Monkey 研究成果,看到Win7 32 版本尽管修改了存储对象类型的方式,却更简化了求解或者存储类型对象的方法。提供了一个导出函数 NTKERNELAPI PVOID NTAPI   ObGetObjectType(  IN PVOID pObject  );  传入对象就可以获取到对象类型的方法,这点我真的服了,这样比起XP获取类型对象的方法要简单的多,因为不需要我们去分析那么多东西,所以简单。
有了这样一个函数,认真读一读,发现它依旧是根据索引值来查找我们的类型对象的,然后返回出去。想到这里,实际上已经可以实现要获取对象类型的功能了,但我的疑问还没有解决呢?那就看看这个方法是怎么实现的吧。

kd> uf ObGetObjectType
nt!ObGetObjectType:
84271d88 8bff            mov     edi,edi
84271d8a 55              push    ebp
84271d8b 8bec            mov     ebp,esp
84271d8d 8b4508          mov     eax,dword ptr [ebp+8]  ;把参数object的地址赋给eax
84271d90 0fb640f4        movzx   eax,byte ptr [eax-0Ch] ; 获取TypeIndex的值,解释一下为什么是减去0Ch  =  eax-0x18h + 0x0Ch
                                                                                         ;eax -0x18h 获取到对象的头地址,然后头地址偏移算得索引值
84271d94 8b0485e0ae1584  mov     eax,dword ptr nt!ObTypeIndexTable (8415aee0)[eax*4];这里很明显就是查表运算咯,
                                                                                                                                                   ;且可以看到表的首地址就是 8415aee0
84271d9b 5d              pop     ebp
84271d9c c20400          ret     4
好了,清晰明了。表的首地址都看见了,对比对比,很明显,那一列就是我们的地址,疑问消除。
那我还是不爽勒,我还没把所有的类型对象给枚举出来嘛,那就查个表看看,查到结果以后,我又有了一个疑问,那就是他们作为固定的类型对象,他们是不是真的被操作系统写死的呢?我认为是的,但也不能说完全是,因为存储类型对象的地址确实发生了一些变化,关机重启验证,发现存表的首地址发生了变化,而且从索引值为2的类型对象地址值也发生了变化,这是为什么呢?要搞清楚类型表中的地址存法,还要知道操作系统初始化时那些地址会被写入到内核中,这是一个很复杂的问题,暂时不去深究。但我们可以确定的是,对于对象管理来说,Win7 32 位版本确实将类型索引列表写入到了一块内存中,而且,我猜他们应该写入在对象管理器存储各个对象之前,因为这样才能正确的存储各个对象。这个很好验证,随便查看根目录下的对象



可以发现一个问题,就是根目录对象的地址还要高于索引表地址,所以猜想是正确的。处理完这些疑问,我们可以先实现一个枚举类型对象的方法,
枚举这一个类型对象的方法就是使用 ObGetObjectType 这个函数,先获取到表中某索引的值,然后向前遍历获取到表首地址,然后写个循环去遍历类型对象,注意遍历此类型对象需要从索引值2开始,其实就是指针加个2。下面就是我的实现代码, 请注意 ,使用了硬编码,所以不算什么好代码,但也足够了,因为正常使用是不需要此遍历的,这主要是研究来用,如果您要安装这个代码到您的Win7 32位机器请注意查看并修改硬编码。



好了,现在类型对象搞定了,接下来就是搞定名字了。
首先来确定存储对象名字的结构有没有发生改变,
发现结构是一样的,只是微软修改了一下第三个类型的名字,而类型并没有得到修改。
然后我们验证一下:

发现XP的方法直接找偏移量寻找到地址的方法行不通了,怎么办呢?那看看大佬 achillis 的思路,发现原来InfoMask 里面的东西才是特别重要的,这里面可以找到我们XP中3大结构的偏移量,那么对于WIN 7 32 位它是怎么去计算的呢?哈哈,WIN7 32 位真是个调皮聪明的娃,又来一个表,这表是什么玩意呢?
说的就是有对象头下的可变对象结构有5个,可有可无,一共会有2的5次方也就是32种情况,而这32种情况就是要InfoMask来锁定的,类似于位运算吧。
先定义一套来分析:

结构1:_OBJECT_HEADER_PROCESS_INFO        sizeof:0x08
结构2:_OBJECT_HEADER_QUOTA_INFO             sizeof:0x10
结构3:_OBJECT_HEADER_HANDLE_INFO           sizeof:0x08
结构4:_OBJECT_HEADER_NAME_INFO               sizeof:0x10
结构5:_OBJECT_HEADER_CREATOR_INFO        sizeof:0x10
分别为他们定义一个掩码来确定有没有此结构:
    #define OB_INFOMASK_PROCESS_INFO     0x10
    #define OB_INFOMASK_QUOTA                     0x08
    #define OB_INFOMASK_HANDLE                   0x04
    #define OB_INFOMASK_NAME                       0x02
    #define OB_INFOMASK_CREATOR_INFO      0x01 
按大佬的思路,我们怎么去验证呢?我的思路是这样的,看到上面\device\video0设备对象的infoMask = 0x2 这说明这个设备对象只存在这一个 OB_INFOMASK_NAME结构体,然后再加上对象头结构和对象体结构,如果按照累计结构定义,那对象头结构的前一段有效的可变对象头结构内存大小应该是根据掩码而定的,对于infoMask = 0x2来说,可以得到对象名结构体的地址必然是对象头地址减去它的大小,即0x884cec32-0x10得到的就是此结构首地址。
看到这一结果,真的是这样,那么,这样就得到了一种获取到对象信息的思路了。什么思路呢?首先要获取到的是对象的地址,然后接着就是从对象的地址中分析出来对象的头结构,然后从对象头结构中分析出来对象的类型,以及可变对象头结构掩码,以此确定此对象拥有什么结构,然后算有效的内存偏移,最后将结构中的有用信息分析出来。这样清晰的思路很有效,从大佬 achillis的文章中,我参照Win7 32 位获取对象信息名的API, NTKERNELAPI   PVOID NTAPI  ObQueryNameInfo(IN PVOID Object) ,我们来反汇编一下看看是这么实现根据对象取出它的名字的呢?
kd> uf ObQueryNameInfo
nt!ObQueryNameInfo:
842c9a73 8bff            mov     edi,edi
842c9a75 55              push    ebp
842c9a76 8bec            mov     ebp,esp
842c9a78 8b4508          mov     eax,dword ptr [ebp+8]; 把参数object的地址赋给eax
842c9a7b 8a48f6          mov     cl,byte ptr [eax-0Ah];似曾相识呢,把对象地址减去0x18得到地址头对象,然后算偏移加0x00e得到地址掩码
842c9a7e 83c0e8          add     eax,0FFFFFFE8h;地址加操作,地址+ (0FFFFFF[1110 1000] 注意补码 (取反之后加1)算就是 0x18), 
842c9a81 f6c102          test    cl,2;test 指令,判断cl寄存器中的地址掩码值得第二位有没有值,也就是说有无对象名称确认,有跳入查询
842c9a84 7411            je      nt!ObQueryNameInfo+0x24 (842c9a97);调用下一个函数

nt!ObQueryNameInfo+0x13:
842c9a86 0fb6c9          movzx   ecx,cl;将掩码值带符号传送
842c9a89 83e103          and     ecx,3;按位与操作,和3进行与操作,则ecx专门用来判断结构4和结构5数据
842c9a8c 0fb68980141984  movzx   ecx,byte ptr nt!ObpInfoMaskToOffset (84191480)[ecx];根据掩码算地址偏移量,0x10 或者0x20
842c9a93 2bc1            sub     eax,ecx;对象头地址减去我们得地址偏移
842c9a95 eb02            jmp     nt!ObQueryNameInfo+0x26 (842c9a99);跳转返回指令

nt!ObQueryNameInfo+0x24:;
842c9a97 33c0            xor     eax,eax;异或指令

nt!ObQueryNameInfo+0x26:
842c9a99 5d              pop     ebp
842c9a9a c20400          ret     4
看完这段汇编代码,满满的感动,没错啊,这就是我们WIN7 32 位下要获取对象的名字的方法呀。您可以不需要实现具体算法,只要调用此函数就可以在Win7 32位系统下获取到对象的名字。至于实现,那就把他们换成我们自己的玩法啦,自己玩一下哈。大佬 achillis 的文章中也已经给出了源代码,很高兴能和大佬的思路一般。请原谅小生的班门弄斧,仅为共享的大白兔敬上。代码实现如下://WIN7_32位的机器上获取对象的名字
void GetObjectNameInWin7_32(PVOID object)
{
//传入对象,按汇编思路,先得到头结构
POBJECT_HEADER_WIN7_32 pObjectHeader;
POBJECT_HEADER_NAME_INFO_WIN7_32 pObejctHeaderNameInfo;
UCHAR InfoMask;
KdPrint(("GetObjectNameInWin7_32() Enter.\n"));
pObjectHeader = OBJECT_TO_OBJECT_HEADER_WIN7_32(object);
KdPrint(("此对象[0x%08x] 的头对象为 [0x%08x].\n", object, pObjectHeader));
//得到掩码的值
InfoMask = pObjectHeader->InfoMask;
KdPrint(("此对象[0x%08x] 的掩码为 [0x%02x]. ObpInfoMaskToOffset[InfoMask] = [0x%08x]\n", object, InfoMask, ObpInfoMaskToOffset[InfoMask]));
//根据掩码值算出我们的名字结构体地址偏移量,同时还要得到最后的名字结构体地址,这里的实现参考大佬的方法
pObejctHeaderNameInfo = (ULONG)pObjectHeader - ObpInfoMaskToOffset[InfoMask & 3];
KdPrint(("此对象[0x%08x] 的名称结构体为 : [0x%08x].\n", object, pObejctHeaderNameInfo));
//最后打印结果
KdPrint(("此对象[0x%08x] 的名称为 : [%wZ].\n", object, &(pObejctHeaderNameInfo->Name)));
}
特别说明,此处 pObejctHeaderNameInfo = (ULONG)pObjectHeader - ObpInfoMaskToOffset[InfoMask & 3];代码中有一个小细节,您要实现代码的时候要对对象的头指针进行一个简单的类型转换,不然做减法运算的时候会出现错误,至于原因,内核级代码就这样,对于指针这样的类型没有办法去实现隐士转换,导致出现计算错误,这个小细节可能会让您的代码更为正确,计算结果如下,正确。

很高兴,能继续探究Win7 32位下对目录对象的遍历方法,到此为止,我们对于对象的操作基本明确,获取到对象的类型,对象的名称,两大重要版块信息也给出了实现方案,那就简单了,至于要实现目录对象的遍历,思路在上篇就说明清楚了,这里就不多细讲了。找到根目录作为起点,遍历出子节点对象的信息,对象地址,对象名,对象类型,如果是目录对象,继续遍历下一个子节点,知道完成遍历过程。
参考Win7 32位版本的目录对象结构体的修改,我定义如下:
typedef struct _OBJECT_DIRECTORY_WIN7_32 *POBJECT_DIRECTORY_WIN7_32;
typedef struct _OBJECT_DIRECTORY_ENTRY_WIN7_32 *POBJECT_DIRECTORY_ENTRY_WIN7_32;

typedef struct _DEVICE_MAP_WIN7_32
{
    POBJECT_DIRECTORY_WIN7_32 DosDevicesDirectory;
    POBJECT_DIRECTORY_WIN7_32 GlobalDosDevicesDirectory;
    PVOID DosDevicesDirectoryHandle;
    ULONG  ReferenceCount;
    ULONG  DriveMap;
    UCHAR DriveType[32];
 } DEVICE_MAP_WIN7_32, *PDEVICE_MAP_WIN7_32;

typedef struct _OBJECT_DIRECTORY_ENTRY_WIN7_32
{
   POBJECT_DIRECTORY_ENTRY_WIN7_32 ChainLink;
   PVOID Object; 
   ULONG HashValue;
} OBJECT_DIRECTORY_ENTRY_WIN7_32, *POBJECT_DIRECTORY_ENTRY_WIN7_32;

typedef struct _OBJECT_DIRECTORY_WIN7_32
{
    POBJECT_DIRECTORY_ENTRY_WIN7_32 HashBuckets[NUMBER_HASH_BUCKETS];
    EX_PUSH_LOCK Lock;
    PDEVICE_MAP_WIN7_32 DeviceMap;
    ULONG   SessionId;
    PVOID   NamespaceEntry;
    PVOID  SessionObject;
    ULONG  Flags;
} OBJECT_DIRECTORY_WIN7_32, *POBJECT_DIRECTORY_WIN7_32;

下面是我的融合源码(里面有XP及win7 32位下的实现),您可以拷贝到一个.c文件中进行编译,如果存在问题,请告知,编译版本和操作系统版本,如果我有时间会为您修复。

///////////////////////////////////////////////////
//作者:wo最爱吃大白兔
//时间:2018/3/30
////////////////////////////////////////////////////
#include <ntifs.h>
#define NUMBER_HASH_BUCKETS 37

//////////////////////////////////////////////////////////////////////////XP 32 位 版本//////////////////////////////////////////////////////////////////////////
typedef struct _OBJECT_DIRECTORY_XP *POBJECT_DIRECTORY_XP;
typedef struct _OBJECT_DIRECTORY_ENTRY_XP *POBJECT_DIRECTORY_ENTRY_XP;
typedef struct _OBJECT_TYPE_XP  *POBJECT_TYPE_XP;
typedef struct _DEVICE_MAP_XP
{
    POBJECT_DIRECTORY_XP DosDevicesDirectory;
    POBJECT_DIRECTORY_XP GlobalDosDevicesDirectory;
    ULONG  ReferenceCount;
    ULONG  DriveMap;
    UCHAR DriveType[32];
 } DEVICE_MAP_XP, * PDEVICE_MAP_XP;

typedef struct _OBJECT_DIRECTORY_ENTRY_XP
{
  POBJECT_DIRECTORY_ENTRY_XP ChainLink;
  PVOID Object;
} OBJECT_DIRECTORY_ENTRY_XP, *POBJECT_DIRECTORY_ENTRY_XP;

typedef struct _OBJECT_DIRECTORY_XP
{
    POBJECT_DIRECTORY_ENTRY_XP HashBuckets[NUMBER_HASH_BUCKETS];
    EX_PUSH_LOCK Lock;
    PDEVICE_MAP_XP DeviceMap;
    ULONG   SessionId;
    USHORT Reserved;
    USHORT SymbolicLinkUsageCount;
} OBJECT_DIRECTORY_XP, * POBJECT_DIRECTORY_XP;

typedef struct _OBJECT_CREATE_INFORMATION_XP 
{
   ULONG Attributes;
   PVOID RootDirectory;
   PVOID ParseContext;
   CHAR ProbeMode;
   ULONG PagedPoolCharge;
   ULONG NonPagedPoolCharge;
   ULONG SecurityDescriptorCharge;
   PVOID SecurityDescriptor;
   PSECURITY_QUALITY_OF_SERVICE SecurityQos;
   SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
}OBJECT_CREATE_INFORMATION_XP,* POBJECT_CREATE_INFORMATION_XP;

typedef struct _OBJECT_HEADER_XP
{
    ULONG PointerCount;
    union
    {
        ULONG HandleCount;
        PVOID NextToFree;
    };
    POBJECT_TYPE_XP Type;
    UCHAR NameInfoOffset;
    UCHAR HandleInfoOffset;
    UCHAR QuotaInfoOffset;
    UCHAR Flags;
    union
    {
        POBJECT_CREATE_INFORMATION_XP ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };
    PVOID SecurityDescriptor;
    QUAD Body;
} OBJECT_HEADER_XP, * POBJECT_HEADER_XP;

typedef struct _OBJECT_HEADER_NAME_INFO_XP 
{
    POBJECT_DIRECTORY_XP Directory;
    UNICODE_STRING Name;
    ULONG QueryReferences;
} OBJECT_HEADER_NAME_INFO_XP, *POBJECT_HEADER_NAME_INFO_XP;

typedef struct _OBJECT_TYPE_INITIALIZER_XP 
{
   ERESOURCE Mutex            ; 
   LIST_ENTRY TypeList        ; 
   UNICODE_STRING Name         ;  
   PVOID DefaultObject ;
   ULONG Index ;
   ULONG TotalNumberOfObjects ;
   ULONG TotalNumberOfHandles ;
   ULONG HighWaterNumberOfObjects ;
   ULONG HighWaterNumberOfHandles ;
   struct _OBJECT_TYPE_INITIALIZER_XP *TypeInfo ;
   ULONG Key             ;
   ERESOURCE ObjectLocks[4];
   USHORT Length ;
   UCHAR UseDefaultObject
   UCHAR CaseInsensitive ;
   ULONG InvalidAttributes ;
   GENERIC_MAPPING GenericMapping   ;
   ULONG ValidAccessMask ;
   UCHAR SecurityRequired ;
   UCHAR MaintainHandleCount ;
   UCHAR MaintainTypeList ;
   POOL_TYPE PoolType               ;
   ULONG DefaultPagedPoolCharge      ;
   ULONG DefaultNonPagedPoolCharge   ;
   PVOID DumpProcedure     ;
   PLONG OpenProcedure     ;
   PVOID CloseProcedure    ;
   PVOID DeleteProcedure   ; 
   PLONG ParseProcedure    ; 
   PLONG SecurityProcedure ;
   PLONG QueryNameProcedure     ;
   PUCHAR OkayToCloseProcedure  ;
} OBJECT_TYPE_INITIALIZER_XP, *POBJECT_TYPE_INITIALIZER_XP;

typedef struct _OBJECT_TYPE_XP 
{
   ERESOURCE Mutex            ; 
   LIST_ENTRY TypeList        ; 
   UNICODE_STRING Name        ;  
   PVOID DefaultObject ;
   ULONG Index ;
   ULONG TotalNumberOfObjects ;
   ULONG TotalNumberOfHandles ;
   ULONG HighWaterNumberOfObjects ;
   ULONG HighWaterNumberOfHandles ;
   OBJECT_TYPE_INITIALIZER_XP TypeInfo ;
   ULONG Key             ;
   ERESOURCE  ObjectLocks[4] ;
 } OBJECT_TYPE_XP, *POBJECT_TYPE_XP;

//获取到对象的结构体部分
#define OBJECT_TO_OBJECT_HEADER_XP( o ) \
    CONTAINING_RECORD( (o), OBJECT_HEADER_XP, Body )

//XP下根据对象的头获取到它的名字信息部分
#define OBJECT_HEADER_TO_NAME_INFO_XP( oh ) ((POBJECT_HEADER_NAME_INFO_XP) \
    ((oh)->NameInfoOffset == 0 ? NULL : ((PCHAR)(oh) - (oh)->NameInfoOffset)))

//////////////////////////////////////////////////////////////////////////WIN7 32 位 版本//////////////////////////////////////////////////////////////////////////

typedef struct _OBJECT_DIRECTORY_WIN7_32 *POBJECT_DIRECTORY_WIN7_32;
typedef struct _OBJECT_DIRECTORY_ENTRY_WIN7_32 *POBJECT_DIRECTORY_ENTRY_WIN7_32;

typedef struct _DEVICE_MAP_WIN7_32
{
    POBJECT_DIRECTORY_WIN7_32 DosDevicesDirectory;
    POBJECT_DIRECTORY_WIN7_32 GlobalDosDevicesDirectory;
    PVOID DosDevicesDirectoryHandle;
    ULONG  ReferenceCount;
    ULONG  DriveMap;
    UCHAR DriveType[32];
 } DEVICE_MAP_WIN7_32, *PDEVICE_MAP_WIN7_32;

typedef struct _OBJECT_DIRECTORY_ENTRY_WIN7_32
{
   POBJECT_DIRECTORY_ENTRY_WIN7_32 ChainLink;
   PVOID Object; 
   ULONG HashValue;
} OBJECT_DIRECTORY_ENTRY_WIN7_32, *POBJECT_DIRECTORY_ENTRY_WIN7_32;

typedef struct _OBJECT_DIRECTORY_WIN7_32
{
    POBJECT_DIRECTORY_ENTRY_WIN7_32 HashBuckets[NUMBER_HASH_BUCKETS];
    EX_PUSH_LOCK Lock;
    PDEVICE_MAP_WIN7_32 DeviceMap;
    ULONG   SessionId;
    PVOID   NamespaceEntry;
    PVOID  SessionObject;
    ULONG  Flags;
} OBJECT_DIRECTORY_WIN7_32, *POBJECT_DIRECTORY_WIN7_32;

typedef struct _OBJECT_CREATE_INFORMATION_WIN7_32 
{
   ULONG Attributes;
   PVOID RootDirectory;
   PVOID ParseContext;
   CHAR ProbeMode;
   ULONG PagedPoolCharge;
   ULONG NonPagedPoolCharge;
   ULONG SecurityDescriptorCharge;
   PVOID SecurityDescriptor;
   PSECURITY_QUALITY_OF_SERVICE SecurityQos;
   SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
}OBJECT_CREATE_INFORMATION_WIN7_32,* POBJECT_CREATE_INFORMATION_WIN7_32;

typedef struct _OBJECT_HEADER_WIN7_32
{
    ULONG PointerCount;
    union
    {
        ULONG HandleCount;
        PVOID NextToFree;
    };
    EX_PUSH_LOCK Lock;
    UCHAR TypeIndex;
    UCHAR TraceFlags;
    UCHAR InfoMask;
    UCHAR Flags;
    union
    {
        POBJECT_CREATE_INFORMATION_WIN7_32 ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };

    PVOID SecurityDescriptor;
    QUAD Body;
} OBJECT_HEADER_WIN7_32, * POBJECT_HEADER_WIN7_32;


typedef struct _OBJECT_TYPE_FlAGS_WIN7_32
{  
    UCHAR CaseInsensitive : 1;  
    UCHAR UnnamedObjectsOnly : 1;  
    UCHAR UseDefaultObject : 1;  
    UCHAR SecurityRequired : 1;  
    UCHAR MaintainHandleCount : 1;  
    UCHAR MaintainTypeList : 1;  
    UCHAR SupportsObjectCallbacks : 1;  
    UCHAR CacheAligned : 1;  
}OBJECT_TYPE_FlAGS_WIN7_32, *POBJECT_TYPE_FlAGS_WIN7_32; 

typedef struct _OBJECT_TYPE_INITIALIZER_WIN7_32 
{
   USHORT Length       ;
   OBJECT_TYPE_FlAGS_WIN7_32 ObjectTypeFlags; 
   ULONG  ObjectTypeCode      ;
   ULONG  InvalidAttributes   ;
   GENERIC_MAPPING   GenericMapping;
   ULONG ValidAccessMask      ;
   ULONG RetainAccess       ;
   POOL_TYPE PoolType               ;
   ULONG DefaultPagedPoolCharge      ;
   ULONG DefaultNonPagedPoolCharge   ;
   PVOID DumpProcedure     ;
   PLONG OpenProcedure     ;
   PVOID CloseProcedure    ;
   PVOID DeleteProcedure   ; 
   PLONG ParseProcedure    ; 
   PLONG SecurityProcedure ;
   PLONG QueryNameProcedure     ;
   PUCHAR OkayToCloseProcedure  ;
} OBJECT_TYPE_INITIALIZER_WIN7_32, *POBJECT_TYPE_INITIALIZER_WIN7_32;

typedef struct _OBJECT_TYPE_WIN7_32 
{
   LIST_ENTRY TypeList        ; 
   UNICODE_STRING Name        ;  
   PVOID DefaultObject       ;
   ULONG Index         ;
   ULONG TotalNumberOfObjects ;
   ULONG TotalNumberOfHandles ;
   ULONG HighWaterNumberOfObjects ;
   ULONG HighWaterNumberOfHandles ;
   OBJECT_TYPE_INITIALIZER_WIN7_32 TypeInfo ;
   EX_PUSH_LOCK TypeLock;       
   ULONG Key             ;
   LIST_ENTRY CallbackList;

 } OBJECT_TYPE_WIN7_32, *POBJECT_TYPE_WIN7_32;

typedef struct _OBJECT_HEADER_NAME_INFO_WIN7_32
{
POBJECT_DIRECTORY_WIN7_32 Directory;
UNICODE_STRING Name;
ULONG ReferenceCount;
} OBJECT_HEADER_NAME_INFO_WIN7_32, *POBJECT_HEADER_NAME_INFO_WIN7_32;

typedef struct  _OBJECT_HEADER_CREATOR_INFO_WIN7_32
{
LIST_ENTRY TypeList;
PVOID CreatorUniqueProcess;
USHORT CreatorBackTraceIndex;
USHORT Reserved;
}OBJECT_HEADER_CREATOR_INFO_WIN7_32, *POBJECT_HEADER_CREATOR_INFO_WIN7_32;

//////////////////////////////////////////////////////////////////

typedef struct  _H_L_COUNT
{
ULONG HandleCount : 24;
ULONG LockCount : 8;
}H_L_COUNT, *P_H_L_COUNT;

typedef struct  _OBJECT_HANDLE_COUNT_ENTRY_WIN7_32
{
PEPROCESS Process;
H_L_COUNT Count;

}OBJECT_HANDLE_COUNT_ENTRY_WIN7_32, *POBJECT_HANDLE_COUNT_ENTRY_WIN7_32;

typedef struct  _OBJECT_HANDLE_COUNT_DATABASE_WIN7_32
{
ULONG CountEntries;
OBJECT_HANDLE_COUNT_ENTRY_WIN7_32 HandleCountEntries[1];
}OBJECT_HANDLE_COUNT_DATABASE_WIN7_32, *POBJECT_HANDLE_COUNT_DATABASE_WIN7_32;

typedef struct  _OBJECT_HEADER_HANDLE_INFO_WIN7_32
{
OBJECT_HANDLE_COUNT_DATABASE_WIN7_32 TypeList;
OBJECT_HANDLE_COUNT_ENTRY_WIN7_32 SingleEntry;
}OBJECT_HEADER_HANDLE_INFO_WIN7_32, *POBJECT_HEADER_HANDLE_INFO_WIN7_32;

//////////////////////////////////////////////////////////////////////
typedef struct _OBJECT_HEADER_QUOTA_INFO_WIN7_32
{
ULONG PagedPoolCharge;
ULONG NonPagedPoolCharge;
ULONG SecurityDescriptorCharge;
PVOID SecurityDescriptorQuotaBlock;
}OBJECT_HEADER_QUOTA_INFO_WIN7_32, *POBJECT_HEADER_QUOTA_INFO_WIN7_32;

typedef struct _OBJECT_HEADER_PROCESS_INFO_WIN7_32
{
PEPROCESS ExclusiveProcess;
ULONG Reserved;
}OBJECT_HEADER_PROCESS_INFO_WIN7_32, *POBJECT_HEADER_PROCESS_INFO_WIN7_32;

//获取到对象的结构体部分
#define OBJECT_TO_OBJECT_HEADER_WIN7_32( o ) \
    CONTAINING_RECORD( (o), OBJECT_HEADER_WIN7_32, Body )
//定义一套掩码用来做地址分析

#define OB_INFOMASK_PROCESS_INFO 0x10
#define OB_INFOMASK_QUOTA               0x08
#define OB_INFOMASK_HANDLE              0x04
#define OB_INFOMASK_NAME                0x02
#define OB_INFOMASK_CREATOR_INFO        0x01 
//还要做一份掩码查询表,定义一个掩码表
ULONG ObpInfoMaskToOffset[32] = { 0 };
 
void InitInfoMaskTable()
 {
ULONG i = 0;
ULONG offset = 0;
do
{
offset = 0;
if (i & OB_INFOMASK_CREATOR_INFO)
offset = sizeof(OBJECT_HEADER_CREATOR_INFO_WIN7_32);
if (i & OB_INFOMASK_NAME)
offset += sizeof(OBJECT_HEADER_NAME_INFO_WIN7_32);
if (i & OB_INFOMASK_HANDLE)
offset += sizeof(OBJECT_HEADER_HANDLE_INFO_WIN7_32);
if (i & OB_INFOMASK_QUOTA)
offset += sizeof(OBJECT_HEADER_QUOTA_INFO_WIN7_32);
if (i & OB_INFOMASK_PROCESS_INFO)
offset += sizeof(OBJECT_HEADER_PROCESS_INFO_WIN7_32);
ObpInfoMaskToOffset[i] = offset;//算出对应掩码值的最大偏移量
KdPrint(("ObpInfoMaskToOffset[%d] = [0x%08x] .\n", i, ObpInfoMaskToOffset[i]));
i++;
} while (i<32);
 }



//传入要遍历的目录
void EnumDirectoryInXp(POBJECT_DIRECTORY_XP pObejctDirectory)
{
  POBJECT_DIRECTORY_ENTRY_XP pObjectDirectoryEntry;
  POBJECT_HEADER_XP pObjectHeader;
  POBJECT_HEADER_NAME_INFO_XP pObjectHeaderNameInfo;
  int i;
    UNICODE_STRING ustrName;
  RtlInitUnicodeString(&ustrName,L"Directory");
  KdPrint(("------------------------------------正在遍历目录对象:[0x%08x]----------------------.\n",pObejctDirectory));
  for(i = 0; i < NUMBER_HASH_BUCKETS; i ++) 
  {
   pObjectDirectoryEntry = pObejctDirectory->HashBuckets[i];
   if (!MmIsAddressValid(pObjectDirectoryEntry))
   {
    //KdPrint(("-->此节点遍历目录连接对象POBJECT_DIRECTORY_ENTRY无效.\n"));
continue;
   }
   do
   {
  if (!MmIsAddressValid(pObjectDirectoryEntry->Object))
  {
//KdPrint(("-->此节点遍历到的对象pObjectDirectoryEntry->Object无效.\n"));
break;
    }
  pObjectHeader = OBJECT_TO_OBJECT_HEADER_XP(pObjectDirectoryEntry->Object);//根据对象来获取到对象
KdPrint(("[节点 = %02d] 此对象地址为:[0x%08x] , 对象类型为:[%wZ] ,",i,pObjectDirectoryEntry->Object,&(pObjectHeader->Type->Name)));
if (pObjectHeader->NameInfoOffset > 0)
{
   pObjectHeaderNameInfo = OBJECT_HEADER_TO_NAME_INFO_XP(pObjectHeader);//获取到对象名结构体
   KdPrint(("此对象名称为:[%wZ].\n",&(pObjectHeaderNameInfo->Name)));
   //RtlUnicodeStringCopy(&ustrName,&(pObjectName->Name));  
}
else
{
  KdPrint(("此对象没有名称.\n"));
  }
  //如果还是目录对象应该将其展开再次遍历
  if (RtlCompareUnicodeString(&(pObjectHeader->Type->Name),&ustrName,TRUE) == 0)
  {
EnumDirectoryInXp((POBJECT_DIRECTORY_XP)pObjectDirectoryEntry->Object);
  }   
  pObjectDirectoryEntry = pObjectDirectoryEntry->ChainLink;

   }while(pObjectDirectoryEntry != NULL);
}
KdPrint(("------------------------------------遍历此目录对象完成----------------------.\n"));
}



//WIN7_32位的机器上获取对象的名字
void GetObjectNameInWin7_32(PVOID object)
{
//传入对象,按汇编思路,先得到头结构
POBJECT_HEADER_WIN7_32 pObjectHeader;
POBJECT_HEADER_NAME_INFO_WIN7_32 pObejctHeaderNameInfo;
UCHAR InfoMask;
KdPrint(("GetObjectNameInWin7_32() Enter.\n"));
pObjectHeader = OBJECT_TO_OBJECT_HEADER_WIN7_32(object);
KdPrint(("此对象[0x%08x] 的头对象为 [0x%08x].\n", object, pObjectHeader));
//得到掩码的值
InfoMask = pObjectHeader->InfoMask;
KdPrint(("此对象[0x%08x] 的掩码为 [0x%02x]. ObpInfoMaskToOffset[InfoMask] = [0x%08x]\n", object, InfoMask, ObpInfoMaskToOffset[InfoMask]));
//根据掩码值算出我们的名字结构体地址偏移量,同时还要得到最后的名字结构体地址,这里的实现参考大佬的方法
pObejctHeaderNameInfo = (ULONG)pObjectHeader - ObpInfoMaskToOffset[InfoMask & 3];
KdPrint(("此对象[0x%08x] 的名称结构体为 : [0x%08x].\n", object, pObejctHeaderNameInfo));
//最后打印结果
KdPrint(("此对象[0x%08x] 的名称为 : [%wZ].\n", object, &(pObejctHeaderNameInfo->Name)));
}

NTSTATUS GetObjectName()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID  Object = 0x8844fa68;
GetObjectNameInWin7_32(Object);
//解除对象引用
return status;
}
//传入要遍历的目录

NTKERNELAPI PVOID NTAPI ObGetObjectType(IN PVOID pObject);
NTKERNELAPI PVOID NTAPI  ObQueryNameInfo(IN PVOID Object);
void EnumDirectoryInWin7_32(POBJECT_DIRECTORY_WIN7_32 pObejctDirectory)
{
  POBJECT_DIRECTORY_ENTRY_WIN7_32 pObjectDirectoryEntry;
  POBJECT_HEADER_WIN7_32 pObjectHeader;
  POBJECT_HEADER_NAME_INFO_WIN7_32 pObjectHeaderNameInfo;
  int i;
    UNICODE_STRING ustrName;
  RtlInitUnicodeString(&ustrName,L"Directory");
  KdPrint(("------------------------------------正在遍历目录对象:[0x%08x]----------------------.\n",pObejctDirectory));
  for(i = 0; i < NUMBER_HASH_BUCKETS; i ++) 
  {
   pObjectDirectoryEntry = pObejctDirectory->HashBuckets[i];
   if (!MmIsAddressValid(pObjectDirectoryEntry))
   {
    //KdPrint(("-->此节点遍历目录连接对象POBJECT_DIRECTORY_ENTRY无效.\n"));
continue;
   }
   do
   {
  if (!MmIsAddressValid(pObjectDirectoryEntry->Object))
  {
//KdPrint(("-->此节点遍历到的对象pObjectDirectoryEntry->Object无效.\n"));
break;
    }
  pObjectHeader = OBJECT_TO_OBJECT_HEADER_WIN7_32(pObjectDirectoryEntry->Object);//根据对象来获取到对象
  KdPrint(("[节点 = %02d] 此对象地址为:[0x%08x] , 对象类型为:[%wZ] ,", i, pObjectDirectoryEntry->Object,&(((POBJECT_TYPE_WIN7_32)ObGetObjectType(pObjectDirectoryEntry->Object))->Name)));

  pObjectHeaderNameInfo = ObQueryNameInfo(pObjectDirectoryEntry->Object);
  if (pObjectHeaderNameInfo != NULL)
{
  //获取到对象名结构体
   KdPrint(("此对象名称为:[%wZ].\n",&(pObjectHeaderNameInfo->Name)));  
}
else
{
  KdPrint(("此对象没有名称.\n"));
  }
  //如果还是目录对象应该将其展开再次遍历
  if (RtlCompareUnicodeString(&(((POBJECT_TYPE_WIN7_32)ObGetObjectType(pObjectDirectoryEntry->Object))->Name), &ustrName, TRUE) == 0)
  {
  EnumDirectoryInWin7_32((POBJECT_DIRECTORY_WIN7_32)pObjectDirectoryEntry->Object);
    }   
  pObjectDirectoryEntry = pObjectDirectoryEntry->ChainLink;

   }while(pObjectDirectoryEntry != NULL);
}
KdPrint(("------------------------------------遍历此目录对象完成----------------------.\n"));
}

//这个函数实现WIN7_32位版本的类型对象的遍历
NTSTATUS EnumTypeObejct()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
//定义一个表来存储类型对象的地址,大小我们可能不知道,但依据分析我就给定一个足够大的空间
POBJECT_TYPE_WIN7_32 ObTypeIndexTable[100];
/*根据WINDBG的思路,我发现地址索引值为2的时候,存储的竟然是Type类型,那思路来了
我不管那么多,我先获取到其中的一个索引值,就拿\Device\Video这个对象来说,我得到他的地址,
然后得到地址头,得到对象类型的索引值,然后取地址向前遍历找到表的首地址,可以不硬编码写的.
*/ 
    POBJECT_TYPE_WIN7_32 ObjectType ;
ULONG i = 0;
    KdPrint(("EnumTypeObejct() Enter.\n")); 
//这里我懒得写那么麻烦了,提供了思路,我这里直接硬编码了,主要是为了验证做法正确与否
memcpy(ObTypeIndexTable, 0x84190ee0, 100 * sizeof(POBJECT_TYPE_WIN7_32));
for (i = 0; i < 100;i++)
{
ObjectType = ObTypeIndexTable[i];
if (ObjectType == NULL)
{
continue;
}
//KdPrint(("EnumTypeObejct() ObTypeIndexTable[%d] = [0x%08x].\n", i, ObTypeIndexTable[i]));
KdPrint(("EnumTypeObejct() ObTypeIndexTable[%d] = [0x%08x], 对象类型名称 : [%wZ].\n", i, ObTypeIndexTable[i], &(ObTypeIndexTable[i]->Name)));

}
return status;
}
NTSTATUS EnumObject()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
OBJECT_ATTRIBUTES oaDirectory; 
UNICODE_STRING ustrDirectory; 
PVOID  DirectoryObject = NULL;
HANDLE hDirectory;
//获取目录对象
RtlInitUnicodeString(&ustrDirectory, L"\\Device");
InitializeObjectAttributes(&oaDirectory, &ustrDirectory, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenDirectoryObject(&hDirectory, 0, &oaDirectory);
if (NT_SUCCESS(status) )
{
//提供对象句柄访问许可,获取到对应目录对象
status = ObReferenceObjectByHandle(hDirectory, 0x10000000, 0, 0, &DirectoryObject, 0);
if ( NT_SUCCESS(status) )
{
//从根目录对对象进行遍利,迭代算法
if (FALSE)
{
//如果是XP下
EnumDirectoryInXp((POBJECT_DIRECTORY_XP)DirectoryObject);
}
else
{
EnumDirectoryInWin7_32((POBJECT_DIRECTORY_WIN7_32)DirectoryObject);
}
//如果是Win732位下

//解除对象引用
ObfDereferenceObject(DirectoryObject);
}
status = ZwClose(hDirectory);
  }
return status;
}


void DriverUnload(PDRIVER_OBJECT drv)
{
  KdPrint(("DriverUnload Enter.\n")); 
}
NTSTATUS myDispatchFunction(PDEVICE_OBJECT device,PIRP irp)
{
    irp->IoStatus.Information = 0;
    irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(irp,IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
NTSTATUS status = STATUS_SUCCESS;
size_t i = 0;
    for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)
    {
        driver->MajorFunction[i] = myDispatchFunction;
    }
    driver->DriverUnload = DriverUnload;
//EnumObject();
KdPrint(("DriverEntry Enter.\n")); 
//EnumTypeObejct();
InitInfoMaskTable();
GetObjectName();
EnumObject();
    return status;
}
再次声明,此代码为本人一手所写且在Win7 32为下通过验证,如果和大佬有一样的地方,这里声明位置就是 InitInfoMaskTable()此函数实现,参考大佬方法,其他若还有出处请大佬告知,本人有侵权必会立即修正,严重则即刻删除。
只为共享的大白兔声明,敬上各位大佬,同爱各位同仁。




[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2018-3-30 17:34 被wo爱吃大白兔编辑 ,原因:
上传的附件:
收藏
免费 1
支持
分享
最新回复 (5)
雪    币: 267
活跃值: (779)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
在GetObjectName()里面,PVOID    Object  =  0x8844fa68;  这  0x8844fa68  是什么东东。
2018-4-3 05:54
0
雪    币: 687
活跃值: (97)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
3
WinDos2K 在GetObjectName()里面,PVOID Object = 0x8844fa68; 这 0x8844fa68 是什么东东。
这个就是当时我测试对象的地址,硬编码直接传进去的,每次您要使用这个值时,需要您自己通过Windbg  调试确认这个具体的硬编码值。
2018-4-3 10:49
0
雪    币: 687
活跃值: (97)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
wo爱吃大白兔 这个就是当时我测试对象的地址,硬编码直接传进去的,每次您要使用这个值时,需要您自己通过Windbg 调试确认这个具体的硬编码值。
请到这个贴子下载最后的福利版本,用于XP,WIN7  32,WIN7  64均已测试通过
2018-4-3 10:50
0
雪    币: 687
活跃值: (97)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
5
https://bbs.pediy.com/thread-225632.htm  此贴中于2018年4月3日最后上传版本,兼容性较好,请下载这个版本用于参考
2018-4-3 10:52
0
雪    币: 267
活跃值: (779)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
明白了。
2018-4-3 12:16
0
游客
登录 | 注册 方可回帖
返回
//