훅의 원리는 의외로 간단한데 훅을 걸려고 하는 드라이버 포인터를 얻어와서 훅 드라이버에
연결시키기만 하면 됩니다.
일단 훅을 걸려고하는 드라이버 포인터를 얻어오겠습니다.
NTSTATUS ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG OPTIONAL,
IN ULONG AccessMode, IN ULONG OPTIONAL2, IN ULONG DesiredAccess OPTIONAL, IN OUT PVOID ParseContext OPTIONAL,
OUT PHANDLE Handle);
PDRIVER_OBJECT SearchDriverObject(PUNICODE_STRING pUni)
{
NTSTATUS st;
HANDLE Handle;
UNICODE_STRING Uni;
OBJECT_ATTRIBUTES ObjectAttributes;
PDRIVER_OBJECT Object;
InitializeObjectAttributes( &ObjectAttributes, pUni, OBJ_CASE_INSENSITIVE, NULL, NULL );
st = ObOpenObjectByName( &ObjectAttributes, 0L, 0L, 0L, 0L, 0L, &Handle );
if( st != STATUS_SUCCESS )
return (PDRIVER_OBJECT)0;
st = ObReferenceObjectByHandle( Handle, 0x80000000, NULL, 0, &Object, NULL );
if( st != STATUS_SUCCESS )
{
ZwClose( Handle );
return (PDRIVER_OBJECT)0;
}
ZwClose( Handle );
ObDereferenceObject( Object );
return Object;
}
위의 SearchDriverObject 함수는 '디바이스 구조와 원리'에서 발췌했습니다.
PDRIVER_OBJECT pDriver;
RtlInitUnicodeString(&Uni, L"\\Driver\\Serial");
pDriver = SearchDriverObject(&Uni);
이렇게 입력하면 시리얼 드라이버 포인터를 얻어오게 됩니다.
이제 원래 드라이버 포인터를 전역변수로 담아 놓습니다. 드라이버 포인터를 담아 놓는 이유는
후킹드라이버를 종료시켰을때를 위해서 입니다.
BackupReadHandler = pDriver->MajorFunction[IRP_MJ_READ];
BackupWriteHandler = pDriver->MajorFunction[IRP_MJ_WRITE];
그리고 새로운 함수포인터를 집어 넣습니다.
pDriver->MajorFunction[IRP_MJ_READ] = ReadHandler;
pDriver->MajorFunction[IRP_MJ_WRITE] = WriteHandler;
이 새로운 함수의 작성은 해당 드라이버의 DDK의 샘플을 참고로 작성하시면 됩니다. 물론 그대로 가져와 쓰셔도 됩니다.
PDRIVER_OBJECT pDriver;
PDEVICE_OBJECT BackupReadHandler;
PDEVICE_OBJECT BackupWriteHandler;
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
PDEVICE_OBJECT devobject = 0;
UNICODE_STRING devlink,devname;
DriverSearch();
DriverObject->MajorFunction[IRP_MJ_READ] = ReadHandler;
DriverObject->MajorFunction[IRP_MJ_CLOSE]=DrvClose;
DriverObject->DriverUnload = DrvUnload;
RtlInitUnicodeString(&devname,devicename);
RtlInitUnicodeString(&devlink,devicelink);
IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &devname, FILE_DEVICE_UNKNOWN, 0, FALSE, &devobject);
IoCreateSymbolicLink(&devlink,&devname);
return 0;
}
void DriverSearch()
{
RtlInitUnicodeString(&Uni, L"\\Driver\\Serial");
pDriver = SearchDriverObject(&Uni);
BackupReadHandler = pDriver->MajorFunction[IRP_MJ_READ];
BackupWriteHandler = pDriver->MajorFunction[IRP_MJ_WRITE];
}
void DrvUnload(IN PDRIVER_OBJECT driver)
{
UNICODE_STRING devlink;
RtlInitUnicodeString(&devlink,devicelink);
pDriver->MajorFunction[IRP_MJ_READ] = BackupReadHandler
pDriver->MajorFunction[IRP_MJ_WRITE] = BackupWriteHandler
IoDeleteSymbolicLink(&devlink);
IoDeleteDevice(driver->DeviceObject);
}
이렇게 3부로 나뉘어진 디바이스 드라이버 훅에 모든 설명이 끝났습니다.
좀 더 많은 부분을 설명하고 싶었는데 아쉽네요. 내공이 부족한 부분도 있고... 자료도 그렇고
특히 키보드나 마우스같은 입력장치 드라이버의 경우 IRP_MJ_WRITE 가 존재하지 않기때문에
버퍼에 직접 접근해서 값을 넣어줘야 합니다.
ntdd8042.h
IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER
사실 처음부터 그런것을 만들려고 했으면 필터드라이버 쪽이 더 편하지 않았나 싶네요.
WDM쪽은 너무 생소해서 해당분야에 종사하시는 분이 아니면 공부하는데도 한계가 있구요.
저도 시간 날때마다 조금씩 공부하는데 상당히 난해합니다....
이번 강좌를 통해서 WDM이 좀 더 쉽게 다가왔으면 하는 바램입니다.
참고 서적
EXPLOITING SOFTWARE : How to break code
MICROSOFT WINDOWS DRIVER MODEL
API로 배우는 Windows 구조와 원리
윈도우즈 드라이버 모델 WDM
디바이스 드라이버 구조와 원리 그리고 제작 노하우
출처 : 데브피아