본문 바로가기

Windows/_System Programming

커널 오브젝트(Kernel Object) - 2

커널 오브젝트의 상태(State) :

리소스에 특정 상황이 발생함에 따라 Signaled 상태(신호를 받은 상태)와
Non-Signaled 상태(신호를 받지 않은 상태)로 나뉜다.

(예 : 프로세스 커널 오브젝트의 상태


종료된 프로세스는 다시 살릴수 없다. 따라서 프로세스 커널 오브젝트의 상태는 Signaled -> Non-Signaled 로
변경될 수 없다)


커널 오브젝트의 상태를 확인하는 함수 :

DWORD WaitForSingleObject(
           HANDLE hHandle,              // 상태 확인을 원하는 커널 오브젝트의 핸들
           DWORD dwMilliseconds      // hHandle가 가리키는 커널 오브젝트가 Signaled 상태가 될 때까지
                                                      기다릴수 있는 최대 시간(INFINITE 전달 : Signaled 상태가 될 때까지 기다림
);

 함수의 리턴값  의미
 WAIT_OBJECT_0  커널 오브젝트가 Signaled 상태가 되었을때 반환값
 WAIT_TIMEOUT  dwMilliseconds 인자를 통해서 설정된 시간이
 다 지난 경우 반환값
 WAIT_ABANDONED  소유 관계와 관련하여 함수가 정상적이지 못한
 오류 발생에 의한 반환값


커널 오브젝트가 둘 이상인 경우 : (핸들이 배열로 묶여있다면) 

DWORD WaitForMultipleObjects(
           DWORD nCount,                      // 배열에 저장되어 있는 핸들 개수
           const HANDLE *lpHandles,      // 핸들을 저장하고 있는 배열의 주소 정보
           BOOL bWaitAll,                       // 관찰 대상이 모두 Signaled 상태가 되기를 기다리는지(TRUE 전달)
                                                            하나라도 Signaled 상태가 되면 반환할 것인지(FALSE 전달) 결정
           DWORD dwMilliseconds           // 타임아웃(Time Out)을 설정하는 인자
);


종료 코드(Exit Code) :

프로세스가 종료되면서 전달하는 값으로 프로세스의 커널 오브젝트에 저장된다
(예 : exit(1);, return 0;)

부모 프로세스는 GetExitCodeProcess 함수 호출을 통하여 자식 프로세스의 종료 코드를 획득할 수 있다.

BOOL GetExitCodeProcess(
          HANDLE hProcess,                // 커널 오브젝트 핸들
          LPDWORD lpdwExitCode        // 종료 코드를 저장할 변수
                                                         (프로세스가 실행중이면 STILL_ACTIVE 반환)
);



프로세스의 커널 오브젝트 핸들 테이블 :

핸들 테이블 : 핸들 정보를 저장하고 있는 테이블로서 프로세스별로 독립적이다.



핸들의 상속 : 자식 프로세스는 부모 프로세스의 핸들 테이블에 등록되어 있는 핸들 정보를 상속받을 수 있다.


상속 여부가  Y인 핸들만 상속이 가능하다.
또 상속 여부에 대한 정보도 변경 없이 그대로 상속된다.(자식 프로세스가 또 그 자식 프로세스에게 상속 가능하다)


핸들의 상속을 위한 전달 인자 :

BOOL CreataProcess 의 5번째 파라미터 BOOL bInheritHandle 은
부모 프로세스가 소유하고 있는 핸들 테이블 정보(상속 여부가 Y인 핸들만)의 상속 여부를 결정한다.
(TRUE : 상속, FALSE : 상속 안함)


핸들의 상속과 커널 오브젝트의 Usage Count :

프로세스의 커널 오브젝트의 핸들 테이블에 해당 핸들에 대한 정보가 갱신(추가)되었을 때
프로세스가 핸들을 얻게 되었다고 한다.


상속이 되기 위한 핸들의 조건 :

핸들의 상속 여부(핸들 테이블에서의 Y or N)는 리소스가 생성되는 순간에 결정된다.
(리소스의 보안 속성을 지정하면 된다)

typedef struct _SECURITY_ATTRIBUTES {
         DWORD nLength;                  // 구조체 변수 크기를 바이트 단위로 설정(반드시 구조체 변수 크기로 초기화)
         LPVOID lpSecurityDescriptor; // NULL로 초기화. 핸들의 상속 관점에서 의미를 지니지 않는다
         BOOL bInheritHandle;            // TRUE로 설정. 상속 여부를 결정 짓는 요소
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;

(예 : CreateProcess 함수를 통해 생성되는 자식프로세스 핸들 상속

SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
……
CreateProcess(. . . . , &sa,  . . , TRUE, . . . . );        // &sa 3번째 파라미터(상속 여부 Y)
                                                                               TRUE 5번째 파라미터(핸들 테이블 상속)
……
)



Pseudo 핸들과 핸들의 중복(Duplicate) :

프로세스가 자신의 핸들을 얻는 방법으로 GetCurrentProcess 함수를 사용한다.
하지만 이 함수를 통해 얻은 핸들은 가짜 핸들(Pseudo 핸들)이다.

핸들 테이블에 등록되어 있지 않은 핸들이며,
다만 현재 실행 중인 프로세스를 참조하기 위한 용도로 정의해 놓은 핸들이다.(약속된 상수로 -1 이 반환)
(참고 : CloseHandle 함수의 파라미터로 전달하더라도 아무 일도 발생하지 않는다)

BOOL DuplicateHandle(              // 진짜 핸들 획득
          HANDLE hSourceProcessHandle,    // 복제할 핸들을 소유하는 프로세스를 지정
          HANDLE hSourceHandle,                // 복제할 핸들을 지정
          HANDLE hTargetProcessHandle,     // 복제된 핸들을 소유할 프로세스를 지정
          LPHANDLE lpTargetHandle,            // 복제된 핸들값을 저장할 변수의 주소를 지정
          DWORD dwDesiredAccess,             // 복제된 핸들의 접근 권한을 지정
          BOOL bInheritHandle,                     // 복제된 핸들의 상속 여부를 지정 
          DWORD dwOptions          // DUPLICATE_SAME_ACCESS : 원본 핸들과 동일한 접근 권한
                                                                                               dwDesiredAccess 파라미터를 무시한다.
                                                   DUPLICATE_CLOSE_SOURCE : CloseHandle 함수와 같은 기능
                                                   이 두 옵션은 비트 단위 OR 연산자를 통해 동시 전달 가능
);

(예 :

DuplicateHandle(
        프로세스 A 핸들,      // 프로세스 A에 존재하는
        256,                        // 핸들 256의 정보를 
        프로세스 B 핸들,      // 프로세스 B의 핸들 테이블에 등록된다.
        &val,                      // 등록된 핸들의 값은 변수 val에 저장한다.
        ……
);

DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &hProcess, 0, TRUE,
                        DUPLICATE_SAME_ACCESS);
// GetCurrentProcess() 함수를 통해서 얻은 가짜 핸들을 진짜 핸들로 구성해서 핸들 테이블에 등록

복사된다고 해서 핸들값까지 똑같진 않다.
그리고 서로 독립된 프로세스 영역의 핸들이기 때문에 값이 같건 다르건 별 의미를 지니지 않는다.

자신의 핸들을 복사할 경우 자식 프로세스에게 자신의 프로세스 커널 오브젝트 핸들을 상속할 수 있다
GetCurrentProcess 함수을 통해 얻은 핸들을 복사할 경우 진짜 핸들이 생성되어 핸들 테이블에 등록된다

DuplicateHandle 함수에 의해서 핸들이 복사되고 나면, UC(Usage Count)는 증가한다.
따라서 복사된 핸들에 대해서도 CloseHandle 함수를 통해 핸들을 반환해야 한다)