Recent Posts
Recent Comments
Link
관리 메뉴

NaggingMachine

[질문]인터럽트개체가 뭐야????? 본문

TechnoBabbler

[질문]인터럽트개체가 뭐야?????

naggingmachine 2007. 8. 19. 00:08
미친감자님의 글에서 가져왔습니다. 역쉬 센스 있으셔~~

-----------

인터럽트 개체가 뭘까????


개체...

멍멍멍이 body???? ㅎㅎㅎㅎ


Windows Internals 라는 책을 봐도 도대체가 무슨말을 하는지 모르겠다.

내 대가리가 좋지 않아..그런건가????????

음...그러면.. 함번 분석해보자....

영어로 되어 있는 것을 확인해보자.

Interrupt Objects The kernel provides a portable mechanism—a kernel control object called an interrupt object—that
인터럽트 개체란 커널이란 놈은 제공한다. 뭐를??? 포터블 메카니즘을 말이다. 이 포터블 메카니즘이 뭔가하면... 커널 콘트롤 오브젝트라는 것이고 이놈을 우리는 인터럽트 개체라고 한다.
allows device drivers to register ISRs for their devices.
디바이스 드라이버를 말이지...ISR을 등록할때 사용한단 말이지.. 그놈이 만든 장치에 대해서 말이다...
(여기까지 이해가 가는가????)
 
An interrupt object contains all the information the kernel needs to associate a device ISR with a particular level of interrupt,
인터럽트 오브젝트라는 것은 포함한다 모든 정보를 말이다. 이정보안에는 커널이란 놈이
including the address of the ISR, the IRQL at which the device interrupts, and the entry in the kernel's IDT with which the
ISR의 주소와 ,IRQL 장치인터럽트의 IRQL말이다.
ISR should be associated.
 When an interrupt object is initialized, a few instructions of assembly language code, called the dispatch code, are copied from an interrupt handling template,
KiInterruptTemplate, and stored in the object. When an interrupt occurs, this code is executed







이그림이 더 잘나와 있군....

정말....이해가 안가..

IDT 테이블에는 ISR 주소만 있는데...이 주소는
함수를 가리치는 주소이고..

이 함수가 실행되면서..위 그림 같이 인터럽트 개체를 참조해서 뭔가를 한단 말인것 같다.

인터럽트 오브젝트...


이제까지..내가 분석해본 초간단 os에서는 이런 인터럽트 개체, 인터럽트 object란 놈은 없었다.

그런데 윈도우즈라는 놈은 하드웨어 , cpu에 독립적인 dependency같은것 없이 만들려고

이런 놈을 만든것이라고 생각이 들었다.

idt테이블위에 인터럽트를 추상화 하는것이라고 생각한다.

IDT 테이블의 ISR이란 놈은 인터럽트 개체를 가리키고.(이것 말안되는데..)암튼...
그래도 계속...

인터럽트 개체의 Dispatch Code는

http://www.google.co.kr/search?complete=1&hl=ko&q=_kinterrupt+&lr= _kinterrupt로 구글에서 검색해 보았다.

다음은 ReactOS의 Kernel 인터럽트 개체구조체이다.

00543 //00544 // Kernel Interrupt Object
00545 //
00546 typedef struct _KINTERRUPT
00547 {
00548     CSHORT Type;
00549     CSHORT Size;
00550     LIST_ENTRY InterruptListEntry;
00551     PKSERVICE_ROUTINE ServiceRoutine;
00552 #if (NTDDI_VERSION >= NTDDI_LONGHORN)
00553     PKSERVICE_ROUTINE MessageServiceRoutine;
00554     ULONG MessageIndex;
00555 #endif
00556     PVOID ServiceContext;
00557     KSPIN_LOCK SpinLock;
00558     ULONG TickCount;
00559     PKSPIN_LOCK ActualLock;
00560     PVOID DispatchAddress;
00561     ULONG Vector;
00562     KIRQL Irql;
00563     KIRQL SynchronizeIrql;
00564     BOOLEAN FloatingSave;
00565     BOOLEAN Connected;
00566     CHAR Number;
00567     UCHAR ShareVector;
00568     KINTERRUPT_MODE Mode;
00569 #if (NTDDI_VERSION >= NTDDI_LONGHORN)
00570     KINTERRUPT_POLARITY Polarity;
00571 #endif
00572     ULONG ServiceCount;
00573     ULONG DispatchCount;
00574 #if (NTDDI_VERSION >= NTDDI_LONGHORN)
00575     ULONGLONG Rsvd1;
00576 #endif
00577     ULONG DispatchCode[KINTERRUPT_DISPATCH_CODES];
00578 } KINTERRUPT, *PKINTERRUPT;
00579

NT계열의 Kernel Interrupt Object의 모양은 어떻게 생겼을까???



이 글은 www.chpie.org 에서 긁어온 글입니다.
이보트 IDT의 ISR을 후킹하는 이야기가 나오는데..이중에 DispatchCode[]배열에 대한 이야기가 나와서 일단 긁어왔습니다.



도움이 되었다니 정말로 기쁘군요 ㅠ_ㅠ
인터럽트객체의 ServiceRoutine은 그야말로 키보드처리의 코어부분만을 뽑아놓은 쓰레드입니다. 코어 쓰레드를 유지하기 위해서 DispatchCode[]배열을 이해해야 하죠. 제 개인적인 견해로는 ServiceRoutine은 공격자의 입장에서 훔치기에는 좋은 위치이지만, 방어하는 경우에서는 ServiceRoutine은 그야말로 간단한 IDT 훅킹에 대해서 전혀 동작하지 않아 보이는군요. 이럴 경우에 기존의 보안 드라이버들은 ServiceRoutine을 후킹하지 않고, IDT 엔트리 주소를 후킹 한 후에 코어 쓰레드를 유지하는 코드부터 코어쓰레드까지 모조리 코딩하는 무서운 코딩능력으로 보호를 한답니다 -_-;;
사실 그러나 기반 후킹 기술인 IDT 엔트리 후킹은 너무나도 간단하여 취약한 구석이 한둘이 아니죠 ㅎㅎ
그럼에도 불구하고 그냥 방어의 입장에서 생각하면 실시간 IDT 엔트리 스왑 기술은 간단하면서도 최고라고 생각합니다.
실시간 스왑을 해줌으로써 어느정도 허접한 프로그램으로부터 후킹의 우선순위를 선점할 수 있으니까요.
그러나 방어가 아닌 키보드 훅킹을 복구하는 솔루션을 생각하신다면 제가 생각하는 가장 좋은 방법은 모든 후킹 가능한 지점을 검사하여 모조리 복구하는 방법이 제일 좋은 것 같습니다. ServiceRoutine뿐만 아니라 인터럽트 제어 칩부터 드라이버, 메세지 훅킹에 이르기까지의 모든 경로에 대하여 접근하는 것이 가장 완벽해 보이는군요.
- IDTR을 조작하는 IDT 베이스 포인트 변경
- I/O APIC 벡터 조작
- I/O APIC Delivery Mode 조작
- 하드웨어 브레이크를 이용한 트랩포인트 설정
- IDT의 Not-Present 플래그를 이용한 Fault트랩
(인텔이 공식적으로 지원하는 훅킹 경로입니다.)
- IDT 엔트리 훅킹
- IDT[n]을 경유하는 임의의 경로에 대하여 jmp 명령어 삽입
(점프 목적지와 현재 위치로부터의 델타값을 검사하시면 될겁니다. 하지만 안해봤어요 -_-ㅋ)
- IDT 엔트리를 경유한 ServiceRoutine 획득
- i8042prt.sys 를 이용한 ServiceRoutine 획득
- DirectInput 을 이용한 글로벌 훅킹
- IME 코드 인젝션을 통한 훅킹
- 시스템 전역 메시지 훅킹
- 그 이외의 저의 필살기(?) ㅋㅋ




디스페치 코드 DispatchCode라고 되어 있는 곳의 값이 이상하다. [106]은 뭐고 0x56535554 라고 하는 값은 뭘까????

이것은 커널 주소가 아닌데....



/*++
NTSTATUS KeyboardInterruptHook(void)

: 실제 키보드 후킹작업을 실행합니다.
InterruptObject(KINTERRUPT)를 추적하여
ServiceRoutine항목을 우리가 만든 NewHandler의 주소로 바꾸어주면 됩니다.

*/
NTSTATUS KeyboardInterruptHook(void)
{
PIdtEntry_t IdtEntry;
ULONG Vector;
PULONG array = NULL;
int InterruptObject;

//
// IOAPIC 내부에 있는 레지스터는 0xfec00000이라는 물리주소를 엔트리로 하는데
// 커널모드에서 물리주소로 직접접근이 허용되지 않으므로,
// 가상메모리의 0번지에 맵핑하여 접근합니다.
//
// 그 후 0x10 + 2 * IRQ 를 쓰고
//
// mapping IOAPIC
_asm mov ebx,0xfec00000
_asm or ebx,0x13
_asm mov eax,0xc0000000
_asm mov dword ptr [eax], ebx

array[0]=0x10 + 2 * IRQ; //write 0x10 + 2 * IRQ to IOREGSEL
Vector=(array[4]&0xff); // read IOWIN register

// IDTR로 부터 IDT의 엔트리 값을 알아냅니다.
_asm sidt buffer
IdtEntry=(PIdtEntry_t)Idtr->Base;

// IDT[Vector]의 값을 읽어들입니다.
InterruptObject = ((unsigned int)IdtEntry[Vector].OffsetHigh<<16U)|
(IdtEntry[Vector].OffsetLow);

//
// Entry ~ DispatchCode
//
InterruptObject -= 0x3c;

PKInt = (PKINTERRUPT)((unsigned int)InterruptObject); // 키보드 InterruptObject의 주소를 저장합니다.
// 저장된 주소는 드라이버가 Unload되며
// ServiceRoutine을 복구해야 할 때에 사용됩니다.

memcpy(&KInt, PKInt, sizeof(KINTERRUPT)); // <- 단순히 app에게 주기위한 정보를 copy하는 것 뿐입니다.

_asm cli
OldISR = PKInt->ServiceRoutine;
PKInt->ServiceRoutine = (ULONG)(NewHandler); // 우리의 NewHandler로 치환.
_asm sti

return STATUS_SUCCESS;
}

위 코드는


Keyboard Interrupt Hook - IDT Hook 버전입니다.

씁... 몇가지 손댈 부분이 보이는데 그냥 귀찮아서 땜빵으로 -_-;;;;;




http://chpie.org/blog/4 에 있는 글과 소스이다.

그런데 IDT의 ISR이라는 값이 서비스 루틴이 아니었단 말인가????

위소스를 보면 아시겠지만...

InterruptObject -= 0x3c;

로 되어 있다.

함수가 아니였다...0x3c 이렇게 하는 이유는 뭘까?????????

이것도 커널 object라는 놈인가???

그리고 하는것이 정말 놀랍다....

서비스 루틴으로 생각했는데 서비스 루틴이 아니라. 구조체라는 것인가????????????

그럴리가 없다.....

뭔가.....있다...

IDT로 부터 InterruptObject를 구하기 위해선

IDT의 값에서 0x3c를 빼주면 되는데

0x3c는 KINTERRUPT 구조체의 사이즈에서

DispatchCode[] 값을 뺀 값입니다


라고 설명하고 있다...

 0x3c를 뺀이유는  IDT의 ISR 이 가리키는 값은 InterruptObject->DispatchCode

를 가리키고 있는 것이여서..그랬던것이다.





http://www.google.co.kr/search?sourceid=navclient&ie=UTF-8&rlz=1T4ADBR_enKR230KR231&q=InterruptObject+%2d%3d+0x3c

http://www.driveronline.org/bbs/view.asp?tb=tipbbs&no=21 <--- 이곳에 아주 자세히 설명하고 있는것 같다.



첫번째 - 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; <- 인터럽트 훅킹 성공


아 .그렇구나.....Dispactch Code

http://chpie.org/blog/attachment/1024411272.pdf

에보니까..정말 잘 정리가 되어 있다.

typedef struct _KINTERRUPT {
CSHORT
Type;
CSHORT
Size;
LIST_ENTRY
InterruptListEntry;
ULONG
ServiceRoutine;
PVOID
ServiceContext;
KSPIN_LOCK
SpinLock;
ULONG
TickCount;
PKSPIN_LOCK
ActualLock;
PLONG
DispatchAddress;
ULONG
Vector;
KIRQL
Irql;
KIRQL
SynchronizeIrql;
UCHAR
FloatingSave;
UCHAR
Connected;
CHAR
Number;
UCHAR
ShareVector[3];
KINTERRUPT_MODE
Mode;
ULONG
ServiceCount;
ULONG
DispatchCount;
ULONG
DispatchCode[106];
} KINTERRUPT, *PKINTERRUPT;
lkd> dt _KINTERRUPT
+0x000 Type
: Int2B
+0x002 Size
: Int2B
+0x004 InterruptListEntry : _LIST_ENTRY
+0x00c ServiceRoutine
: Ptr32
+0x010 ServiceContext
: Ptr32 Void
+0x014 SpinLock
: Uint4B
+0x018 TickCount
: Uint4B
+0x01c ActualLock
: Ptr32 Uint4B
+0x020 DispatchAddress : Ptr32
+0x024 Vector
: Uint4B
+0x028 Irql
: UChar
+0x029 SynchronizeIrql : UChar
+0x02a FloatingSave
: UChar
+0x02b Connected
: UChar
+0x02c Number
: Char
+0x02d ShareVector
: UChar
+0x030 Mode
: _KINTERRUPT_MODE
+0x034 ServiceCount
: Uint4B
+0x038 DispatchCount
: Uint4B
+0x03c DispatchCode
: [106] Uint4B
typedef struct _KINTERRUPT {
CSHORT
Type;
CSHORT
Size;
LIST_ENTRY
InterruptListEntry;
ULONG
ServiceRoutine;
PVOID
ServiceContext;
KSPIN_LOCK
SpinLock;
ULONG
TickCount;
PKSPIN_LOCK
ActualLock;
PLONG
DispatchAddress;
ULONG
Vector;
KIRQL
Irql;
KIRQL
SynchronizeIrql;
UCHAR
FloatingSave;
UCHAR
Connected;
CHAR
Number;
UCHAR
ShareVector[3];
KINTERRUPT_MODE
Mode;
ULONG
ServiceCount;
ULONG
DispatchCount;
ULONG
DispatchCode[106];
} KINTERRUPT, *PKINTERRUPT;
lkd> dt _KINTERRUPT
+0x000 Type
: Int2B
+0x002 Size
: Int2B
+0x004 InterruptListEntry : _LIST_ENTRY
+0x00c ServiceRoutine
: Ptr32
+0x010 ServiceContext
: Ptr32 Void
+0x014 SpinLock
: Uint4B
+0x018 TickCount
: Uint4B
+0x01c ActualLock
: Ptr32 Uint4B
+0x020 DispatchAddress : Ptr32
+0x024 Vector
: Uint4B
+0x028 Irql
: UChar
+0x029 SynchronizeIrql : UChar
+0x02a FloatingSave
: UChar
+0x02b Connected
: UChar
+0x02c Number
: Char
+0x02d ShareVector
: UChar
+0x030 Mode
: _KINTERRUPT_MODE
+0x034 ServiceCount
: Uint4B
+0x038 DispatchCount
: Uint4B
+0x03c DispatchCode
: [106] Uint4B
typedef struct _KINTERRUPT {
CSHORT
Type;
CSHORT
Size;
LIST_ENTRY
InterruptListEntry;
ULONG
ServiceRoutine;
PVOID
ServiceContext;
KSPIN_LOCK
SpinLock;
ULONG
TickCount;
PKSPIN_LOCK
ActualLock;
PLONG
DispatchAddress;
ULONG
Vector;
KIRQL
Irql;
KIRQL
SynchronizeIrql;
UCHAR
FloatingSave;
UCHAR
Connected;
CHAR
Number;
UCHAR
ShareVector[3];
KINTERRUPT_MODE
Mode;
ULONG
ServiceCount;
ULONG
DispatchCount;
ULONG
DispatchCode[106];
} KINTERRUPT, *PKINTERRUPT;
lkd> dt _KINTERRUPT
+0x000 Type
: Int2B
+0x002 Size
: Int2B
+0x004 InterruptListEntry : _LIST_ENTRY
+0x00c ServiceRoutine
: Ptr32
+0x010 ServiceContext
: Ptr32 Void
+0x014 SpinLock
: Uint4B
+0x018 TickCount
: Uint4B
+0x01c ActualLock
: Ptr32 Uint4B
+0x020 DispatchAddress : Ptr32
+0x024 Vector
: Uint4B
+0x028 Irql
: UChar
+0x029 SynchronizeIrql : UChar
+0x02a FloatingSave
: UChar
+0x02b Connected
: UChar
+0x02c Number
: Char
+0x02d ShareVector
: UChar
+0x030 Mode
: _KINTERRUPT_MODE
+0x034 ServiceCount
: Uint4B
+0x038 DispatchCount
: Uint4B
+0x03c DispatchCode
: [106] Uint4B
typedef struct _KINTERRUPT {
CSHORT
Type;
CSHORT
Size;
LIST_ENTRY
InterruptListEntry;
ULONG
ServiceRoutine;
PVOID
ServiceContext;
KSPIN_LOCK
SpinLock;
ULONG
TickCount;
PKSPIN_LOCK
ActualLock;
PLONG
DispatchAddress;
ULONG
Vector;
KIRQL
Irql;
KIRQL
SynchronizeIrql;
UCHAR
FloatingSave;
UCHAR
Connected;
CHAR
Number;
UCHAR
ShareVector[3];
KINTERRUPT_MODE
Mode;
ULONG
ServiceCount;
ULONG
DispatchCount;
ULONG
DispatchCode[106];
} KINTERRUPT, *PKINTERRUPT;
lkd> dt _KINTERRUPT
+0x000 Type
: Int2B
+0x002 Size
: Int2B
+0x004 InterruptListEntry : _LIST_ENTRY
+0x00c ServiceRoutine
: Ptr32
+0x010 ServiceContext
: Ptr32 Void
+0x014 SpinLock
: Uint4B
+0x018 TickCount
: Uint4B
+0x01c ActualLock
: Ptr32 Uint4B
+0x020 DispatchAddress : Ptr32
+0x024 Vector
: Uint4B
+0x028 Irql
: UChar
+0x029 SynchronizeIrql : UChar
+0x02a FloatingSave
: UChar
+0x02b Connected
: UChar
+0x02c Number
: Char
+0x02d ShareVector
: UChar
+0x030 Mode
: _KINTERRUPT_MODE
+0x034 ServiceCount
: Uint4B
+0x038 DispatchCount
: Uint4B
+0x03c DispatchCode
: [106] Uint4B
http://www.codeproject.com/script/Articles/list_articles.asp?userid=846502

Articles by Anton Bassov (5 articles found)

Average article rating: 4.8

System

General

Entering the kernel without a driver and getting interrupt information from APIC
Last Updated: 19 Aug 2005  Page views: 44,872  Rating: 4.8/5  Votes: 70  Popularity: 8.9
Tips and tricks of Windows masters.

Hooking the kernel directly
Last Updated: 4 Apr 2006  Page views: 38,277  Rating: 4.9/5  Votes: 32  Popularity: 7.3
How to hook the kernel functions directly.

Hooking the native API and controlling process creation on a system-wide basis
Last Updated: 18 Oct 2005  Page views: 61,731  Rating: 4.9/5  Votes: 59  Popularity: 8.6
How to hook the native API and control process creation on a system-wide basis.

Kernel-mode API spying - an ultimate hack
Last Updated: 22 Apr 2004  Page views: 70,228  Rating: 4.7/5  Votes: 38  Popularity: 7.4
An article on kernel-mode API spying.

Process-wide API spying - an ultimate hack
Last Updated: 11 Mar 2004  Page views: 230,627  Rating: 4.5/5  Votes: 71  Popularity: 8.3
Process-wide API spying.