본문 바로가기

프로그래밍/미분류

크래시덤프분석 ObInsertObject

반응형

PspCreateProcess 는 프로세스 객체를 생성하고 초기화하고, 프로세스 핸들을 리턴해 준다. 객체 생성은 ObCreateObject 를 호출하여 이루어진다.


ObCreateObject(

KeGetPreviousMode(),

PsProcessType,

ObjectAttributes,

KeGetPreviousMode(),

0,

0x258,

0,

0,

&ProcessObject);


위의 예에서는 PsProcessType 객체 타입의 객체가 만들어지고, 0x258 이라는 사이즈는 윈도우 버전마다 틀리다. ProcessObject 는 다른 객체처럼 OBJECT_HEADER 헤더가 붙는다. OBJECT_HEADER는 다음과 같다.


OBJECT_HEADER:

   +0x000 PointerCount     : Int4B

   +0x004 HandleCount      : Int4B

   +0x004 NextToFree       : Ptr32 Void

   +0x008 Type             : Ptr32 _OBJECT_TYPE

   +0x00c NameInfoOffset   : UChar

   +0x00d HandleInfoOffset : UChar

   +0x00e QuotaInfoOffset  : UChar

   +0x00f Flags            : UChar

   +0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION

   +0x010 QuotaBlockCharged : Ptr32 Void

   +0x014 SecurityDescriptor : Ptr32 Void

   +0x018 Body             : _QUAD


ObCreateObject 가 리턴하면 Flags 플래그는 OB_FLAG_CREATE_INFO, 즉 0x1 비트가 세팅된 값이다. 그리고 ObjectCreateInfo는 OBJECT_CREATE_INFORMATION 구조체를 가리키는 포인터다.


ObInsertObject 가 호출되면, OB_FLAG_CREATE_INFO가 아직 세팅되어 있다. 이건 언제나 그렇다.


위는 http://uninformed.org/index.cgi?v=1&a=5&p=5 의 일부를 발췌 번역한 것.


이런데, 내가 만난 문제상황의 덤프는 다음과 같다.


EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx


FAULTING_IP: 

nt!ObInsertObject+1ad

8056fb30 8b4e1c          mov     ecx,dword ptr [esi+1Ch]


TRAP_FRAME:  a8f64a48 -- (.trap 0xffffffffa8f64a48)

ErrCode = 00000000

eax=a8f64bb8 ebx=00000000 ecx=86bb5e00 edx=00000000 esi=00000001 edi=00000000

eip=8056fb30 esp=a8f64abc ebp=a8f64b8c iopl=0         nv up ei ng nz na pe nc

cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010286

nt!ObInsertObject+0x1ad:

8056fb30 8b4e1c          mov     ecx,dword ptr [esi+1Ch] ds:0023:0000001d=????????


esi가 1이고, 1+0x1C 의 메모리를 읽으려 하다가 예외가 발생했다.


당시의 스택은


ChildEBP RetAddr  

a8f64b8c 8058d8a4 nt!ObInsertObject+0x1ad

a8f64ce4 8058da4e nt!PspCreateProcess+0x635

a8f64d38 804df99f nt!NtCreateProcessEx+0x7e

a8f64d38 7c93e514 nt!KiFastCallEntry+0xfc

003cf03c 7c93d16a ntdll!KiFastSystemCallRet

003cf040 7c7e92e2 ntdll!NtCreateProcessEx+0xc

003cfa90 7c7d2362 kernel32!CreateProcessInternalW+0x1327

003cfac8 7c84602a kernel32!CreateProcessW+0x2c

003cffb4 7c7db729 kernel32!ConsoleIMERoutine+0xd7

003cffec 00000000 kernel32!BaseThreadStart+0x37


이와 같다.


ObInsertObject 를 디스어셈해 보면 다음과 같다. esi 에 주목. (주석은 본인, ReactOS 소스 등을 참고하여 달아 봄)


nt!ObInsertObject:

8056fa64 8bff            mov     edi,edi

8056fa66 55              push    ebp

8056fa67 8bec            mov     ebp,esp

8056fa69 81ecc4000000    sub     esp,0C4h

8056fa6f 8b4508          mov     eax,dword ptr [ebp+8] ; eax = object

8056fa72 8b48f0          mov     ecx,dword ptr [eax-10h] ; ecx = OBJECT_TYPE(object) // object-0x10

8056fa75 83c0e8          add     eax,0FFFFFFE8h ; eax = OBJECT_TO_OBJECT_HEADER(object) // object-0x18

8056fa78 53              push    ebx

8056fa79 33db            xor     ebx,ebx ; ebx = 0

8056fa7b 894ddc          mov     dword ptr [ebp-24h],ecx ; _24 = object_type

8056fa7e 8a480c          mov     cl,byte ptr [eax+0Ch] ; cl = object_header->NameInfoOffset

8056fa81 3acb            cmp     cl,bl ; cl == bl

8056fa83 56              push    esi

8056fa84 8b7010          mov     esi,dword ptr [eax+10h] ; esi = object_header->ObjectCreateInfo

8056fa87 57              push    edi

8056fa88 895df8          mov     dword ptr [ebp-8],ebx ; _8 = 0

8056fa8b 895dd8          mov     dword ptr [ebp-28h],ebx ; _28 = 0

8056fa8e 0f84bb150000    je      nt!ObInsertObject+0x56 (8057104f)

8056fa94 0fb6d1          movzx   edx,cl ; edx = object_header->NameInfoOffset

8056fa97 8bc8            mov     ecx,eax ; ecx = object_header

8056fa99 2bca            sub     ecx,edx ; ecx = object_header + object_header->NameInfoOffset

8056fa9b 894dd4          mov     dword ptr [ebp-2Ch],ecx ; _2C = object_header + object_header->NameInfoOffset

8056fa9e 0f84ab150000    je      nt!ObInsertObject+0x56 (8057104f)

8056faa4 8d510c          lea     edx,[ecx+0Ch] ; edx = object_header + object_header->NameInfoOffset + 0xC

8056faa7 8b02            mov     eax,dword ptr [edx] ; eax = *(object_header + object_header->NameInfoOffset + 0xC)

8056faa9 3bc3            cmp     eax,ebx ; eax == 0

8056faab 8945d0          mov     dword ptr [ebp-30h],eax ; _30 = eax

8056faae 0f849b150000    je      nt!ObInsertObject+0x56 (8057104f)

8056fab4 8d7801          lea     edi,[eax+1] ; edi = eax+1

8056fab7 f00fb13a        lock cmpxchg dword ptr [edx],edi ; compare and exchange

8056fabb 3b45d0          cmp     eax,dword ptr [ebp-30h] ; eax = _30

8056fabe 75e9            jne     nt!ObInsertObject+0x4f (8056faa9)

8056fac0 f6420380        test    byte ptr [edx+3],80h ; edx+3 == 80

8056fac4 0f85e7300900    jne     nt!ObInsertObject+0x109 (80602bb1)

8056faca 8bf9            mov     edi,ecx ; edi = ecx

8056facc 3bfb            cmp     edi,ebx ; edi == 0

8056face 895dd4          mov     dword ptr [ebp-2Ch],ebx ; _2C = 0

8056fad1 740b            je      nt!ObInsertObject+0x6a (8056fade)

8056fad3 395f08          cmp     dword ptr [edi+8],ebx

8056fad6 7406            je      nt!ObInsertObject+0x6a (8056fade)

8056fad8 8d4704          lea     eax,[edi+4]

8056fadb 8945d4          mov     dword ptr [ebp-2Ch],eax

8056fade 64a124010000    mov     eax,dword ptr fs:[00000124h]

8056fae4 8a8040010000    mov     al,byte ptr [eax+140h]

8056faea 8845d0          mov     byte ptr [ebp-30h],al

8056faed 8b45dc          mov     eax,dword ptr [ebp-24h]

8056faf0 38587c          cmp     byte ptr [eax+7Ch],bl

8056faf3 7509            jne     nt!ObInsertObject+0x17b (8056fafe)

8056faf5 395dd4          cmp     dword ptr [ebp-2Ch],ebx

8056faf8 0f8499690000    je      nt!ObInsertObject+0x8e (80576497)

8056fafe 395d0c          cmp     dword ptr [ebp+0Ch],ebx

8056fb01 752a            jne     nt!ObInsertObject+0x1aa (8056fb2d)

8056fb03 8d853cffffff    lea     eax,[ebp-0C4h]

8056fb09 89450c          mov     dword ptr [ebp+0Ch],eax

8056fb0c 8b45dc          mov     eax,dword ptr [ebp-24h]

8056fb0f 83c068          add     eax,68h

8056fb12 50              push    eax

8056fb13 ff7510          push    dword ptr [ebp+10h]

8056fb16 8d45b0          lea     eax,[ebp-50h]

8056fb19 50              push    eax

8056fb1a 8d853cffffff    lea     eax,[ebp-0C4h]

8056fb20 50              push    eax

8056fb21 e845efffff      call    nt!SeCreateAccessState (8056ea6b) ; SeCreateAccessState( , , desired_access, )

8056fb26 3bc3            cmp     eax,ebx

8056fb28 894510          mov     dword ptr [ebp+10h],eax

8056fb2b 7c1a            jl      nt!ObInsertObject+0x137 (8056fb47)

8056fb2d 8b450c          mov     eax,dword ptr [ebp+0Ch] ; eax = access_state

8056fb30 8b4e1c          mov     ecx,dword ptr [esi+1Ch];!!!!!!!!!!!!!!!!!!!!!!!; ecx = object_header->ObjectCreateInfo->SecurityDescriptor

8056fb33 50              push    eax

8056fb34 89482c          mov     dword ptr [eax+2Ch],ecx ; access_state->SecurityDescriptor = object_header->ObjectCreateInfo->SecurityDescriptor

8056fb37 e82de7ffff      call    nt!ObpValidateAccessMask (8056e269) ; ObpValidateAccessMask(access_state)

8056fb3c 3bc3            cmp     eax,ebx

8056fb3e 894510          mov     dword ptr [ebp+10h],eax

8056fb41 0f8dd8300900    jge     nt!ObInsertObject+0x1c4 (80602c1f)

8056fb47 3bfb            cmp     edi,ebx

8056fb49 0f858b300900    jne     nt!ObInsertObject+0x13b (80602bda)

8056fb4f 8b4d08          mov     ecx,dword ptr [ebp+8]

8056fb52 e8d93df7ff      call    nt!ObfDereferenceObject (804e3930)

8056fb57 8b4510          mov     eax,dword ptr [ebp+10h]

8056fb5a 5f              pop     edi

8056fb5b 5e              pop     esi

8056fb5c 5b              pop     ebx

8056fb5d c9              leave

8056fb5e c21800          ret     18h


결국 esi는 프로세스 오브젝트의 헤더의 ObjectCreateInfo 값이었고, 그 값은 1이었다. 당시의 오브젝트 헤더를 덤프해 보면,


1: kd> dt _OBJECT_HEADER 86afad88

nt!_OBJECT_HEADER

   +0x000 PointerCount     : 0n1

   +0x004 HandleCount      : 0n0

   +0x004 NextToFree       : (null) 

   +0x008 Type             : 0x86bb5e70 _OBJECT_TYPE

   +0x00c NameInfoOffset   : 0 ''

   +0x00d HandleInfoOffset : 0 ''

   +0x00e QuotaInfoOffset  : 0 ''

   +0x00f Flags            : 0 ''

   +0x010 ObjectCreateInfo : 0x00000001 _OBJECT_CREATE_INFORMATION

   +0x010 QuotaBlockCharged : 0x00000001 Void

   +0x014 SecurityDescriptor : (null) 

   +0x018 Body             : _QUAD


Flags도 0이었고, ObjectCreateInfo도 유효하지 않은 포인터. 혹시 이 주소가 잘못된 것인지 확인하기 위해 _OBJECT_TYPE을 덤프해 본다.


1: kd> dt _OBJECT_TYPE 86bb5e70

ntdll!_OBJECT_TYPE

   +0x000 Mutex            : _ERESOURCE

   +0x038 TypeList         : _LIST_ENTRY [ 0x86bb5ea8 - 0x86bb5ea8 ]

   +0x040 Name             : _UNICODE_STRING "Process"

   +0x048 DefaultObject    : (null) 

   +0x04c Index            : 5

   +0x050 TotalNumberOfObjects : 0x38

   +0x054 TotalNumberOfHandles : 0xba

   +0x058 HighWaterNumberOfObjects : 0x38

   +0x05c HighWaterNumberOfHandles : 0xbf

   +0x060 TypeInfo         : _OBJECT_TYPE_INITIALIZER

   +0x0ac Key              : 0x636f7250

   +0x0b0 ObjectLocks      : [4] _ERESOURCE


Name 필드가 유니코드 "Process" 로 잘 들어 있음을 확인할 수 있다.


상황을 정리해 보면, PspCreateProcess 에서 ObInsertObject 를 호출했고, ObInsertObject에서 인자로 받은 Object의 헤더가 무슨 이유에서인가 망가져 있었다. 어떤 이유에서 이렇게 망가졌는지는 분석하지 못했다.


프로세스는 cmd.exe , cmd.exe 가 생성하려던 프로세스는 conime.exe 였다.

728x90