내가 만들려고 하는 것은 '특정 프로세스의 실행을 차단'하는 것이다.
두가지 방법이 있다.
첫째, 프로세스 콜백등록(PsSetCreateProcessNotifyRoutineEx)
둘째, IRP를 이용하여 프로세스 차단 <-이거에 중점 적으로 볼 것이다.
첫번째 방법
윈도우 드라이버는 프로세스가 생성되는 시기를 알 수 있다. 그것이 PsSetCreateProcessNotifyRoutineEx() API 이다.
( 프로세스를 감시한다.)
샘플 드라이버에서 PsSetCreateProcessNotifyRoutineEx()를 이용해 콜백루틴을 설치하고, 드라이버를 서비스로 등록하면 프로세스가 실행될때마다 이 샘플 드라이버의 콜백루틴에 걸린다.
보통 백신에서 이러한 방식을 사용한다고 한다...
이 링크를 참고하면 좋을것 같다.
* 두번째 방법 *
I/O에 IRP_MJ_CREATE IRP가 들어오면 처리를 해주는 방식이다.
https://github.com/microsoft/Windows-driver-samples/tree/master/filesys/miniFilter/avscan
위의 코드를 활용하여 '누리랩'에서 수정한 것으로 보이는 코드를 이용해서 분석해보려 한다.
(맨 아래 '참조'를 보면 소스코드가 있다.)
▼
이제부터 설명할 부분은 코드를 분석하면서 어렵고 이해가 가질 않는 부분만을 다루려 한다.
나머지는 '참조'를 보고 공부하면 충분히 이해가 갈 것이다.
▲
전체적인 동작과정은 아래 사진과 같다.
(아래에 적은 번호랑 위 사진의 번호는 별개이다.)
1. Create가 발생하면 I/O관리자는 필터드라이버에게 IRP_MJ_CREATE IRP를 전달한다.
2. 이때 CALLBACK으로 IRP_MJ_CREATE를 두어야하고, 그러면 모든 Create irp는 이 필터 드라이버를 거치게 된다.
3. Create IRP가 발생하면 FltGetFileNameInformation()으로 어떤 파일이 발생시켰는지 확인 할 수 있다.
4. 그래서 SendMessage로 유저영역의 어플리케이션에 보내고, 유저는 FilterGetMessage로 메세지를 전달받고 Reply로 결과를 전달해 준다.
먼저, 필터드라이버를 보자.
- MSDN을 보면 FltGetFileNameInformation()으로 입출력을 요청한 파일의 정보를 얻을 수 있다. 여기서 nameInfo로 바로 데이터에 접근할 수 있는 것이 아니라 FltParseFileNameInformation()을 호출해 주어야만 비로소 파일에 접근이 가능하다.
- FltSendMessage()함수로 IRP를 보낸 파일에대한 정보를 유저 어플리케이션으로 전송을 한다.
- 이때 차단 여부를 notificcation으로 받게 된다.
scanner.sys의 코드는 어렵지 않다. 하지만, 이 필터드라이버와 통신하기 위한 유저 어플리케이션이 문제다.
------------------------------------
유저 어플리케이션 코드를 살펴보자.
- 전체적으로 보면 쓰레드를 생성해서 requestCount만큼 FilterGetMessage()를 한다. 이는 드라이버가 보낸 메세지를 읽어 들이는 행위로 볼 수 있고, 이후 if문으로 'EROOR_IO_PEDING'인지 검사를 하는데 ERROR_IO_PEDING에 관한 개념은 다음과 같다.
[*] ERROR_IO_PENDING - 실패가 아니라, 비동기 입출력이 완료되었음을 나타낸다. - 비동기 입출력이거나 쓰기에 실패하면 0(FALSE)를 반환한다. GetLastError 코드가 ERROR_IO_PENDING이면 쓰기에 실패한 것이 아닌 비동기 입출력에 의한 반환을 의미한다. |
[*] 여기서 가장 중요한 포인트는 FilterGetMessage()함수의 마지막 인자이다.! 하지만 이것을 설명하기전에 WriteFile()함수의 원형부터 보자.
WriteFile API를 사용하면서 마지막 인자인 lpOverlapped를 간과했다. ㅜㅜ 사실 한번도 써본적이 없다.
결론은 이 마지막 인자가 하는 역할은 비동기 입출력을 위한 OVERLAPPED 구조체의 포인터 이다.!!!!!
즉, NULL로 셋팅하면 일반적 입출력(동기화)이지만 값을 설정해주면 비동기 입출력을 하겠다는 뜻이다.
그래서 비동기 입출력에 관해 공부를하였다.
아래는 공부하면서 참고했던 URL이다.
- https://youtu.be/m1StIH8lzlw - https://ice-bear.tistory.com/22 - https://emongfactory.tistory.com/110 - https://underground2.tistory.com/149 |
------------------
* 다음으로 가장 이해가 가지 않았던 ScanWork Thread에 대해 보자!!! *
ScanWorker의 코드 중 위 사진에서 보이는 GetQueueCompletionStatus() 부분이 이해가질 않았다.
문서를 읽어보면 'I/O Completion packet'을 dequeue한다고 나와있다. 처음에는 이 말을 이해하지 못했지만, 잘 생각해 보면 완료된 I/O를 저장하는 큐가 있다는 것을 알 수 있다.
즉, 비동기 입출력이 수행이되고 완료가되면 I/O Completion Queue에 그 결과가 저장이 된다는 것이다.
(참고로 이 Queue에 PostQueuedCompletionStatus()로 정보를 직접 큐잉할 수 있다.)
함수의 마지막 인자로 INFINITE를 줌으로써 dequeue가 될 때 까지 대기를 한다.
그러면 도대체 이 I/O Completion Queue에 언제 값이 큐잉되냐???
[중요] 위에서 보았던 FilterGetMessage()함수가 비동기입출력이 완료 되면 I/O Completion Queue에 담긴다는 것이다.!!! 이렇게 queue에 데이터가 담기면 대기하고있던 GetQueuedCompletionStatus()가 데이터를 dequeue한다.
근데 왜?????? FilterGetMessage()가 끝나면 그 큐에 담기냐? 그 이유는 코드를 보면 앞에서 CreateIoCompletionPort의 return value 즉, 핸들을 FilterGetMessage()에서 사용해 주었기 때문에 큐에 담긴 것으로 보인다.
[중요] ' https://ozt88.tistory.com/23' <- 여기에 기가막히게 설명해 놓았으니 꼭~! 참고해라
비동기 입출려관련 참고 자료 url을 보셨다면 알 것이다. Ovlp에 전달하고 싶은 값을 담을 수 있다 .
CONTAINING_RECORD()매크로를 통해 전달 받은 Ovlp의 최상위 에있는 구조체?를 가지고 온다.
( 사실 이부분은 개념이 정확하지 않아서 잘모르겟다..... )
이렇게 해서 모르는 부분을 정리하였고, 이제 컴파일을 하고 필터 드라이버를 서비스로 등록했는데!!!
동작이 안된다....................................
많은 삽질 끝에 '고도'에 관해 살펴 보았다.
inf파일에 '고도'라는 것을 설정해주어야했다. 아래의 링크를 보면
우리가 필요로 하는 고도는 위 사진의 값과 같다. 이 값을 inf파일에 셋팅 해주어야한다.
non-paged -메모리에 계속 상주시키겠다.
paged - 그렇지않다.
[*] 참고 자료 및 출처
미니필터 드라이버 서비스 실행 : https://kochuns.blogspot.com/2017/03/minispy.html
소스코드 : https://github.com/nurilab/scanner_filepath/
참고자료 : https://nurilab.github.io/2020/05/25/kicomav_driver_2/
https://www.joinc.co.kr/w/man/4200/GetQueuedCompletionStatus
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=wwwkasa&logNo=80188929974
'WindowsDriver' 카테고리의 다른 글
특정 프로세스 차단 드라이버 개발 (최종) (0) | 2021.07.07 |
---|---|
Mini Filter Driver Dev Part1. (feat. 개념) (0) | 2021.06.20 |
WindowsDriver Develop Basic2 [정리중] (0) | 2020.09.23 |
WindowsDriver Develop Basic [정리중] (0) | 2020.09.22 |