이 함수들은 제가 직접 작성한 것으로, 현재 떠 있는 프로세스를 구할 수 있습니다.
PsGetFirstProcess()
Idle Process를 제외한 가장 첫번째 프로세스의 EPROCESS 구조체의 포인터를 구합니다.
성공시 STATUS_SUCCESS를 리턴,
실패시 STATUS_NOT_FOUND, STATUS_INVALID_PARAMETER를 리턴.
구현은 했지만, 그다지 필요한 것 같지는 않네요(그럼 왜 구현한 거지 ㅡ.ㅡ)
PsGetNextProcess()
이 함수의 원형은
PEPROCESS
PsGetNextProcess(
IN PEPROCESS Process);
라고 합니다.
(하지만, 제가 임의로 바꾸었습니다.)
인자로 들어온 EPROCESS 구조체의 포인터에서 ActiveProcessLinks를 얻어와 다음 프로세스의 EPROCESS 구조체의 포인터를 구합니다.
성공시 STATUS_SUCCESS를 리턴,
실패시 STATUS_UNSUCCESSFUL, STATUS_NOT_FOUND, STATUS_INVALID_PARAMETER를 리턴.
이 함수는 다음 Windows에서 성공적으로 테스트되었습니다:
Windows 2000 Professional SP4
NTSTATUS
NTAPI
PsGetFirstProcess(
OUT PEPROCESS *FirstProcess)
{
if(!FirstProcess) return STATUS_INVALID_PARAMETER;
*FirstProcess=PsInitialSystemProcess;
/*PsInitialSystemProcess=System Process Object*/
if(!*FirstProcess) return STATUS_NOT_FOUND;
/*Success, return it*/
return STATUS_SUCCESS;
}
솔직히, PsGetFirstProcess()는 위의 코드대로라면 PsInitialSystemProcess로 대체시킬 수 있습니다.
단순히 값을 얻어온 후 검사하고 리턴하는 기능만 하기 때문이죠.
NTSTATUS
NTAPI
PsGetNextProcess(
IN OUT PEPROCESS *NextProcess)
{
ULONG ActiveProcessLinksOffset=0, ProcessIdOffset=0;
BOOLEAN bFound=FALSE;
PLIST_ENTRY ActiveProcessLinks;
PEPROCESS Process;
PEPROCESS CurrentProcess=PsGetCurrentProcess();
HANDLE CurrentProcessId=PsGetCurrentProcessId();
/*PsInitialSystemProcess is System Process' Process Object.*/
HANDLE SystemProcessId=PsGetProcessId(PsInitialSystemProcess);
if(!NextProcess) return STATUS_INVALID_PARAMETER;
/*Reference the Object*/
Status=ObReferenceObjectByPointer(*NextProcess, PROCESS_ALL_ACCESS,
PsProcessType, KernelMode);
/*invalid EPROCESS structure Pointer, return it*/
if(!NT_SUCCESS(Status)) return Status;
/*Get ProcessId Offset*/
for(ProcessIdOffset=0;ProcessIdOffset<PAGE_SIZE*4;ProcessIdOffset++)
{
if(*(PHANDLE)((PCHAR)CurrentProcess+ProcessIdOffset)==CurrentProcessId)
{
bFound=TRUE;
break;
}
}
if(!bFound)
{
/*Cannot find ProcessId Offset, return status*/
return STATUS_UNSUCCESSFUL;
}
/*ActiveProcessLinks Offset=UniqueProcessId Offset+4*/
ActiveProcessLinksOffset=ProcessIdOffset+4;
/*Get ActiveProcessLinks*/
ActiveProcessLinks=(PLIST_ENTRY)((char *)*NextProcess+ActiveProcessLinksOffset);
/*Move to Next Process*/
Process=(PEPROCESS)ActiveProcessLinks->Flink;
Process=(PEPROCESS)((char *)Process-ActiveProcessLinksOffset);
/*(PEPROCESS)Process!=null*/
if(Process)
{
if(SystemProcessId!=PsGetProcessId(Process))
{
/*Found it! Now, Dereference the Object*/
ObDereferenceObject(*NextProcess);
/*Save the EPROCESS Pointer*/
*NextProcess=Process;
/*return success......*/
return STATUS_SUCCESS;
}
}
/*End of Process, or Process not found*/
return STATUS_NOT_FOUND;
}
위의 함수들은 ActiveProcessLinks로 다음 프로세스를 찾아 이동하므로,
ActiveProcessLinks를 Unlink한다면 Unlink된 프로세스의 EPROCESS는 구할 수 없지만,
ZwQuerySystemInformation() 후킹으로 인한 숨겨진 프로세스는 찾아낼 수 있습니다.
다음에는, 이를 이용한 PsLookupProcessByProcessId() 구현에 대해 올려놓겠습니다.