한땀한땀 정성들인 코딩

윈도우 드라이버 개발하기 본문

개발/윈도우

윈도우 드라이버 개발하기

romance penguin 2019. 4. 9. 09:33
반응형

윈도우 서비스를 만들었으면 테스트 환경을 준비해 준다. 

- window XP sp3 x64 (VM 환경)

- window 7 이상부터는 드라이버 인증서가 필요하다.

 

1. wdk 커널 빌드 환경

wdk 7600 bin 폴더

  • cmd를 관리자 권한으로 실행한 뒤 bin폴더 아래에 있는 setenv.bat을 실행한다.
  • 드라이버 빌드환경에 맞게(i386, amd64) 옵션을 줘서 진행한다.
  • 소스가 존재하는 폴더에 들어가 build를 하면 된다.

 

 

2. 유저모드 (window console application)

win32 콘솔 응용프로그램 프로젝트

  • 미리 컴파일된 헤더로 프로젝트를 생성

2.1 서비스 생성(드라이버 로드용)

bool _util_load_sysfile(cahr *theDriverName)
{
	char aPath[1024];
	char aCurrentDirectory[515];
	SC_HANDLE sh = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if(!sh)
	{
		return false;
	}
	GetCurrentDirectory(512, aCurrentDirectory);
	_snprintf(aPath, 1022, "%s\\%s.sys", aCurrentDirectory, theDriverName);
	SC_HANDLE rh = CreateService(sh, theDriverName, theDriverName, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, aPath,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL);
	if(!rh){
		if(GetLastError() == ERROR_SERVICE_EXISTS){
			rh = OpenService(sh, theDriverName, SERVICE_ALL_ACCESS);
			if(!rh){
				CloseServiceHandle(sh);
				return false;
			}
			else{
				CloseServiceHandle(sh);
				return false;
			}
		}
		if(rh){
			if(0 == StartService(rh, 0, NULL)){
				if(ERROR_SERVICE_ALREDY_RUNNING == GetLastError()){
					
				}
				else{
					CloseServiceHandle(sh);
					CloseServiceHandle(rh);
					return false;
				}
			}
			CloseServiceHandle(sh);
			CloseServiceHandle(rh);
		}
		return true;
	}
}
  • OpenSCManager
  • CreateService or OpenService
  • StartService ...

2.2 드라이버 통신용으로 프로젝트 하나 더 생성

#include "stdafx.h"
#include "Windows.h"

int main()
{
	HANDLE hDevice;
	hDevice = CreateFile(L"\\\\.\\MyDevice",
		GENERIC_READ|GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);
	if (hDevice == ((HANDLE)-1)) {
		printf("handle fail \n");
		return -1;
	}
	printf("handle success : %d\n", hDevice);
	CloseHandle(hDevice);
	return 0;

 

 

3. 드라이버 코드 simple.sys

#include "ntddk.h"
#include "wdm.h"

const WCHAR deviceLinkBuffer[] = L"\\DosDevices\\MyDevice";
const WCHAR deviceNameBuffer[] = L"\\Device\\MyDevice";
PDEVICE_OBJECT g_RootkitDevice;

NTSTATUS OnStubDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
	Irp -> IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject ){
	UNICODE_STRING Name;
	DbgPrint("OnUnload called\n");
	
	RtlInitUnicodeString(&Name, deviceLinkBuffer);
	IoDeleteSymbolicLink(&Name);
	IoDeleteDevice(DriverObject->DeviceObject);
	DbgPrint("Unload complete!\n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT myDriver, IN PUNICODE_STRING theRegistryPath){
	NTSTATUS ntStatus;
	UNICODE_STRING deviceNameUnicodeString;
	UNICODE_STRING deviceLinkUnicodeString;
	int i;
	
	for(i=0; i<IRP_MJ_MAXIMUM_FUNCTION;i++){
		myDriver->MajorFunction[i] = OnStubDispatch;
	}
	myDriver->DriverUnload = OnUnload;
	
	RtlInitUnicodeString(&deviceNameUnicodeString, deviceNameBuffer);
	RtlInitUnicodeString(&deviceLinkUnicodeString, deviceLinkBuffer);
	
	ntStatus = IoCreateDevice(myDriver, 0, &deviceNameUnicodeString, FILE_DEVICE_UNKNOWN,0, TRUE, &g_RootkitDevice);
	
	if(NT_SUCCESS(ntStatus)){
		ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString, &deviceNameUnicodeString);
	}
	
	return STATUS_SUCCESS;
}

 

MAKEFILE

TARGETNAME=simple
TARGETPATH=.\sys
TARGETTYPE=DRIVER
SOURCES=device-test.c

 

SOURCES

!INCLUDE $(NTMAKEENV)\makefile.def

 

  • IRP 테이블에 myDriver->MajorFunction[i] = OnStubDispatch; 이런식으로 read, write, ioctl 함수를 대체.
  • 즉 winapi중 하나인 ReadFile을 호출하면 매핑해논 드라어버의 IRP가 호출된다.
  • BOOL ReadFile( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped );

 

check!

NTSTATUS OnStubDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
	Irp -> IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

유저 프로세스에서 ReadFile 호출 시 STATUS_SUCCESS 리턴하는지 확인

반응형