ACPI调试
Linux内核调试
Windows内核调试
 
  调试战役
调试原理
新工具观察
 
  Linux
Windows Vista
Windows
 
  Linux驱动
WDF
WDM
 
  PCI Express
PCI/PCI-X
USB
无线通信协议
 
  64位CPU
ARM
IA-32
  CPU Info Center
 
  ACPI标准
系统认证
Desktop
服务器
 
  Embedded Linux
嵌入式开发工具
VxWorks
WinCE
嵌入式Windows
沪ICP备05041459号
About AdvDbg Consult Train Services Products Tools Community Contact   登录 | 注册

跟踪随笔一则

首先预祝张老师5月份即将出版的新书《软件调试》(Debugging Principle) 能获得巨大的成功!^_^ 其实就张老师十余年的技术积累、沉淀来看该书的成功也是必然。怎奈鄙人才疏学浅,许多方面只是一知半解(Machine Checked Architect / JTAG Debugging / KD Engine etc...),并不敢妄加评论... 所以我还是力所能及,先写点小文章道个喜吧。

也确实好久没写随笔了,一直忙于各种杂事和内核跟踪。今天整理一些平时的跟踪涂鸦贴过来,请各位前辈指正!
C的代码就不完整列了,毕竟微$不让... 感兴趣的话需要自己对照着查阅 WRK1.2 或是 ReactOS0.44,所以下面的信息都是汇编的,而且我每一行都写了注释。

不过也不是什么函数都值得往下面列,大部分情况下编译器生成的代码都中规中矩,看C足矣。细节看多了除了能让你更加清楚过程调用和强身健体以外没什么特别的好处;但也有时编译器会给你些惊喜(当然,好的或抓狂的都有),这些惊喜会让你看到C语言不易被察觉的地方。正好这两天在研究 \ob 文件夹,我选了nt!ObpAllocateObject 这个 ASM 较为特别的函数入手。

; 平台:Win-XP SP2
; 下面的注释缩小显示, 需要研究细节的朋友请拷贝到适当的编辑环境下查看


nt!ObpAllocateObject:
805b6008 8bff            mov     edi,edi                                                    ; ┓
805b600a 55              push    ebp                                                        ; ┣ Prologue
805b600b 8bec            mov     ebp,esp                                                    ; ┛
805b600d 51              push    ecx                                                        ;
805b600e 8b4d08          mov     ecx,dword ptr [ebp+8]                                      ; ECX <-- IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
805b6011 53              push    ebx                                                        ;
805b6012 56              push    esi                                                        ;
805b6013 8b7514          mov     esi,dword ptr [ebp+14h]                                    ; ESI <-- IN PUNICODE_STRING ObjectName
805b6016 33d2            xor     edx,edx                                                    ; ┓ if(ObjectCreateInfo == NULL)
805b6018 3bca            cmp     ecx,edx                                                    ; ┛
805b601a 57              push    edi                                                        ;
805b601b 8b7d10          mov     edi,dword ptr [ebp+10h]                                    ; EDI <-- IN POBJECT_TYPE ObjectType OPTIONAL
805b601e 750e            jne     nt!ObpAllocateObject+0x26 (805b602e)                       ; else 的执行流 (我们目前不走这个执行流)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; 下面这段代码编译器生成的很绝!
805b6020 6a10            push    10h                                                        ; ┓ sizeof(OBJECT_HEADER_NAME_INFO) == sizeof(OBJECT_HEADER_CREATOR_INFO)
805b6022 5b              pop     ebx                                                        ; ┛
805b6023 8955fc          mov     dword ptr [ebp-4],edx                                      ; QuotaInfoSize = 0;
805b6026 895510          mov     dword ptr [ebp+10h],edx                                    ; HandleInfoSize = 0;
805b6029 895d14          mov     dword ptr [ebp+14h],ebx                                    ; CreatorInfoSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
805b602c eb63            jmp     nt!ObpAllocateObject+0x89 (805b6091)                       ; NameInfoSize = sizeof(OBJECT_HEADER_NAME_INFO); 这句最绝,用 EBX 寄存器保存 NameInfoSize,连局部变量都不要
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
805b602e 8b4110          mov     eax,dword ptr [ecx+10h]                                    ; ┓
805b6031 3b8784000000    cmp     eax,dword ptr [edi+84h]                                    ; ┣ (ObjectCreateInfo->PagedPoolCharge != ObjectType->TypeInfo.DefaultPagedPoolCharge)
805b6037 7514            jne     nt!ObpAllocateObject+0x45 (805b604d)                       ; ┛
805b6039 8b4114          mov     eax,dword ptr [ecx+14h]                                    ; ┓
805b603c 3b8788000000    cmp     eax,dword ptr [edi+88h]                                    ; ┣ (ObjectCreateInfo->NonPagedPoolCharge != ObjectType->TypeInfo.DefaultNonPagedPoolCharge)
805b6042 7509            jne     nt!ObpAllocateObject+0x45 (805b604d)                       ; ┛
805b6044 81791800080000  cmp     dword ptr [ecx+18h],800h                                   ; (ObjectCreateInfo->SecurityDescriptorCharge > SE_DEFAULT_SECURITY_QUOTA)
805b604b 7611            jbe     nt!ObpAllocateObject+0x56 (805b605e)                       ; ┓
805b604d 64a124010000    mov     eax,dword ptr fs:[00000124h]                               ; ┃
805b6053 8b4044          mov     eax,dword ptr [eax+44h]                                    ; ┣ (PsGetCurrentProcess() != PsInitialSystemProcess)
805b6056 3b0554a35580    cmp     eax,dword ptr [nt!PsInitialSystemProcess (8055a354)]       ; ┃
805b605c 7508            jne     nt!ObpAllocateObject+0x5e (805b6066)                       ; ┛
805b605e f60120          test    byte ptr [ecx],20h                                         ; (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)
805b6061 8955fc          mov     dword ptr [ebp-4],edx                                      ; ┓ QuotaInfoSize = 0;
805b6064 7407            je      nt!ObpAllocateObject+0x65 (805b606d)                       ; ┛
805b6066 c745fc10000000  mov     dword ptr [ebp-4],10h                                      ; QuotaInfoSize = sizeof(OBJECT_HEADER_QUOTA_INFO);
805b606d 8a477d          mov     al,byte ptr [edi+7Dh]                                      ; --[2 if(ObjectType->TypeInfo.MaintainHandleCount)
805b6070 8b5e04          mov     ebx,dword ptr [esi+4]                                      ; --[3 if(ObjectName->Buffer != NULL)
805b6073 f6d8            neg     al                                                         ; --[2 如果执行NEG指令时操作数为0,则CF将被置0;如果操作数为非零,则CF将被置1
805b6075 1bc0            sbb     eax,eax                                                    ; --[2 (ObjectType->TypeInfo.MaintainHandleCount)为零时,EAX为0;非零时EAX为-1
805b6077 83e008          and     eax,8                                                      ; --[2 得出结果
805b607a f7db            neg     ebx                                                        ; --[3 如果执行NEG指令时操作数为0,则CF将被置0;如果操作数为非零,则CF将被置1
805b607c 894510          mov     dword ptr [ebp+10h],eax                                    ; --[2 保存结果
805b607f 8a477e          mov     al,byte ptr [edi+7Eh]                                      ; --[4 if(ObjectType->TypeInfo.MaintainTypeList)
805b6082 1bdb            sbb     ebx,ebx                                                    ; --[3 if(ObjectName->Buffer != NULL)为零时,EBX为0;非零时EBX为-1
805b6084 83e310          and     ebx,10h                                                    ; --[3 得出结果 (就保存在EBX)
805b6087 f6d8            neg     al                                                         ; --[4 如果执行NEG指令时操作数为0,则CF将被置0;如果操作数为非零,则CF将被置1
805b6089 1bc0            sbb     eax,eax                                                    ; --[4 if(ObjectType->TypeInfo.MaintainTypeList)为零时,EAX为0;非零时EAX为-1
805b608b 83e010          and     eax,10h                                                    ; --[4 得出结果
805b608e 894514          mov     dword ptr [ebp+14h],eax                                    ; --[4 保存结果
--------------------------------------------------------------------------------------------
805b6091 8b4514          mov     eax,dword ptr [ebp+14h]                                    ; CreatorInfoSize == 10h
805b6094 8b4dfc          mov     ecx,dword ptr [ebp-4]                                      ; QuotaInfoSize == 00h
805b6097 03c3            add     eax,ebx                                                    ; NameInfoSize == 10h
805b6099 034510          add     eax,dword ptr [ebp+10h]                                    ; HandleInfoSize == 00h
805b609c 3bfa            cmp     edi,edx                                                    ; (ObjectType == NULL)
805b609e 8d4c0818        lea     ecx,[eax+ecx+18h]                                          ; 这句对象头累加操作也非常绝!
805b60a2 740b            je      nt!ObpAllocateObject+0xa7 (805b60af)                       ; 我们的执行流          o-----------------------------+
805b60a4 399780000000    cmp     dword ptr [edi+80h],edx                                    ; || (ObjectType->TypeInfo.PoolType == NonPagedPool)  |
805b60aa 7403            je      nt!ObpAllocateObject+0xa7 (805b60af)                       ; 我们的执行流          o-----------------------------+
805b60ac 33d2            xor     edx,edx                                                    ; ┓ PoolType = PagedPool;                            |
805b60ae 42              inc     edx                                                        ; ┛                                                  |
805b60af 85ff            test    edi,edi                                                    ; ObjectType == NULL ?  <-----------------------------/
805b60b1 b84f626a54      mov     eax,546A624Fh                                              ; 1. 'TjbO'  我们的执行流          o------------------+
805b60b6 7406            je      nt!ObpAllocateObject+0xb6 (805b60be)                       ;                                                     |
805b60b8 8b87ac000000    mov     eax,dword ptr [edi+0ACh]                                   ; 2. ObjectType->Key               o------------------+
805b60be 0d00000080      or      eax,80000000h                                              ; | PROTECTED_POOL                 <------------------/
805b60c3 50              push    eax                                                        ; (ARG3) : (ObjectType == NULL ? 'TjbO' : ObjectType->Key) | PROTECTED_POOL
805b60c4 8b4518          mov     eax,dword ptr [ebp+18h]                                    ; ┓
805b60c7 03c8            add     ecx,eax                                                    ; ┣ (ARG2) : HeaderSize + ObjectBodySize
805b60c9 51              push    ecx                                                        ; ┛
805b60ca 52              push    edx                                                        ; (ARG1) : PoolType
805b60cb e8b0eff8ff      call    nt!ExAllocatePoolWithTag (80545080)                        ; {FUN} : ExAllocatePoolWithTag()
805b60d0 8bd0            mov     edx,eax                                                    ; ┓
805b60d2 85d2            test    edx,edx                                                    ; ┣ if(ObjectHeader == NULL)
805b60d4 750a            jne     nt!ObpAllocateObject+0xd8 (805b60e0)                       ; ┛
805b60d6 b89a0000c0      mov     eax,0C000009Ah                                             ; return STATUS_INSUFFICIENT_RESOURCES;
805b60db e925010000      jmp     nt!ObpAllocateObject+0x1fd (805b6205)                      ; -=[ 程序错误退出 ]=-
--------------------------------------------------------------------------------------------
805b60e0 8b4dfc          mov     ecx,dword ptr [ebp-4]                                      ; ┓
805b60e3 85c9            test    ecx,ecx                                                    ; ┣ 1. 我们没有 _OBJECT_HEADER_QUOTA_INFO 结构
805b60e5 7421            je      nt!ObpAllocateObject+0x100 (805b6108)                      ; ┛
805b60e7 8b4508          mov     eax,dword ptr [ebp+8]                                      ; ┓
805b60ea 8b4010          mov     eax,dword ptr [eax+10h]                                    ; ┣ QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
805b60ed 8902            mov     dword ptr [edx],eax                                        ; ┛
805b60ef 8b4508          mov     eax,dword ptr [ebp+8]                                      ; ┓
805b60f2 8b4014          mov     eax,dword ptr [eax+14h]                                    ; ┣ QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
805b60f5 894204          mov     dword ptr [edx+4],eax                                      ; ┛
805b60f8 8b4508          mov     eax,dword ptr [ebp+8]                                      ; ┓
805b60fb 8b4018          mov     eax,dword ptr [eax+18h]                                    ; ┣ QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge;
805b60fe 83620c00        and     dword ptr [edx+0Ch],0                                      ; QuotaInfo->ExclusiveProcess = NULL;
805b6102 894208          mov     dword ptr [edx+8],eax                                      ; ┛
805b6105 83c210          add     edx,10h                                                    ; 对象头指针跳过可选头 _OBJECT_HEADER_QUOTA_INFO
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
805b6108 837d1000        cmp     dword ptr [ebp+10h],0                                      ; ┓ 2. 我们没有 _OBJECT_HEADER_HANDLE_INFO 结构
805b610c 7407            je      nt!ObpAllocateObject+0x10d (805b6115)                      ; ┛
805b610e 83620400        and     dword ptr [edx+4],0                                        ; HandleInfo->SingleEntry.HandleCount = 0;
805b6112 83c208          add     edx,8                                                      ; 对象头指针跳过可选头 _OBJECT_HEADER_HANDLE_INFO
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
805b6115 85db            test    ebx,ebx                                                    ; ┓ 3. 我们存在 _OBJECT_HEADER_NAME_INFO 结构
805b6117 7418            je      nt!ObpAllocateObject+0x129 (805b6131)                      ; ┛
805b6119 8b06            mov     eax,dword ptr [esi]                                        ; EAX <-- IN PUNICODE_STRING ObjectName
805b611b 894204          mov     dword ptr [edx+4],eax                                      ; ┓
805b611e 8b4604          mov     eax,dword ptr [esi+4]                                      ; ┣ NameInfo->Name = *ObjectName;
805b6121 832200          and     dword ptr [edx],0                                          ; NameInfo->Directory = NULL;
805b6124 894208          mov     dword ptr [edx+8],eax                                      ; ┛
805b6127 c7420c01000000  mov     dword ptr [edx+0Ch],1                                      ; NameInfo->QueryReferences = 1;
805b612e 83c210          add     edx,10h                                                    ; 对象头指针跳过可选头 _OBJECT_HEADER_NAME_INFO
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
805b6131 837d1400        cmp     dword ptr [ebp+14h],0                                      ; ┓ 4. 我们存在 _OBJECT_HEADER_CREATOR_INFO 结构
805b6135 741f            je      nt!ObpAllocateObject+0x14e (805b6156)                      ; ┛
805b6137 6683620c00      and     word ptr [edx+0Ch],0                                       ; CreatorInfo->CreatorBackTraceIndex = 0;
805b613c 64a124010000    mov     eax,dword ptr fs:[00000124h]                               ; ┓
805b6142 8b4044          mov     eax,dword ptr [eax+44h]                                    ; ┣ PsGetCurrentProcess()->UniqueProcessId;
805b6145 8b8084000000    mov     eax,dword ptr [eax+84h]                                    ; ┛
805b614b 894208          mov     dword ptr [edx+8],eax                                      ; CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcess()->UniqueProcessId;
805b614e 895204          mov     dword ptr [edx+4],edx                                      ; ┓ InitializeListHead(&CreatorInfo->TypeList);
805b6151 8912            mov     dword ptr [edx],edx                                        ; ┛
805b6153 83c210          add     edx,10h                                                    ; 对象头指针跳过可选头 _OBJECT_HEADER_CREATOR_INFO
--------------------------------------------------------------------------------------------
805b6156 85c9            test    ecx,ecx                                                    ; ┓ 1. 我们没有 _OBJECT_HEADER_QUOTA_INFO 结构
805b6158 740d            je      nt!ObpAllocateObject+0x15f (805b6167)                      ; ┛ if(QuotaInfoSize != 0)
805b615a 024d10          add     cl,byte ptr [ebp+10h]                                      ; ┓
805b615d 02cb            add     cl,bl                                                      ; ┃ ObjectHeader->QuotaInfoOffset = (UCHAR)(QuotaInfoSize +   \
805b615f 024d14          add     cl,byte ptr [ebp+14h]                                      ; ┣        HandleInfoSize +   \
805b6162 884a0e          mov     byte ptr [edx+0Eh],cl                                      ; ┃        NameInfoSize   +   \
805b6165 eb04            jmp     nt!ObpAllocateObject+0x163 (805b616b)                      ; ┛        CreatorInfoSize);
805b6167 c6420e00        mov     byte ptr [edx+0Eh],0                                       ; ObjectHeader->QuotaInfoOffset = 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
805b616b 837d1000        cmp     dword ptr [ebp+10h],0                                      ; ┓ 2. 我们没有 _OBJECT_HEADER_HANDLE_INFO 结构
805b616f 740d            je      nt!ObpAllocateObject+0x176 (805b617e)                      ; ┛ if(HandleInfoSize != 0)
805b6171 8a4510          mov     al,byte ptr [ebp+10h]                                      ; ┓
805b6174 02c3            add     al,bl                                                      ; ┃ ObjectHeader->HandleInfoOffset = (UCHAR)(HandleInfoSize +  \
805b6176 024514          add     al,byte ptr [ebp+14h]                                      ; ┣        NameInfoSize   +   \
805b6179 88420d          mov     byte ptr [edx+0Dh],al                                      ; ┃        CreatorInfoSize);
805b617c eb04            jmp     nt!ObpAllocateObject+0x17a (805b6182)                      ; ┛
805b617e c6420d00        mov     byte ptr [edx+0Dh],0                                       ; ObjectHeader->HandleInfoOffset = 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
805b6182 33c9            xor     ecx,ecx                                                    ; ┓ 3. 我们存在 _OBJECT_HEADER_NAME_INFO 结构
805b6184 3bd9            cmp     ebx,ecx                                                    ; ┛ if(NameInfoSize != 0)
805b6186 7408            je      nt!ObpAllocateObject+0x188 (805b6190)                      ; ┓
805b6188 025d14          add     bl,byte ptr [ebp+14h]                                      ; ┣ ObjectHeader->NameInfoOffset = (UCHAR)(NameInfoSize +  \
805b618b 885a0c          mov     byte ptr [edx+0Ch],bl                                      ; ┃        CreatorInfoSize);
805b618e eb04            jmp     nt!ObpAllocateObject+0x18c (805b6194)                      ; ┛
805b6190 c6420c00        mov     byte ptr [edx+0Ch],0                                       ; ObjectHeader->NameInfoOffset = 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
805b6194 394d14          cmp     dword ptr [ebp+14h],ecx                                    ; ┓ 4. 我们存在 _OBJECT_HEADER_CREATOR_INFO 结构,但没有单独的域表示 CreatorInfoOffset
805b6197 c6420f01        mov     byte ptr [edx+0Fh],1                                       ; ObjectHeader->Flags = OB_FLAG_NEW_OBJECT;
805b619b 7404            je      nt!ObpAllocateObject+0x199 (805b61a1)                      ; ┛
805b619d c6420f05        mov     byte ptr [edx+0Fh],5                                       ; OB_FLAG_NEW_OBJECT | OB_FLAG_CREATOR_INFO
805b61a1 394d10          cmp     dword ptr [ebp+10h],ecx                                    ; ┓ if(HandleInfoSize != 0) {
805b61a4 7404            je      nt!ObpAllocateObject+0x1a2 (805b61aa)                      ; ┣     ObjectHeader->Flags |= OB_FLAG_SINGLE_HANDLE_ENTRY;
805b61a6 804a0f40        or      byte ptr [edx+0Fh],40h                                     ; ┛ }
805b61aa 807d0c00        cmp     byte ptr [ebp+0Ch],0                                       ; ┓ if(OwnershipMode == KernelMode)
805b61ae c70201000000    mov     dword ptr [edx],1                                          ; ObjectHeader->PointerCount = 1;                    <<<<
805b61b4 894a04          mov     dword ptr [edx+4],ecx                                      ; ObjectHeader->HandleCount = 0;                     <<<<
805b61b7 897a08          mov     dword ptr [edx+8],edi                                      ; ObjectHeader->Type = ObjectType;                   <<<<
805b61ba 7504            jne     nt!ObpAllocateObject+0x1b8 (805b61c0)                      ; ┣ ObjectHeader->Flags |= OB_FLAG_KERNEL_OBJECT;
805b61bc 804a0f02        or      byte ptr [edx+0Fh],2                                       ; ┛
805b61c0 8b4508          mov     eax,dword ptr [ebp+8]                                      ; ┓
805b61c3 3bc1            cmp     eax,ecx                                                    ; ┣ (ObjectCreateInfo != NULL)
805b61c5 7412            je      nt!ObpAllocateObject+0x1d1 (805b61d9)                      ; ┛
805b61c7 f60010          test    byte ptr [eax],10h                                         ; && (ObjectCreateInfo->Attributes & OBJ_PERMANENT)
805b61ca 7404            je      nt!ObpAllocateObject+0x1c8 (805b61d0)                      ; ┓ ObjectHeader->Flags |= OB_FLAG_PERMANENT_OBJECT;
805b61cc 804a0f10        or      byte ptr [edx+0Fh],10h                                     ; ┛
805b61d0 f60020          test    byte ptr [eax],20h                                         ; && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)
805b61d3 7404            je      nt!ObpAllocateObject+0x1d1 (805b61d9)                      ; ┓ ObjectHeader->Flags |= OB_FLAG_EXCLUSIVE_OBJECT;
805b61d5 804a0f08        or      byte ptr [edx+0Fh],8                                       ; ┛
805b61d9 3bf9            cmp     edi,ecx                                                    ; ┓ if(ObjectType != NULL)
805b61db 894210          mov     dword ptr [edx+10h],eax                                    ; ObjectHeader->ObjectCreateInfo = ObjectCreateInfo; <<<<
805b61de 894a14          mov     dword ptr [edx+14h],ecx                                    ; ObjectHeader->SecurityDescriptor = NULL;           <<<<
805b61e1 741b            je      nt!ObpAllocateObject+0x1f6 (805b61fe)                      ; ┛
805b61e3 8d7750          lea     esi,[edi+50h]                                              ; ┓
805b61e6 89750c          mov     dword ptr [ebp+0Ch],esi                                    ; ┃
805b61e9 b801000000      mov     eax,1                                                      ; ┣ InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects);
805b61ee 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]                                    ; ┃
805b61f1 0fc101          xadd    dword ptr [ecx],eax                                        ; ┃
805b61f4 8b36            mov     esi,dword ptr [esi]                                        ; ┛
805b61f6 3b7758          cmp     esi,dword ptr [edi+58h]                                    ; if(ObjectType->TotalNumberOfObjects > ObjectType->HighWaterNumberOfObjects) {
805b61f9 7603            jbe     nt!ObpAllocateObject+0x1f6 (805b61fe)                      ;     ObjectType->HighWaterNumberOfObjects = ObjectType->TotalNumberOfObjects;
805b61fb 897758          mov     dword ptr [edi+58h],esi                                    ; }
--------------------------------------------------------------------------------------------
805b61fe 8b451c          mov     eax,dword ptr [ebp+1Ch]                                    ; ┓ *ReturnedObjectHeader = ObjectHeader;
805b6201 8910            mov     dword ptr [eax],edx                                        ; ┛
805b6203 33c0            xor     eax,eax                                                    ; return STATUS_SUCCESS;
805b6205 5f              pop     edi                                                        ; ┓
805b6206 5e              pop     esi                                                        ; ┃
805b6207 5b              pop     ebx                                                        ; ┣ Epilogue
805b6208 c9              leave                                                              ; ┃
805b6209 c21800          ret     18h                                                        ; ┛



对于Win内核程序员来说“对象管理器”应该是一门必修课。众所周知,在对象体的负向偏移处,还有一个大小为18字节的 _OBJECT_HEADER 以及 4个(至多)大小不等的可选头部:

         +-----------------------------------------------------------------+
+------->|  ( _OBJECT_HEADER_QUOTA_INFO )                                  |
|  +---->|  ( _OBJECT_HEADER_HANDLE_INFO )                                 |
|  |  +->|  ( _OBJECT_HEADER_NAME_INFO )                                   |
|  |  |  |  ( _OBJECT_HEADER_CREATOR_INFO )                                |
|  |  |  +------------------------[ Object Header ]------------------------+
|  |  |  | nt!_OBJECT_HEADER                                               |
|  |  |  |   +0x000 PointerCount       : Int4B                             |
|  |  |  |   +0x004 HandleCount        : Int4B                             |
|  |  |  |   +0x004 NextToFree         : Ptr32 Void                        |
|  |  |  |   +0x008 Type               : Ptr32 _OBJECT_TYPE                |
|  |  +-o|   +0x00c NameInfoOffset     : UChar                             |
|  +----o|   +0x00d HandleInfoOffset   : UChar                             |
+-------o|   +0x00e QuotaInfoOffset    : UChar                             |
         |   +0x00f Flags              : UChar                             |
         |   +0x010 ObjectCreateInfo   : Ptr32 _OBJECT_CREATE_INFORMATION  |
         |   +0x010 QuotaBlockCharged  : Ptr32 Void                        |
         |   +0x014 SecurityDescriptor : Ptr32 Void                        |
         |   +0x018 Body               : _QUAD                             |
         +-------------------------[ Object Body ]-------------------------+
         | OBJECT_DIRECTORY, DRIVER_OBJECT, DEVICE_OBJECT, FILE_OBJECT...  |
         +-----------------------------------------------------------------+



那么你是否好奇过,这些结构是在哪里诞生的? 相互关系怎样? 顺序怎样? 等等等等,Well,这些答案都在函数 nt!ObpAllocateObject 里。它的大致内容是这样的:

1.
根据函数的参数一等 (IN POBJECT_CREATE_INFORMATION ObjectCreateInfo) 确定4个可选头部是否存在。
2. 计算首部大小,并根据函数的参数五 (IN ULONG ObjectBodySize) 分配整个对象的空间(包括可选头部、头部和对象体)
3. 如空间分配成功,依次给可选头部初始化
4. 初始化 _OBJECT_HEADER
5. 返回  _OBJECT_HEADER 的指针,程序结束,外层的封装函数继续初始化对象体


可以想见,这个函数的调用会非常的频繁,因为每一个对象(包括头部)都是由它来分配空间并初始化(对象体是由外部的封装函数初始化)的,所以,在这里 Inline Hook 一下我们可以干坏事... 先打住~

Type Object Type 为例,它的头结构是这样的(_OBJECT_BODY 由外层封装 nt!ObCreateObjectType 初始化):

kd> dt nt!_OBJECT_HEADER_NAME_INFO 82ded5d0-20

   +0x000 Directory        : (null)
   +0x004 Name             : _UNICODE_STRING "Type"
   +0x00c QueryReferences  : 1

kd> dt nt!_OBJECT_HEADER_CREATOR_INFO 82ded5d0-10
   +0x000 TypeList         : _LIST_ENTRY [ 0x82ded5c0 - 0x82ded5c0 ]   ; 这个域是可以遍历的 ObpTypeObjectType
   +0x008 CreatorUniqueProcess : (null)
   +0x00c CreatorBackTraceIndex : 0
   +0x00e Reserved         : 0

kd> dt nt!_OBJECT_HEADER 82ded5d0
   +0x000 PointerCount     : 1                  ; 指针引用计数
   +0x004 HandleCount      : 0                  ; 句柄引用计数
   +0x004 NextToFree       : (null)
   +0x008 Type             : (null)             ; 注意这里,目前仍是 NULL
   +0x00c NameInfoOffset   : 0x20 ' '
   +0x00d HandleInfoOffset : 0 ''
   +0x00e QuotaInfoOffset  : 0 ''
   +0x00f Flags            : 0x7 ''             ; OB_FLAG_NEW_OBJECT | OB_FLAG_CREATOR_INFO | OB_FLAG_KERNEL_OBJECT
   +0x010 ObjectCreateInfo : (null)
   +0x010 QuotaBlockCharged : (null)
   +0x014 SecurityDescriptor : (null)
   +0x018 Body             : _QUAD



那么,这个函数的汇编代码有什么特别的地方吗? 其实也什么... 只是看惯了中规中矩的代码后这里有几个地方值得讲一讲:

1.
在确定4个可选头部是否存在的时候,汇编代码混合使用了 NEG / SBB / AND 指令(1个用普通方法,3个用 NEG / SBB),而我个人比较偏爱后者

C的代码是这样的:
        ..............

1)      /* Check if we have quota */
        if (((ObjectCreateInfo->PagedPoolCharge != ObjectType->TypeInfo.DefaultPagedPoolCharge ||
              ObjectCreateInfo->NonPagedPoolCharge != ObjectType->TypeInfo.DefaultNonPagedPoolCharge ||
              ObjectCreateInfo->SecurityDescriptorCharge > SE_DEFAULT_SECURITY_QUOTA) &&
                 PsGetCurrentProcess() != PsInitialSystemProcess) ||
            (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) {

            /* Set quota size */
            QuotaInfoSize = sizeof( OBJECT_HEADER_QUOTA_INFO );
        } else {

            /* No Quota */
            QuotaInfoSize = 0;
        }


2)      /* Check if we have a handle database */
        if (ObjectType->TypeInfo.MaintainHandleCount) {

            /* Set handle database size */
            HandleInfoSize = sizeof( OBJECT_HEADER_HANDLE_INFO );
       } else {

            /* None */
            HandleInfoSize = 0;
        }

        ..............

1) 和 2) 的语义基本一致,可生成的汇编代码却大相径庭:1) 的中规中矩;2) 的简洁高效(连选择分支的跳转语句都没有):

1)   805b602e 8b4110          mov     eax,dword ptr [ecx+10h]
     805b6031 3b8784000000    cmp     eax,dword ptr [edi+84h]
     805b6037 7514            jne     nt!ObpAllocateObject+0x45 (805b604d)
     805b6039 8b4114          mov     eax,dword ptr [ecx+14h]
     805b603c 3b8788000000    cmp     eax,dword ptr [edi+88h]
     805b6042 7509            jne     nt!ObpAllocateObject+0x45 (805b604d)
     805b6044 81791800080000  cmp     dword ptr [ecx+18h],800h
     805b604b 7611            jbe     nt!ObpAllocateObject+0x56 (805b605e)
     805b604d 64a124010000    mov     eax,dword ptr fs:[00000124h]
     805b6053 8b4044          mov     eax,dword ptr [eax+44h]
     805b6056 3b0554a35580    cmp     eax,dword ptr [nt!PsInitialSystemProcess (8055a354)]
     805b605c 7508            jne     nt!ObpAllocateObject+0x5e (805b6066)
     805b605e f60120          test    byte ptr [ecx],20h
     805b6061 8955fc          mov     dword ptr [ebp-4],edx
     805b6064 7407            je      nt!ObpAllocateObject+0x65 (805b606d)
     805b6066 c745fc10000000  mov     dword ptr [ebp-4],10h

2)   805b606d 8a477d          mov     al,byte ptr [edi+7Dh]
     805b6073 f6d8            neg     al
     805b6075 1bc0            sbb     eax,eax
     805b6077 83e008          and     eax,8
     805b607c 894510          mov     dword ptr [ebp+10h],eax

熟悉反汇编的人应该经常能看到 neg / sbb 对,这种代码在处理某些条件语句上往往有很好的效率体现。此时您一定还会说我偷梁换柱,因为 1) 的入口条件过于复杂,是不可以用 neg 指令影响 CF 做简单判定的 —— 嘿嘿,我这里只是示意一下编译上的差别,而这也正是 Win 编译器在编译上述代码时生成了3个简单句1个复杂句的原因。neg / sbb 指令对的原理请参见代码注释,这里不再累述。


2. nt!ObpAllocateObject 函数局部变量的使用经过了优化

C的代码:
    ULONG QuotaInfoSize;
    ULONG HandleInfoSize;
    ULONG NameInfoSize;
    ULONG CreatorInfoSize;
    .........

    //
    //  Now compute the total header size
    //

    HeaderSize = QuotaInfoSize +
                 HandleInfoSize +
                 NameInfoSize +
                 CreatorInfoSize +
                 FIELD_OFFSET( OBJECT_HEADER, Body );
    .........

四个本应该在局部变量空间上的变量被优化成:1个在局部(栈)上、2个在参数空间上、一个在寄存器里,非常和谐...

     805b6091 8b4514          mov     eax,dword ptr [ebp+14h]    ; CreatorInfoSize == 10h  - 占用了参数空间!
     805b6094 8b4dfc          mov     ecx,dword ptr [ebp-4]      ; QuotaInfoSize   == 00h
     805b6097 03c3            add     eax,ebx                    ; NameInfoSize    == 10h  - 占用了 EBX 寄存器!
     805b6099 034510          add     eax,dword ptr [ebp+10h]    ; HandleInfoSize  == 00h  - 占用了参数空间!
     805b609e 8d4c0818        lea     ecx,[eax+ecx+18h]          ; 这句对象头累加操作也非常绝!



既然聊到了对象管理器,那下面显然还应该聊聊句柄表。句柄表是由函数 nt!ExpAllocateHandleTable 创建的,它的第一次调用位于 nt!ObInitSystem,目标是 SYSTEM 进程。

nt!ExpAllocateHandleTable:
8060325c 8bff            mov     edi,edi                                                    ; ┓
8060325e 55              push    ebp                                                        ; ┣ Prologue
8060325f 8bec            mov     ebp,esp                                                    ; ┛
80603261 56              push    esi                                                        ; : HandleTable
80603262 684f627462      push    6274624Fh                                                  ; (ARG) : 'btbO'
80603267 6a44            push    44h                                                        ; (ARG) : sizeof(HANDLE_TABLE)
80603269 6a01            push    1                                                          ; (ARG) : PagedPool
8060326b e8101ef4ff      call    nt!ExAllocatePoolWithTag (80545080)                        ; {FUN} : ExAllocatePoolWithTag()
80603270 8bf0            mov     esi,eax                                                    ; ┓
80603272 85f6            test    esi,esi                                                    ; ┣ ExAllocatePoolWithTag() 返回值判断
80603274 0f84b1000000    je      nt!ExpAllocateHandleTable+0xcf (8060332b)                  ; ┛
8060327a 53              push    ebx                                                        ; : Process
8060327b 8b5d08          mov     ebx,dword ptr [ebp+8]                                      ; ┓ EBX <-- Process
8060327e 85db            test    ebx,ebx                                                    ; ┣ if(ARGUMENT_PRESENT(Process))
80603280 741b            je      nt!ExpAllocateHandleTable+0x41 (8060329d)                  ; ┛
80603282 6a44            push    44h                                                        ; (ARG) : sizeof(HANDLE_TABLE)
80603284 53              push    ebx                                                        ; (ARG) : Process
80603285 e8c641f2ff      call    nt!PsChargeProcessPagedPoolQuota (80527450)                ; {FUN} : PsChargeProcessPagedPoolQuota()
8060328a 85c0            test    eax,eax                                                    ; ┓ 函数 ExpAllocateHandleTable() 的返回值判断
8060328c 7d0f            jge     nt!ExpAllocateHandleTable+0x41 (8060329d)                  ; ┛ 正确的程序执行流
8060328e 6a00            push    0                                                          ; (ARG) : 0
80603290 56              push    esi                                                        ; (ARG) : HandleTable
80603291 e85017f4ff      call    nt!ExFreePoolWithTag (805449e6)                            ; {FUN} : ExFreePoolWithTag()
80603296 33c0            xor     eax,eax                                                    ; return NULL;
80603298 e98d000000      jmp     nt!ExpAllocateHandleTable+0xce (8060332a)                  ; -=[ 程序错误退出 ]=-
--------------------------------------------------------------------------------------------
8060329d 57              push    edi