?? vlogger.txt
字號:
Writing Linux Kernel Keylogger|=---------------------=[ rd <rd@vnsecurity.net> ]=----------------------=||=-----------------------------------------------------------------------=||=------------------------=[ June 19th, 2002 ]=--------------------------=|--[ Contents 1 - Introduction 2 - How Linux keyboard driver work 3 - Kernel based keylogger approaches 3.1 - Interrupt handler 3.2 - Function hijacking 3.2.1 - handle_scancode 3.2.2 - put_queue 3.2.3 - receive_buf 3.2.4 - tty_read 3.2.5 - sys_read/sys_write 4 - vlogger 4.1 - The syscall/tty approach 4.2 - Features 4.3 - How to use 5 - Greets 6 - References--[ 1 - Introduction This article is divided into two parts. The first part of the papergives an overview on how the linux keyboard driver work, and discussesmethods that can be used to create a kernel based keylogger. This partwill be useful for those who want to write a kernel based keylogger, or towrite their own keyboard driver (for supporting input of non-supportedlanguage in linux environment, ...) or to program taking advantage of manyfeatures in the Linux keyboard driver. The second part presents detail of vlogger, a smart kernel based linuxkeylogger, and how to use it. Keylogger is a very interesting code beingused widely in honeypots, hacked systems, ... by white and black hats. Asmost of us known, besides user space keyloggers (such as iob, uberkey,unixkeylogger, ...), there are some kernel based keyloggers. The earliestkernel based keylogger is linspy of halflife which was published in Phrack50 (see [4]). And the recent kkeylogger is presented in 'Kernel BasedKeylogger' paper by mercenary (see [7]) that I found when was writing thispaper. The common method of those kernel based keyloggers using is to loguser keystrokes by intercepting sys_read or sys_write system call.However, this approach is quite unstable and slowing down the whole systemnoticeably because sys_read (or sys_write) is the generic read/writefunction of the system; sys_read is called whenever a process wants to readsomething from devices (such as keyboard, file, serial port, ...). Invlogger, I used a better way to implement it that hijacks the tty bufferprocessing function. The reader is supposed to possess the knowledge on Linux Loadable KernelModule. Articles [1] and [2] are recommended to read before furtherreading.--[ 2 - How Linux keyboard driver work Lets take a look at below figure to know how user inputs from consolekeyboard are processed: _____________ _________ _________ / \ put_queue| |receive_buf| |tty_read/handle_scancode\-------->|tty_queue|---------->|tty_ldisc|------->\ / | | |buffer | \_____________/ |_________| |_________| _________ ____________ | |sys_read| |--->|/dev/ttyX|------->|user process| | | | | |_________| |____________| Figure 1 First, when you press a key on the keyboard, the keyboard will sendcorresponding scancodes to keyboard driver. A single key press can producea sequence of up to six scancodes. The handle_scancode() function in the keyboard driver parses the streamof scancodes and converts it into a series of key press and key releaseevents called keycode by using a translation-table via kbd_translate()function. Each key is provided with a unique keycode k in the range 1-127.Pressing key k produces keycode k, while releasing it produces keycodek+128. For example, keycode of 'a' is 30. Pressing key 'a' produces keycode 30.Releasing 'a' produces keycode 158 (128+30). Next, keycodes are converted to key symbols by looking them up on theappropriate keymap. This is a quite complex process. There are eightpossible modifiers (shift keys - Shift , AltGr, Control, Alt, ShiftL,ShiftR, CtrlL and CtrlR), and the combination of currently active modifiersand locks determines the keymap used. After the above handling, the obtained characters are put into the rawtty queue - tty_flip_buffer. In the tty line discipline, receive_buf() function is called periodicallyto get characters from tty_flip_buffer then put them into tty read queue. When user process want to get user input, it calls read() function onstdin of the process. sys_read() function will calls read() functiondefined in file_operations structure (which is pointed to tty_read) ofcorresponding tty (ex /dev/tty0) to read input characters and return to theprocess. The keyboard driver can be in one of 4 modes: - scancode (RAW MODE): the application gets scancodes for input. It is used by applications that implement their own keyboard driver (ex: X11) - keycode (MEDIUMRAW MODE): the application gets information on which keys (identified by their keycodes) get pressed and released. - ASCII (XLATE MODE): the application effectively gets the characters as defined by the keymap, using an 8-bit encoding. - Unicode (UNICODE MODE): this mode only differs from the ASCII mode by allowing the user to compose UTF8 unicode characters by their decimal value, using Ascii_0 to Ascii_9, or their hexadecimal (4-digit) value, using Hex_0 to Hex_9. A keymap can be set up to produce UTF8 sequences (with a U+XXXX pseudo-symbol, where each X is an hexadecimal digit). Those modes influence what type of data that applications will get askeyboard input. For more details on scancode, keycode and keymaps, pleaseread [3].--[ 3 - Kernel based keylogger approaches We can implement a kernel based keylogger in two ways by writing our ownkeyboard interrupt handler or hijacking one of input processing functions. ----[ 3.1 - Interrupt handler To log keystrokes, we will use our own keyboard interrupt handler. UnderIntel architectures, the IRQ of the keyboard controlled is IRQ 1. Whenreceives a keyboard interrupt, our own keyboard interrupt handler read thescancode and keyboard status. Keyboard events can be read and written viaport 0x60(Keyboard data register) and 0x64(Keyboard status register)./* below code is intel specific */#define KEYBOARD_IRQ 1 #define KBD_STATUS_REG 0x64 #define KBD_CNTL_REG 0x64 #define KBD_DATA_REG 0x60 #define kbd_read_input() inb(KBD_DATA_REG) #define kbd_read_status() inb(KBD_STATUS_REG) #define kbd_write_output(val) outb(val, KBD_DATA_REG) #define kbd_write_command(val) outb(val, KBD_CNTL_REG) /* register our own IRQ handler */request_irq(KEYBOARD_IRQ, my_keyboard_irq_handler, 0, "my keyboard", NULL);In my_keyboard_irq_handler(): scancode = kbd_read_input(); key_status = kbd_read_status(); log_scancode(scancode); This method is platform dependent. So it won't be portable amongplatforms. And you have to be very careful with your interrupt handler ifyou don't want to crash your box ;)----[ 3.2 - Function hijacking Based on the Figure 1, we can implement our keylogger to log user inputsby hijacking one of handle_scancode(), put_queue(), receive_buf(),tty_read() and sys_read() functions. Note that we can't intercepttty_insert_flip_char() function because it is an INLINE function.------[ 3.2.1 - handle_scancode This is the entry function of the keyboard driver (see keyboard.c). Ithandles scancodes which are received from keyboard.# /usr/src/linux/drives/char/keyboard.cvoid handle_scancode(unsigned char scancode, int down); We can replace original handle_scancode() function with our own to logsall scancodes. But handle_scancode() function is not a global and exportedfunction. So to do this, we can use kernel function hijacking techniqueintroduced by Silvio (see [5])./* below is a code snippet written by Plasmoid */static struct semaphore hs_sem, log_sem;static int logging=1;#define CODESIZE 7static char hs_code[CODESIZE];static char hs_jump[CODESIZE] = "\xb8\x00\x00\x00\x00" /* movl $0,%eax */ "\xff\xe0" /* jmp *%eax */ ;void (*handle_scancode) (unsigned char, int) = (void (*)(unsigned char, int)) HS_ADDRESS;void _handle_scancode(unsigned char scancode, int keydown){ if (logging && keydown) log_scancode(scancode, LOGFILE); /* * Restore first bytes of the original handle_scancode code. Call * the restored function and re-restore the jump code. Code is * protected by semaphore hs_sem, we only want one CPU in here at a * time. */ down(&hs_sem); memcpy(handle_scancode, hs_code, CODESIZE); handle_scancode(scancode, keydown); memcpy(handle_scancode, hs_jump, CODESIZE); up(&hs_sem);}HS_ADDRESS is set by the Makefile executing this commandHS_ADDRESS=0x$(word 1,$(shell ksyms -a | grep handle_scancode)) Similar to method presented in 3.1, the advantage of this method is theability to log keystrokes under X and the console, no matter if a tty isinvoked or not. And you will know exactly what key is pressed on thekeyboard (including special keys such as Control, Alt, Shift, Print Screen,...). But this method is platform dependent and won't be portable amongplatforms. This method also can't log keystroke of remote sessions and isquite complex for building an advance logger.------[ 3.2.2 - put_queue This function is called by handle_scancode() function to put charactersinto tty_queue. # /usr/src/linux/drives/char/keyboard.cvoid put_queue(int ch); To intercept this function, we can use the above technique as in section(3.2.1).------[ 3.2.3 - receive_buf receive_buf() function is called by the low-level tty driver to sendcharacters received by the hardware to the line discipline for processing.# /usr/src/linux/drivers/char/n_tty.c */static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)cp is a pointer to the buffer of input character received by the device.fp is a pointer to a pointer of flag bytes which indicate whether acharacter was received with a parity error, etc.Lets take a deeper look into tty structures# /usr/include/linux/tty.hstruct tty_struct { int magic; struct tty_driver driver; struct tty_ldisc ldisc; struct termios *termios, *termios_locked;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -