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 루틴 은 메모리 회수 작업 만 맡 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.