Modul ini dibuat sebagai bagian dari tesis master saya pada tahun 2010. Tema tesis master adalah Keylogging di kernel Linux . Gagasan utama adalah untuk menemukan cara untuk mencegat panggilan sistem untuk kernel Linux x64 arch, terutama untuk kernel 2.6.34.7-61.fc13.x86_64.
Pendahuluan
Ada banyak artikel berbeda tentang intersepsi panggilan sistem untuk arch x32. Sebagai bagian dari penelitian, saya menghadapi masalah tentang cara mencegat panggilan sistem untuk x86_64 arch melalui modul Linux-kernel.
Bagaimana kita bisa mencegat panggilan sistem?
- Cari tahu alamat tabel syscall.
- Ganti panggilan sistem yang asli dengan yang baru.
Alamat tabel syscall
IDT ( I nterrupt D escription T mampu) membatasi interrupt handler & kode interupsi . Dalam mode terproteksi, IDT adalah larik deskriptor yang disimpan dalam memori. Setiap prosesor memiliki register IDTR khusus. Register terdiri dari alamat fisik IDT dan panjang IDT. Asumsi pertama adalah untuk mendapatkan alamat IDT dari register IDTR dan setelah itu menghitung alamat tabel syscall. Namun, anggapan itu salah, karena, dalam kasus itu, kami mendapat alamat penangan x32.
Asumsi kedua lebih menarik. Sebelum melanjutkan, saya ingin Menjelaskan MSR (Macodell Specific R egister). MSR adalah salah satu dari berbagai register kontrol dalam set instruksi x86 yang digunakan untuk debugging, pelacakan eksekusi program, pemantauan kinerja komputer, dan mengganti fitur CPU tertentu. Mari kita bicara tentang MSR_LSTAR
- 0xc0000082
(target SYSCALL mode lama). Anda bisa mendapatkan daftar lengkap di /usr/include/asm/msr-index.h
.
MSR_LSTAR
menyimpan entri panggilan sistem untuk arsitektur x86-64. Anda bisa mendapatkan alamatnya:
int i, lo, hi; asm volatile("rdmsr" : "=a" (lo), "=d" (hi) : "c" (MSR_LSTAR)); system_call = (void*)(((long)hi<<32) | lo);
Mari kita melangkah lebih jauh. Saya telah mendapatkan alamat & sedang mencari \xff\x14\xc5
. \xff\x14\xc5
adalah angka ajaib. Jika Anda melihat melalui kode kernel 2.6.34.7-61.fc13.x86_64, terutama, fungsi system_call
, Anda akan mengetahui bahwa 4 byte berikutnya adalah alamat syscall_table.
Kami tahu alamat tabel syscall, itu berarti bahwa kami bisa mendapatkan alamat syscall handler & mengganti / memotongnya.
Kode sumber:
unsigned char *ptr; for (ptr=system_call, i=0; i<500; i++) { if (ptr[0] == 0xff && ptr[1] == 0x14 && ptr[2] == 0xc5) return (void*)(0xffffffff00000000 | *((unsigned int*)(ptr+3))); ptr++; }
Intersepsi panggilan sistem
Saya menghadapi masalah. Ada kesalahan saat mengubah alamat dalam tabel panggilan sistem. Untungnya, itu semudah pie:
- Nonaktifkan perlindungan memori.
- Menulis ulang alamat penangan syscall.
- Aktifkan perlindungan memori.
Jika Anda ingin menonaktifkan perlindungan memori, Anda harus tahu: register CR0
terdiri dari flag. Bendera mengelola perilaku prosesor. Bendera WP adalah Write Protect
, itu adalah bit ke-48 di CR0
.
Nonaktifkan perlindungan memori:
asm("pushq %rax"); asm("movq %cr0, %rax"); asm("andq $0xfffffffffffeffff, %rax"); asm("movq %rax, %cr0"); asm("popq %rax");
Aktifkan perlindungan memori:
asm("pushq %rax"); asm("movq %cr0, %rax"); asm("xorq $0x0000000000001000, %rax"); asm("movq %rax, %cr0"); asm("popq %rax");
Kesimpulan
Di satu sisi, itu harus cukup untuk berurusan dengan intersepsi panggilan sistem, tetapi di sisi lain, saya tidak yakin bahwa tidak ada yang berubah sejak 2010. Jadi gunakan apa adanya. Kode sumber ditempatkan di github.com/ultral/linux-keylogger .
PS