본문 바로가기

reversing/Windows Driver

I/O Control Codes [IOCTL] 정리

SMALL

IOCTL 관련 번역

I/O control code는 유저모드와 드라이버간에 통신을 위해서 사용되었고 같은 스택의 드라이버간에 통신을 위해서 사용되었다. 

I/O control code는 IRP를 이용해서 전달되어진다.

유저 모드의 어플리케이션은 DeviceControl 함수를 호출함으로써 드라이버에 IOCTL을 전달한다고 MS SDK 문서에 설명되어있다.

DeviceControl 함수를 호출 하는것은 I/O Manager가 IRP_MJ_DEVICE_CONTROL을 생성을 발생시키고 최상위에 있는 드라이버에게 전달한다.

추가적으로, 상대적으로 상위에 있는 드라이버는 하위에 있는 드라이버에게 IRP_MJ_DEVICE_CONTROL와 

IRP_MJ_INTERNAL_DEVICE_CONTROL의 IOCTL을 전송할 수 있다. 

드라이버는 이러한 요청[드라이버간의 IOCTL 요청]은 DispatchDeviceControlDispatchInternalDeviceControl루틴을 이용해서

처리한다. (유저모드 어플리케이션일 경우 IRP_MJ_INTERNAL_DEVICE_CONTROL은 불가능)

몇몇 IOCTL은 "public"하고 몇몇은 "private"하다.

[다른 I/O스택 시스템에서 접근 가능 여부]

Public IOCTL들은 시스템에서 정의되어 있는 특정한 녀석들이다. MS, WDK, SDK에 문서화되어 있다. 

Public IOCTL들은 유저모드 구성요소의 경우 DeviceIoControl 호출을 이용해서 전달되어지거나 커널 모드의 드라이버간의 통신은 IRP_MJ_DEVICE_CONTROL,

IRP_MJ_INTERNAL_DEVICE_CONTROL의 사용함으로써 이루어진다.한편, Private IOCTL는 밴더사들의 소프트웨어 구성요소들이 서로 통신하기 위해서 

배타적으로 사용되어지는 것을 의미한다.

[각자의(고유한) 소프트웨어끼리 통신하기 위해서 각자의 프로토콜을 맞추는 개념]

Private IOCTL은 특별하기 벤더사에서 제공하는 헤더파일에 정의도어 있고 공식적으로 문서화되어 있지는 않다.

위의 Public IOCTL과 마찬가지로 통신하는 방식은 동일하다.

Public이나 Private 사이의 코딩에서는 차이가 없다. 하지만 내부적으로 사용할 때는 차이가 존재한다. 만약에 내가 원하는용도로 정의되어있는 IOCTL이 불편?

별로면 새로 정의해서 사용하면 된다. 기존의 벤더사들이 하는 방식처럼.


새로운 IOCTL을 정의할 때, 지켜야할 중요한 규칙에 대해서 설명한다.

새로운 IOCTL은 유저모드 소프트웨어에서 사용한다면, 해당 IOCTL은 IRP_MJ_DEVICE_CONTROL 요청을 사용해야만한다. 

[위의 말은 유저모드와의 통신을 할 때, 반드시 IRP_MJ_DEVICE_CONTROL에서 처리해야한다]

유저모드의 구성요소들은 IRP_MJ_DEVICE_CONTROL 요청을 32bit DeviceIoControl 호출해서 발생시킬것이다.

만약에 새로운 IOCTL이  커널 모드 드라이버간의 통신에 사용된다면, 해당 IOCTL의 경우 IRP_MJ_INTERNAL_DEVICE_CONTROL 요청을 반드시 사용해야한다.

[위의 말은 커널 드라이버간의  통신을 할 때, 반드시 IRP_MJ_INTERNAL_DEVICE_CONTROL에서 처리해야한다]

커널모드의 구성요소는 IoBuildDeviceIoControlRequest 함수를 이용해서 IRP_MJ_INTERNAL_DEVICE_CONTROL 를 생성할수있다. 


[그림1]


I/O Control Code의 경우 여러 필드로 구성된 32bit 값이다. 위의 [그림1]은 I/O Control Code의 레이아웃을 보여준다.

시스템에서 제공해주는 매크로인 CTL_CODE를 사용하면 된다. 해당 매크로는 Wdm, ntddk 에 정의되어 있고 새로운 I/O control code를 정의한다.

아래 코드의 포맷 형식으로 IRP_MJ_DEVICE_CONTROLIRP_MJ_INTERNAL_DEVICE_CONTROL에서 사용할 새로운 I/O control code를 만든다.


1
#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)
cs


IOCTL_Device_Function 파트는 해당 IOCTL의 이름을 나타낸다.

Device 파트는 장치의 유형을 나타낸다.

Function어떠한 동작[처리]을 하는지 나타낸다.

IOCTL 중에서 IOCTL_VIDEO_ENABLE_CURSOR 를 예를들어서 설명한다.

Supply the following parameters to the CTL_CODE macro

아래에서 설명하는 부분은 CTL_CODE 매크로의 파라미터를 설명한다.


DeviceType

해당 인자는 디바이스 타입을 식별하기 위해서 사용된다.

해당 값은 반드시 드라이버가 생성한 DEVICE_OBJECT의 Device_Type 맴버 값으로 설정해야한다.

0x8000 까지의 값은 MS에서 예약된 값이고 그 이상을 사용하면 된다.


FunctionCode

드라이버에서 수행되어야 할 함수를 식별하는데 사용된다. 

해당 값은 0x800까지는 예약된 값이고 그 이상을 사용하면 된다.


TransferType

DeviceIoControl과 같음 함수를 이용해서 어떠한 방식으로 데이터를 전송할 것인지 식별하는데 사용한다.

그러면 드라이버는 식별된 방법을 통해서 IRP 가 처리된다.

아래에는 다음과 같은 옵션이 있다.


METHOD_BUFFERED

buffered I/O 방식을 지정하는 인자이다. 가장 많이 사용된다.


METHOD_IN_DIRECT or METHOD_OUT_DIRECT

direct I/O 방식을 지정하는 인자이다. 대량의 데이터를 직접적으로 물리 메모리와 같이 연결할때 사용된다.

위의 두 옵션 중 METHOD_IN_DIRECT 과 METHOD_OUT_DIRECT 의 차이는 전자는 driver로 전달이고 후자는 전달 하는 옵션이다.

METHOD_NEITHER

neither buffered nor direct I/O 방식을 지정하는 인자이다.

IRP에서 유저모드의 주소를 통해서 입력과 출력 버퍼를 사용한다. 이때 주소간의 맵핑이나 MDL등 사용하지 않는다.

ps. netstate와 같은 소켓 통신?에서 사용


RequiredAccess

요구되는 접근 방식을 지정한다.

호출자가 요청하는 접근 권한을 명확하게 명시하여야 한다. 파일 오브젝트를 열때는 IRP

I/O Manager는 호출자가 요청하는 정확한 권한을 이용해서 IRP를 생성하고 driver를 호출할것이다.

해당 접근 권한은 아래에 정의되어 있는 것을 사용한다.


FILE_ANY_ACCESS

모든 접근권한을 가지고 있다.

I / O 관리자는 대상 장치 개체를 나타내는 파일 개체에 대한 핸들이있는 모든 호출자에 대해 IRP를 보냅니다.

[좀 더 찾아보기..]


FILE_READ_DATA

읽기 접근권한을 가지고 있다.

I / O 관리자는 읽기 액세스 권한이있는 호출자에 대해서만 IRP를 전송하므로 기본 장치 드라이버가 장치에서 시스템 메모리로 데이터를 전송


FILE_WRITE_DATA

쓰기 접근권한을 가지고 있다.

I / O 관리자는 쓰기 권한이있는 호출자에 대해서만 IRP를 전송하므로 기본 장치 드라이버가 시스템 메모리에서 해당 장치로 데이터를 전송


FILE_READ_DATA 와 FILE_WRITE_DATA는 두 권한 모두 가져야 한다면 비트 연산 | 을 통해서도 가능하다.


Other useful macros

IOCTL로 부터 DeviceType을 추출하거나, TransferType을 추출하는데 사용하는 메크로임

1
2
3
#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode)   (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#define METHOD_FROM_CTL_CODE(ctrlCode)        ((ULONG)(ctrlCode & 3))
 
cs


[참고] https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/defining-i-o-control-codes

[참고] https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-i-o-control-codes


LIST

'reversing > Windows Driver' 카테고리의 다른 글

Buffered I/O  (0) 2017.08.17
MDL(Memory Descriptor List)[1]  (1) 2017.08.08
WinDBG 명령어 [CallStack]  (0) 2017.08.08
IRP, I/O Stack 관련 내용 정리 [3]  (0) 2017.08.04
IRP, I/O Stack 관련 내용 정리 [2]  (0) 2017.08.04