메모장 입니다2

IDT 후킹 본문

Study/Programming

IDT 후킹

Wooum@n 2017. 3. 22. 11:48

1.인터럽트(Interrupt)


 -CPU 작업 중, 다른 장치나 예외상황의 일처리가 필요할 경우, 프로세서에게 알리는 것.

(<->폴링: 어떤 장치의 처리를 위해, 주기적으로 감시하는 것)






2.IDT(Interrupt Descriptor Table)


 -정의

->인터럽트 서비스 루틴이 담긴 배열.

->(*보호모드일 때) 8바이트의 256개의 엔트리로 구성됨.

->-각 엔트리는 ISR의 주소와 보안 관련 정보가 담김.



 -IDT Enty 구성

#pragma pack(1)

typedef struct

{

unsigned short LowOffset;

unsigned short selector;

unsigned char zero;

unsigned char type_attr;

unsigned short HiOffset;

} IDTENTRY;

#pragma pack()


->Low/Hi Offset은 ISR의 주소를 나타낸다.

->IDTENTRY 구조체 멤버는 프로세서에 따라 다르다.

http://wiki.osdev.org/Interrupt_Descriptor_Table



 -인터럽트 서비스 루틴(ISR)

->해당 인터럽트 발생시, 실행될 코드가 담긴 루틴.

->인터럽트 벡터라고도 함.



-인터럽트 오브젝트

->인터럽트와 관련된 주요정보가 담김.

>>ServiceRoutine 주소, 인터럽트 레벨 정보 등.

->ISR 내부에서 호출되는 nt!KiInterruptDispatch()의 인자로 전달되어, 

인터럽트 권한이 설정된 뒤, ServiceRoutine이 실행됨.


*ISR: 인터럽트 설정 과정(트랩프레임 구성, IRQL 조정, 시스템 인터럽트 Enable)을 진행한 후에 

InterruptDispatch() 호출.

->InterruptDispatch()내부에서 ServiceRoutine이 호출됨.

*ServiceRoutine: 실질적인 인터럽트 처리 코드가 담긴 루틴.



http://egloos.zum.com/micingamja/v/3587980

http://yangil06.tistory.com/entry/3-1-1-%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8-%EB%94%94%EC%8A%A4%ED%8C%A8%EC%B9%AD



-IDT 구하기

`IDTR을 이용`

->IDTR 레지스터에 IDT의 주소가 담김.

->IDTR은 명령어를 통해 값을 조작할 수 있다.

1)SIDT(Store IDT)

->IDTR의 값을 다음 구조체 형태로 반환.

typedef struct

{

unsigned short IDTLimit;

unsigned short LowIDTbase;

unsgined short HiIDTbase;

}IDTINFO;


->High, Low가 나뉘어 있기 때문에, 매크로(MAKELONG)을 통해 4바이트로 합쳐줘야 한다.


#define MAKELONG(low, high) ((unsigned long) (((unsigned short) (low)) I ((unsigned long) ((unsigned short) (high))) << 16)) 


2)LIDT(Load IDT)

->IDTR의 값을 변경. //예제에서 사용되진 않음. IDT가 아니라 IDT 멤버를 조작하는 것이기 때문.

`PCR(Processor Control Region)을 이용`



 -Interrupt Object 구하기

->운영체제 버전에 따라 다름

1)XP

: ISR 시작주소 - 0x3c.

2)7

:아직 확인안됨(0x3c 빼는 것으론 구할 수 없음.)

->InterruptDispatch의 인자로 전달되는 값을 확인하여 알 수 있다.

->Windows 10에선 오브젝트의 위치가 고정되지 않기 때문에, 이 방식으로 찾을 수 없다.

http://m.blog.naver.com/gloryo/220400046050



 -IDT Hooking 탐지

->명확한 기준이 없다.

 인터럽트의 처리루틴은 불특정 영역에 존재하기 때문에.

(<-> SSDT 후킹 탐지: ntoskernel.exe 영역에만 존재.) 

->추측을 통한 방지만 

https://www.google.co.kr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&cad=rja&uact=8&ved=0ahUKEwjAlsu9h5PTAhULopQKHQUDC5YQFggkMAI&url=http%3A%2F%2Fskensita.tistory.com%2Fattachment%2F4938ddd6944deCE.pdf&usg=AFQjCNHhLTl3TMPhBMGQx3pZP6Hse7HAAQ&sig2=_V_K19FIzniq7QDzURldaQ




/*키보드 인터럽트 루틴(ServiceRoutine)을 후킹하여 PS/2 스캔코드 출력*/

/*소스*/

#include <ntddk.h>

#include <stdio.h>



#define MAKELONG(low, high) (unsigned long) (((unsigned short) low) | ((unsigned long) (((unsigned short) high) << 16))) 

#define MAX_IDT_ENTRY 150

#define Vector_Keyboard_XP 0x93

#define Vector_Keyboard_10 0x70


#pragma warning(disable: 4214)

#pragma warning(disable: 4013)

#pragma warning(disable: 4047)

#pragma warning(disable: 4024)

#pragma warning(disable: 4616)

#pragma warning(disable: 4101)

#pragma warning(disable: 4305)

#pragma warning(disable: 4333)

#pragma pack(1)

typedef struct

{

unsigned short LowOffset;

unsigned short selector;

unsigned char zero;

unsigned char type_attr;

unsigned short HiOffset;

} IDTENTRY;

#pragma pack()


typedef struct

{

unsigned short IDTLimit;

unsigned short LowIDTbase;

unsigned short HiIDTbase;

}IDTINFO;



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;


VOID WP_OFF()

{

__asm {

push eax

mov eax, CR0

and eax, 0x0FFFEFFFF

mov CR0, eax

pop eax

}

}


VOID WP_ON()

{

__asm {

push eax

mov eax, CR0

or eax, NOT 0x0FFFEFFFF

mov CR0, eax

pop eax

}

}

//////////////

ULONG OldServiceRoutine;

PKINTERRUPT IntObject;

/////////////

__declspec(naked) MyServceRoutine()

{

unsigned char c;

DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "MyServiceRoutine!!\n");

c=READ_PORT_UCHAR(0x60);

WRITE_PORT_UCHAR(0x64, c);

DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "scan code: %x\n", c);


__asm {

jmp [OldServiceRoutine]

}

}


VOID OnUnload(PDRIVER_OBJECT DriverObject)

{

UNREFERENCED_PARAMETER(DriverObject);

IntObject->ServiceRoutine = OldServiceRoutine;


DbgPrint("Unloading Dirver!!!");

}



NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)

{

IDTINFO idt_info;

IDTENTRY* idt_entries;

IDTENTRY* keyEntry;


int count;


UNREFERENCED_PARAMETER(RegistryPath);


DbgPrint("Driver Loading!!");

DriverObject->DriverUnload = OnUnload;



//////////////


/* IDT 테이블의 각 ISR 주소값 DbgPrint*/


/*IDT 주소 가져오기*/

__asm sidt idt_info


idt_entries = (IDTENTRY*)(((unsigned int)idt_info.HiIDTbase << 16U) | (idt_info.LowIDTbase));

DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "IDT:%4x\n", idt_entries);


keyEntry = (IDTENTRY*)(((unsigned int)idt_entries[Vector_Keyboard_XP].HiOffset << 16U) | (idt_entries[Vector_Keyboard_XP].LowOffset));


DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "KEY IDT:%4x\n", keyEntry); 


/*보호모드 테스트 w10

WP_OFF();

keyEntry->HiOffset = ((unsigned short) MyServceRoutine >> 16);

keyEntry->LowOffset = ((unsigned short)MyServceRoutine);

WP_ON();

*/

IntObject = (PKINTERRUPT)((ULONG)keyEntry - (ULONG)0x3c);

OldServiceRoutine= IntObject->ServiceRoutine;

IntObject->ServiceRoutine = MyServceRoutine;


DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "KEY ServiceRoutine:%4x\n", OldServiceRoutine);


/*idt entry 출력

for (count = 0; count < MAX_IDT_ENTRY; count++)

{

char _t[255];

char _t2[255];

IDTENTRY *i = &idt_entries[count];

unsigned long addr = 0;

addr = ((unsigned int)i->HiOffset << 16U) | (i->LowOffset);

_snprintf(_t2,

253,

"[%d] idt_entry:%x\n", count, (unsigned int)i);

DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, _t2);

_snprintf(_t,

253,

"Interrupt %d: ISR %4x\n", count, addr);

DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, _t);

}*/


return STATUS_SUCCESS;

}