ZwQueryInformationProcess(ProcessImageFileName)와 시스템 프로세스
시스템 프로세스에 대해 ZwQueryInformationProcess(ProcessImageFileName)를 호출해 이미지 경로를 구하려고 하면 경로가 나오지 않는다.
무심코 사용하다가 이런 상황이 발생하니 당황스러워 정리해 둔다.
(MSDN에 적혀 있지도 않아서...)
현재 프로세스는 시스템 프로세스다.
kd> !process 843bdd08 0
PROCESS 843bdd08 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 00185000 ObjectTable: 88001be0 HandleCount: 1153.
Image: System
현재 콜스택은 MyDrv가 ZwQueryInformationProcess()를 호출하고 있는 상황이다.
kd> k
ChildEBP RetAddr
920796ec 82c0dd87 nt!SeLocateProcessImageName+0x26
92079738 82c4375b nt!PsQueryFullProcessImageName+0x1d
92079a30 82a491ea nt!NtQueryInformationProcess+0x116
92079a30 82a479ad nt!KiFastCallEntry+0x12a
92079abc 876eb3c6 nt!ZwQueryInformationProcess+0x11
92079af8 876eb46c MyDrv!GetProcessImageName+0x86
...
92079d90 82abc219 nt!PspSystemThreadStartup+0x9e
00000000 00000000 nt!KiThreadStartup+0x19
이미지 경로가 나오지 않는 이유를 알아보기 위해 커널 내부에서 어떻게 처리하고 있는지 살펴봤다.
콜스택에 보이는 마지막 함수(SeLocateProcessImageName)가 실제로 커널에서 이미지 경로를 얻어 주는 함수다.
kd> u 82c4c7e8 L12
nt!SeLocateProcessImageName:
82c4c7e8 8bff mov edi,edi
82c4c7ea 55 push ebp
82c4c7eb 8bec mov ebp,esp
82c4c7ed 51 push ecx
82c4c7ee 8b450c mov eax,dword ptr [ebp+0Ch]
82c4c7f1 832000 and dword ptr [eax],0
82c4c7f4 53 push ebx
82c4c7f5 8b5d08 mov ebx,dword ptr [ebp+8]
82c4c7f8 56 push esi
82c4c7f9 57 push edi
82c4c7fa 8bc3 mov eax,ebx
82c4c7fc e861000000 call nt!SePopulateProcessImageName (82c4c862)
82c4c801 894508 mov dword ptr [ebp+8],eax
82c4c804 85c0 test eax,eax
82c4c806 7c4a jl nt!SeLocateProcessImageName+0x6a (82c4c852)
82c4c808 8b83ec010000 mov eax,dword ptr [ebx+1ECh]
82c4c80e 0fb77002 movzx esi,word ptr [eax+2] <===
마지막 두 줄에서 이미지 경로를 얻어오기 시작한다.
ebx는 첫번째 파라미터인 [ebp+8]이고 프로세스 오브젝트 포인터다.
ebx+1EC는 뭔가 했더니 프로세스 생성 정보고 이미지 경로가 들어 있는 영역이다.
다음과 같이 확인이 가능하다.
kd> dt _EPROCESS
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x098 ProcessLock : _EX_PUSH_LOCK
...
+0x1ec SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
_SE_AUDIT_PROCESS_CREATION_INFO가 뭔지 확인해 보면 결국 UNICODE_STRING으로 밝혀진다.
kd> dt _SE_AUDIT_PROCESS_CREATION_INFO
ntdll!_SE_AUDIT_PROCESS_CREATION_INFO
+0x000 ImageFileName : Ptr32 _OBJECT_NAME_INFORMATION
kd> dt _OBJECT_NAME_INFORMATION
ntdll!_OBJECT_NAME_INFORMATION
+0x000 Name : _UNICODE_STRING
프로세스 포인터를 적용해 내용을 살펴보면 황당하게도 이름이 없다.
kd> dt _EPROCESS SeAuditProcessCreationInfo. 843bdd08
ntdll!_EPROCESS
+0x1ec SeAuditProcessCreationInfo :
+0x000 ImageFileName : 0x880010a0 _OBJECT_NAME_INFORMATION
kd> dt 0x880010a0 _OBJECT_NAME_INFORMATION
ntdll!_OBJECT_NAME_INFORMATION
+0x000 Name : _UNICODE_STRING ""
kd> dt 0x880010a0 _UNICODE_STRING
ntdll!_UNICODE_STRING ""
+0x000 Length : 0
+0x002 MaximumLength : 0
+0x004 Buffer : (null)
kd> dd 0x880010a0 L2
880010a0 00000000 00000000
시스템 프로세스는 SeAuditProcessCreationInfo.ImageFileName이 비어 있음을 알 수 있다.
시스템 프로세스에 대해서는 ZwQueryInformationProcess(ProcessImageFileName)를 호출해도 얻어지는 데이터가 없으므로 호출하지 않는 것이 좋겠다.