포스트

[프로세스와 잡] 최소 프로세스와 피코 프로세스

[프로세스와 잡] 최소 프로세스와 피코 프로세스

최소 프로세스

  • NtCreateProcessEx 함수에 특별한 플래그가 지정되어 있고, 호출자가 커널 모드에 있으면 이 함수는 조금 다르게 동작해 PsCreateMinimalProcess API의 실행을 유발한다.
  • PsCreateMinimalProcess는 다음과 같은 부분 없이 프로세스를 생성한다.
    • 유저 모드 주소 공간이 설정되지 않으며, PEB 관련 구조체도 존재하지 않는다.
    • NTDLL이 프로세스에 매핑되지 않으며, 로더/API 세트 정보도 매핑되지 않는다.
    • 섹션 객체가 프로세스에 연관되지 않는다. 이는 실행 가능 이미지 파일이 프로세스 실행이나 이름에 연관되지 않음을 의미한다.
    • Minimal 플래그가 EPROCESS에 설정될 수 있다. 이는 모든 스레드가 최소 스레드가 되게 하며, 자신에 대한 TEB나 유저 모드 스택 같은 유저 모드 할당을 방지한다.
  • 윈도우 10은 적어도 두 개의 최소 프로세스(시스템 프로세스와 메모리 압축 프로세스)를 가지며, 가상화 기반의 보안이 활성화되어 있다면 세 번째 최소 프로세스인 안전한 시스템 프로세스도 가진다.
  • 윈도우 10 시스템에서 실행하는 최소 프로세스를 가질 수 있는 다른 방법으로는 WSL 옵션 기능을 활성화하는 것이다. 이렇게 하면 lxss.syslxcore.sys 드라이버로 이루어진 인박스 피코 공급자를 설치한다.

피코 프로세스

  • 최소 프로세스는 커널 컴포넌트로부터 유저 모드 가상 주소 공간에 대한 접근 허용과 보호에 있어서 제한적인 반면 피코 프로세스피코 공급자로 불리는 특수한 컴포넌트로 하여금 운영체제 관점에서 자신들의 실행에 관한 대부분을 제어하게 한다는 점에서 중요한 역할을 한다.
    • 이런 수준의 제어는 윈도우 기반의 운영체제에서 실행했던 유저 모드 바이너리를 알 필요도 없이 이들 공급자로 하여금 완전히 다른 운영체제 커널의 동작을 에뮬레이트하게 해준다.
    • 이는 마이크로소프트 리서치의 Drawbridge 프로젝트 구현에 필수적이었으며, 리눅스 용도의 SQL 서버 지원에도 사용된다.
  • 시스템이 피코 프로세스를 가지려면 공급자가 먼저 존재해야 한다. 이런 공급자는 PsRegisterPicoProvider API로 등록할 수 있지만, 다음의 매우 특수한 규칙을 준수해야 한다.
    • 피코 공급자는 서드파티 드라이버가 로드되기 전에 로드돼야 한다. 실제로 수십 개의 핵심 드라이버 중 단 하나만이 기능이 비활성화되기 전에 이 API를 호출하게 허용된다.
    • 이들 핵심 드라이버는 마이크로소프트 서명자 인증서와 윈도우 컴포넌트 EKU로써 서명돼야 한다.
    • 옵션인 WSL 컴포넌트가 활성화된 윈도우 시스템에서 이 핵심 드라이버는 lxss.sys라 불리며, 다른 드라이버(lxcore.sys)가 곧바로 로드돼 피코 공급자의 역할을 떠맡기 이전까지 스텁 역할을 한다.
  • 피코 공급자가 등록 API를 호출할 때 이 API는 피코 프로세스를 생성하고 허용하는 다음과 같은 함수 포인터 집합을 받는다.
    • 피코 프로세스와 피코 스레드를 생성하기 위한 함수
    • 피코 프로세스의 컨텍스트를 구하고 이를 설정하기 위한 함수. 이것은 ETHREAD/EPROCESSPicoContext에 존재한다.
    • 피코 스레드의 CPU 컨텍스트 구조체를 구하고 이를 설정하기 위한 함수
    • 피코 스레드의 FS/GS 세그먼트를 변경하기 위한 함수. 이는 유저 모드 코드가 일부 스레드 로컬 구조체를 가리키는 데 일반적으로 사용된다.
    • 피코 스레드와 피코 프로세스를 종료하기 위한 함수
    • 피코 스레드를 일시 중지시키고 재개하기 위한 함수
  • 피코 공급자는 위와 같은 함수를 통해 이제 자신이 초기 시작 상태와 세그먼트 레지스터, 관련 데이터를 제어하면서 커스텀 프로세스와 스레드를 안전하게 생성할 수 있다.
  • 하지만 이것만으로는 다른 운영체제를 에뮬레이트할 수 있는 능력을 갖출 수 없다. 두 번째 함수 포인터 세트가 공급자로부터 커널로 전달된다. 이들 포인터는 관심을 둔 특정 행위가 피코 스레드나 프로세스에 의해 수행될 때마다 콜백 역할을 한다.
    • 피코 스레드가 SYSCALL 명령어를 사용해 시스템 호출을 할 때마다의 콜백
    • 피코 스레드로부터 예외가 발생할 때마다의 콜백
    • 메모리 디스크립터 리스트에 대한 검사와 락 동작 중 장애가 발생할 때의 콜백
    • 호출자가 피코 프로세스의 이름을 요청할 때마다의 콜백
    • 윈도우의 이벤트 트레이싱이 피코 프로세서의 유저 모드 스택 추적을 요청할 때마다의 콜백
    • 애플리케이션이 피코 프로세스와 피코 스레드에 대한 핸들을 열고자 할 때마다의 콜백
    • 누군가 피코 프로세스의 종료를 요청할 때마다의 콜백
    • 피코 스레드나 피코 프로세스가 예상치 않게 종료할 때마다의 콜백
  • 피코 공급자는 커널 패치 보호를 이용해 자신의 콜백과 시스템 호출을 보호하고, 악의적인 피코 공급자가 합법적인 피코 공급자의 상단에 등록되는 것을 방지한다.
  • 피코 프로세스/스레드와 바깥세상 간의 유저-커널로의 전환이나 커널-유저로의 상호작용에 대한 이런 독보적인 접근 덕분에 피코 공급자는 윈도우 커널과는 완전히 상이한 커널 구현을 감싸기 위해 커널을 완전히 캡슐화할 수 있다.
  • 피코 공급자는 본질적으로 피코 프로세스가 유발할 수 있는 가능한 이벤트 목록에 응답하는 데 필요한 콜백을 구현하는 커스텀 작성 커널 모듈이다. 시스템 호출 에뮬레이션과 관련 기능의 완벽함에 있어서 제약이 따르지만 이것이 바로 WSL이 변경되지 않은 리눅스 ELF 바이너리를 유저 모드에서 실행할 수 있는 방법이다.
  • 통상적인 NT 프로세스와 최소 프로세스, 피코 프로세스 각각에 대해 서로 다른 구조를 보여주는 그림
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.