<2024年5月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

文章分类

导航

订阅

跟踪随笔一则

首先预祝张老师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                                                        ; : 字符串操作目的地址
8060329e 6a11            push    11h                                                        ; ┓ sizeof(HANDLE_TABLE)
806032a0 59              pop     ecx                                                        ; ┛ 循环计数 44h
806032a1 6800100000      push    1000h                                                      ; (ARG) : TABLE_PAGE_SIZE  (编译器优化-对应下面的函数)
806032a6 33c0            xor     eax,eax                                                    ; ZERO it
806032a8 8bfe            mov     edi,esi                                                    ; 字符串操作目的地址-刚才分配的句柄表
806032aa 53              push    ebx                                                        ; (ARG) : Process          (编译器优化-对应下面的函数)
806032ab f3ab            rep stos dword ptr es:[edi]                                        ; {FUN} : RtlZeroMemory()
806032ad e81afeffff      call    nt!ExpAllocateTablePagedPool (806030cc)                    ; {FUN} : ExpAllocateTablePagedPool() 注意!这里和C代码不同
806032b2 85c0            test    eax,eax                                                    ; ┓ 函数 ExpAllocateTablePagedPool() 的返回值判断
806032b4 7517            jne     nt!ExpAllocateHandleTable+0x71 (806032cd)                  ; ┛ 正确的程序执行流
806032b6 50              push    eax                                                        ; (ARG) : 0
806032b7 56              push    esi                                                        ; (ARG) : HandleTable
806032b8 e82917f4ff      call    nt!ExFreePoolWithTag (805449e6)                            ; {FUN} : ExFreePoolWithTag()
806032bd 85db            test    ebx,ebx                                                    ; ┓
806032bf 7408            je      nt!ExpAllocateHandleTable+0x6d (806032c9)                  ; ┃
806032c1 6a44            push    44h                                                        ; ┣ {FUN} : PsChargeProcessPagedPoolQuota()
806032c3 53              push    ebx                                                        ; ┃
806032c4 e89542f2ff      call    nt!PsReturnProcessPagedPoolQuota (8052755e)                ; ┛
806032c9 33c0            xor     eax,eax                                                    ; return NULL;
806032cb eb5c            jmp     nt!ExpAllocateHandleTable+0xcd (80603329)                  ; -=[ 程序错误退出 ]=-
--------------------------------------------------------------------------------------------
806032cd 6a04            push    4                                                          ; ┓ 下面的代码循环初始化刚刚创建的0级句柄表
806032cf 5a              pop     edx                                                        ; ┛ 这里的 EDX 是循环的累加基数
806032d0 8d4804          lea     ecx,[eax+4]                                                ; 取0级句柄表第一项 NextFreeTableEntry 域的地址
806032d3 8906            mov     dword ptr [esi],eax                                        ; 核心!HandleTable->TableCode = (ULONG_PTR)HandleTableTable;
806032d5 8bfa            mov     edi,edx                                                    ; EDI <-- 要初始化成的初值 4
806032d7 8bd9            mov     ebx,ecx                                                    ; EBX <-- 要初始化的首地址 (见上面)
806032d9 893b            mov     dword ptr [ebx],edi                                        ; 赋值操作
806032db 03fa            add     edi,edx                                                    ; [下一次操作准备] 下一个值
806032dd 83c308          add     ebx,8                                                      ; [下一次操作准备] 下一个地址
806032e0 81ff04080000    cmp     edi,804h                                                   ; ┓ 循环次数,共 200h 次,一个页的大小
806032e6 72f1            jb      nt!ExpAllocateHandleTable+0x7d (806032d9)                  ; ┛
--------------------------------------------------------------------------------------------
806032e8 c701feffffff    mov     dword ptr [ecx],0FFFFFFFEh                                 ; ECX(NextFreeTableEntry) = EX_ADDITIONAL_INFO_SIGNATURE;
806032ee 33c9            xor     ecx,ecx                                                    ; ┓ 清空0级句柄表最后一项表示结束标志
806032f0 8988fc0f0000    mov     dword ptr [eax+0FFCh],ecx                                  ; ┛
806032f6 8b4508          mov     eax,dword ptr [ebp+8]                                      ; 取栈上的参数 Process
806032f9 895630          mov     dword ptr [esi+30h],edx                                    ; HandleTable->FirstFree = HANDLE_VALUE_INC;
806032fc c7463800080000  mov     dword ptr [esi+38h],800h                                   ; HandleTable->NextHandleNeedingPool = LOWLEVEL_COUNT * HANDLE_VALUE_INC;
80603303 894604          mov     dword ptr [esi+4],eax                                      ; HandleTable->QuotaProcess = Process;
80603306 64a124010000    mov     eax,dword ptr fs:[00000124h]                               ; EAX <-- PsGetCurrentThread()
8060330c 8b4044          mov     eax,dword ptr [eax+44h]                                    ; EAX <-- PsGetCurrentProcess()
8060330f 8b8084000000    mov     eax,dword ptr [eax+84h]                                    ; EAX <-- PsGetCurrentProcess()->UniqueProcessId;
80603315 894608          mov     dword ptr [esi+8],eax                                      ; HandleTable->UniqueProcessId = PsGetCurrentProcess()->UniqueProcessId;
80603318 33c0            xor     eax,eax                                                    ; 为下面的 ExInitializePushLock() 准备
8060331a 894e40          mov     dword ptr [esi+40h],ecx                                    ; HandleTable->Flags = 0;
8060331d 8d7e0c          lea     edi,[esi+0Ch]                                              ; ┓  #define HANDLE_TABLE_LOCKS 4
80603320 ab              stos    dword ptr es:[edi]                                         ; ┃
80603321 ab              stos    dword ptr es:[edi]                                         ; ┣  for (Idx = 0; Idx < HANDLE_TABLE_LOCKS; Idx++) {
80603322 ab              stos    dword ptr es:[edi]                                         ; ┃      ExInitializePushLock (&HandleTable->HandleTableLock[Idx]);
80603323 ab              stos    dword ptr es:[edi]                                         ; ┛  }
80603324 894e24          mov     dword ptr [esi+24h],ecx                                    ; ExInitializePushLock(&HandleTable->HandleContentionEvent);
80603327 8bc6            mov     eax,esi                                                    ; return HandleTable;
80603329 5f              pop     edi                                                        ; ┓
8060332a 5b              pop     ebx                                                        ; ┣ 清除栈上的局部变量
8060332b 5e              pop     esi                                                        ; ┛
8060332c 5d              pop     ebp                                                        ; 还原局部堆栈指针
8060332d c20400          ret     4                                                          ; 注意参数!WRK1.2 的C代码是这样的:HandleTable = ExpAllocateHandleTable( Process, TRUE );



我们都清楚对象是基于进程的,为了进程间更好的共享内核对象、更好的控制对象的生命周期,Windows 设计了引用计数域。除了这个域以外 Windows 还做了更多的封装 —— 引申出 _OBJECT_HEADER 的概念(这是 Linux 所没有的),之后,针对于对象头的操作(即方法),Windows 则更是抽象出了所谓的 OB 模块。

既然对象是基于进程的,那么设计一套关联二者的机制便是理所应当。Windows 的设计方案是“句柄表”,查表的 KEY 就是大家经常要打交道的“句柄值”。可以想见 —— 32位的句柄值如何解释一定和句柄表的设计密切相关 —— 而历来这也是微软隐藏最好的地方...

句柄表的设计不是一蹴而就的,它涉及到效率、内存使用量等多个方面。从 Windows 98 到 Windows 2000、windows XP 句柄表一直在变,而这句话的潜台词就是“32位句柄值”的解释也是一直在改变的。


Win-2000 的句柄表设计上颇有 Intel 分页机制的影子,以 Intel 4KB 页大小的映射粒度为例:
CR3寄存器定基址、2^10寻址PDE、2^10寻址PTE、最后2^12寻址实际的物理地址,设计非常精巧,整个32位(线性地址)没有一点浪费,给人感觉很和谐...

而 M$ 再次 Copy /* Steve Jobs : You've Got to Find What You Love */ 了别人的设计思路,搞了 Win-2000 的句柄表蓝本,他们空出了8位多余位(而这8位的“多余位”还是打散的,以3:1的比例分布在句柄值的开头和结尾处),用剩下的24位做句柄表的索引,因此32位的句柄值必须先除以4(空出2个多余位),然后2^8索引第0级句柄表;2^8索引第1级句柄表;最后2^8索引实际的句柄项。

那么您有没有想过 Win-2000 下一个进程的最少句柄表开销是多少? 答案是:256*4 + 256*4 + 256*8 = 1KB。1KB的空间只能存放 256个 句柄项,您不觉得其利用率少的可笑吗?

也许微软也发现了,所以他们在 Win-XP 时彻底改变了句柄表的设计 —— 改变的重点就是句柄表的内存利用率。新的级联机制真正做到按需划分,默认情况下只有包含句柄项的第0级。此时,在同样占内存1KB的情况下,HANDLE-ENTRY 的个数是 512,比 Win-2000 的利用率整整提高了100%。


但这并不值得称赞!我真正想说的是,连句柄转换这套机制其实都是多余,这套机制本身就是在浪费效率,而最终的目的只有微软自己心里清楚 —— 他们比 Linux 内核有着更多的考虑 —— 他们需要隐藏信息、他们不想公开数据结构、他们不想给程序员指针、他们想把内核数据结构完全的封装起来,而操作数据结构的任务由他们来代理,程序员得到的只有那该死的“令牌” —— 句柄...... 显然,他们太有才了。


OK,OK,言归正传,函数 nt!ExpAllocateHandleTable 跑完之后,生成的第0级句柄表在内存里是这样的:
至于原因请参看下面的注释
//
//  Now setup the free list.  We do this by chaining together the free
//  entries such that each free entry give the next free index (i.e.,
//  like a fat chain).  The chain is terminated with a 0.  Note that
//  we'll skip handle zero because our callers will get that value
//  confused with null.
//

kd> dd e1002000 e1002ffc
e1002000  00000000 fffffffe 00000000 00000008

e1002010  00000000 0000000c 00000000 00000010
e1002020  00000000 00000014 00000000 00000018
e1002030  00000000 0000001c 00000000 00000020
e1002040  00000000 00000024 00000000 00000028
e1002050  00000000 0000002c 00000000 00000030
e1002060  00000000 00000034 00000000 00000038
e1002070  00000000 0000003c 00000000 00000040
e1002080  00000000 00000044 00000000 00000048
e1002090  00000000 0000004c 00000000 00000050
e10020a0  00000000 00000054 00000000 00000058
e10020b0  00000000 0000005c 00000000 00000060
e10020c0  00000000 00000064 00000000 00000068
e10020d0  00000000 0000006c 00000000 00000070
e10020e0  00000000 00000074 00000000 00000078
e10020f0  00000000 0000007c 00000000 00000080
e1002100  00000000 00000084 00000000 00000088
e1002110  00000000 0000008c 00000000 00000090
e1002120  00000000 00000094 00000000 00000098
e1002130  00000000 0000009c 00000000 000000a0
e1002140  00000000 000000a4 00000000 000000a8
e1002150  00000000 000000ac 00000000 000000b0
e1002160  00000000 000000b4 00000000 000000b8
e1002170  00000000 000000bc 00000000 000000c0
e1002180  00000000 000000c4 00000000 000000c8
e1002190  00000000 000000cc 00000000 000000d0
e10021a0  00000000 000000d4 00000000 000000d8
e10021b0  00000000 000000dc 00000000 000000e0
e10021c0  00000000 000000e4 00000000 000000e8
e10021d0  00000000 000000ec 00000000 000000f0
e10021e0  00000000 000000f4 00000000 000000f8
e10021f0  00000000 000000fc 00000000 00000100
e1002200  00000000 00000104 00000000 00000108
e1002210  00000000 0000010c 00000000 00000110
e1002220  00000000 00000114 00000000 00000118
e1002230  00000000 0000011c 00000000 00000120
e1002240  00000000 00000124 00000000 00000128
e1002250  00000000 0000012c 00000000 00000130
e1002260  00000000 00000134 00000000 00000138
e1002270  00000000 0000013c 00000000 00000140
e1002280  00000000 00000144 00000000 00000148
e1002290  00000000 0000014c 00000000 00000150
e10022a0  00000000 00000154 00000000 00000158
e10022b0  00000000 0000015c 00000000 00000160
e10022c0  00000000 00000164 00000000 00000168
e10022d0  00000000 0000016c 00000000 00000170
e10022e0  00000000 00000174 00000000 00000178
e10022f0  00000000 0000017c 00000000 00000180
e1002300  00000000 00000184 00000000 00000188
e1002310  00000000 0000018c 00000000 00000190
e1002320  00000000 00000194 00000000 00000198
e1002330  00000000 0000019c 00000000 000001a0
e1002340  00000000 000001a4 00000000 000001a8
e1002350  00000000 000001ac 00000000 000001b0
e1002360  00000000 000001b4 00000000 000001b8
e1002370  00000000 000001bc 00000000 000001c0
e1002380  00000000 000001c4 00000000 000001c8
e1002390  00000000 000001cc 00000000 000001d0
e10023a0  00000000 000001d4 00000000 000001d8
e10023b0  00000000 000001dc 00000000 000001e0
e10023c0  00000000 000001e4 00000000 000001e8
e10023d0  00000000 000001ec 00000000 000001f0
e10023e0  00000000 000001f4 00000000 000001f8
e10023f0  00000000 000001fc 00000000 00000200
e1002400  00000000 00000204 00000000 00000208
e1002410  00000000 0000020c 00000000 00000210
e1002420  00000000 00000214 00000000 00000218
e1002430  00000000 0000021c 00000000 00000220
e1002440  00000000 00000224 00000000 00000228
e1002450  00000000 0000022c 00000000 00000230
e1002460  00000000 00000234 00000000 00000238
e1002470  00000000 0000023c 00000000 00000240
e1002480  00000000 00000244 00000000 00000248
e1002490  00000000 0000024c 00000000 00000250
e10024a0  00000000 00000254 00000000 00000258
e10024b0  00000000 0000025c 00000000 00000260
e10024c0  00000000 00000264 00000000 00000268
e10024d0  00000000 0000026c 00000000 00000270
e10024e0  00000000 00000274 00000000 00000278
e10024f0  00000000 0000027c 00000000 00000280
e1002500  00000000 00000284 00000000 00000288
e1002510  00000000 0000028c 00000000 00000290
e1002520  00000000 00000294 00000000 00000298
e1002530  00000000 0000029c 00000000 000002a0
e1002540  00000000 000002a4 00000000 000002a8
e1002550  00000000 000002ac 00000000 000002b0
e1002560  00000000 000002b4 00000000 000002b8
e1002570  00000000 000002bc 00000000 000002c0
e1002580  00000000 000002c4 00000000 000002c8
e1002590  00000000 000002cc 00000000 000002d0
e10025a0  00000000 000002d4 00000000 000002d8
e10025b0  00000000 000002dc 00000000 000002e0
e10025c0  00000000 000002e4 00000000 000002e8
e10025d0  00000000 000002ec 00000000 000002f0
e10025e0  00000000 000002f4 00000000 000002f8
e10025f0  00000000 000002fc 00000000 00000300
e1002600  00000000 00000304 00000000 00000308
e1002610  00000000 0000030c 00000000 00000310
e1002620  00000000 00000314 00000000 00000318
e1002630  00000000 0000031c 00000000 00000320
e1002640  00000000 00000324 00000000 00000328
e1002650  00000000 0000032c 00000000 00000330
e1002660  00000000 00000334 00000000 00000338
e1002670  00000000 0000033c 00000000 00000340
e1002680  00000000 00000344 00000000 00000348
e1002690  00000000 0000034c 00000000 00000350
e10026a0  00000000 00000354 00000000 00000358
e10026b0  00000000 0000035c 00000000 00000360
e10026c0  00000000 00000364 00000000 00000368
e10026d0  00000000 0000036c 00000000 00000370
e10026e0  00000000 00000374 00000000 00000378
e10026f0  00000000 0000037c 00000000 00000380
e1002700  00000000 00000384 00000000 00000388
e1002710  00000000 0000038c 00000000 00000390
e1002720  00000000 00000394 00000000 00000398
e1002730  00000000 0000039c 00000000 000003a0
e1002740  00000000 000003a4 00000000 000003a8
e1002750  00000000 000003ac 00000000 000003b0
e1002760  00000000 000003b4 00000000 000003b8
e1002770  00000000 000003bc 00000000 000003c0
e1002780  00000000 000003c4 00000000 000003c8
e1002790  00000000 000003cc 00000000 000003d0
e10027a0  00000000 000003d4 00000000 000003d8
e10027b0  00000000 000003dc 00000000 000003e0
e10027c0  00000000 000003e4 00000000 000003e8
e10027d0  00000000 000003ec 00000000 000003f0
e10027e0  00000000 000003f4 00000000 000003f8
e10027f0  00000000 000003fc 00000000 00000400
e1002800  00000000 00000404 00000000 00000408
e1002810  00000000 0000040c 00000000 00000410
e1002820  00000000 00000414 00000000 00000418
e1002830  00000000 0000041c 00000000 00000420
e1002840  00000000 00000424 00000000 00000428
e1002850  00000000 0000042c 00000000 00000430
e1002860  00000000 00000434 00000000 00000438
e1002870  00000000 0000043c 00000000 00000440
e1002880  00000000 00000444 00000000 00000448
e1002890  00000000 0000044c 00000000 00000450
e10028a0  00000000 00000454 00000000 00000458
e10028b0  00000000 0000045c 00000000 00000460
e10028c0  00000000 00000464 00000000 00000468
e10028d0  00000000 0000046c 00000000 00000470
e10028e0  00000000 00000474 00000000 00000478
e10028f0  00000000 0000047c 00000000 00000480
e1002900  00000000 00000484 00000000 00000488
e1002910  00000000 0000048c 00000000 00000490
e1002920  00000000 00000494 00000000 00000498
e1002930  00000000 0000049c 00000000 000004a0
e1002940  00000000 000004a4 00000000 000004a8
e1002950  00000000 000004ac 00000000 000004b0
e1002960  00000000 000004b4 00000000 000004b8
e1002970  00000000 000004bc 00000000 000004c0
e1002980  00000000 000004c4 00000000 000004c8
e1002990  00000000 000004cc 00000000 000004d0
e10029a0  00000000 000004d4 00000000 000004d8
e10029b0  00000000 000004dc 00000000 000004e0
e10029c0  00000000 000004e4 00000000 000004e8
e10029d0  00000000 000004ec 00000000 000004f0
e10029e0  00000000 000004f4 00000000 000004f8
e10029f0  00000000 000004fc 00000000 00000500
e1002a00  00000000 00000504 00000000 00000508
e1002a10  00000000 0000050c 00000000 00000510
e1002a20  00000000 00000514 00000000 00000518
e1002a30  00000000 0000051c 00000000 00000520
e1002a40  00000000 00000524 00000000 00000528
e1002a50  00000000 0000052c 00000000 00000530
e1002a60  00000000 00000534 00000000 00000538
e1002a70  00000000 0000053c 00000000 00000540
e1002a80  00000000 00000544 00000000 00000548
e1002a90  00000000 0000054c 00000000 00000550
e1002aa0  00000000 00000554 00000000 00000558
e1002ab0  00000000 0000055c 00000000 00000560
e1002ac0  00000000 00000564 00000000 00000568
e1002ad0  00000000 0000056c 00000000 00000570
e1002ae0  00000000 00000574 00000000 00000578
e1002af0  00000000 0000057c 00000000 00000580
e1002b00  00000000 00000584 00000000 00000588
e1002b10  00000000 0000058c 00000000 00000590
e1002b20  00000000 00000594 00000000 00000598
e1002b30  00000000 0000059c 00000000 000005a0
e1002b40  00000000 000005a4 00000000 000005a8
e1002b50  00000000 000005ac 00000000 000005b0
e1002b60  00000000 000005b4 00000000 000005b8
e1002b70  00000000 000005bc 00000000 000005c0
e1002b80  00000000 000005c4 00000000 000005c8
e1002b90  00000000 000005cc 00000000 000005d0
e1002ba0  00000000 000005d4 00000000 000005d8
e1002bb0  00000000 000005dc 00000000 000005e0
e1002bc0  00000000 000005e4 00000000 000005e8
e1002bd0  00000000 000005ec 00000000 000005f0
e1002be0  00000000 000005f4 00000000 000005f8
e1002bf0  00000000 000005fc 00000000 00000600
e1002c00  00000000 00000604 00000000 00000608
e1002c10  00000000 0000060c 00000000 00000610
e1002c20  00000000 00000614 00000000 00000618
e1002c30  00000000 0000061c 00000000 00000620
e1002c40  00000000 00000624 00000000 00000628
e1002c50  00000000 0000062c 00000000 00000630
e1002c60  00000000 00000634 00000000 00000638
e1002c70  00000000 0000063c 00000000 00000640
e1002c80  00000000 00000644 00000000 00000648
e1002c90  00000000 0000064c 00000000 00000650
e1002ca0  00000000 00000654 00000000 00000658
e1002cb0  00000000 0000065c 00000000 00000660
e1002cc0  00000000 00000664 00000000 00000668
e1002cd0  00000000 0000066c 00000000 00000670
e1002ce0  00000000 00000674 00000000 00000678
e1002cf0  00000000 0000067c 00000000 00000680
e1002d00  00000000 00000684 00000000 00000688
e1002d10  00000000 0000068c 00000000 00000690
e1002d20  00000000 00000694 00000000 00000698
e1002d30  00000000 0000069c 00000000 000006a0
e1002d40  00000000 000006a4 00000000 000006a8
e1002d50  00000000 000006ac 00000000 000006b0
e1002d60  00000000 000006b4 00000000 000006b8
e1002d70  00000000 000006bc 00000000 000006c0
e1002d80  00000000 000006c4 00000000 000006c8
e1002d90  00000000 000006cc 00000000 000006d0
e1002da0  00000000 000006d4 00000000 000006d8
e1002db0  00000000 000006dc 00000000 000006e0
e1002dc0  00000000 000006e4 00000000 000006e8
e1002dd0  00000000 000006ec 00000000 000006f0
e1002de0  00000000 000006f4 00000000 000006f8
e1002df0  00000000 000006fc 00000000 00000700
e1002e00  00000000 00000704 00000000 00000708
e1002e10  00000000 0000070c 00000000 00000710
e1002e20  00000000 00000714 00000000 00000718
e1002e30  00000000 0000071c 00000000 00000720
e1002e40  00000000 00000724 00000000 00000728
e1002e50  00000000 0000072c 00000000 00000730
e1002e60  00000000 00000734 00000000 00000738
e1002e70  00000000 0000073c 00000000 00000740
e1002e80  00000000 00000744 00000000 00000748
e1002e90  00000000 0000074c 00000000 00000750
e1002ea0  00000000 00000754 00000000 00000758
e1002eb0  00000000 0000075c 00000000 00000760
e1002ec0  00000000 00000764 00000000 00000768
e1002ed0  00000000 0000076c 00000000 00000770
e1002ee0  00000000 00000774 00000000 00000778
e1002ef0  00000000 0000077c 00000000 00000780
e1002f00  00000000 00000784 00000000 00000788
e1002f10  00000000 0000078c 00000000 00000790
e1002f20  00000000 00000794 00000000 00000798
e1002f30  00000000 0000079c 00000000 000007a0
e1002f40  00000000 000007a4 00000000 000007a8
e1002f50  00000000 000007ac 00000000 000007b0
e1002f60  00000000 000007b4 00000000 000007b8
e1002f70  00000000 000007bc 00000000 000007c0
e1002f80  00000000 000007c4 00000000 000007c8
e1002f90  00000000 000007cc 00000000 000007d0
e1002fa0  00000000 000007d4 00000000 000007d8
e1002fb0  00000000 000007dc 00000000 000007e0
e1002fc0  00000000 000007e4 00000000 000007e8
e1002fd0  00000000 000007ec 00000000 000007f0
e1002fe0  00000000 000007f4 00000000 000007f8
e1002ff0  00000000 000007fc 00000000 00000000

嘿嘿,列多了~


最后再添个代码的截图,小玩意~ 我把解析对象头(包括可选头部)的代码封成了一个lib,以后调用着方便。




NUPT   WANGyu

 

 

 

 


 

posted on 2008年4月15日 9:23 由 WANGyu

# re: 跟踪随笔一则 @ 2008年4月16日 8:22

期待张老师的书,呵呵

llx571030

# re: 跟踪随笔一则 @ 2008年4月18日 9:11

期待张老师的新书,顺便顶一下贴!:)

xiaowei

# re: 跟踪随笔一则 @ 2008年4月19日 22:57

分析的很不错。对象管理这块是至今仍很神秘的一块,就连Sven B. Schreiber在写Undocument Windows 2000时都草草收场。BTW,多谢几位对《软件调试》的期待!

Raymond

# re: 跟踪随笔一则 @ 2008年6月27日 10:41

Raymond 老师过讲了,其实分析的不好。

写的只算是 OB 模块冰山一角的冰山一角...

有时间我来继续小结一些 OB 模块的分析。 ^_^

WANGyu

Powered by Community Server Powered by CnForums.Net