2015. 3. 13. 17:49ㆍSecurity ★ Development/Windows Driver
NDIS를 통한 프로젝트를 진행하면서 그나마 최신 국내 NDIS 프로그래밍 포스팅이 없어서 간략하게 정리를 하려고합니다. 더 상세하게는 필요하다고 생각되면 따로 포스팅하겠습니다. 또한 저도 학생의 신분으로 이쪽으로 깊게 공부한 것은 아니기 때문에 잘못된 부분이 있으면 알려주시면 감사하겠습니다.
NDIS에 대한 개념적인 소개는 생략하겠습니다. MSDN의 NDIS 6.0 Filter Driver Sample을 바탕으로 진행합니다. 우선 NDIS를 통해 할 수 있는 건 윈도우 7에서는 MAC address부터 payload까지 전부 볼 수 있습니다. WFP는 윈도우8부터 Ethernet을 볼 수 있어서 윈도우7에서 MAC을 보기위해선 NDIS를 이용해야 합니다.
솔루션을 열면 주로 filter.c를 수정하게 됩니다.
DriverEntry 함수를 보면
FChars.SendNetBufferListsHandler = FilterSendNetBufferLists;
FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists;
이 부분이 있는데 저 두 함수에서 패킷의 처리를 해줄 수 있습니다.
또한 어플리케이션과의 연동이 필요하면 여기서 심볼릭 링크를 생성하고 IRP의 function을 등록해주는 초기화를 합니다.
FilterSendNetBufferLists를 보겠습니다. FilterReceiveNetBufferLists도 비슷하게 진행됩니다.
이 함수내에서 패킷들은 PNET_BUFFER_LIST로 관리됩니다. 여기서 패킷데이터를 참조할 수 있습니다.
함수의 인자로 받는 NetBufferLists로부터 첫번째 NetBuffer를 구하고 현재MDL을 구합니다. 그리고 Offset을 계산하여 바로 Ethernet헤더에 접근할 수 있습니다. 이더넷 헤더 구조체를 정의하고 참조해주면 됩니다. 이후에는 TCP인지, UDP인지 등에 따라 오프셋만큼 위치를 옮겨가며 데이터를 참조해가면 해당하는 패킷의 페이로드를 구할 수 있다는 것이 기본 전략입니다. 각 값들(ip, port 등)은 평소 쓰는 것처럼 보기좋게 10진수로 표시되지 않으니 적절하게 변환해주어야합니다.
이 함수에서 패킷을 검사하고 보내고싶지 않으면 차단할 수 있습니다. 통과시킬 때에는 NdisFSendNetBufferLists함수를 불러주고 차단하고 싶으면 NdisFSendNetBufferListsComplete함수를 이용합니다.
어플리케이션과의 연동을 위해 필요한건 컨트롤 코드, 링크네임, 디바이스네임입니다. Send, Recv함수에서 패킷 데이터를 참조하기 위해선 참조하려는 헤더 구조체를 선언해두어야합니다.
저는 DeviceIoControl을 이용해서 어플리케이션과 통신을 했는데 이는 IRP_MJ_DEVICE_CONTROL에 정의해주어야 하고 그 외 CREATE, CLOSE, CLEANUP도 해주어야합니다.
FilterUnload에서 IOCTL통신을 위해 만들어두었던 링크와 디바이스를 제거해줍니다.
대략적인 개요는 위와 같습니다. 아래부터는 좀만 더 깊게 보겠습니다.
위에서 본 Send와 Recv함수에서 패킷은 NetBufferList의 형태로 관리가 됩니다. NETBufferList는 NetBuffer의 묶음이고 NetBuffer는 하나 이상의 MemoryDescriptorList로 구성되어 있습니다. 여기서 NetBuffer하나가 패킷 하나를 의미합니다. MemoryDescriptorList, 즉 MDL은 이 패킷 데이터를 이루는 가상의 연속적인 데이터 버퍼입니다. NBL은 패킷의 묶음이 되겠죠.
예를 보겠습니다. 함수내부에서 NBL은 다음 NBL의 포인터를 가지고 있습니다. 그리고 위 이미지에서 NBL은 2개의 NB로 이루어져있고 이는 2개의 패킷데이터를 의미합니다. 또한 첫번째 NB는 2개의 MDL로 이루어져있습니다. MLD 1에서는 MAC과 IP를 구할 수 있고 MDL 2에서는 TCP+DATA 영역을 구할 수 있습니다. 이런 과정을 거쳐 패킷의 데이터를 가져옵니다.
하지만 MDL은 항상 유효한 값만 있는게 아닙니다. NDIS는 NB에서 유효한 데이터를 구하기위해 내부적으로 NB_Offset의 값을 늘리고 줄입니다. 결과적으로 NB_Offset의 값이 Offset의 값보다 클 경우 이 값을 맞춰주기 위해 유효하지 않은 MDL을 추가합니다. 그렇기 때문에 항상 유효한 MDL로부터 데이터를 구하도록 해주어야 합니다. 그렇지 않으면 쉽게 블루스크린을 볼 수 있습니다.
대략적으로 NDIS에서 패킷을 눈으로 보는데 까지는 위의 작업을 거치면 됩니다. 처음 NDIS 하겠다고 드라이버 디버깅 환경 구축부터, 샘플 드라이버는 설치했는데 패킷은 어디서 볼 수 있는지... 많이 해맸는데 처음 하시는 분들께 조금이나마 도움이 되었으면 좋겠습니다.
'Security ★ Development > Windows Driver' 카테고리의 다른 글
드라이버 개발 시작 (0) | 2015.11.01 |
---|---|
WFP Driver programming (0) | 2015.03.19 |
윈도우 커널 드라이버 개발 디버깅 환경 구축 (0) | 2014.12.26 |