개발/VC++

[스크랩] Kernel object 와 오브젝트 핸

99iberty 2021. 7. 19. 23:22

https://popcorntree.tistory.com/57

 

[06. 커널 오브젝트와 오브젝트 핸들]

* 이 내용은 '뇌를 자극하는 윈도우즈 시스템 프로그래밍' 책의 내용을 정리한 것 입니다. 커널 오브젝트에 대한 이해 커널이란? 컴퓨터를 운영하는 데 있어서 중심이 되는 운영체제 핵심 부분.

popcorntree.tistory.com

이 내용은 '뇌를 자극하는 윈도우즈 시스템 프로그래밍' 책의 내용을 정리한 것 입니다.

 

커널 오브젝트에 대한 이해

커널이란? 컴퓨터를 운영하는 데 있어서 중심이 되는 운영체제 핵심 부분. 일반적으로 커널이라는 용어와 운영체제라는 용어를 같은 의미로 사용한다. 

그러나, "커널 오브젝트"라는 단어는 고유명사처럼 하나로 이해하도록 해라.

커널 오브젝트란? 커널에서 관리하는 중요한 정보를 담아둔 데이터 블록을 가리켜 커널 오브젝트라 한다.

  • 커널 오브젝트의 이해
    • 운영체제가 여러개의 프로세스를 관리할 때 고정적으로 저장하고 생신해야할 정보들이 생긴다.
      • 프로세스 상태 정보(Ready, Blocked, Running)
      • 우선순위 정보
    • 위와 같은 것들을 저장하고 변경하고 참조하기 위해  Windows 운영체제 개발자들은 구조체 하나를 정의했다.
      • "프로세스 관리 구조체"라 부르도록 하자.
    • 프로세스가 생성될 때마다 "프로세스 관리 구조체" 변수가 하나씩 생기고, 새롭게 생성된 프로세스 정보들로 초기화 된다.
    • 이것이 바로 "커널 오브젝트"의 정체(!)이다.

 

  • 그 이외의 커널 오브젝트들
    • 프로세스가 생성될 떄에만 커널 오브젝트가 생기는 건 아니다.
    • 프로세스 내부에서 스레드를 생성할 때, IPC(Inter Process Communication)을 위해 사용되는 파이프나 메일슬롯을 생성할 때에도, 커널 오브젝트를 생성해서 필요한 정보들을 채워야 한다.
    • Windows에서 만드는 모든 종류의 커널 오브젝트들은 동일한 구조체로부터 생성될까?
      • 아니다.
      • 관리되어야 할 사항들이 다르기 때문에, 커널 오브젝트 형태도 다를 수밖에 없다.
    • Windows 운영체제는 프로세스, 스레드 혹은 파일과 같은 리소스(Resource)들을 원활히 관리하기 위해 필요한 정보를 저장해야 한다. 이 때 데이터를 저장하는 메모리 블록을 가리켜 커널 오브젝트라 한다.

커널 오브젝트 여러개가 생성된 상태

 

 

 

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

  • 프로세스 우선순위 (Priority) 변경
    • 스레드때 자세히 하겠지만 우선 간단하게 우선순위를 바꾸는 방법
      • BOOL SetPriorityClass(Handle hProcess, DWORD dwPriorityClass);
        • hProcess : 우선순위를 변경할 프로세스의 핸들을 전달
          • 핸들이란? 커널 오브젝트에 할당되는 숫자
        • dwPriorityClass : 새롭게 적용할 우선순위 정보를 전달
        • 즉, hProcess가 가리키는 프로세스의 우선순위를 dwPrioritClass로 변경시킨다 는 뜻.
    • 커널 오브젝트에 할당되는 숫자 핸들(Handle)
      • 우선순위를 바꾸기 위해 특정 커널 오브젝트의 우선순위를 변경해야 한다.
      • Windows는 커널 오브젝트를 생성할 때마다 핸들이라는 정수값을 하나씩 부여한다.
        • 이걸 통해 특정 커널 오브젝트를 지목하는 것은 아주 쉽다.
        • 여기서 설명한 핸들은 커널 오브젝트를 지시하는 용도로 사용된다는 의미에서 "커널 오브젝트 핸들" 또는 "오브젝트 핸들" 이라고 불린다.

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

  • 핸들 정보는 어디서?
    • 핸들의 정보를 얻는 방법은 커널 오브젝트의 종류에 따라 다양하다. 
      • 프로세스 커널 오브젝트냐 ? 파일의 커널 오브젝트냐?
    • 현재 실행되고 있는 프로세스의 핸들을 얻는 방법은?
      • HANDLE GetCurrentProcess(VOID);
        • 반환값을 통해 핸들을 얻는다.

 

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

  • 커널 오브젝트의 종속관계
    • 커널 오브젝트는 Windows 운영체제에 종속적이다
    • 종속적? 독립적이지 못하다.
    • 1. 커널 오브젝트는 프로세스에 종속적인 것이 아니라, 운영체제에 종속적인 관계로 커널 오브젝트의 소멸은 운영체제에 의해 결정된다.
      • 마찬가지로, 커널 오브젝트는 프로세스에 종속적인 것이 아니라, 운영체제에 종속적인 관계로 커널 오브젝트의 소멸 시점은 운영체제에 의해서 결정된다.
    • 2. 커널 오브젝트는 프로세스에게 종속되는 것이 아니므로 여러 프로세스에 의해 접근이 가능하다
      • 마찬가지로, 커널 오브젝트는 프로세스에 종속적인 것이 아니라 운영체제에 종속적인 관계로 여러 프로세스에 의해서 접근 가능하다. (물론 함수 호출을 통한 간접 접근이다)
  • 핸들의 종속관계
    • 커널 오브젝트는 프로세스가 아닌 운영체제에 종속적이라고 했다면, 핸들은?
      • 핸들(핸들테이블)은 운영체제에 종속적이지 않고 프로세스에 종속적이다.
  • 예제를 통한 종속관계의 이해
    • 이런 시나리오가 가능하다
      • "A프로세스가 B프로세스를 생성한다. 그러자 B프로세스는 자신의 우선순위를 높인다. 잠시후 A프로세스는 B프로세스의 우선순위를 원래대로 돌려 놓는다.
    • A프로세스가 B프로세스의 우선순위를 변경한다는 것은?
      • B프로세스의 커널 오브젝트에 A프로세스가 접근 가능하다.
      • 하나의 커널 오브젝트에 둘 이상의 프로세스가 접근 가능하다.
  • PROCESS_INFORMATION 구조체
typedef struct _PROCESS_INFORMATION
{
      HANDLE hProcess; 		//프로세스의 핸들
      HANDLE hThread; 		//스레드 핸들
      DWORD dwProcessId; 		//프로세스의 ID
      DWORD dwThreadId;		//스레드 ID
} PROCESS_INFORMATION;
  • 운영체제는 프로세스를 생성할 때마다 프로세스들을 구분짓기 위한 ID(식별자를 할당한다. 
  • 위 구조체의 3번째 멤버에는 새로 생성되는 프로세스 ID 정보로 채워진다.
    • 그렇다면, 프로세스 핸들과 프로세스 ID의 차이점은?
    • 프로세스 핸들은 프로세스의 커널 오브젝트를 가리키기(구분짓기) 위한 것이다
    • 프로세스 ID는 커널 오브젝트가 아니라 프로세스 자체를 구분짓기 위한 것이다.
  • 2번째, 4번째 멤버
    • Windows 운영체제는 프로세스를 생성하면 프로세스 내부적으로 스레드라는 개념의 '가벼운 프로세스'를 생성해서 이를 통해 main 함수가 호출되도록 디자인되었다.
    • 즉, CreateProcess 함수를 통해 프로세스를 생성하면, 스레드라는 시스템 리소스도 더불어 생성되는 것. 
    • 이것이 스레드 핸들과, id정보가 각각 두번째 네번째 멤버로 채워진다.

 

커널 오브젝트와 Usage Count

  • 커널 오브젝트는 프로세스에 종속적인 것이 아니라 운영체제에 종속적인 관계 커널 오브젝트 소멸시기는 운영체제에 의해서 결정된다.
    • 우리, 혹은 실행 프로그램은 운영체제에게 프로세스를 만들어달라고 요청할 뿐, 커널 오브젝트의 생성은 운영체제가 프로세스 관리의 용이성을 위해 생성하는 것이다.
  • CloseHandle 함수에 대한 정확한 이해
    • A라는 프로세스가 생성되면, A 프로세스를 위한 커널 오브젝트도 생성된다.
      • 이 때 커널 오브젝트는 완전히 프로세스를 대표하게 된다.
    • 그렇다면, 역은 성립할까? 
      • 아니다
      • 프로세스가 소멸된다고 해서 커널 오브젝트가 소멸된다고 말할 수 없다.
      • 소멸될 수도, 소멸되지 않을수도 있다.
        • 소멸 시기는 운영체제가 결정하기 때문이다.
      • 그렇다면 운영체제가 소멸 시키를 결정하는 기준은 무엇일까?
        • CloseHandle 함수를 보자
    • CloseHandle 함수의 기능은 이름처럼 핸들의 반환이다.
      • 핸들이 가리키는 리소스가 필요하지 않으니 이에 해당하는 리소스를 해제하고 커널 오브젝트를 소멸시켜라? 이게 아니다.
      • 상황 가정 ) A프로세스가 실행중에 B프로세스를 CreatProcess 했다면, 동시에 커널 오브젝트도 생성될 것이다. 그 후 A 프로세스에서 B 프로세스의 핸들을 이용해서 CloseHandle 했다면?
        • B 프로세스에 대해서 더 이상 내가 관여할 바 아니니, B 프로세스 핸들을 반환하라.
        • 호출시점에서 B 프로세스가 종료된다면, CloseHandle 함수는 프로세스 종료 및 커널 오브젝트 반환 기능이 있다고 결론지을 수 있을 것이다.
    • 실행 결과를 통한 분석
      •   A프로세스가 프로그램 종료를 의미하는 문자열 "Press any key to continue"를 출력했음에도 그 뒤에 프로세스 B에 의한 출력은 계속되고 있다.
      • 이는 CloseHandle 함수 호출에 의해서 B 프로세스가 소멸되지 않았음을 확인할 수 있다.
  • CloseHandle 함수와 프로세스 종료코드
    • 그럼 다시, 운영체제는 커널 오브젝트 소멸 시점을 어떻게 결정짓는가?
      • 일단, 프로세스가 종료되어야 한다.
      • 그러나 프로세스 종료 시 해당 커널 오브젝트를 소멸시면 문제가 발생할 수 있다. 
        • 프로세스 종료 코드 기반으로 문제가 발생할 수 있는 경우는?
          • 프로그램에는 정상 종료, 비정상 종료가 있는데 부모 프로세스가 자식 프로세스의 종료 코드를 핸들을 통해 커널 오브젝트에서 가져와 읽을 수 있고 적절한 조치를 취할 수 있다.
  • 커널 오브젝트와 Usage Count
    • 자식 프로세스의 종료 코드는 어디에 저장되는가?
      • 자식 프로세스의 커널 오브젝트에 저장된다.
      • 때문에, 자식 프로세스가 종료될 때 커널 오브젝트도 소멸된다면? 
      • 부모 프로세스는 종료코드를 얻을 수 없게 된다. 
        • 그래서, 프로세스가 종료되었다고 해서 커널 오브젝트까지 소멸시키지 않는 것이다.
    • 그렇다면 언제 커널 오브젝트를 소멸시키는 것이 적절한가?
      • 해당 커널 오브젝트를 참조하는 대상이 하나도 없을 때 소멸 시키는 것이 가장 이상적이다.
        • 그리고 이것이 Windows가 커널 오브젝트 소멸시기를 결정하는 방식이다.
        • 즉, 커널 오브젝트를 참조하는 프로세스가 하나라도 있을 시 커널 오브젝트는 소멸되지 않는다.
      • 그래서 Usage Count(참조 횟수) 라는 것을 관리해서 Windows는 커널 오브젝트 소멸 시기를 결정짓는다.
        • 이게 0이 되는 순간 해당 커널 오브젝트는 소멸한다.
        • 프로세스는 생성과 동시에 Usage Count 가 1이 된다.
          • 그런데, 나에게 즉, 커널 오브젝트에 접근 가능한 핸들의 개수가 증가할수록 1씩 증가한다.
          • 그러므로 자식 프로세스의 Usage Count는 부모 프로세스까지 포함해서 2가 되어야 한다. 
          • 실제로도 2가 된다.
        • 그리고 이 Usage Count 역시 커널 오브젝트의 멤버로 존재한다.
    • Usage Count 와 CloseHandle
      • Usage Count가 증가하는 것은 알았으니, 그렇다면 0이 되어 커널 오브젝트가 소멸되는 시점을 보자.
      • CloseHandle 함수는 핸들을 반환하면서 커널 오브젝트의 Usage Count를 하나 감소시키는 기능을 지닌다.
        • 또한, CloseHandle 이 불리는 경우 외에, 프로세스(스레드도 마찬가지)가 종료되는 시점에서도 Usage Count는 감소한다.
      • 어떤 프로세스에서 계산기를 자식 프로세스로 생성하는 프로그램이 있을 때, 자식 프로세스가 종료되더라도 부모 프로세스가 있기 때문에 Usage Count는 1이어서 커널 오브젝트가 소멸되지 않고 계속 남아있는 문제가 있다. 
        • 이걸 해결하기 위해서는 부모 프로세스에서 CreateProcess 하자마자 바로 CloseHandle을 하면 해결된다. 
        • 그러나 이렇게 문제를 해결하더라도 스레드에 관련된 문제점을 갖고 있다. 이건 나중에 다루도록 하자.
    • 바탕화면에 있는 아이콘을 더블클릭 해서 프로세스를 생성할 경우 이 프로세스의 Usage Count는 1일까? 
      • 이 경우는 2이다. 바탕화면도 독립적으로 실행중에 있는 프로세스이기 때문이다.
      • 더블클릭이라는 이벤트를 통해서 바탕화면 프로세스에게 프로세스 생성을 요청하는 것이다.
      • 그렇기 때문에 바탕화면에서 실행하든, 탐색기를 통해 실행시키든, 명령프롬프트상에서 실행시키든 부모 프로세스를 기반으로 자식 프로세스가 생성되는 것이 된다. 즉 프로세스는 생성과 동시에 Usage Count 가 2가 된다.
      • 그러면 위와 같은 문제가 일어날 것 같은데, 그렇지 않은게 위의 문제를 해결한 방식대로 바탕화면 프로세스는 자식 프로세스 생성과정에서 얻게되는 핸들을 그 즉시 반환하기 때문에 그런 문제가 일어나지 않는다.

 

 

명령 프롬프트 프로젝트 기능 추가

  • echo 명령어와 start 명령어에 대해 알아보자
    • start 명령어
      • 명령 프롬프트 상에서 start만 그냥 입력해도 새로운 명령 프롬프트가 생성된다.
      • 그리고 dir 앞에 start를 붙이면, 새로운 명령 프롬프트를 띄운 다움에 dir명령어가 실행된다.
        • dir : 파일 및 디렉터리 리스트 출력 명령어
    • echo 명령어
      • echo 명령어를 구현하는 이유는 start 명렁어의 완성도를 테스트 하기 위해서.
      • 말 그대로 에코 출력이다.
      • echo 명령어 뒤에 입력된 문자열을 그대로 출력하는 기능을 가진다.
        • start와 묶으면? 
          • start echo This is a echo Message 라고 입력하면 새로운 명령 프롬프트 창에서 This is a echo Message 라는 문자열이 출력된다.
    • 실습은 위의 두 명령어를 구현해보는 것이다.

 



출처: https://popcorntree.tistory.com/57 [어떤 프로그래머]

 

 

https://givemesource.tistory.com/37

 

6. 커널 오브젝트와 오브젝트 핸들

1. 커널 오브젝트에 대한 이해 : 커널이란, 컴퓨터를 운영하는데 있어서 중심이 되는 운영체제 핵심 부분을 뜻하는 것이다. : 일반적으로 커널과 운영체제는 같은 의미로 사용되어지기 때문에 명

givemesource.tistory.com

https://dakuo.tistory.com/84

 

커널 오브젝트(Kernel Object)

커널 오브젝트 : Windows 운영체제에서 리소스(Resource : 프로세스, 쓰레드, 파일)들을                      관리하기 위한 데이터를 저장하는 메모리 블록 Windows에서 관리하는 리소스..

dakuo.tistory.com