Programming/Kernel / Driver2008. 12. 3. 11:35

이 함수들은 제가 직접 작성한 것으로, 현재 떠 있는 프로세스를 구할 수 있습니다.


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() 구현에 대해 올려놓겠습니다.

Posted by skensita