Windows 구동 기술 개발 상세 설명드라이버 의 기본 구조

드라이버 의 중요 한 데이터 구조
구동 대상: DRIVEROBJECT
모든 드라이버 는 유일한 드라이버 대상 과 대응 합 니 다. 이 드라이버 대상 은 드라이버 가 불 러 올 때 커 널 의 대상 관리 프로그램 에 의 해 만들어 집 니 다.
DRIVER_OBJECT 데이터 구조:
typedef struct _DRIVER_OBJECT {
    CSHORT Type;
    CSHORT Size;	
    PDEVICE_OBJECT DeviceObject;
    ULONG Flags;
    PVOID DriverStart;
    ULONG DriverSize;
    PVOID DriverSection;
    PDRIVER_EXTENSION DriverExtension;
    UNICODE_STRING DriverName;
    PUNICODE_STRING HardwareDatabase;
    PFAST_IO_DISPATCH FastIoDispatch;
    PDRIVER_INITIALIZE DriverInit;
    PDRIVER_STARTIO DriverStartIo;
    PDRIVER_UNLOAD DriverUnload;
    PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
	
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;

그 중에서 비교적 중요 한 필드:
DeviceObject (장치 대상): 모든 드라이버 에 하나 이상 의 장치 대상 이 있 습 니 다. 모든 장치 대상 은 링크 형식 으로 연결 되 어 있 습 니 다. 구동 대상 의 장치 대상 필드 는 모든 장치 대상 의 첫 번 째 대상 을 말 합 니 다. 이 를 통 해 모든 설치 대상 을 옮 겨 다 닐 수 있 습 니 다.
드라이버 Name (드라이버 이름): 이 드라이버 의 이름 은 유 니 코드 로 이 문자열 을 인 코딩 하 는 일반적인 형식 으로\드라이버\[드라이버 이름] 입 니 다.
DriverUnload (드라이버 마 운 트 해제): 이 드라이버 의 마 운 트 해제 함수 주 소 를 가 리 킵 니 다.
MajorFunction (파견 함수 포인터 배열): 이 배열 의 모든 포인터 구성원 은 응답 하 는 처리 IRP 의 파견 함 수 를 가리킨다.
장치 대상: DEVICEOBJECT
모든 드라이버 에는 하나 이상 의 장치 대상 이 있 습 니 다. 모든 장치 대상 은 링크 형식 으로 연결 되 어 있 습 니 다. 구동 대상 의 장치 대상 필드 는 모든 장치 대상 의 첫 번 째 대상 을 말 합 니 다. 이 를 통 해 모든 장치 대상 을 옮 겨 다 닐 수 있 습 니 다.
DEVICE_OBJECT 의 데이터 구조:
typedef struct _DEVICE_OBJECT {
    CSHORT Type;
    USHORT Size;
    LONG ReferenceCount;
    struct _DRIVER_OBJECT *DriverObject;
    struct _DEVICE_OBJECT *NextDevice;
    struct _DEVICE_OBJECT *AttachedDevice;
    struct _IRP *CurrentIrp;
    PIO_TIMER Timer;
    ULONG Flags;                                // See above:  DO_...
    ULONG Characteristics;                      // See ntioapi:  FILE_...
    PVPB Vpb;
    PVOID DeviceExtension;
    DEVICE_TYPE DeviceType;
    CCHAR StackSize;
    union {
        LIST_ENTRY ListEntry;
        WAIT_CONTEXT_BLOCK Wcb;
    } Queue;
    ULONG AlignmentRequirement;
    KDEVICE_QUEUE DeviceQueue;
    KDPC Dpc;
	
    ULONG ActiveThreadCount;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    KEVENT DeviceLock;
	
    USHORT SectorSize;
    USHORT Spare1;
	
    struct _DEVOBJ_EXTENSION  *DeviceObjectExtension;
    PVOID  Reserved;
} DEVICE_OBJECT;
typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT; 

그 중에서 비교적 중요 한 필드:
DriverObject (구동 대상): 이 장치 가 어느 구동 대상 에 속 하 는 지 알려 줍 니 다.
NextDevice (다음 장치 대상): 다음 장치 대상 을 가리 키 며 이 필드 를 통 해 전체 장치 대상 체인 을 옮 겨 다 닐 수 있 습 니 다.
AttachedDevice: 다음 장치 대상 을 가리 킵 니 다.이 드라이브 에 더 높 은 구동 대상 이 추 가 될 때 AttachDevice 가 가리 키 는 것 은 더 높 은 구동 이다.
DeviceExtension (장치 확장 대상): 장치 의 확장 대상 을 가리 키 며 모든 장치 가 하나의 장치 확장 대상 을 지정 합 니 다. 장치 확장 대상 이 기록 한 자신 이 정의 한 구조 체 이자 이 장치 자체 의 특수 구조 체 입 니 다.
NT 식 구동 의 기본 구조
구동 입구 함수 (DriverEntry)
일반 과 마찬가지 로 드라이버 에 도 자신의 입구 함수 가 있 고 일반 프로그램의 main () 함수 와 마찬가지 로 드라이버 의 입구 함수 이름 은 DriverEntry () 입 니 다.
함수 원형:
extern "C" NTSTATUS DriverEntry (
			IN PDRIVER_OBJECT pDriverObject,
			IN PUNICODE_STRING pRegistryPath	) 

extern "C"를 주의 하 십시오. C++ 드라이버 를 쓸 때 C++ 는 함수 의 재 부팅 을 지원 하기 때문에 컴 파일 러 가 컴 파일 한 함수 이름과 C 언어 로 컴 파일 된 함수 이름 이 다 를 수 있 습 니 다. 따라서 여기 서 extern "C"키 워드 를 사용 하여 C++ 컴 파일 된 함수 이름 이 C 언어 와 일치 하도록 합 니 다. 그렇지 않 으 면 연결 오류 가 발생 할 수 있 습 니 다.
DriverEntry () 함 수 는 주로 드라이버 의 초기 화 작업 을 담당 하 며 시스템 프로 세 스 에서 호출 됩 니 다.
함수 가 상 태 량 NTSTATUS 를 되 돌려 줍 니 다. NTSTATUS 는 32 비트 부호 없 는 긴 성형 으로 정의 되 었 는데 그 중에서 서로 다른 데 이 터 는 서로 다른 반환 상 태 를 대표 합 니 다.
pDriverObject 매개 변 수 는 시스템 대상 관리자 가 자동 으로 만 든 구동 대상 을 가리킨다.
PUNICODE_STRING 매개 변수 가 장치 서 비 스 를 가리 키 는 키 문자열
드라이버 작성 에서 함수 의 매개 변 수 는 'IN', 'OUT' 또는 'INOUT' 수정자 가 있 습 니 다. 그들 은 매크로 에 의 해 빈 문자열 로 정의 되 고 실제 적 인 의미 가 없 으 며 주석 과 유사 한 역할 을 합 니 다. IN 은 입력 매개 변 수 를 대표 합 니 다. 등급 사용 자 는 이 지침 자 체 를 바 꿀 수 없습니다. OUT 는 출력 매개 변 수 를 대표 합 니 다.
DriverEntry 의 구체 적 인 실현 을 살 펴 보 겠 습 니 다.
#pragma INITCODE
extern "C" NTSTATUS DriverEntry (
			IN PDRIVER_OBJECT pDriverObject,
			IN PUNICODE_STRING pRegistryPath	) 
{
	NTSTATUS status;
	KdPrint(("Enter DriverEntry
")); // pDriverObject->DriverUnload = HelloDDKUnload; pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine; // status = CreateDevice(pDriverObject); KdPrint(("DriverEntry end
")); return status; }

장치 개체 만 들 기
NT 식 구동 에서 장치 대상 을 만 드 는 것 은 IOCreate Device 커 널 함수 가 완 성 된 것 입 니 다.
함수 원형:
NTSTATUS IoCreateDevice( IN PDRIVER_OBJECT DriverObject,
						IN ULONG DeviceExtensionSize, 
						IN PUNICODE_STRING DeviceName OPTIONAL, 
						IN DEVICE_TYPE DeviceType, 
						IN ULONG DeviceCharacteristics,
						IN BOOLEAN Exclusive, 
						OUT PDEVICE_OBJECT *DeviceObject )

DriverObject: 매개 변 수 를 입력 하 십시오. 이 드라이버 에 대응 하 는 유일한 드라이버 대상 입 니 다.
DeviceExtensionSize: 인 자 를 입력 하고 장치 확장의 크기 를 지정 합 니 다.
DeviceName: 인자, 장치 대상 의 이름 을 입력 하 십시오.
DeviceCharacteristics: 입력 매개 변수, 장치 대상 의 특징.예 를 들 어 가상 장 치 를 만 들 려 면 파 라 메 터 는 FILE 일 수 있 습 니 다.DEVICE_UNKNOWN.
Exclusive: 파 라 메 터 를 입력 하고 커 널 대상 이 커 널 모드 에서 사용 할 지 여 부 를 설정 합 니 다. 일반적으로 TRUE 로 설정 합 니 다.
DeviceObject: 출력 매개 변수, I/O 관리 자 는 이 장치 대상 을 만 드 는 것 을 책임 집 니 다.
반환 값: 이 함수 의 줄 사용 상태 입 니 다.
장치 대상 을 만 드 는 방법 을 보 려 면 CreateDevice 함 수 를 쓸 수 있 습 니 다.
#pragma INITCODE
NTSTATUS CreateDevice (
		IN PDRIVER_OBJECT	pDriverObject) 
{
	NTSTATUS status;
	PDEVICE_OBJECT pDevObj;
	PDEVICE_EXTENSION pDevExt;
	
	//      
	UNICODE_STRING devName;
	RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
	
	//    
	status = IoCreateDevice( pDriverObject,
						sizeof(DEVICE_EXTENSION),
						&(UNICODE_STRING)devName,
						FILE_DEVICE_UNKNOWN,
						0, TRUE,
						&pDevObj );
	if (!NT_SUCCESS(status))
		return status;

	pDevObj->Flags |= DO_BUFFERED_IO;
	pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
	pDevExt->pDevice = pDevObj;
	pDevExt->ustrDeviceName = devName;
	//      
	UNICODE_STRING symLinkName;
	RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
	pDevExt->ustrSymLinkName = symLinkName;
	status = IoCreateSymbolicLink( &symLinkName,&devName );
	if (!NT_SUCCESS(status)) 
	{
		IoDeleteDevice( pDevObj );
		return status;
	}
	
	return STATUS_SUCCESS;
}

그 중에서 일부 코드 는 심 볼 릭 링크 를 만 드 는 코드 입 니 다. 심 볼 릭 링크 란 이 장치 의 '별명' 입 니 다. 한 장치 의 장치 이름 은 커 널 모드 에서 다른 드라이버 에 의 해 만 인식 되 기 때문에 사용자 모드 에서 프로그램 이 이 장 치 를 식별 하려 면 두 가지 방법 이 있 습 니 다. 그 중 하 나 는 심 볼 릭 링크 를 통 해 이 장치 에 별명 을 지어 주 는 것 입 니 다.
DriverUnload 루틴
드라이버 가 끝 날 때 DriverEntry 에서 만 든 장치 대상 을 삭제 하 는 함수 가 필요 합 니 다. 함수 하 나 를 써 서 이 기능 을 완성 합 니 다.
#pragma PAGEDCODE
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) 
{
	PDEVICE_OBJECT	pNextObj;
	KdPrint(("Enter DriverUnload
")); pNextObj = pDriverObject->DeviceObject; while (pNextObj != NULL) { PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pNextObj->DeviceExtension; // UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName; IoDeleteSymbolicLink(&pLinkName); pNextObj = pNextObj->NextDevice; IoDeleteDevice( pDevExt->pDevice ); } }

이 코드 에서 우 리 는 장치 대상 의 NextDevic e 도 메 인 을 통 해 전체 장치 체인 을 옮 겨 다 니 며 모두 삭제 합 니 다.
WDM 구동 의 기본 구조
WDM 구동 에 있어 일반적으로 층 을 나 누 는 것 을 바탕 으로 한다. 즉, 하나의 설비 의 조작 을 완성 하려 면 적어도 두 개의 설비 가 공동으로 완성 해 야 한 다 는 것 이다.하 나 는 물리 장치 대상 PDO 이 고, 다른 하 나 는 기능 장치 대상 FDO 다.그 관 계 는 '부가' 와 '부가' 의 관계 이다.
PC 가 어떤 장 치 를 삽입 할 때 PDO 는 자동 으로 생 성 됩 니 다. 정확히 말 하면 버스 구동 으로 생 성 됩 니 다.그러나 PDO 는 장 비 를 따로 조작 할 수 없고, FDO 와 함께 사용 해 야 한다.
WDM 구동 의 입구 함수
NT 드라이브 와 마찬가지 로 WDM 드라이브 의 입구 함수 도 DriverEntry 이지 만 장 치 를 만 드 는 책임 은 DriverEntry 가 아니 라 AddDevide 루틴 에 있 습 니 다.또한 WDM 의 DriverEntry 에 IRP 를 설정 해 야 합 니 다.MJ_PNP 처리 파견 함수
WDM 의 DriverEntry 함 수 를 보 겠 습 니 다.
#pragma INITCODE 
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
								IN PUNICODE_STRING pRegistryPath)
{
	KdPrint(("Enter DriverEntry
")); pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice; pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = pDriverObject->MajorFunction[IRP_MJ_CREATE] = pDriverObject->MajorFunction[IRP_MJ_READ] = pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine; pDriverObject->DriverUnload = HelloWDMUnload; KdPrint(("Leave DriverEntry
")); return STATUS_SUCCESS; }

이 코드 가 NT 구동 과 다른 점 은:
1. AddDevice 루틴 을 추 가 했 습 니 다. WDM 드라이브 가 불 러 오 면 PDO 는 운영 체제 가 자동 으로 생 성 되 고 FDO 는 AddDice 루틴 으로 생 성 되 며 PDO 에 추 가 됩 니 다.
2. IRP 에 가입MJ_PNP 의 파견 반환 함수, RIPMJ_PNP 는 주로 컴퓨터 에 꽂 으 면 바로 사용 하 는 처 리 를 책임 진다.
WDM 의 AddDevice 루틴
AddDevice 루틴 은 WDM 드라이브 에 만 있 는 것 입 니 다.AddDevice 루틴 의 함수 주 소 는 구동 대상 의 확장 대상 에 있 는 AddDevice 필드 입 니 다.
pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;

구체 적 인 AddDevice 루틴 을 살 펴 보 겠 습 니 다.
#pragma PAGEDCODE
NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
                           IN PDEVICE_OBJECT PhysicalDeviceObject)
{ 
	PAGED_CODE();
	KdPrint(("Enter HelloWDMAddDevice
")); NTSTATUS status; PDEVICE_OBJECT fdo; UNICODE_STRING devName; RtlInitUnicodeString(&devName,L"\\Device\\MyWDMDevice"); status = IoCreateDevice( DriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); if( !NT_SUCCESS(status)) return status; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension; pdx->fdo = fdo; pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject); UNICODE_STRING symLinkName; RtlInitUnicodeString(&symLinkName,L"\\DosDevices\\HelloWDM"); pdx->ustrDeviceName = devName; pdx->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName); if( !NT_SUCCESS(status)) { IoDeleteSymbolicLink(&pdx->ustrSymLinkName); status = IoCreateSymbolicLink(&symLinkName,&devName); if( !NT_SUCCESS(status)) { return status; } } fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; fdo->Flags &= ~DO_DEVICE_INITIALIZING; KdPrint(("Leave HelloWDMAddDevice
")); return STATUS_SUCCESS; }

AddDevice 루틴 함 수 는 두 개의 입력 매개 변수 가 있 습 니 다. 하 나 는 PDO 이 고 하 나 는 FDO 입 니 다.
AddDevice 루틴 함 수 는 IOCreateDevice 함 수 를 통 해 FDO 를 만 듭 니 다.
그리고 IoAttach DeviceToDeviceStack 을 통 해 FDO 를 PDO 에 추가 합 니 다.
다음은 장치 대상 을 만 드 는 심 볼 릭 링크 입 니 다.
DriverUnload 루틴
NT 드라이브 에서 DriverUnload 루틴 은 주로 장치 와 심 볼 릭 링크 를 삭제 하 는 것 을 책임 집 니 다.WDM 드라이브 에서 이 부분 은 IRP 에 의 해 작 동 됩 니 다.MN_REMOVE_DEVICE IRP 의 처리 함 수 는 책임 지고 DriverUnlaod 루틴 은 메모리 회수 작업 만 맡 습 니 다.

좋은 웹페이지 즐겨찾기