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 였다.
'프로그래밍 > 미분류' 카테고리의 다른 글
윈도우 환경에서 플랫폼 SDK 사용하기 (0) | 2012.06.03 |
---|---|
stack frame 그림. (0) | 2012.05.24 |
[VS2008] AddVariable 시 DoDataExchange에 컨트롤과 변수 연결코드가 자동으로 생성되지 않는다. (0) | 2011.12.07 |
64비트 : 64비트 시스템의 32비트 프로세스에 붙은 64비트 DLL (0) | 2011.10.12 |
2004년 개발 시작하며 적었던 노트 (0) | 2011.07.01 |