응용 프로그램 과 드라이버 통신 DeviceIoControl

IO 제어 코드 정의 
사실 일종 의 통신 협의 로 볼 수 있다
CTL 봐 봐.CODE 원형:

#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
  ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
  )
이 매크로 네 개의 매개 변 수 는 자 연 스 럽 게 32 비트 가 4 부분 으로 나 뉘 어 있 고 높이 16 비트 저장 장치 유형,14~15 비트 접근 권한,2~13 비트 조작 기능,마지막 0,1 두 비트 는 버퍼 가 어떻게 I/O 와 파일 시스템 데이터 버퍼 와 데이터 전달 방식 을 하 는 지 확인 하 는 것 입 니 다.가장 흔히 볼 수 있 는 것 은 METHOD 입 니 다.BUFFERED。
사용자 정의 CTLCODE:
#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)
IOCTL_Device_Function:생 성 된 IRP 의 MinorFunction
DeviceType:장치 대상 의 유형 입 니 다.장치 종류 참고:http://blog.csdn.net/liyun123gx/article/details/38058965
Function:사용자 정의 IO 제어 코드 입 니 다.자신 이 정의 할 때 0x 800 에서 0xFFF 를 가 져 옵 니 다.왜냐하면 0x0 에서 0x7FF 는 마이크로소프트 가 보류 하기 때 문 입 니 다.
Method:데이터 조작 모드.
METHOD_BUFFERED:버퍼 모드
METHOD_IN_DIRECT:직접 쓰기 모드
METHOD_OUT_DIRECT:직접 읽 기 모드
METHOD_NEITHER:Neither 모드
Access:접근 권한,가 치 는 다음 과 같 습 니 다.
FILE_ANY_ACCESS:사용자 가 모든 권한 을 가지 고 있 음 을 나타 낸다.
FILE_READ_DATA:읽 기 전용 권한 표시
FILE_WRITE_DATA:쓰기 권한 표시
할 수 있어 FILEWRITE_DATA | FILE_READ_DATA:읽 기 및 쓰기 권한 을 표시 하지만 FILE 에 미 치지 못 했 습 니 다.ANY_ACCESS 권한.
이 버퍼 의 데이터 전달 방식 방법 을 계속 소개 합 니 다.
Method 는 Ring 3/Ring 0 의 통신 중의 메모리 접근 방식 을 나타 내 는데 네 가지 방식 이 있다.
#defineMETHOD_BUFFERED0
#defineMETHOD_IN_DIRECT1
#defineMETHOD_OUT_DIRECT2
#defineMETHOD_NEITHER3
(1)METHOD 를 사용 하면BUFFERED 는 시스템 이 사용자 의 입 출력 을 pIrp->Associated Irp.SystemBuffer 를 통 해 버퍼 링 하기 때문에 이런 방식 의 통신 이 비교적 안전 하 다 는 것 을 나타 낸다.
METHOD_BUFFERED 방식 은 Ring 3 의 입 출력 을 모두 버퍼 링 한 셈 이다.
METHOD_BUFFERED 방식:

(2)METHOD 를 사용 하면IN_DIRECT 또는 METHODOUT_DIRECT 방식 은 시스템 이 입력 버퍼 를 pIrp->Associated Irp.SystemBuffer 에 고정 시 키 고 출력 버퍼 를 잠 근 다음 커 널 모드 에서 주 소 를 다시 표시 하 는 것 도 안전 하 다 는 것 을 나타 낸다.
METHOD_IN_DIRECT 와 METHODOUT_DIRECT 는'직접 방식'이 라 고 할 수 있 으 며,시스템 이 여전히 Ring 3 의 입력 버퍼 를 버퍼 링 하지만 Ring 3 의 출력 버퍼 는 버퍼 링 없 이 커 널 에 잠 겨 있 는 것 을 말한다.이렇게 Ring 3 출력 버퍼 는 드라이버 가 I/O 요청 을 완료 하기 전에 접근 할 수 없 으 며 어느 정도 안전성 을 보장 합 니 다.
Ring 3 에 대한 입력 버퍼 와 METHODBUFFERED 방식 은 일치 합 니 다.Ring 3 의 출력 버퍼 에 대해 서 는 먼저 시스템 에 의 해 잠 겨 있 고 pIrp->MdlAddress 를 사용 하여 이 메모 리 를 설명 합 니 다.드라이버 는 MmGetSystem Address ForMdlSafe 함 수 를 사용 하여 이 메모 리 를 커 널 메모리 주소(OutputBuffer)에 투사 한 다음 에 OutputBuffer 주 소 를 직접 기록 할 수 있 습 니 다.마지막 으로 구동 파견 루틴 을 되 돌려 준 후에 시스템 에서 이 메모리 의 잠 금 을 해제 할 수 있 습 니 다.
METHOD_IN_DIRECT 와 METHODOUT_DIRECT 방식 의 메모리 접근
METHOD_IN_DIRECT 와 METHODOUT_DIRECT 방식 의 차 이 는 장 치 를 열 수 있 는 권한 에 만 있 습 니 다.읽 기 전용 권한 으로 장 치 를 열 때 METHODIN_DIRECT 방식 의 IoControl 은 성공 하고 METHOD 는OUT_DIRECT 방식 은 실패 합 니 다.읽 기와 쓰기 권한 으로 장 치 를 열 면 두 가지 방식 이 성공 합 니 다.
METHOD_IN_DIRECT 와 METHODOUT_DIRECT 방식:

(3)METHOD 를 사용 하면NEITHER 방식,'기타 방식'은 통신 의 효율 성 이 높 아 졌 지만 안전 하지 않다.구동 하 는 파견 함수 에 버퍼 를 입력 하면 I/O 스 택(IOSTACK_LOCATION)의 stack->Parameters.deviceIo Control.Type3InputBuffer 를 받 았 습 니 다.출력 버퍼 는 pIrp->UserBuffer 를 통 해 얻 을 수 있 습 니 다.구동 중의 파견 함 수 는 전 달 된 사용자 의 입력 과 출력 주 소 를 보장 할 수 없 기 때문에 이 주 소 를 쓰 는 버퍼 를 직접 읽 지 않 는 것 이 좋다.읽 기와 쓰기 전에 Probe ForRead 와 Probe ForWrite 함 수 를 사용 하여 주 소 를 읽 을 수 있 고 쓸 수 있 는 지 확인 해 야 합 니 다.
METHOD_ NEITHER 방식 은 버퍼 링 을 하지 않 습 니 다.드라이버 에서 Ring 3 의 입 출력 메모리 주 소 를 직접 사용 할 수 있 습 니 다.
드라이버 는 pIrpStack->Parameters.deviceIoControl.Type3InputBuffer 를 통 해 Ring 3 의 입력 버퍼 주 소 를 얻 을 수 있 습 니 다(그 중에서 pIrpStack 은 IoGetCurrent IrpStack Location(pIrp)의 반환 입 니 다).pIrp->UserBuffer 를 통 해 Ring 3 의 출력 버퍼 주 소 를 얻 을 수 있 습 니 다.
METHOD 때문에NEITHER 방식 은 안전 하지 않 으 므 로 Type3InputBuffer 가 읽 기 전에 Probe ForRead 함 수 를 사용 하여 탐지 하고 UserBuffer 가 쓰기 전에 Probe ForWrite 함 수 를 사용 하여 탐지 한 다음 이상 이 발생 하지 않 았 을 때 읽 기 및 쓰기 작업 을 하 는 것 이 좋 습 니 다.
METHOD_NEITHER 방식:

2.드라이버 이름,심 볼 릭 링크 이름 정의
IO 제어 코드 CTL 정의 되 었 습 니 다.CODE,두 번 째 드라이버 는 드라이버 이름과 심 볼 릭 링크 이름 도 준비 해 야 합 니 다.
Ring 0 층 에서 드라이버 이름 을 설정 하 는 동시에 기호 링크 이름 을 설정 해 야 하 는 이 유 는 기호 링크 이름 만 사용자 모드 에서 응용 프로그램 에 의 해 인식 되 기 때문이다.
windows 의 장 치 는'\Device\[장치 이름]'형식 으로 명명 되 었 다.
예 를 들 어 디스크 파 티 션 의 c 디스크,d 디스크 의 장치 이름 은'\Device\HarddiskVolume 1','\Device\HarddiskVolume 2'입 니 다.물론 장치 이름 을 지정 하지 않 아 도 됩 니 다.
IoCreateDevice 에 장치 이름 이 지정 되 어 있 지 않 으 면 I/O 관리 자 는 자동 으로 장치 이름 으로 숫자 를 할당 합 니 다.
예 를 들 어"\\Device\0000001".\Device\\[장치 이름]은 기억 하기 쉽 지 않 습 니 다.보통 심 볼 릭 링크 는 장치 의 별명 으로 이해 할 수 있 습 니 다.더 중요 한 것 은 장치 이름 입 니 다.커 널 모드 의 다른 드라이버 에 의 해 만 인식 되 고 별명 은 사용자 모드 에서 의 응용 프로그램 에 의 해 식별 될 수 있 습 니 다.예 를 들 어 c 디스크 는'c:'라 는 심 볼 릭 링크 입 니 다.그 진정한 장치 대상 은'\Device\HarddiskVolume 1'입 니 다.그래서 드라이버 를 쓸 때 보통 우 리 는 심 볼 릭 링크 를 만 듭 니 다.드라이버 에 사용 되 지 않 더 라 도 이것 은 좋 은 습관 이 라 고 할 수 있 습 니 다.
구동 중 심 볼 릭 링크 이름 은 이렇게 쓰 여 있 습 니 다.
L"\\??\\HelloDDK" --->\??\HelloDDK
혹은
L"\\DosDevices\\HelloDDK"--->\DosDevices\HelloDDK
응용 프로그램 에서 심 볼 릭 링크 이름:
L"\\\\.\\HelloDDK"-->\\.\HelloDDK
DosDevices 의 심 볼 릭 링크 이름 은??,그래서'\\DosDevice\\XXXX'는 바로\\??\\XXXX

#define DEVICE_OBJECT_NAME  L"\\Device\\BufferedIODeviceObjectName"
//         
#define DEVICE_LINK_NAME    L"\\DosDevices\\BufferedIODevcieLinkName"
//   Ring3    
3.기호 링크 이름과 장치 대상 이름 을 연결 하고 IO 제어 코드 를 기다린다.
드라이버 가 해 야 할 마지막 단 계 는 먼저 IoCreate Device 함수 로 장치 대상 을 만 든 다음 에 IoCreate SymbolicLink 로 기호 링크 이름 을 장치 대상 이름과 연결 시 켜 큰 성 과 를 거 두 었 고 IO 제어 코드 를 기다 리 고 있 습 니 다.

 //        
RtlInitUnicodeString(&DeviceObjectName,DEVICE_OBJECT_NAME);
//      
Status = IoCreateDevice(DriverObject,NULL,
    &DeviceObjectName,
    FILE_DEVICE_UNKNOWN,
    0, FALSE,
    &DeviceObject);
if (!NT_SUCCESS(Status))
{
    return Status;
}
 
//        
RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME);
//              
Status = IoCreateSymbolicLink(&DeviceLinkName,&DeviceObjectName);
 
if (!NT_SUCCESS(Status))
{
    IoDeleteDevice(DeviceObject);
    return Status;
}       
4.응용 프로그램 이 장치 핸들 을 가 져 오고 IO 제어 코드 를 보 냅 니 다.
드라이버 패드 를 다 듬 은 후에 응용 프로그램 은 심 볼 릭 링크 이름 으로 Create File 함 수 를 통 해 장치 핸들 DeviceHandle 을 얻 고 이 필드 의 주인공 을 사용 할 수 있 습 니 다.DeviceIoControl 은 이 DeviceHandle 을 통 해 제어 코드 를 보 낼 수 있 습 니 다.
먼저 이 두 함 수 를 보 세 요.

BOOL WINAPI DeviceIoControl(
  _In_         HANDLE hDevice,       //CreateFile         
  _In_         DWORD dwIoControlCode,//       
  _In_opt_     LPVOID lpInBuffer,    //     
  _In_         DWORD nInBufferSize,  //        
  _Out_opt_    LPVOID lpOutBuffer,   //     
  _In_         DWORD nOutBufferSize, //        
  _Out_opt_    LPDWORD lpBytesReturned, //        ,       pIrp->IoStatus.Information。
  _Inout_opt_  LPOVERLAPPED lpOverlapped //        。    NULL,DeviceIoControl       ;  ,            
);
HANDLE CreateFile(
  LPCTSTR lpFileName,                         //      
  DWORD dwDesiredAccess,                    //    
  DWORD dwShareMode,                      //    
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,   //    
  DWORD dwCreationDisposition,               //                
  DWORD dwFlagsAndAttributes,                //      (  、  、  、        )
  HANDLE hTemplateFile                       //      
);
5.DeviceIoControl 의 통신 절 차 를 정리 합 니 다.
1.드라이버 와 응용 프로그램 이 IO 제어 코드 를 사용자 정의(CTLCODE 매크로 4 개의 매개 변수,32 비트,4 부분,저장 장치 유형,접근 권한,조작 기능,버퍼 데이터 전달 방식(4 가지)
2.드라이버 는 드라이버 이름,심 볼 릭 링크 이름 을 정의 하고 심 볼 릭 링크 이름 을 장치 대상 이름과 연결 시 켜 IO 제어 코드(IoCreateDevice,IoCreateSymbolicLink)를 기다린다.
3.응용 프로그램 은 심 볼 릭 링크 이름 으로 CreateFile 함 수 를 통 해 장치 핸들 DeviceHandle 을 가 져 오고 이 필드 의 주인공 을 사용 합 니 다.DeviceIoControl 은 이 장치 핸들 을 통 해 제어 코드 를 파견 함수 에 보 냅 니 다.
소스 코드
BufferedIO.h

#pragma once
#include <ntifs.h>

#define CTL_SYS \
    CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS)

#define DEVICE_OBJECT_NAME  L"\\Device\\BufferedIODeviceObjectName"
//         
#define DEVICE_LINK_NAME    L"\\DosDevices\\BufferedIODevcieLinkName"
//   Ring3    
VOID DriverUnload(PDRIVER_OBJECT DriverObject);
NTSTATUS PassThroughDispatch(PDEVICE_OBJECT  DeviceObject, PIRP Irp);
NTSTATUS ControlThroughDispatch(PDEVICE_OBJECT  DeviceObject, PIRP Irp);
BufferedIO.c

#include "BufferedIO.h"

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PDEVICE_OBJECT  DeviceObject = NULL;
    UNICODE_STRING  DeviceObjectName;
    UNICODE_STRING  DeviceLinkName;
    ULONG           i;
    //    
    //    
    //     (global Static Const)
    DriverObject->DriverUnload = DriverUnload;
 
    //        
    RtlInitUnicodeString(&DeviceObjectName,DEVICE_OBJECT_NAME);
 
    //      
    Status = IoCreateDevice(DriverObject,NULL,
        &DeviceObjectName,
        FILE_DEVICE_UNKNOWN,
        0, FALSE,
        &DeviceObject);
    if (!NT_SUCCESS(Status))
    {
        return Status;
    }
    //        
    RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME);
 
    //              
    Status = IoCreateSymbolicLink(&DeviceLinkName,&DeviceObjectName);
 
    if (!NT_SUCCESS(Status))
    {
        IoDeleteDevice(DeviceObject);
        return Status;
    }
    //             
    for (i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)
    {
        DriverObject->MajorFunction[i] = PassThroughDispatch;   //    
    }
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlThroughDispatch;
    return Status;
}
//    
NTSTATUS PassThroughDispatch(PDEVICE_OBJECT  DeviceObject,PIRP Irp)
{
    Irp->IoStatus.Status = STATUS_SUCCESS;     //LastError()
    Irp->IoStatus.Information = 0;             //ReturnLength
    IoCompleteRequest(Irp, IO_NO_INCREMENT);   // Irp   Io   
    return STATUS_SUCCESS;
}
NTSTATUS ControlThroughDispatch(PDEVICE_OBJECT  DeviceObject, PIRP Irp)
{
    NTSTATUS Status;
    ULONG_PTR Informaiton = 0;
    PVOID InputData = NULL;
    ULONG InputDataLength = 0;
    PVOID OutputData = NULL;
    ULONG OutputDataLength = 0;
    ULONG IoControlCode = 0;
    PIO_STACK_LOCATION  IoStackLocation = IoGetCurrentIrpStackLocation(Irp);  //Irp    
    IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode;
    InputData  = Irp->AssociatedIrp.SystemBuffer;
    OutputData = Irp->AssociatedIrp.SystemBuffer;
    InputDataLength  = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
    OutputDataLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
    switch (IoControlCode)
    {
    case CTL_SYS:
    {
        if (InputData != NULL&&InputDataLength > 0)
        {
            DbgPrint("%s\r
", InputData); } if (OutputData != NULL&&OutputDataLength >= strlen("Ring0->Ring3") + 1) { memcpy(OutputData, "Ring0->Ring3", strlen("Ring0->Ring3") + 1); Status = STATUS_SUCCESS; Informaiton = strlen("Ring0->Ring3") + 1; } else { Status = STATUS_INSUFFICIENT_RESOURCES; // Informaiton = 0; } break; } default: break; } Irp->IoStatus.Status = Status; //Ring3 GetLastError(); Irp->IoStatus.Information = Informaiton; IoCompleteRequest(Irp, IO_NO_INCREMENT); // Irp Io return Status; //Ring3 DeviceIoControl() } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { UNICODE_STRING DeviceLinkName; PDEVICE_OBJECT v1 = NULL; PDEVICE_OBJECT DeleteDeviceObject = NULL; RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME); IoDeleteSymbolicLink(&DeviceLinkName); DeleteDeviceObject = DriverObject->DeviceObject; while (DeleteDeviceObject != NULL) { v1 = DeleteDeviceObject->NextDevice; IoDeleteDevice(DeleteDeviceObject); DeleteDeviceObject = v1; } }
IO.cpp

//    IO.cpp :              。
//
 
#include "stdafx.h"
#include <windows.h>
#define DEVICE_LINK_NAME    L"\\\\.\\BufferedIODevcieLinkName"
 
#define CTL_SYS \
    CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS)
int main()
{
    HANDLE DeviceHandle = CreateFile(DEVICE_LINK_NAME,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    if (DeviceHandle==INVALID_HANDLE_VALUE)
    {
        return 0;
    }
    char BufferData = NULL;
    DWORD ReturnLength = 0;
    BOOL IsOk = DeviceIoControl(DeviceHandle, CTL_SYS,
        "Ring3->Ring0",
        strlen("Ring3->Ring0")+1,
        (LPVOID)BufferData,
        0,
        &ReturnLength,
        NULL);
    if (IsOk == FALSE)
    {
        int LastError = GetLastError();
 
        if (LastError == ERROR_NO_SYSTEM_RESOURCES)
        {
            char BufferData[MAX_PATH] = { 0 };
            IsOk = DeviceIoControl(DeviceHandle, CTL_SYS,
                "Ring3->Ring0",
                strlen("Ring3->Ring0") + 1,
                (LPVOID)BufferData,
                MAX_PATH,
                &ReturnLength,
                NULL);
 
            if (IsOk == TRUE)
            {
                printf("%s\r
", BufferData); } } } if (DeviceHandle != NULL) { CloseHandle(DeviceHandle); DeviceHandle = NULL; } printf("Input AnyKey To Exit\r
"); getchar(); return 0; }
이상 은 응용 프로그램 과 드라이버 통신 DeviceIoControl 의 상세 한 내용 입 니 다.응용 프로그램 드라이버 통신 DeviceIoControl 에 관 한 자 료 는 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기