관리 메뉴

kisoo

키보드 인터럽트 훅킹 방법 본문

01.About Programming /2.Kernel Lab

키보드 인터럽트 훅킹 방법

JamesK78 2009. 12. 8. 14:08
키보드 인터럽트 훅킹 ( http://www.driveronline.org/bbs/view.asp?tb=tipbbs&no=21 )

키보드 인터럽트를 훅킹하기 위한 2가지 방법을 제안하고자 합니다.

첫번째 - IDT를 단서로한 키보드 인터럽트 훅킹
두번째 - 키보드 디바이스 드라이버를 단서로한 인터럽트 훅킹

키보드 인터럽트 훅킹의 가장 중요한 핵심은 Interrupt Object(KINTERRUPT)를 찾는 일입니다.

Dumping IDT :
....
92: 828c39bc serial!SerialCIsrSw (KINTERRUPT 828c3980)
93: 82d2b254 i8042prt!I8042KeyboardInterruptService (KINTERRUPT 82d2b218)
94: 82b6fb44 NDIS!ndisMIsr (KINTERRUPT 82b6fb08)
a3: 82b0718c i8042prt!I8042MouseInterruptService (KINTERRUPT 82b07150)
...

저의 시스템에서 93번 벡터를 가지는 키보드 인터럽트는 0x82d2b218 에 인터럽트 객체가 있습니다.
그럼 두가지 방법을 자세히 알아보죠

첫번째 - IDT를 이용하기

드라이버온라인(여기) 자료실에 있는 IDT 훅킹 예제는 매우 좋은 지침이 될 겁니다.
IDT를 이용하기 위해선 우선 키보드 인터럽트의 벡터값을 알아내야 하는데,
시스템마다 다르기 때문에 정적으로 직접 코딩하여선 안됩니다.

I/O APIC가 키보드 인터럽트 벡터값을 가지고 있는데 인텔 IOAPIC 데이터시트를 참고
하시면 많은 도움이 될 겁니다.

벡터값에 시스템에 의존하는 약간의 수식을 첨가하면 IDT의 키보드 인터럽트 인덱스가 나오는데
만약 그 값이 93 이라고 가정하면
IDT[0x93] <- 키보드 인터럽트의 처리 함수 엔트리가 됩니다.
하지만 바로 IDT의 93번째값을 우리의 핸들러로 치환하는것은 너무 성급합니다.

디바이스 드라이버가 인터럽트를 등록할때에 Interrupt Object를 이용하시는것을 아시죠?
IDT를 바로 수정하게 되면 멀티태스킹을 유지하는 코드들마저 실행할 수 없게되어
시스템이 파울을 선언할 겁니다.

InterruptObject내부에 있는 ServiceRoutine을 우리의 핸들러로 치환해야 합니다.
그 이유를 알기 위해선 Windows의 인터럽트 디스패칭 알고리즘에 대해 알아야 합니다.

인터럽트가 발생하면 IOAPIC로 부터 정해진 벡터값을 이용해서 윈도우는 IDT테이블을 참조하고
IDT테이블에 적혀있는 함수를 실행합니다.

IDT테이블에 적혀있는 함수는 스택에 트랩프레임을 구성하고, IRQL을 조정하며, 시스템인터럽트를 Enable시키고, 내부 InterruptDispatch ( 또는 ChainedDispatch ) 라 불리우는 함수를 부르게 됩니다.

InterruptDispatch함수는 또한 약간의 작업 후에 그 내부에서 InterruptObject->ServiceRoutine을 호출합니다.

따라서 윈도우즈의 멀티태스킹 유지작업을 생각해준다면 InterruptObject->ServiceRoutine을 수정해야합니다.

IDT로 부터 InterruptObject를 구하기 위해선 IDT의 값에서 0x3c를 빼주면 되는데
0x3c는 KINTERRUPT 구조체의 사이즈에서 DispatchCode[] 값을 뺀 값입니다.

PKINTERRUPT InterruptObject = IDT[Vector] - 0x3c;   <- 인터럽트 객체를 얻었다!
InterruptObject->ServiceRoutine = NewHandler;          <- 인터럽트 훅킹 성공

두번째 - 키보드 디바이스 드라이버를 이용하기

i8042prt.sys 드라이버는 키보드 인터럽트 처리 루틴을 가지고 있습니다. 실제로 키보드 인터럽트가
처리되는 코드는 i8042prt.sys내부에 있는거죠.

i8042prt.sys 의 소스코드는 DDK 샘플에 있습니다.

키보드 디바이스 드라이버로부터 인터럽트 객체를 추적해내기 위해서
IoGetDeviceObjectPointer 함수를 사용합니다.

저 함수로는 kbdclass의 최상위 디바이스 객체밖에 알아낼 수 없는데
디바이스 스택의 최상위 디바이스 객체는 isr을 가지고 있지 않습니다, 또한 이 객체는
i8042prt.sys것이 아니라 아마도 kbdclass.sys가 가지고 있는 것일겁니다.

스택의 하단에 존재하는 i8042prt를 추적하기 위하여
윈도우즈 내부의 undocumented된 구조체를 사용합니다.
ntddk.h에 정의되어 있는 _DEVOBJ_EXTENSION은 여러개의 필드가 누락되어있는데
windbg를 이용해서 _DEVOBJ_EXTENSION 구조체를 펼쳐보죠

lkd> dt _DEVOBJ_EXTENSION
   +0x000 Type             : Int2B
   +0x002 Size             : Uint2B
   +0x004 DeviceObject     : Ptr32 _DEVICE_OBJECT
   +0x008 PowerFlags   &
Comments