'ZwOpenProcess()'에 해당되는 글 1건

  1. 2008.12.03 ZwOpenProcess()을 구현해보자!
Programming/Kernel / Driver2008. 12. 3. 11:33

Windows에서 프로세스를 다루기 위해서는, 대부분 프로세스 핸들을 얻어 와야 합니다.

핸들을 얻기 위해 사용되는 함수는 OpenProcess()이며, Kernel32.dll에 Export되어 있습니다.

하지만, OpenProcess()는 ntdll.dll의 NtOpenProcess()를 호출하고, NtOpenProcess()는 실질적으로

ntoskrnl.exe의 ZwOpenProcess()를 호출합니다.

이러한 ZwXxx 함수들은 대개 ntdll.dll의 NtXxx 함수들이 결과적으로 호출하게 되는 실질적인 함수인데,

이번에는 ZwOpenProcess()에 대해서만 알아보고, 구현해봅시다.


ZwOpenProcess()는 DDK 헤더 파일에 정의되어 있지 않습니다.(NtOpenProcess()는 정의되어 있는것 같다)

함수의 원형은 다음과 같습니다.

NTKERNELAPI

NTSTATUS

NTAPI

ZwOpenProcess(

      OUT PHANDLE ProcessHandle,                          //성공했을 시 여기로 프로세스 핸들이 넘어온다

      IN ACCESS_MASK DesiredAccess,                    //프로세스를 어떤 권한으로 열 것인가??

      IN POBJECT_ATTRIBUTES ObjectAttributes,         //핸들 상속 권한, 프로세스 이름(ObjectAttributes->ObjectName)

      IN PCLIENT_ID ClientId OPTIONAL);                    //ClientId->UniqueProcess에 프로세스 아이디를 넣으면 된다

이제 원형과 인자들에 대해서 대충 알아보았으니, ZwOpenProcess()가 어떻게 핸들을 얻어오는지 알아봅시다.


ZwOpenProcess()는 일단 SeCreateAccessState()를 호출해서 AccessState를 얻어온 후, 디버그 권한이 있는지를 확인하여 디버그 권한이 있을 경우, AccessState에 추가 권한을 부여합니다.

ObjectAttributes->ObjectName이 NULL 스트링이 아닌 경우, ObOpenObjectByName()을 이용하여 프로세스 핸들을 얻어옵니다.

다른 경우에는(ClientId->UniqueProcess가 유효한 경우) PsLookupProcessByProcessId()를 이용하여 프로세스가 존재하는지를 파악하고, 프로세스 객체를 얻습니다. 그리고 프로세스 객체는 ObOpenObjectByPointer()를 호출하는데에 쓰이게 됩니다.

결과적으로, ObOpenObjectByName()이나 ObOpenObjectByPointer()를 이용하여 얻어온 핸들은 ProcessHandle에 넘겨지게 됩니다.


이제 ZwOpenProcess()가 어떻게 프로세스 핸들을 얻어 오느냐를 알았으니, 간단히 구현해봅시다.

(참고로, 엑세스 권한 확인은 뺐습니다)


NTSTATUS
NTAPI
ZwOpenProcess(
 OUT PHANDLE ProcessHandle,
 IN ACCESS_MASK DesiredAccess,
 IN POBJECT_ATTRIBUTES ObjectAttributes,
 IN PCLIENT_ID ClientId OPTIONAL)
{
 KPROCESSOR_MODE PreviousMode=KeGetPreviousMode();
 NTSTATUS Status=STATUS_SUCCESS;
 PEPROCESS Process;
 if(!ProcessHandle) return STATUS_INVALID_PARAMETER_1;

 /*Unexpected Situation! Has ProcessId And ObjectName*/
 if(ClientId && ObjectAttributes->ObjectName!=NULL)
  return STATUS_INVALID_PARAMETER_MIX;
 if(ClientId)
 {

  /*Is Process Valid?*/
  Status=PsLookupProcessByProcessId(ClientId->UniqueProcess, &Process);
  if(NT_SUCCESS(Status))
  {

   /*OK, Now Get Process Handle By Pointer(EPROCESS *)*/
   Status=ObOpenObjectByPointer(Process, ObjectAttributes->Attributes, NULL, 0, PsProcessType, PreviousMode, ProcessHandle);
  }

  /*Return Status*/
  return Status;
 }
 else if(ObjectAttributes->ObjectName!=NULL)
 {

  /*Get Process Handle By Process Name*/
  Status=ObOpenObjectByName(ObjectAttributes, PsProcessType, PreviousMode, NULL, 0, NULL, ProcessHandle);

  /*Return Status*/
  return Status;
 }

 /*Both Process Id And Object Name is Invalid, Return NtCurrentProcess().*/
 *ProcessHandle=(HANDLE)0xffffffff;

 /*Return Success*/
 return STATUS_SUCCESS;
}


p.s : 테스트는 아직 못해봤습니다

Posted by skensita