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) 시킨다.
참고
- 하제소프트 대표이사 이봉석님의 윈도우 드라이버 연대기
'Windows > DeviceDriver' 카테고리의 다른 글
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 |