יום שישי, 15 בנובמבר 2013

Kernel Hooking



זאת לא הפעם הראשונה שאני כותב על 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 של הפונקציה החדשה ממקום הפונקציה הישנה.

#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;
}
//pointing to custom init function when the module loaded
module_init(init_driver);

//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 בלבד.

בהצלחה...

אין תגובות:

הוסף רשומת תגובה