Statistics

Members: 1925
News: 292
Web Links: 1
Visitors: 3645343

Who's Online

We have 1 guest online
Damn Vulnerable LinuxDamn Vulnerable Linux (DVL) is a Linux-based (modified Damn Small Linux) tool for IT-Security & IT-Anti- Security and Attack & Defense. [CLICK HERE FOR MORE INFOS! ]

Featured Conference Video

T16-Recon2006-Joe_Stewart-OllyBonE.gif OllyBone - Semi-Automatic Unpacking on IA-32. View the conference video here!
Home
Using the raw keyboard mode under Linux
User Rating: / 0
PoorBest 
Written by Karsten Scheibler   


If you read something from STDIN, the read bytes are normally in ASCII format. In some cases it is useful to get the keyboard input as raw as possible. Imagine: Your program should react on the Alt or Ctrl Key with menu highlightning. In raw keyboard mode such things are possible. In this mode you get directly the untranslated keycodes coming from your keyboard. It doesn't generate ASCII like codes it is far away from that. If you press a key on your keyboard two codes are send to the controller in your PC a so called make code if you press a key and a break code if you release a key. The most generated codes are 1 byte codes. It is easy to recognize which sort of code you have received: bit 7 clear = make, bit 7 set = break.
Remark (a):
Save this page as rawkb.html and use the following command to extract the source code with a sample Makefile:
sh -c "( mkdir rawkb && cd rawkb && awk '/^<!--eof/{d=0}{if(d)print>f}/^<!--sof/{f=\$2;d=1}' ) < rawkb.html"
Remark (b):
Some browsers try to be super smart and reformat the html code so you may have trouble to extract the files. This is the right time to learn more about wget, a tool to download files via http or ftp ;-)
Remark (c):
Some versions of nasm are known to generate broken code. I have used nasm-0.98 for this example which worked for me.

If you read something from STDIN, the read bytes are normally in ASCII format. In some cases it is useful to get the keyboard input as raw as possible. Imagine: Your program should react on the Alt or Ctrl Key with menu highlightning. In raw keyboard mode such things are possible. In this mode you get directly the untranslated keycodes coming from your keyboard. It doesn't generate ASCII like codes it is far away from that. If you press a key on your keyboard two codes are send to the controller in your PC a so called make code if you press a key and a break code if you release a key. The most generated codes are 1 byte codes. It is easy to recognize which sort of code you have received: bit 7 clear = make, bit 7 set = break.

Examples:

  • ESC: make:001h, break:081h
  • RETURN: make:01ch, break:09ch
  • LEFT SHIFT: make:02ah, break:0aah
  • ...

But there are also codes longer than 1 byte, such codes are escaped with a leading 0e0h. Example: RIGHT CTRL: 0e0h 01dh (make), 0e0h 09eh (break). Three byte codes are escaped with 0e1h (there should be only one such key on your keyboard: PAUSE. This key is a little bit special because it generates make and break codes without any delay if you press it).

The example code below will simply dump the hex code of every key to the terminal. Use ESC to exit the program. It will only work on local console.

The translation to ASCII Codes in the kernel is done via tables (the same tables are changed if you run the command loadkeys, which loads the correct keytable for your country). You can reach this tables with the ioctl's KDGKBENT and KDSKBENT. They expect a pointer to a structure of the type kbentry (see /usr/src/linux/include/linux/kd.h). If you want to get an entry you have to set the values kb_table and kb_index, if you want to set an entry kb_value must also be set. kb_index is the raw keycode, kb_table contains bits for the keys Shift, Alt, AltGr and Ctrl (it is some kind of table selector, for making things like Shift+A easier). kb_value contains the ASCII Code. For simple keyhandling this should be enough, the real key translation in the kernel seems to be a little bit more complex (think of escape sequences if you press a cursor key), in such cases kb_value contains some magic values.

Like all low level accesses you should try as hard as you can to restore the original state, because if you fail the keyboard stays in raw mode and this means the local console is unusable (Ctrl+Alt+Del doesn't work, no terminal switching etc.). Therefore you should catch all signals, which can terminate your program (including SIGSEGV) with an exit handler.

Note:
The ioctl KDGKBMODE expects like the most ioctl's an address as third argument, but KDSKBMODE expects directly the mode (K_RAW for the raw keyboard mode K_XLATE for the normal mode). There is also a K_MEDIUMRAW available but i let it up to you to figure out the differences between K_RAW and K_MEDIUMRAW ;-). To find out more about available ioctls you may consult the console_ioctls manpage. Because i have already mentioned a manpage i will also mention another one: console_codes. There you will find escape codes for changing terminal colors etc.

short procedure for switching to raw keyboard mode:

  1. use the TIOCLINUX or VT_GETMODE ioctl's to determine if you your program was called from local console.
  2. save the current terminal state (ioctl's TCGETS and KDGKBMODE and friends)
  3. set signal handlers
  4. set the terminal values:
    1. switch off input flags: ISTRIP, INLCR, ICRNL, IGNCR, IXON, IXOFF.
    2. switch off local flags: ECHO, ICANON, ISIG.
    3. Disable kernel keyboard translation.

In this example we use STDIN as file descriptor for sys_ioctl. This is ok as long as nobody redirects it to a file or pipe. If you want that the program even works in this cases: open /dev/tty and use that file descriptor instead.

If you find mistakes or have suggestions, mail This e-mail address is being protected from spam bots, you need JavaScript enabled to view it .


;****************************************************************************
;****************************************************************************
;*
;* USING THE RAW KEYBOARD MODE UNDER LINUX
;*
;* written by Karsten Scheibler, 2003-DEC-08
;*
;****************************************************************************
;****************************************************************************
global rawkb_start
;****************************************************************************
;* some assign's
;****************************************************************************
%assign SYS_READ			3
%assign SYS_WRITE			4
%assign SYS_OPEN			5
%assign SYS_CLOSE			6
%assign SYS_IOCTL			54
%assign TCGETS				0x00005401
%assign TCSETSW				0x00005403
%assign KDGKBMODE			0x00004b44
%assign KDSKBMODE			0x00004b45
%assign K_RAW				0
%assign ISTRIP				000400q
%assign INLCR				000100q
%assign IGNCR				000200q
%assign ICRNL				000400q
%assign IXON				002000q
%assign IXOFF				010000q
%assign ISIG				1
%assign ICANON				2
%assign ECHO				8
%assign STDIN				0
%assign STDOUT				1
%assign O_RDWR				2
%assign STATE_TERMIOS_SAVED		0x01
%assign STATE_KBMODE_SAVED		0x02
struc	ttermios
alignb	4
termios_input_flags:			resd	1
termios_output_flags:			resd	1
termios_control_flags:			resd	1
termios_local_flags:			resd	1
termios_line_discipline:		resb	1
termios_control_characters:		resb	64
endstruc
;****************************************************************************
;* data
;****************************************************************************
section .data
align	4
tty_state:				dd	0
section .bss
align	4
tty_termios_saved:			resb	ttermios_size
tty_kbmode_saved:			resd	1
tty_termios:				resb	ttermios_size
hex_number:				resd	1
character:				resb	1
;****************************************************************************
;* rawkb_start
;****************************************************************************
section .text
rawkb_start:
;save terminal state
mov	dword eax, SYS_IOCTL
mov	dword ebx, STDIN
mov	dword ecx, KDGKBMODE
mov	dword edx, tty_kbmode_saved
int	byte  0x80
test	dword eax, eax
js	near  rawkb_error
or	dword [tty_state], STATE_KBMODE_SAVED
mov	dword eax, SYS_IOCTL
mov	dword ebx, STDIN
mov	dword ecx, TCGETS
mov	dword edx, tty_termios_saved
int	byte  0x80
test	dword eax, eax
js	near  rawkb_error
or	dword [tty_state], STATE_TERMIOS_SAVED
;set terminal values
cld
mov	dword ecx, ttermios_size
mov	dword esi, tty_termios_saved
mov	dword edi, tty_termios
rep movsb
and	dword [tty_termios + termios_input_flags], (~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF))
and	dword [tty_termios + termios_local_flags], (~(ECHO | ICANON | ISIG))
mov	dword eax, SYS_IOCTL
mov	dword ebx, STDIN
mov	dword ecx, TCSETSW
mov	dword edx, tty_termios
int	byte  0x80
test	dword eax, eax
js	near  rawkb_error
mov	dword eax, SYS_IOCTL
mov	dword ebx, STDIN
mov	dword ecx, KDSKBMODE
mov	dword edx, K_RAW
int	byte  0x80
test	dword eax, eax
js	near  rawkb_error
;display the hex codes of all pressed keys, ESC exits
.display:
mov	dword eax, SYS_READ
mov	dword ebx, STDIN
mov	dword ecx, character
mov	dword edx, 1
int	byte  0x80
xor	dword ebx, ebx
xor	dword ecx, ecx
mov	byte  bl, [character]
mov	byte  cl, bl
cmp	byte  bl, 0x01
je	near  rawkb_end
shr	dword ecx, 4
and	byte  bl, 0x0f
mov	dword eax, 0x0a680000
mov	byte  ah, [.hex_table + ebx]
mov	byte  al, [.hex_table + ecx]
mov	dword [hex_number], eax
mov	dword eax, SYS_WRITE
mov	dword ebx, STDOUT
mov	dword ecx, hex_number
mov	dword edx, 4
int	byte  0x80
jmp	short .display
.hex_table:				db	"0123456789abcdef"
;****************************************************************************
;* rawkb_restore ************************************************************
;****************************************************************************
section .text
rawkb_restore:
test	dword [tty_state], STATE_KBMODE_SAVED
jz	short .no_kbmode
mov	dword eax, SYS_IOCTL
mov	dword ebx, STDIN
mov	dword ecx, KDSKBMODE
mov	dword edx, [tty_kbmode_saved]
int	byte  0x80
.no_kbmode:
test	dword [tty_state], STATE_TERMIOS_SAVED
jz	short .no_termios
mov	dword eax, SYS_IOCTL
mov	dword ebx, STDIN
mov	dword ecx, TCSETSW
mov	dword edx, tty_termios_saved
int	byte  0x80
.no_termios:
ret
;****************************************************************************
;* rawkb_error **************************************************************
;****************************************************************************
section .text
rawkb_error:
call	near  rawkb_restore
xor	dword eax, eax
inc	dword eax
mov	dword ebx, eax
int	byte  0x80
;****************************************************************************
;* rawkb_end
;****************************************************************************
section .text
rawkb_end:
call	near  rawkb_restore
xor	dword eax, eax
mov	dword ebx, eax
inc	dword eax
int	byte  0x80
;*********************************************** 
 This e-mail address is being protected from spam bots, you need JavaScript enabled to view it
  *