핸들테이블의 작동 방식, 프로세스가 메일슬롯 함수를 호출하면 메일슬롯 커널오브젝트 핸들값을 호출한다.


핸들값은 프로세스의 핸들테이블에 들어가고 핸들테이블은 프로세스별로 독립적이고 해당 프로세스에게만 의미가 있다.



부모 프로세스가 자식 프로세스를 생성할 때, 상속이 가능한 핸들에 따라 자식 프로세스에 부모 프로세스의 핸들을 상속할 수 있다.


여기서, 사용자는 bnheritHandles를 통해 상속유무를 직접 설정할 수 있다.



메일슬롯의 CreateMailSlot 함수와 CreateFile 함수에는 이러한 인자들이 있다.


1
2
3
4
5
6
HANDLE CreateMailslot(
           LPCTSTR lpName,
           DWORD nMaxMessageSize,
           DWORD lReadTimeout,
           LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
cs


CreateFile 함수는 첫번째, 두번째, 다섯번째 인자만 알고 있으면 된다.

첫 번째 인자는 파일 이름이다.

두 번째 인자는 개방 모드이다. (Write , Read 등등) 여기선 쓰기모드로 GENERIC_WIRTE를 인자로 주었다.

다섯 번째 인자는 파일의 생성방식을 결정짓는 용도이다.


라고 적어놨는데, 4번째 인자에 위 그림의 SECURITY_ATTRIBUTES 구조체가 포인터가 들어간다.


여기서 SECURITY_ATTRIBUTES 구조체의 핸들 중 BOOL bInheritHandle; 요 변수가 상속여부를 결정한다.


또한 이 함수는 CreateProcess의 다섯번째 인자이기도 하다.




https://mm5-gnap.tistory.com/72


CreateProcess 함수의 선헌 형태를 보자.


지금은 이걸 다 이해할 필요는 없다. 그냥 보자


1. LPCTSTR lpApplicationName


생성할 프로세스의 실행파일 이름을 인자로 전달한다.


경로명을 추가로 지정할 수 있다. 경로명을 지정하지 않을 경우 현재 디렉터리에서 찾는다.


. . .

5. BOOL bInheritHandles


전달인자가 TRUE 이면, 생성되는 자식 프로세스는 부모 프로세스가 소유하는 핸들 중 상속 가능한 핸들들을 상속받는다.


. . .

10. LPPROCESS_INFORMATION lpProcessInformation


생성하는 프로세스 정보를 얻기 위해 사용되는 정보이다.


메일슬롯 이외의 리소스(함수?)에도 저러한 SECURITY_ATTRIBUTES 구조체 포인터가 들어가는 부분이 있다. 넣어주면 된다.



부모 프로세스가 어떤 커널오브젝트를 사용하는 리소스(함수?)나 프로세스를 호출한다면 UC는 1이 된다.


여기서 자식 프로세스에 특정 프로세스, 리소스를 상속시킨다면 UC는 2가 된다.



MailSender가 CreateFile로 Receiver에 연결하는 리소스를 생성하면 Sender의 CreateFile(0x1700번지) UC는 1이다.


여기서 상속으로 자식 프로세스에 0x1700번지 커널 오브젝트를 상속하면 UC가 2로 증가한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*
        MailSender2_1.cpp
*/
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
 
#define SLOT_NAME _T("\\\\.\\mailslot\\mailbox")
 
int _tmain(int argc, LPTSTR argv[])
{
    HANDLE hMailSlot;
    TCHAR message[50];
    DWORD bytesWritten;  // number of bytes write
 
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
 
    hMailSlot = CreateFile(SLOT_NAME, GENERIC_WRITE, FILE_SHARE_READ, &sa,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
    if (hMailSlot == INVALID_HANDLE_VALUE)
    {
        _fputts(_T("Unable to create mailslot!\n"), stdout);
        return 1;
    }
 
    _tprintf(_T("Inheritable Handle : %d \n"), hMailSlot);
    FILE* file = _tfopen(_T("InheritableHandle.txt"), _T("wt"));
    _ftprintf(file, _T("%d"), hMailSlot);
    fclose(file);
    STARTUPINFO si = { 0, };
    PROCESS_INFORMATION pi;
    si.cb = sizeof(si);
    TCHAR command[] = _T("Branch2.exe");
    CreateProcess(NULL,
        command,
        NULL,
        NULL,
        TRUE,  // 자식 프로세스에게 핸들을 상속!
        CREATE_NEW_CONSOLE,
        NULL,
        NULL,
        &si,
        &pi
    );  //CreateProcess
    while (1)
    {
        _fputts(_T("MY CMD>"), stdout);
        _fgetts(message, sizeof(message) / sizeof(TCHAR), stdin);
        if (!WriteFile(hMailSlot, message, _tcslen(message) * sizeof(TCHAR), &bytesWritten, NULL))
        {
            _fputts(_T("Unable to write!"), stdout);
            CloseHandle(hMailSlot);
            return 1;
        }
        if (!_tcscmp(message, _T("exit")))
        {
            _fputts(_T("Good Bye!"), stdout);
            break;
        }
    }
    CloseHandle(hMailSlot);
    return 0;
}
cs


16 ~ 19 : 상속 관련된 SECURITY_ATTRIBUTES를 정의하고 있다.


31 ~ 33 : 핸들을 저장하고있다.


38 : CreateProcess로 자식 프로세스를 생성한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*
        MailSender2_2.cpp
*/
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
 
int _tmain(int argc, LPTSTR argv[])
{
    HANDLE hMailSlot;
    TCHAR message[50];
    DWORD bytesWritten;  // number of bytes write
        /************* 핸들을 얻는 코드 *****************/
    FILE* file = _tfopen(_T("InheritableHandle.txt"), _T("rt"));
    _ftscanf(file, _T("%d"), &hMailSlot);
    fclose(file);
    _tprintf(_T("Inheritable Handle : %d \n"), hMailSlot);
    /**********************************************/
    while (1)
    {
        _fputts(_T("MY CMD>"), stdout);
        _fgetts(message, sizeof(message) / sizeof(TCHAR), stdin);
        if (!WriteFile(hMailSlot, message, _tcslen(message) * sizeof(TCHAR), &bytesWritten, NULL))
        {
            _fputts(_T("Unable to write!"), stdout);
            _gettchar();
            CloseHandle(hMailSlot);
            return 1;
        }
        if (!_tcscmp(message, _T("exit")))
        {
            _fputts(_T("Good Bye!"), stdout);
            break;
        }
    }
    CloseHandle(hMailSlot);
    return 0;
}
cs

자식 프로세스는 다음과 같다.


14 ~ 16 : 핸들을 얻어오고 있다. 핸들은 다음과 같이 생성된 txt파일을 열어서 읽고 종료한다.


커널이 좀 더 깊게 관여할 줄 알았더니 마냥 그런것도 아니다...


그래서 


23 : 읽은 핸들로 문자열을 전송하고있다.



프로세스의 핸들은 가짜핸들이다. 임의 프로세스 A의 커널 오브젝트 핸들값은 -1인가 그렇다고 했는데, 그게 바로 가짜핸들이다.


자기 자신을 의미하는 핸들일 뿐이지 실제 핸들 테이블에 등록되는 핸들값이 아니라는 것이다


그래서 가짜 핸들을 진짜 핸들로 넘기려면 위와 같은 코드를 사용해야한다.



DublicateHandle?

 번째 인자는 복제할 핸들을 소유하는 프로세스를 지정한다.

 

 번째 인자는 복제할 핸들을 지정한다.

 

 번째 인자는 복제된 핸들을 소유할 프로세스를 지정한다.

 

 번째 인자는 복제된 핸들값을 저장할 변수의 주소를 지정한다.


두번째 인자의 핸들값을 지정한다 하더라도, 세번째 인자의 핸들값이 두번째 인자의 핸들값과 동일하다는 보장은 되어있지 않다.


하지만 두 프로세스의 핸들값(256, 364)이 가리키는 주소는 동일하다. 이를 통해 커널 오브젝트에 간접 접근이 가능하다.


1. 등록하는 방법


자식 프로세스에 상속시키기 위해서는 부모 테이블의 핸들을 자기 자신의 핸들 테이블에 등록시켜야 한다.

그 때, 사용하는 것이 DublicateHandle 함수를 사용한다.


DuplicateHandle(

    HANDLE hSourceProcessHandle,

    HANDLE hSourceHandle,

    HANDLE hTargetProcessHandle,

    LPHANDLE lpTargetHandle,

    DWORD dwDesiredAccess,

    BOOL bInheritHandle,

    DWORD dwOptions

    );

 

 번째 인자는 복제할 핸들을 소유하는 프로세스를 지정한다.

 

 번째 인자는 복제할 핸들을 지정한다.

 

 번째 인자는 복제된 핸들을 소유할 프로세스를 지정한다.

 

 번째 인자는 복제된 핸들값을 저장할 변수의 주소를 지정한다.


다섯 번째 인자는 접근 권할을 지정한다.일단 0  전달한다. 자세한건 MSDN 참고


여섯 번째 인자는 복제된 핸들의 상속 여부를 지정한다.

ㅇㅇ


2. 왜 상속을 시키려고 하나


부모 프로세스의 핸들을 자식 프로세스에 상속시키면 자식 프로세스도 부모 프로세스가 종료되길 기다릴 수 있다.

Signal vs Non-Signal 편의 WaitForSingleObject 함수사용 참고



1. 등록하는 방법 이어서



첫번째 인자와 세번째 인자가 같다. 자기 자신에게 256을 복사한다는 것이다. 하지만 256은 고유하기 때문에 핸들은 다른 값으로 복사된다. 이 때 UC는 증가한다

CloseHandle을 두번 호출해줘야 한다!!



자기 자신을 기준으로 자기 자신에 자기 자신의 핸들값을 복사하는 방식이다.


여기서 두번째 인자는 가짜 핸들값이 나오는데, 가짜 핸들을 복사하게 되면 해당 프로세스의 핸들 테이블에 진짜 핸들값이 구성되어서 들어간다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
    DuplicateHandleOne.cpp
*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <tchar.h>
int _tmain(int argc, TCHAR* argv[])
{
    HANDLE hProcess;
    TCHAR cmdString[1024];
    DuplicateHandle(
        GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(),
        &hProcess, 0, TRUE, DUPLICATE_SAME_ACCESS
    );
    _stprintf(cmdString, _T("%s %u"), _T("Branch2.exe"), (unsigned)hProcess);
    STARTUPINFO si = { 0, };
    PROCESS_INFORMATION pi = { 0, };
    si.cb = sizeof(si);
    BOOL isSuccess = CreateProcess(
        NULL, cmdString, NULLNULL, TRUE, CREATE_NEW_CONSOLE, NULLNULL&si, &pi);
    if (isSuccess == FALSE)
    {
        _tprintf(_T("CreateProcess failed \n"));
        return -1;
    }
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    _tprintf(_T("[Parent Process]\n"));
    _tprintf(_T("ooooooooooooooooooooooopps! \n"));
    return 0;
}
cs


13 : 보면 이러케 나온다. hProcess에 핸들값이 담긴다.  번째 인자는 복제된 핸들값을 저장할 변수의 주소를 지정한다.

그 핸들값을 일케 절케 해서 프로세스를 생성한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
    DuplicateHandleChildProcess.cpp
*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <tchar.h>
 
int _tmain(int argc, TCHAR* argv[])
{
    HANDLE hParent = (HANDLE)_ttoi(argv[1]);
    DWORD isSuccess = WaitForSingleObject(hParent, INFINITE);
    _tprintf(_T("[Child Process] \n"));
    if (isSuccess == WAIT_FAILED)
    {
        _tprintf(_T("WAIT_FAILED returned!"));
        Sleep(1000);
        return -1;
    }
    else
    {
        _tprintf(_T("General Lee said, \"Don't inform the enemy my death\""));
        Sleep(1000);
        return 0;
    }
}
cs


12 : 전달받은 핸들을 넣고 부모 프로세스가 끝날때까지 기다린다.


자식 프로세스는 부모 프로세스가 끝날때까지 기다리고 부모 프로세스가 끝나면 20 행부터 출력된다.


으아으아으ㅏ으아으아ㅡ아으ㅏㅡ아으ㅏㄹ암나ㅣㅓㄹㅇ남ㄴㄹ어ㅏㅣㄻㅇ니;ㄹㄴㅁ아ㅓ;ㅣㄴㄹ머ㅏ이;ㅏ먼;ㅣㅇ란ㄹ어;민ㅁㄹ어ㅏ;ㅣ나어;림ㅁㄴㄹ아ㅓ;ㅣㄹ망;ㅣㅓㄴㅁㄹ아ㅓ;ㄴㄻ아ㅓㅣ;ㅁㄴㅇ러ㅏ;ㅣㄹㅇㅁ너ㅏㅣ;ㅁㄴㅇ러ㅏ;ㅣㄴㅁㅇ러;ㅏㅣㅇ러ㅏ;ㅣㄴㅇㄹ머ㅏ;ㅣㅁㄴㅇ라ㅓ;ㅣㄴㅁㅇ라ㅓㅣ;ㅁㄴㅇㄻㄹㄴ어ㅏ;ㅣㄴㅁㅇ라;ㅣㅓㅁㄴㅇ라;ㅓㄴㅇㅁ라ㅓ;ㄴㅁㅇㄹ;ㅏㅓㅣㄴㅇㄻ;ㅏㅓㅣㄴㅁㅇ라;ㅣㅓㅁㄴㅇ라ㅓ;ㅣㅁㄴㄹ어ㅏㄴㅇㅁ라ㅓ;ㅁㄴㅇㄹ;ㅓㅏㅣㄴㅁㄹ아ㅓ;ㅁㄹㄴ아;ㅓㅣㅁㄴㅇ러ㅏㄴㅁㅇ라ㅓ;ㅣㅁㄴㅇㄹ;ㅓㅏㅣㄴㄹㅇㅁ;ㅏㅣㅓㄴㅇ러마ㅣㅓㅁㄴㅇ라ㅣㅓㅁ;ㅏㄴㄹㅇ;ㅓㅏㅣㄴㅇㄹㅇㄴ롬ㄹㄴ옴ㄴㄹㅇㅁ놈ㄴㅇㄻㄴㄹ이ㅗㅁㄹ뇌미로민롬ㄹㄴ오롬ㄴ옴ㄹㄴ어ㅏㄹㄴㅇ몲님ㄴㄹ엄ㄴ옮ㄹ나ㅣㅣㄻㄴ엄ㄴㅇ리아아앙러ㅏㄹ어ㅏㄹㄴ어ㅏㄴㅇ러ㅏㅣㄴㅇ라ㅓㅣㄴㅇ라ㅓㅣㅇㄹ나ㅓㅇㄴ라ㅓㅁㄴ;ㅁ어ㅏㅁㄹㄴ어ㅏ;ㅁㄹㅇ너ㅏㅁㄹㅇ너ㅏ;ㅓㅏㄻㄹㄹ나ㅓㅁ아ㅓㅏㄹㅇㄴ머ㅏㄻ;나ㅣ어ㅏ러라;ㅁㄴ어ㅏㅓㅏ;ㅁㄴ러ㅏㅓ;ㅏㅣㄴㄹㅇ머ㅏ;ㅣ;ㅓㅏㅣㅁㄹㄴ어ㅏㅓ;만ㅇ리ㅓㅏㅣㅁㄴ이ㅓㅏㅁ나ㅣ;ㅏㅓㅁㅇ나ㅓㄹ;ㅏㅓㅣㅏㅓㅣㅓㅏ;;러안;ㅏㅁㄴ어ㅏ러ㅏㅁ;닝ㄹ;ㅓㅏㅓㅏㅁ;ㄴㅇ리ㅓ;ㅏㄹㄴㅇ머;ㅏㅓㅁㄴㅇ라ㅏ;ㅁㄴ;ㅇ러ㅏㅓㅏㅇㄴㅁ러;ㅏㅁㄹ너ㅏ;ㅓㅏ러ㅏㅁㄹㅇ너ㅏㅣㅁ러ㅏㅓㅏㄹ;ㅇ;ㅓㅏㅁㄹ어ㅏ;ㅁㄹㄴㅇ;ㅓㅏㅣㅓㅁ라;이;ㅓㅏㅁㄹㅇ너ㅏ;ㄹ엄나;ㅓㅏ;너ㅏ;ㄴㅇㅁ러ㅏ;ㅁㄴㄹ어ㅏㅁㄴㅇ라;ㅣㅓㅁㄹㄴ어ㅏ;ㅣㅁㅇㄴ러ㅏㅓ마;ㄴㄹ이ㅏㅓ;나ㅓ;ㅁㄹㅇ나ㅓㄹㅇㄴ머ㅏㄹ멍ㄴ;ㅏ;ㅓ아;ㅓ;ㅓㅏㅁㄴㅇ러;ㅏㅁ;ㅓㅏ러;ㅏㅁ어나러ㅏ;ㅁㄴ;ㅓㅏㄴㅁㅇㄹ;ㅓㅏㅣㅏㅓㅣㄴ;ㅓㅏㄹ;ㅓㅏㅁ날어;ㅏㅓㅁㄹ너ㅏㄴ어ㅏㅓㅁㄴㅇ라ㅓ마ㅓ나ㅓㅏㅓㅣㅁ너ㅏㄹㅇ;ㅓㅏ머ㅏ;어ㅏ;ㅁㄴ어라;ㅓㅏㅁㄹ어ㅏㅣㅁ너ㅏ이ㅓㅏㅓㅏ;ㄹㅇㄴ머ㅏ나ㅓㅣ;ㅓㅏㅣㄴ;ㅓㅏㅣㄹ어;ㅏㅣㄹㄴ안ㅁㅇ러ㅏㅣ;ㅏㅓㅁ;리너;ㅏ어ㅏ;ㅁㄴ어;ㅏㄹ;ㅏㅓㅣㅇㅁㄴㄹ;ㅓㅏ;만;ㄹ아ㅏㅣㅇ나ㅓㅁㄹ;ㅓㅁ나;ㄹ어ㅏㅁㄹㄴ어ㅏㅣ;ㅓㅏㄻ너ㅏ;ㅣ머ㅏ;ㅣㅓㅏ;;ㅓㅏㅁㄴㅇㄹ;ㅓㅏ;란ㅇㅁ;ㅓㅏㅣㄹㄴ어ㅏ;ㅣㅇㄻㄴ;ㅓㅏ;ㅓㅏㅁㄴㅇㄹ;ㅓㅏㅁㄴㄹ어ㅏ



흐으흐으그

'운영체제 > 윈도우 시스템' 카테고리의 다른 글

프로세스와 쓰레드, 윈도우 쓰레드  (0) 2019.10.08
컴구세번째 함수호출  (0) 2019.10.08
Signaled Non-Signaled  (0) 2019.09.27
프로세스간 통신  (0) 2019.09.26
커널 오브젝트, 핸들의 종속관계  (0) 2019.09.26

+ Recent posts