06. 프로그램 실행 제어

2021. 4. 25. 18:07·SW개발/Windows Device Driver
반응형

06. 프로그램 실행 제어

  • 프로그램의 실행을 통제하는 드라이버

이론

윈도우 프로세스 실행 과정

  • 프로그램을 실행시키면, 메모리에 프로세스를 위한 공간을 할당하고 EPROCESS 등의 구조체를 생성한다.

  • 공간 할당이 끝나면, 커널이 등록된 Notify Routine 함수를 호출하여 프로세스의 실행 여부를 결정한다.


드라이버에게 프로세스의 생성과 소멸 시기를 알려주기

  • 프로세스가 실행될 때마다 호출할 함수를 커널에 등록해야 한다.

  • WDK에서 제공되는, Notify Routine 함수를 등록하는 함수들

    • PsSetCreateProcessNotifyRoutine

      NTSTATUS
      PsSetCreateProcessNotifyRoutine(
        IN PCREATE_PROCESS_NOTIFY_ROUTINE  NotifyRoutine,
        IN BOOLEAN  Remove
        );
      
      VOID
      (*PCREATE_PROCESS_NOTIFY_ROUTINE) (
        IN HANDLE  ParentId,
        IN HANDLE  ProcessId,
        IN BOOLEAN  Create
        );
      • 이 방식으로 설치하는 NotifyRoutine은 프로세스가 생성되거나 제거되는 상황을 알 수는 있지만, 생성 과정을 제어할 수 없다.

      • 설치할 때는 두 번째 인자인 Remove를 0으로, 제거할 때는 1로 설정한다.

  • PsSetCreateProcessNotifyRoutineEx

    NTSTATUS
    PsSetCreateProcessNotifyRoutineEx(
      IN PCREATE_PROCESS_NOTIFY_ROUTINE_EX  NotifyRoutine,
      IN BOOLEAN  Remove
      );
    
    VOID
    CreateProcessNotifyEx(
      __inout PEPROCESS  Process,
      __in HANDLE  ProcessId,
      __in_opt PPS_CREATE_NOTIFY_INFO  CreateInfo
      );
    
    typedef struct _PS_CREATE_NOTIFY_INFO {
      __in SIZE_T  Size;
      union {
        __in ULONG  Flags;
        struct {
          __in ULONG  FileOpenNameAvailable : 1;
          __in ULONG  Reserved : 31;
        };
      };
      __in HANDLE  ParentProcessId;
      __in CLIENT_ID  CreatingThreadId;
      __inout struct _FILE_OBJECT  *FileObject;
      __in PCUNICODE_STRING  ImageFileName;
      __in_opt PCUNICODE_STRING  CommandLine;
      __inout NTSTATUS  CreationStatus;
    } PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;
    • 위 함수의 단점을 보완한 것으로, 프로세스의 생성 과정을 제어할 수 있다.

    • 프로세스가 종료될 때는 CreateProcessNotifyEx 함수의 세 번째 인자에 NULL이 들어간다.

      • 프로세스의 종료를 제어하려면 이 인자가 NULL일 경우를 처리하면 된다.
    • _PS_CREATE_NOTIFY_INFO 구조체의 ImageFileName는 실행하려는 파일의 Full Path Name이다.

    • _PS_CREATE_NOTIFY_INFO 구조체의 CreationStatus는 프로세스 실행 여부를 결정한다.

유의사항

  • 드라이버 바이너리 파일이 변조될 위험이 있기 때문에, 윈도우에서는 파일의 무결성을 체크한다.

    • 이를 위해 링커 옵션에 /integritycheck를 추가해야 한다.
  • 드라이버가 메모리에서 해제될 때는 등록했던 Notify Routine을 제거해야 한다.

    • PsSetCreateProcessNotifyRoutineEx 함수의 두 번째 인자인 Remove에 1(TRUE) 값을 주면, 첫 번째 인자인 NotifyRoutine의 등록을 해제한다.

실습

#include <ntddk.h>

WCHAR g_TempString[512] = { 0, };
void NotifyRoutine(PEPROCESS Process, HANDLE ProcessId, \
  PPS_CREATE_NOTIFY_INFO CreateInfo)
{
  Process = Process; ProcessId = ProcessId;
  if (CreateInfo == NULL)
    goto exit;

  memset(g_TempString, 0, sizeof(WCHAR) * 512);
  memcpy(g_TempString, CreateInfo->ImageFileName->Buffer, CreateInfo->ImageFileName->Length);
  _wcsupr(g_TempString);
  if (wcswcs(g_TempString, L"NOTEPAD.EXE"))
  {
    CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL;
  }

exit:
  return;
}

void SampleDriverUnload(PDRIVER_OBJECT pDrvObj)
{
  pDrvObj = pDrvObj;

  PsSetCreateProcessNotifyRoutineEx(NotifyRoutine, TRUE);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
{
  pRegPath = pRegPath;

  pDrvObj->DriverUnload = SampleDriverUnload;

  PsSetCreateProcessNotifyRoutineEx(NotifyRoutine, FALSE);

  return STATUS_SUCCESS;
}
  • 프로젝트의 속성(Ctrl + Enter)에서 Linker - All Options 탭의 Additional Options에 /integritycheck를 추가해야 정상적으로 Notify Routine 함수가 실행된다.

    • 무결성 체크 옵션을 주지 않고 빌드하여 드라이버를 올리면, 일단 정상적으로 올라가긴 하는데 메모장도 실행이 된다. 아마 PsSetCreateProcessNotifyRoutineEx 함수가 작동하지 않는 것 같다.

  • 빌드하고 .sys 드라이버 파일은 가상 머신에, .pdb 심볼 파일은 WinDbg에서 지정한 위치로 옮긴 후 관리자 권한의 CMD에서 sc start sample 명령어로 드라이버를 올린다.

  • 그 후 notepad 명령어로 메모장을 실행하면 다음과 같은 오류가 발생한다.

    시스템이 지정된 프로그램을 실행할 수 없습니다.
  • 관리자 권한으로 메모장을 실행하면 다음과 같은 오류를 볼 수 있다.

  • sc stop sample 명령으로 드라이버를 내리면 Notify Routine 함수가 내려가므로 정상적으로 메모장을 실행할 수 있다.

프로세스가 실행될 때 해당 프로그램의 경로 확인

  • WinDbg에서 브레이크 포인트를 걸어준다.

    bp sample!NotifyRoutine
  • sc start sample 명령어를 실행하면 Notify Routine 함수가 실행되는데, 세 번째 인자인 CreateInfo가 NULL로 들어오기 때문에 바로 함수를 종료하게 된다.

  • 메모장을 실행하게 되면 다시 Notify Routine 함수가 호출되고, 여기서 CreateInfo->ImageFileName->Buffer를 통해 파일의 전체 경로를 볼 수 있다.

    • 꼭 메모장 뿐만 아니라, 모든 프로세스가 실행될 때 등록한 Notify Routine 함수가 호출된다.

  • Notify Routine 함수에 브레이크 포인트를 걸면 프로세스를 종료할 때도 브레이크가 걸리는 것을 알 수 있다.

    • 시스템 종료를 눌러도 Notify Routine이 호출된다.

브레이크 포인트 명령어

  • bl

    • 브레이크 포인트의 리스트를 볼 수 있다.

    • 명령어를 입력하면 브레이크 포인트의 번호와, 클릭할 수 있는 Disable, Clear이 나온다.

      • Disable은 잠깐 비활성화 시키는 것이고, Clear는 브레이크 포인트를 해제하는 것이다.
  • bd 번호

    • bl 명령어로 각 브레이크 포인트의 번호를 얻을 수 있는데, 이를 인자로 받아서 브레이크 포인트를 비활성화(Disable) 시킨다.
  • be 번호

    • bd로 비활성화한 브레이크 포인트를 다시 활성화(Enable) 시킨다.
  • bc 번호

    • 브레이크 포인트를 해제(Clear) 시킨다.

참고

  • 하제소프트 대표이사 이봉석님의 윈도우 드라이버 연대기
반응형
저작자표시 (새창열림)

'SW개발 > Windows Device Driver' 카테고리의 다른 글

05. 5편 구조체분석1 (DRIVER_OBJECT, UNICODE_STRING)  (0) 2021.04.25
4. 프로세스 강제 종료 방지 연습  (0) 2021.04.20
3. 간단한 드라이버와 디버깅  (0) 2021.04.20
2. 윈도우 디버거 환경을 준비하자  (0) 2021.04.20
1. 윈도우 드라이버 개발 환경 준비  (0) 2021.04.20
'SW개발/Windows Device Driver' 카테고리의 다른 글
  • 05. 5편 구조체분석1 (DRIVER_OBJECT, UNICODE_STRING)
  • 4. 프로세스 강제 종료 방지 연습
  • 3. 간단한 드라이버와 디버깅
  • 2. 윈도우 디버거 환경을 준비하자
Caniro
Caniro
  • Caniro
    Minimalism
    Caniro
  • 전체
    오늘
    어제
    • 전체보기 (318) N
      • SW개발 (268)
        • Java Spring (6)
        • C++ (186)
        • Python (21)
        • Linux (16)
        • 알고리즘 (13)
        • Git (4)
        • Embedded (1)
        • Raspberrypi (9)
        • React (3)
        • Web (2)
        • Windows Device Driver (6)
      • IT(개발아님) (45)
        • Windows (25)
        • MacOS (7)
        • Utility (11)
      • 챗봇 짬통 (0)
      • 일상 (2) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    윈도우 명령어
    logi options
    Windows 11
    SFC
    unix
    로지텍 마우스 제스처
    windows
    spring
    SunOS 5.1
    알림
    mspaint
    vscode
    EXCLUDE
    윈도우
    Solaris 10
    시스템 복구
    스프링 프레임워크 핵심 기술
    MacOS
    Workspace
    KakaoTalk
    그림판
    dism
    스프링
    제외
    citrix workspace
    백기선
    java
    맥북 카카오톡 알림 안뜸
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Caniro
06. 프로그램 실행 제어
상단으로

티스토리툴바