Programming/Kernel / Driver2008. 12. 3. 11:00
이번에는 실질적으로 드라이버에 훅을 걸어보겠습니다.
 
훅의 원리는 의외로 간단한데 훅을 걸려고 하는 드라이버 포인터를 얻어와서 훅 드라이버에
연결시키기만 하면 됩니다.
 
일단 훅을 걸려고하는 드라이버 포인터를 얻어오겠습니다.
 
 
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
디바이스 드라이버 구조와 원리 그리고 제작 노하우

출처 : 데브피아
Posted by skensita