프로세스 핸들 테이블
- 프로세스별로 독립적인 핸들을 저장하는 테이블
- 프로세스가 핸들을 얻게 되는 경우 프로세스 자신의 핸들 테이블에 해당 커널 오브젝트의 핸들 추가
- 시스템 리소스가 생성되면 커널 오브젝트가 생성
- 해당 커널 오브젝트의 핸들이 핸들 테이블에 추가된 뒤 핸들 값 반환
- 핸들을 통해 커널 오브젝트에 접근 가능
- 핸들 값 256 에 대한 커널 오브젝트가 0x2400 에 존재
핸들의 상속
- CreateProcess 함수를 통해 자식 프로세스를 생성하면 자식 프로세스의 핸들 테이블도 생성
- CreateProcess 함수의 인자를 통해 부모 프로세스 핸들 테이블의 핸들을 자식 프로세스가 상속 가능
핸들의 상속 여부
- 자식 프로세스는 부모 프로세스의 핸들 테이블에서 상속 가능한 핸들 상속
- CreateProcess 함수의 5 번째 인자 bInheritHandles 이 TRUE 인 경우
- 핸들의 상속 여부는 부모 프로세스와 동일하게 상속
핸들의 상속과 커널 오브젝트 Usage Count
- 커널 오브젝트를 참조하는 프로세스의 조건
- 핸들 테이블에 해당 커널 오브젝트의 핸들이 존재하는 경우
- 부모 프로세스의 핸들 테이블에만 핸들이 존재하는 경우 Usage Count 는 1
- 자식 프로세스가 핸들을 상속한 경우 Usage Count 는 2
상속이 되기 위한 핸들의 조건
- 핸들의 상속 여부는 리소스가 생성되는 순간에 결정
- 리소스를 생성하는 함수의 인자를 통해 각 핸들의 상속 여부 설정 가능
CreateMailslot 함수
HANDLE CreateMailslot(
[in] LPCTSTR lpName,
[in] DWORD nMaxMessageSize,
[in] DWORD lReadTimeout,
[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
- 4 번째 인자 lpSecurityAttributes
- SECURITY_ATTRIBUTES 구조체의 포인터
- NULL 인 경우 생성되는 메일 슬롯의 핸들은 자식 프로세스에게 상속되지 않는다
CreateProcess 함수
BOOL CreateProcess(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
- 3 번째 인자 lpProcessAttributes
- SECURITY_ATTRIBUTES 구조체의 포인터
- NULL 인 경우 생성되는 프로세스의 핸들은 자식 프로세스에게 상속되지 않는다
- 4 번째 인자 lpThreadAttributes
- SECURITY_ATTRIBUTES 구조체의 포인터
- NULL 인 경우 생성되는 쓰레드의 핸들은 자식 프로세스에게 상속되지 않는다
SECURITY_ATTRIBUTES 구조체
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
- 핸들의 상속은 프로세스 입장에서 보안에 관련된 사항
- 상속에 대한 선언을 보안 관련 인자를 통해 전달
- nLength
- 구조체의 바이트 단위 크기
- lpSecurityDescriptor
- 오브젝트에 대한 액세스를 제어하는 SECURITY_DESCRIPTOR 구조체에 대한 포인터
- NULL 인 경우 default security descriptor 할당
- bInheritHandle
- 핸들의 상속 여부
- TRUE 인 경우 핸들을 상속
메일 슬롯
- 핸들 테이블은 프로세스별로 독립적이므로 핸들 값은 다를 수 있다
mailSlot = CreateMailslot(MAILSLOT_NAME, 0, MAILSLOT_WAIT_FOREVER, NULL);
- Receiver 프로세스는 CreateMailslot 함수를 통해 메일 슬롯 생성
- 4 번째 인자가 NULL 인 경우 핸들은 자식 프로세스에게 상속되지 않는다
mailSlot = CreateFile(MAILSLOT_NAME, GENERIC_WRITE, FILE_SHARE_READ, NULL, ...);
- Sender 프로세스는 CreateFile 함수를 통해 메일 슬롯에 데이터를 전송하기 위한 데이터 스트림 형성
- 4 번째 인자가 NULL 인 경우 핸들은 자식 프로세스에게 상속되지 않는다
메일 슬롯 커널 오브젝트의 핸들 상속
메일 슬롯 Sender Parent (링크)
// Mailslot Sender Parent
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#define MAILSLOT_NAME _T("\\\\.\\mailslot\\test")
int _tmain(void)
{
HANDLE mailSlot;
TCHAR message[64];
DWORD size;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
mailSlot = CreateFile(
MAILSLOT_NAME, GENERIC_WRITE, FILE_SHARE_READ,
&sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
);
STARTUPINFO si;
PROCESS_INFORMATION pi;
SecureZeroMemory(&si, sizeof(si));
SecureZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
TCHAR commandLine[64];
_stprintf_s(
commandLine, sizeof(TCHAR) * 64,
_T("MailslotSenderChild.exe %lld"), mailSlot
);
CreateProcess(
NULL, commandLine, NULL, NULL,
TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi
);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
for (;;)
{
_tscanf_s(_T("%s"), message, sizeof(TCHAR) * 64);
WriteFile(
mailSlot, message,
sizeof(TCHAR) * _tcslen(message), &size, NULL
);
if (!_tcscmp(message, _T("exit")))
break;
}
CloseHandle(mailSlot);
return 0;
}
- 자식 프로세스를 생성하고 핸들을 상속한 뒤 메일 슬롯으로 데이터를 전송
- SECURITY_ATTRIBUTES 구조체를 통해 핸들의 상속 여부를 TRUE 로 설정
- CreateFile 함수의 4 번째 인자로 SECURITY_ATTRIBUTES 구조체의 포인터 전달
- 자식 프로세스에서 상속된 핸들에 접근할 수 있도록 commandLine 을 통해 핸들 전달
- 핸들의 값은 실행 시 변경된다
- 핸들 테이블의 핸들을 자식 프로세스에서 확인할 수 없다
- 자식 프로세스를 생성하고 핸들 상속
- CreateProcess 함수의 5 번째 인자로 TRUE 전달
메일 슬롯 Sender Child (링크)
// Mailslot Sender Child
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
int _tmain(int argc, TCHAR* argv[])
{
HANDLE mailSlot = (HANDLE)_tstoll(argv[1]);
TCHAR message[64];
DWORD size;
for (;;)
{
_tscanf_s(_T("%s"), message, sizeof(TCHAR) * 64);
WriteFile(
mailSlot, message,
sizeof(TCHAR) * _tcslen(message), &size, NULL
);
if (!_tcscmp(message, _T("exit")))
break;
}
CloseHandle(mailSlot);
return 0;
}
- 상속된 핸들을 통해 메일 슬롯으로 데이터를 전송
- 상속된 핸들에 접근하기 위해 commandLine 을 통해 전달된 핸들 문자열을 HANDLE 형으로 변환
실행 결과
- Receiver 는 Sender 부모와 자식에서 전송한 문자열 출력
참고 자료
https://pharan.tistory.com/entry/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%83%9D%EC%84%B1
프로세스 생성
CreateProcess 함수를 통해 프로세스를 생성해보자 processthreadsapi.h 헤더는 CreateProcess를 UNICODE 전처리기 상수의 정의에 따라,이 함수의 ANSI 또는 UNICODE 버전을 자동으로 선택하는 별칭으로 정의하고
pharan.tistory.com
커널 오브젝트와 핸들
Windows 운영체제는 프로세스, 쓰레드, 파일과 같은 리소스 (Resource) 들을관리하기 위해 필요한 정보를 커널 오브젝트에 저장한다 커널운영체제의 핵심이 되는 소프트웨어운영체제의 가장 아래
pharan.tistory.com
https://learn.microsoft.com/ko-kr/windows/win32/api/wtypesbase/ns-wtypesbase-security_attributes
SECURITY_ATTRIBUTES - Win32 apps
SECURITY_ATTRIBUTES 구조체는 개체에 대한 보안 설명자를 포함하고 이 구조를 지정하여 검색된 핸들을 상속할 수 있는지 여부를 지정합니다.
learn.microsoft.com
C++에서 새 개체에 대한 보안 설명자 만들기 - Win32 apps
다음 예제에서는 다음 프로세스를 사용하여 새 레지스트리 키에 대한 보안 설명자를 만듭니다. 유사한 코드를 사용하여 다른 개체 형식에 대한 보안 설명자를 만들 수 있습니다.
learn.microsoft.com
atoll, _atoll_l, _wtoll, _wtoll_l
자세한 정보: 환초, _atoll_l, _wtoll, _wtoll_l
learn.microsoft.com
https://www.youtube.com/playlist?list=PLVsNizTWUw7E2KrfnsyEjTqo-6uKiQoxc
뇌를 자극하는 윈도우즈 시스템 프로그래밍
www.youtube.com
'Windows' 카테고리의 다른 글
커널 오브젝트의 상태 (0) | 2024.05.07 |
---|---|
메일 슬롯 방식 IPC (0) | 2024.05.07 |
커널 오브젝트와 핸들 (0) | 2024.04.26 |
표준 검색경로 (0) | 2024.04.11 |
프로세스 생성 (0) | 2024.04.10 |