ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2015.01.20 커널 오브젝트
    Legacy/뇌자극 - WinSysProg 2015. 1. 20. 22:43
    728x90

    커널 오브젝트

    커널 : 운영하는 데 있어서 중심이 되는 운영체제 핵심 부분을 뜻함

    커널 오브젝트 : 커널에서 관리하는 중요한 정보를 담아둔 데이터 블록


    운영체제가 프로세스를 관리하기 위해 프로세스에 관련된 몇몇 정보를 저장할 수 있어야 하고, 참조 및 변경도 가능해야 한다. 이를 위해 Windows 운영체제 개발자들은 구조체 하나를 정의하기에 이른다. 이 구조체는 프로세스 상태 정보를 저장하기 위해 정의한 것.

    프로세스가 생성될 때마다 이러한 구조체 변수가 하나씩 생성되고, 새롭게 생성된 프로세스 정보들로 초기화되는데, 이것이 바로 커널 오브젝트(Kernel Object)이다.



    프로세스가 생성될 때에만 커널 오브젝트가 생성되는 것은 아니다. 프로세스 내에서 쓰레드를 생성할 때에도, IPC(Inter Process Communication)를 위해 사용되는 파이프나 메일슬롯을 생성할 때에도 커널 오브젝트를 생성해서 필요한 정보들을 채워야만 한다. 그래야 운영체제가 이들을 관리할 수 있다. Windows에서는 파일을 생성할 때에도 커널 오브젝트가 생성된다.

    "Windows 운영체제는 프로세스, 쓰레드 혹은 파일과 같은 리소스(Resource)들을 원활히 관리하기 위해 필요한 정보를 저장해야 한다. 이때 데이터를 저장하는 메모리 블록을 가리켜 커널 오브젝트라 한다."


    오브젝트 핸드(Handle)을 이용한 커널 오브젝트의 조작

    프로그래머가 직접 커널 오브젝트를 조작할 수 없다. 하지만, 함수 호출에 의해 간접적인 조작까지 불가능한 것은 아니다.


    프로세스 우선순위(Priority) 변경

    BOOL SetPriorityClass (

    HANDLE hProcess,

    DWORD dwPriorityClass

    );

    If the function fails, the return value is zero.

    hProcess : 우선순위를 변경할 프로세스의 핸들(Handle)을 전달한다.

    dwPriorityClass : 새롭게 적용할 우선순위 정보를 전달한다.


    핸들이란 커널 오브젝트에 할당되는 숫자에 지나지 않는다.

    SetPriorityClass 함수는

    "hProcess가 가리키는 프로세스의 우선순위를 dwPriorityClass로 변경시킨다."

    라고 한 문장으로 표현할 수 있다.


    커널 오브젝트에 할당되는 숫자! 핸들(Handle)

    우리가 지금 하려는 것은 특정 프로세스의 우선 순위를 높이는 일이다. 그렇다면 우선순위 정보를 변경해 줘야만 한다. 우선순위 정보는 어디에 있다슷고 하였는가? 프로세스 커널 오브젝트에 존재한다고 하지 않았는가! 여기에 저장되어 있는 우선순위 정보를 변경해야만 실제 프로세스에 반영될 것이다. SetPriorityClass 함수를 통해서 다음과 같은 요구를 해야만 한다.

    "저기 있는 저 커널 오브젝트에 저장된 우선순위 정보를 높여 주세요"

    여기서 문제는 특정 커널 오브젝트를 가리키는 일이다. 그러나 걱정할 필요가 없다. Windows는 커널 오브젝트를 생성할 때마다 핸들이라는 정수값을 하나씩 부여하기 때문이다. 이 정수값만 알 수 있다면 커널 오브젝트를 지시하는 것은 아주 쉬운 일이 된다. 핸들이라는 개념이 존재하는 이유도 바로 여기에 있다.

    핸들은 리눅스의 PID와 같은 개념이라고 생각하면 쉽다.

    파일의 경우에는 파일 디스크립터

    다음 그림은 핸들이라는 개념과 커널 오브젝트 그리고 리소스 사이의 개념을 표현한 그림이다.



    typedef void * HANDLE;

    커널 오브젝트 핸들 혹은 오브젝트 핸들이라고 불림.


    "함수가 호출되어 실행되는 중간에도 실행되는 프로세스가 변경될 수 있음."



    커널 오브젝트와 핸들의 종속 관계

    "커널 오브젝트는 Windows 운영체제에 종속적이다."


    1. 커널 오브젝트는 프로세스에 종속적인 것이 아니라, 운영체제에 종속적인 관계로 커널 오브젝트의 소멸시점은 운영체제에 의해서 결정된다.

    2. 커널 오브젝트는 프로세스에 종속적인 것이 아니라 운영체제에 종속적인 관계로 여러 프로세스에 의해서 접근 가능하다.(함수 호출을 통한 간접 접근)


    "핸들은 운영체제에 종속적이지 않고 프로세스에 종속적이다."


    예제를 하나 들어보겠음.

    "A 프로세스가 B 프로세스를 생성한다. 그러자 B 프로세스는 자신의 우선순위를 높인다. 잠시 후 열받은 A 프로세스는 B 프로세스의 우선순위를 원래대로 돌려 놓는다."

    A 프로세스가 B 프로세스의 우선순위를 변경시킨다는 것은, B 프로세스의 커널 오브젝트에 A 프로세스가 접근 가능하다는 뜻이 된다. 이는 하나의 커널 오브젝트에 둘 이상의 프로세스가 접근 가능하다는 결론으로 이어진다.


    KerObjShare.cpp

    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
    #include <stdio.h>
    #include <tchar.h>
    #include <Windows.h>
     
    int _tmain(int argc, TCHAR* argv[])
    {
        STARTUPINFO si = {0,};
        PROCESS_INFORMATION pi;
        si.cb = sizeof(si);
        TCHAR command[] = _T("Operation2.exe");
     
        CreateProcess (
            NULL, command, NULL, NULL,
            TRUE, 0, NULL, NULL, &si, &pi
            );
     
        DWORD timing = 0;
     
        while(1)
        {
            for(DWORD i = 0; i < 10000; i++)
                for(DWORD i = 0; i < 10000; i++);
     
            _fputts( _T("Parent \n"), stdout );
     
            timing += 1;
            if(timing == 2)
                SetPriorityClass(pi.hProcess, NORMAL_PRIORITY_CLASS);
        }
     
        return 0;
    }


    Operation2.cpp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #include <stdio.h>
    #include <tchar.h>
    #include <Windows.h>
     
    int _tmain(int argc, TCHAR* argv[])
    {
        SetPriorityClass(GetCurrentProcess(),  HIGH_PRIORITY_CLASS);
     
        while(1)
        {
            for(DWORD i = 0; i < 10000; i++)
                for(DWORD i = 0; i < 10000; i++);
     
            _fputts( _T("Operation2.exe \n"), stdout);
        }
        return 0;
    }


    Operation2.cpp는 실행되 동시에 자신의 우선순위를 높이도록 구현되어 있다. 우선 순위를 높이기 위해서는 핸들을 이용해 커널 오브젝트에 접근해야만 한다. 이때 자기 자신의 핸들 정보를 얻기 위해서 GetCurrentProcess() 라는 함수를 사용했다.

    이번에는 구조체 변수 pi의 멤버에 대해 살펴보자.

    typedef struct _PROCESS_INFORMATION

    {

    HANDLE hProcess;        // 프로세스의 핸들

    HANDLE hThread;         // 쓰레드의 핸들

    DWORD dwProcessId;   // 프로세스의 ID

    DWORD dwThreadId;    // 쓰레드의 ID

    } PROCESS_INFORMATION;


    결론을 내리면 위 예제에서는 프로세스 생성 시 얻은 프로세스의 핸들을 통해서 Operation2.exe의 커널 오브젝트에 접근하고 있는 상황이다. 결과적으로 두 개의 프로세스가 하나의 커널 오브젝트에 순서대로 접근하였다. 한번은 우선순위를 높이기 위해서, 또 한번은 우선순위를 되돌리기 위해서 커널 오브젝트가 공유되었다.

    한 가지 더 주목할 것은 커널 오브젝트 접근을 위해 핸들을 얻는 방법이다. Operation2.cpp에서는 GetCurrentProcess 함수를 사용했지만, KerObjShare.cpp에서는 PROCESS_INFORMATION 구조체의 변수인 pi를 이용해 접근했다. 커널 오브젝트의 종류와 상황에 따라 핸들을 얻는 방법이 달라진다.


    PROCESS_INFORMATION

    운영체제는 프로세스를 생성할 때마다 프로세스들을 구분짓기 위한 ID를 할당한다. 위 구조체의 세 번째 멤버 dwProcessId는 새로 생성되는 프로세스 ID 정보로 채워지게 된다.

    "프로세스 핸들은 프로세스의 커널 오브젝트를 가리키기 위한 것이고, 프로세스 ID는 커널 오브젝트가 아니라 프로세스 자체를 구분짓기 위한 것이다."

    모호하지만, 핸들 테이블에 관련된 내용을 공부하고 나면 모호함이 사라짐.

    hThread와 dwThreadId에 대해선 쓰레드에 대한 이해가 필요한 데, 쓰레드는 프로세스 내부에 존재한다. '가벼운 프로세스'라고 생각하면 좋다.

Designed by Tistory.