시스템 프로세스에 대해 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)를 호출해도 얻어지는 데이터가 없으므로 호출하지 않는 것이 좋겠다.