프로세스들 사이에서 커널 오브젝트를 공유하는 방법은 세가지가 있습니다.
1. 핸들 상속
2. 네임드 오브젝트
3. 오브젝트 핸들 복사
핸들 값이 프로세스별로 고유하게 설계된 이유는 바로 안정성 때문입니다.
만약, 프로세스 핸들 값이 전역적으로 설계되어 있었다면 관련 없는 프로세스의 핸들 값을 가져와 다른 프로세스를 오동작시킬 수 있는 가능성들이 있기 때문입니다.
그럼에도 불구하고, 프로세스 사이에서 커널 오브젝트를 공유하려고 하는 이유는 바로 연관성 있는 프로세스들이 동작 할 수 있게 하기 위함입니다.
1. 핸들 상속
핸들 상속은 핸들 값을 공유하려고 하는 프로세스들이 부모-자식 관계를 이루어야 가능합니다.
커널 오브젝트 핸들이 부모 프로세스에서 사용되고 있고, 이 부모 프로세스가 새로운 자식 프로세스를 생성하게 되면 요때, 자식 프로세스는 부모의 커널 오브젝트 핸들을 상속받도록 할 수 있습니다.
그렇게 하기 위해서는 SECURITY_ATTRIBUTES 구조체 중 bInheritHandle = TRUE로 설정해주면 됩니다.
- nLength : sizeof(SECURITY_ATTRIBUTES)
- lpSecurityDescriptor : 보안 디스크립터를 의미하는데 접근 권한을 설정해줄 수 있습니다. 보안 디스크립터와 관련된 내용은 차후에 포스팅할 수 있도록 하겠습니다.
- bInheritHandle : TRUE (상속 가능한 핸들), FALSE (상속 불가능한 핸들)
부모 프로세스에서 커널 오브젝트를 사용하기 위해 핸들을 생성할 때 SECURITY_ATTRIBUTES 구조체를 상속 가능한 핸들로 만들어서 사용하고
이 핸들을 물려주기(상속)위해 부모 프로세스의 코드에서 자식 프로세스를 생성하는 CreateProcess 함수를 호출할 때
(우선 다른 인자들에 대한 설명은 생략하고 핸들 상속을 설명하기 위해 bInheritHandles 인자만 언급하도록 하겠습니다.)
- bInheritHandles : TRUE (부모 프로세스의 핸들을 상속받습니다.), FALSE (핸들을 상속받지 아니함)
- TRUE로 세팅된 경우 자식 프로세스가 만들어질 때 비어있는 핸들 테이블을 생성 -> 부모 프로세스의 상속 가능한 핸들을 복사해 핸들 테이블에 채움
이런 과정을 거쳐서 동일한 커널 오브젝트에 부모-자식 프로세스가 접근할 수 있게 됩니다.
- 핸들 테이블을 복사할 때 커널 오브젝트의 참조 카운트도 증가합니다.
한 가지 주의할 점으로
- 부모-자식 프로세스가 생성 완료된 시점에서 부모 프로세스가 새로운 핸들을 상속 가능하도록 생성하더라도 자식 프로세스가 이미 생성된 상태라면 공유되지 않습니다.
- CreateProcess 시점에만 상속됩니다.
- 물론 요런 경우에는 프로세스간 통신 방법으로 핸들을 전달하면 됩니다.
2. 네임드 오브젝트
네임드 오브젝트를 생성할 수 있는 함수들은 아래와 같습니다.
- HANDLE CreateMutex
- HANDLE CreateEvent
- HANDLE CreateSemaphore
- HANDLE CreateWaitableTimer
- HANDLE CreateFileMapping
- HANDLE CreateJobObject
요 함수들은 공통으로 마지막 인자로 PCTSTR pszName을 갖고 있습니다.
이 인자를 문자열로 채워주게 되면 바로 네임드 오브젝트가 되는 것입니다.
생성 예(MutexObject 이용)
HANDLE hMutexProcessA = CreateMutex(NULL, FALSE, TEXT("HSharedMutex"));
HANDLE hMutexProcessB = CreateMutex(NULL, FALSE, TEXT("HSharedMutex"));
- A프로세스에서 HSharedMutexA 뮤텍스 오브젝트 생성
- B프로세스에서 HSharedMutexB 뮤텍스 오브젝트 생성 시도
- 이미 HSharedMutext로 생성된 뮤텍스가 존재
- 이 경우 뮤텍스가 새로 생성되는 것이 아니라 A뮤텍스에 접근할 수 있는 핸들값이 생성됨
- 따라서, B프로세스에서 A프로세스의 뮤텍스에 접근할 수 있게 됨 (뮤텍스 오브젝트 카운트 증가)
이 경우 주의할 점
1. 명시한 이름이 같지만 종류가 다를 경우
HANDLE hMutexProcessA = CreateMutex(NULL, FALSE, TEXT("HSharedMutex"));
HANDLE hMutexProcessB = CreateSemaphore(NULL, 1, 1, TEXT("HSharedMutex"));
- 이름은 같지만 종류가 다르기 때문에 NULL 리턴
- 동일한 이름의 네임드 오브젝트는 생성할 수 없습니다.
2. SECURITY_ATTRIBUTES, 이외 나머지 인자들에 대한 정보가 다를 때
가장 먼저 만들어진 네임드 오브젝트의 속성으로 세팅
- 이후에 설정된 인자들은 모두 무시됩니다.
이미 생성된 네임드 오브젝트의 핸들을 가져올 수 있는 방법도 있습니다.
- HANDLE OpenMutex
- HANDLE OpenEvent
- HANDLE OpenSemaphore
- HANDLE OpenWaitableTimer
- HANDLE OpenFileMapping
- HANDLE OpenJobObject
Create대신 Open으로 치환된 것으로 이미 생성된 네임드 오브젝트의 핸들을 가져오는 함수들입니다.
요 경우에는 다른 프로세스에서 Open* 함수를 통해 핸들 획득을 시도하면, 접근권한을 확인한 이후에 가능하다면 핸들 값을 공유하게 됩니다.
- 함수 인자는 Create* 계열과 동일
- PCTSTR pszName으로 NULL을 세팅할 수 없음 (Open이기 때문에 이미 생성된 네임드 오브젝트만 열 수 있음)
핸들을 생성할 때 네임드 오브젝트를 활용해서 생성하게 되면 동일 프로세스 내 중복 핸들 생성을 방지할 수도 있습니다.
- 프로세스 간 공유할 이유가 없는 핸들들은 네임드 오브젝트를 하지 않는것이 좋습니다. : ACCESS_DENIED 공격 대상
- ACCESS_DENIED : 같은 이름으로 네임드 오브젝트를 먼저 생성해 수행되어야 할 프로세스의 실행을 차단하는 것
- 이런 경우 프라이빗 네임스페이스를 사용하면 됩니다. (네임스페이스 생성 후 네임드 오브젝트 생성, 요러면 동일 네임스페이스 바깥에서는 네임드 오브젝트를 호출할 수 없습니다)
3. 오브젝트 핸들 복사
오브젝트 핸들을 복사하기 위해서는 아래의 함수가 사용됩니다.
말 그대로 특정 프로세스의 핸들을 다른 프로세스로 복사하는 함수입니다.
- hSourceProcessHandle : 공유하고자 하는 커널 오브젝트의 핸들
- hSourceHandle : 공유하고자 하는 커널 오브젝트 핸들을 가지고 있는 프로세스의 핸들
- hTargetProcessHandle : hSourceProcessHandle과 같은 커널 오브젝트의 핸들 (복사 후 결과값이기 때문에 Source랑 타입이 같아야 합니다.)
- lpTargetHandle : 복사된 HANDLE의 주소값 저장 (hSourceProcessHandle)
- 나머지 3개 인자 : 액세스 마스크, 상속 플래그, 옵션 (일반적으로는 0)을 설정
hSourceProcessHandle -> lpTargetHandle로 복사되게 됩니다.
사용 예)
https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms724251(v=vs.85).aspx
MSDN 참고했습니다.
뮤텍스 핸들을 복사해 스레드를 동작시키는 예제입니다.
- hMutex로 뮤텍스 생성 (RefCount +1)
- DuplicateHandle 함수로 hMutex 핸들을 hMutexDup로 복사 (RefCount +2)
- CreateThread 함수로 복사한 hMutexDup 핸들을 이용해 새로운 스레드를 생성,
- 최초 생성했던 hMutex 핸들 Close (RefCount -1 = 1), RefCount가 1이기 때문에 커널 오브젝트 해제되지 않음
- 스레드 동작 -> ThreadProc -> CloseHandle (RefCount -1 = 0), 커널 오브젝트 해제
핸들이 복사(hMutex->hMutexDup)되어 동일 커널 오브젝트를 참조했고,
참조 카운트를 공유하기 때문에 (동일 커널 오브젝트를 참조하기 때문) hMutex 핸들을 닫는다고 커널 오브젝트가 해제되지 않습니다. (복사된 hMutexDup이 동일 커널 오브젝트에 대해 참조 카운트를 여전히 갖고있기 때문)
'Windows > Windows Programming' 카테고리의 다른 글
프로세스의 생성 2 - CreateProcess() (2) | 2016.02.13 |
---|---|
프로세스의 생성 1 - CreateProcess() (0) | 2016.02.09 |
윈도우 핸들 (Windows Handle Object) (0) | 2015.12.31 |
에러 핸들링 (0) | 2015.09.28 |
윈도우 메세지 (0) | 2014.11.16 |