זאת לא הפעם הראשונה שאני כותב על Hooking ובד"כ המושג הזה נשמע מאיים במיוחד בתחום אבטחת המידע אבל ב Linux זאת טכניקה לגיטימית בפיתוח ב Kernel ובגלל שמדובר בקוד פתוח המידע נגיש וחשוף לכולם בניגוד ל Windows שעושה את החיים לא קלים ומקשה מאוד על כתיבה ב Kernel, האפשרות לשלוט ב Kernel בצורה כלכך חופשית מאפשרת למפתחים למצוא פתרונות ופטנטים ייחודיים עבור המערכות שלהם.
שימו לב!
- עבודה מול ה Kernel עלולה להזיק למחשב שלך, מומלץ להשתמש במכונה וירטואלית.
- המאמר נכתב על Fedora 14 גרסת Kernel - 2.6.35.
- אני לא אחראי על אופי השימוש בתוכן.
Hooking
אז למי ששכח (לדוג) Hooking זו שיטה שמאפשרת להחליף את הקריאות לפונקציות המקוריות במערכת עם פונקציות אחרות שנטענו ב Module, זאת נקודת בניים שהמתכנת יכול להחליט עם להעביר את המידע לפונקציה המקורית או להפעיל פונקציות אחרות, המשחק עצמו הוא סביב טבלה שמכילה את כל הכתובות לפונקציות של ה System Calls ב Windows זה (כמעט...) בלתי אפשרי למצוא אותה אבל ב Linux זה פשוט מאוד, קיים קובץ בתיקיית ה boot שמכיל את הכתובות לפונקציות של ה System Call, יש להכניס את הפקודה הבאה ב Terminal:
הכתובות לפונקציות של ה System Call נמצאות באיזור שמוגדר כ Read Only אבל בגלל שאנחנו ב Kernel אנחנו יכולים לשנות את ה Control Register שדרכו נהפוך את האיזור גם לכתיבה, נחתום את ה Pointer של הפונקציה החדשה ממקום הפונקציה הישנה.
הכתובות לפונקציות של ה System Call נמצאות באיזור שמוגדר כ Read Only אבל בגלל שאנחנו ב Kernel אנחנו יכולים לשנות את ה Control Register שדרכו נהפוך את האיזור גם לכתיבה, נחתום את ה Pointer של הפונקציה החדשה ממקום הפונקציה הישנה.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/string.h>
static char * filewatch;
//charp - type of the parameter is string
module_param(filewatch, charp,0);
MODULE_PARM_DESC(filewatch,"destination file pointer");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("simple hooking driver");
//extract using cat /boot/System.map | grep sys_call
unsigned long *syscall_table = (unsigned long *)0xc07b0328;
//original system call signature
asmlinkage int (*original_sys_open)(const char* filename,int flags,int mode);
//hook function
asmlinkage int fake_sys_open(const char* filename, int flags,int mode)
{
//check if open function requested on the filewatch
if(strcmp(filename,filewatch) == 0)
{
//write to log
printk("File open(\"%s\", %X, %X)\n", filename,flags,mode);
//drop the request - operation not permitted
return -EPERM;
}
//continue normal routine back to original function
return (*original_sys_open)(filename,flags,mode);
}
static int init_driver(void) {
printk("load hook module\n");
//change read only area to write availability
write_cr0 (read_cr0 () & (~ 0x10000));
//save the original __NR_write pointer using uistd.h defines
original_sys_open = (void *)syscall_table[__NR_open];
//write to pointer to the fake function
syscall_table[__NR_open] = fake_sys_open;
//change the write area back to read only
write_cr0 (read_cr0 () | 0x10000);
return 0;
}
static void clean_driver(void) {
//change read only area to write availability
write_cr0 (read_cr0 () & (~ 0x10000));
//return the original pointer to the system call table
syscall_table[__NR_open] = original_sys_open;
//change the write area back to read only
write_cr0 (read_cr0 () | 0x10000);
printk("unload hook module\n");
return;
}
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/string.h>
static char * filewatch;
//charp - type of the parameter is string
module_param(filewatch, charp,0);
MODULE_PARM_DESC(filewatch,"destination file pointer");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("simple hooking driver");
//extract using cat /boot/System.map | grep sys_call
unsigned long *syscall_table = (unsigned long *)0xc07b0328;
//original system call signature
asmlinkage int (*original_sys_open)(const char* filename,int flags,int mode);
//hook function
asmlinkage int fake_sys_open(const char* filename, int flags,int mode)
{
//check if open function requested on the filewatch
if(strcmp(filename,filewatch) == 0)
{
//write to log
printk("File open(\"%s\", %X, %X)\n", filename,flags,mode);
//drop the request - operation not permitted
return -EPERM;
}
//continue normal routine back to original function
return (*original_sys_open)(filename,flags,mode);
}
static int init_driver(void) {
printk("load hook module\n");
//change read only area to write availability
write_cr0 (read_cr0 () & (~ 0x10000));
//save the original __NR_write pointer using uistd.h defines
original_sys_open = (void *)syscall_table[__NR_open];
//write to pointer to the fake function
syscall_table[__NR_open] = fake_sys_open;
//change the write area back to read only
write_cr0 (read_cr0 () | 0x10000);
return 0;
}
static void clean_driver(void) {
//change read only area to write availability
write_cr0 (read_cr0 () & (~ 0x10000));
//return the original pointer to the system call table
syscall_table[__NR_open] = original_sys_open;
//change the write area back to read only
write_cr0 (read_cr0 () | 0x10000);
printk("unload hook module\n");
return;
}
//pointing to custom init function when the module loaded
module_init(init_driver);
//pointing to custom cleanup function when the module unloaded
//pointing to custom cleanup function when the module unloaded
module_exit(clean_driver);
התוכנית שבדוגמה מקבלת פרמטר חיצוני, בעזרת המאקרו module_param נעביר את הנתיב של הקובץ שרוצים לנעול, כאשר נפתח קובץ במערכת מופעלת הפונקציה open ב system call , בשלב טעינת ה Module נשנה את ה Pointer לפונקציה עם פונקציה מזוייפת וכאשר ינסו לפתוח את הקובץ יקבלו שגיאה, בשאר הקבצים הפונקציה תעביר את המידע לפונקציה המוקרית כאילו כלום לא קרה.
סיכום:
השליטה על ה System Call עלולה לפתוח דלת לפיתוחים זדוניים אבל מצד שני מאפשרת שליטה מלאה על המערכת, במאמרים האחרונים ראינו כיצד ניתן לממש Object Oriented Programming בסביבת ה Kernel ובעזרת C בלבד.
בהצלחה...
סיכום:
השליטה על ה System Call עלולה לפתוח דלת לפיתוחים זדוניים אבל מצד שני מאפשרת שליטה מלאה על המערכת, במאמרים האחרונים ראינו כיצד ניתן לממש Object Oriented Programming בסביבת ה Kernel ובעזרת C בלבד.
בהצלחה...
אין תגובות:
הוסף רשומת תגובה