Linux Kernel sys_call_table、Kernel Symbols Export Table Generation Principle、Difference Between System Calls Entrance In 32bit、64bit Linux


目錄

1. sys_call_table:系統調用表
2. 內核符號導出表:Kernel-Symbol-Table
3. Linux 32bit、64bit環境下系統調用入口的異同
4. Linux 32bit、64bit環境下sys_call_table replace hook

 

1. sys_call_table:系統調用表

0x1: sys_call_table簡介

sys_call_table在Linux內核中是在Linux內核中的一段連續內存的數組,數組中的每個元素保存着對應的系統調用處理函數的內存地址

1. 32bit:
cat /boot/System.map-3.13.0-32-generic | grep sys_call_table
c1663140 R sys_call_table

2. 64bit
cat /boot/System.map-2.6.32-220.23.2.ali878.el6.x86_64 | grep sys_call_table
ffffffff81600460 R sys_call_table

3. 64bit 兼容 32bit
cat /boot/System.map-2.6.32-220.23.2.ali878.el6.x86_64 | grep ia32sys_call_table
ffffffff8160a1f8 r ia32_sys_call_table

sys_call_table由Linux內核在初始化的時候填充,從內核源代碼中可以得到它的聲明和定義

1. 32bit:
/source/arch/x86/kernel/syscall_32.c
__visible const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = 
{
/*
* Smells like a compiler bug -- it doesn't work
* when the & below is removed.
*/
    [0 ... __NR_syscall_max] = &sys_ni_syscall, 
    #include <asm/syscalls_32.h>
};

2. 64bit
/source/arch/x86/kernel/syscall_64.c
asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = 
{
/*
* Smells like a compiler bug -- it doesn't work
* when the & below is removed.
*/
    [0 ... __NR_syscall_max] = &sys_ni_syscall,
    #include <asm/syscalls_64.h>
};

3. 64bit 兼容 32bit
/source/arch/x86/ia32/syscall_ia32.c
const sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = 
{
/*
* Smells like a compiler bug -- it doesn't work
* when the & below is removed.
*/
    [0 ... __NR_ia32_syscall_max] = &compat_ni_syscall,
    #include <asm/syscalls_32.h>
};

Relevant Link:

深入linux內核架構(中文版).pdf
http://www.cnblogs.com/LittleHann/p/3850653.html
http://www.cnblogs.com/LittleHann/p/3854977.html

0x2: Linux下獲取sys_call_table內核地址的方式

http://www.cnblogs.com/LittleHann/p/3854977.html
//搜索:0x3: 獲取sys_call_table的常用方法

 

2. 內核符號導出表:Kernel-Symbol-Table
驅動LKM也是存在於內核空間的,函數中的函數、變量都會有對應的符號,這部分符號也可以稱作內核符號,這些內核符號有兩種狀態

1. 導出(EXPORT_SYMBOL)
在內核代碼中明確聲明EXPORT_SYMBOL(xxxx_FUNCTION)之后,這個函數就可以作為內核對外的接口,供外部使用了。對於這部分導出的內核符號表我們稱之為"內核導出符號表"

2. 不導出
對於不導出的內核函數,只能在內核中使用

insmod的時候並不是所有的函數都得到內核符號表去尋找對應的符號,每一個驅動在自已的分配的空間里也會存在一份符號表,里面有關於這個驅動里使用到的變量以及函數的一些符號,首先驅動會在這里面找,如果發現找不到就會去公共內核符號表中搜索,搜索到了則該模塊加載成功,搜索不到則該模塊加載失敗

可以通過nm -l xx.ko來查看一個模塊里的符號情況

nm -l find_sys_call_table.ko
/*
00000000 T cleanup_module
00000030 T find_sys_call_table
000000b6 T init_module
         U loops_per_jiffy
         U mcount
00000ef8 r __module_depends
         U printk    find_sys_call_table.c:0
000000b6 t syscall_init
000001c1 t syscall_release
00000000 B syscall_table
         U sys_close
00007980 D __this_module
00000ec9 r __UNIQUE_ID_license0
00000ed5 r __UNIQUE_ID_srcversion1
00000f01 r __UNIQUE_ID_vermagic0
00003c20 r ____versions
*/

在Linux內核中,大部分的函數、變量都是導出的,我們可以通過對內核符號表的遍歷搜索得到我們想要獲得的內核函數、內核變量的地址
 

3. Linux 32bit、64bit下系統調用入口的異同

以sys_execve、sys_socketcall、sys_init_module這三個系統調用作為研究對象,為了更好的說明問題,我們打印一下Linux 64bit的sys_call_table的函數指針地址

find_sys_call_table.c

#include <linux/module.h>
#include <linux/init.h> #include <linux/types.h> #include <asm/uaccess.h> #include <asm/cacheflush.h> #include <linux/syscalls.h> #include <linux/delay.h> // loops_per_jiffy /* Just so we do not taint the kernel */ MODULE_LICENSE("GPL"); void **syscall_table; unsigned long **find_sys_call_table(void); unsigned long **find_sys_call_table() { unsigned long ptr; unsigned long *p; for (ptr = (unsigned long)sys_close; ptr < (unsigned long)&loops_per_jiffy; ptr += sizeof(void *)) { p = (unsigned long *)ptr; if (p[__NR_close] == (unsigned long)sys_close) { printk(KERN_DEBUG "Found the sys_call_table!!!\n"); return (unsigned long **)p; } } return NULL; } static int __init syscall_init(void) { int ret; unsigned long addr; unsigned long cr0; int num = 0; syscall_table = (void **)find_sys_call_table(); if (!syscall_table) { printk(KERN_DEBUG "Cannot find the system call address\n"); return -1; } do { printk("%d: the address is: %16x\n", num, syscall_table[num]); num++; } while (num < 400); return 0; } static void __exit syscall_release(void) { } module_init(syscall_init); module_exit(syscall_release);

Makefile

obj-m := find_sys_call_table.o 
PWD       := $(shell pwd) all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: rm -rf *.o *~ core .*.cmd *.mod.c ./tmp_version *.ko modules.order Module.symvers clean_omit: rm -rf *.o *~ core .*.cmd *.mod.c ./tmp_version modules.order Module.symvers

0x1: Linux 32bit

1. sys_execve

對於Linux 32bit操作系統來說,sys_execve的系統調用號、以及在它在sys_call_table中的索引位置

\linux-3.15.5\arch\sh\include\uapi\asm\unistd_32.h
#define __NR_execve         11

//系統調用處理函數在內核內存中的地址可以通過以下方式得到
cat /boot/System.map-3.13.0-32-generic | grep sys_execve
c117fc00 T sys_execve

//和sys_call_table中的函數地址進行逐行對比
cat info | grep c117fc00
[16595.247404] 11:  the address is:         c117fc00

在正常情況下(當前linux沒有被rootkit、sys_call_table沒有被hooked),sys_call_table(系統調用表)中的函數地址和內核導出符號表中的函數地址應該是相同的,即

sys_call_table[__NR_sys_execve] = cat /boot/System.map-3.13.0-32-generic | grep sys_execve

系統調用函數的入口點跟蹤如下

linux-3.15.5\fs\exec.c

SYSCALL_DEFINE3(execve,
        const char __user *, filename,
        const char __user *const __user *, argv,
        const char __user *const __user *, envp)
{
    return do_execve(getname(filename), argv, envp);
}

這是個宏定義,等價於對sys_execve的聲明

int do_execve(struct filename *filename,
    const char __user *const __user *__argv,
    const char __user *const __user *__envp)
{
    struct user_arg_ptr argv = { .ptr.native = __argv };
    struct user_arg_ptr envp = { .ptr.native = __envp };
    return do_execve_common(filename, argv, envp);
}

2. sys_socketcall

\linux-3.15.5\arch\sh\include\uapi\asm\unistd_32.h
#define __NR_socketcall        102

//系統調用處理函數在內核內存中的地址可以通過以下方式得到
cat /boot/System.map-3.13.0-32-generic | grep sys_socketcall
c1560100 T sys_socketcall

//和sys_call_table中的函數地址進行逐行對比
cat info | grep c1560100
[16595.247515] 102:  the address is:         c1560100

\linux-3.15.5\net\socket.c

/*
進行socket調用派發
*/
SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
{
    unsigned long a[AUDITSC_ARGS];
    unsigned long a0, a1;
    int err;
    unsigned int len;

    if (call < 1 || call > SYS_SENDMMSG)
        return -EINVAL;

    len = nargs[call];
    if (len > sizeof(a))
        return -EINVAL;

    /* copy_from_user should be SMP safe. */
    if (copy_from_user(a, args, len))
        return -EFAULT;

    err = audit_socketcall(nargs[call] / sizeof(unsigned long), a);
    if (err)
        return err;

    a0 = a[0];
    a1 = a[1];

    switch (call) {
    case SYS_SOCKET:
        err = sys_socket(a0, a1, a[2]);
        break;
    case SYS_BIND:
        err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
        break;
    case SYS_CONNECT:
        err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
        break;
    case SYS_LISTEN:
        err = sys_listen(a0, a1);
        break;
    case SYS_ACCEPT:
        err = sys_accept4(a0, (struct sockaddr __user *)a1,
                  (int __user *)a[2], 0);
        break;
    case SYS_GETSOCKNAME:
        err =
            sys_getsockname(a0, (struct sockaddr __user *)a1,
                    (int __user *)a[2]);
        break;
    case SYS_GETPEERNAME:
        err =
            sys_getpeername(a0, (struct sockaddr __user *)a1,
                    (int __user *)a[2]);
        break;
    case SYS_SOCKETPAIR:
        err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]);
        break;
    case SYS_SEND:
        err = sys_send(a0, (void __user *)a1, a[2], a[3]);
        break;
    case SYS_SENDTO:
        err = sys_sendto(a0, (void __user *)a1, a[2], a[3],
                 (struct sockaddr __user *)a[4], a[5]);
        break;
    case SYS_RECV:
        err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
        break;
    case SYS_RECVFROM:
        err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
                   (struct sockaddr __user *)a[4],
                   (int __user *)a[5]);
        break;
    case SYS_SHUTDOWN:
        err = sys_shutdown(a0, a1);
        break;
    case SYS_SETSOCKOPT:
        err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);
        break;
    case SYS_GETSOCKOPT:
        err =
            sys_getsockopt(a0, a1, a[2], (char __user *)a[3],
                   (int __user *)a[4]);
        break;
    case SYS_SENDMSG:
        err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
        break;
    case SYS_SENDMMSG:
        err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
        break;
    case SYS_RECVMSG:
        err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
        break;
    case SYS_RECVMMSG:
        err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
                   (struct timespec __user *)a[4]);
        break;
    case SYS_ACCEPT4:
        err = sys_accept4(a0, (struct sockaddr __user *)a1,
                  (int __user *)a[2], a[3]);
        break;
    default:
        err = -EINVAL;
        break;
    }
    return err;
}

3. sys_init_module

\linux-3.15.5\arch\sh\include\uapi\asm\unistd_32.h
#define __NR_init_module    128

//系統調用處理函數在內核內存中的地址可以通過以下方式得到
cat /boot/System.map-3.13.0-32-generic | grep sys_init_module
c10c4820 T sys_init_module

//和sys_call_table中的函數地址進行逐行對比
cat info | grep c10c4820
[16595.247540] 128:  the address is:         c10c4820

\linux-3.15.5\kernel\module.c

SYSCALL_DEFINE3(init_module, void __user *, umod,
        unsigned long, len, const char __user *, uargs)
{
    int err;
    struct load_info info = { };

    err = may_init_module();
    if (err)
        return err;

    pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n", umod, len, uargs);

    err = copy_module_from_user(umod, len, &info);
    if (err)
        return err;

    return load_module(&info, uargs, 0);
}

0x2: Linux 64bit

在Linux 64bit下,系統調用的入口點和32bit下有一點區別

1. sys_execve

/source/arch/x86/syscalls/syscall_64.tbl
#
# 64-bit system call numbers and entry vectors
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The abi is "common", "64" or "x32" for this file.
59      64      execve                  stub_execve

//在內核符號導出表中得到的內核內存地址
cat /boot/System.map-2.6.32-220.23.2.ali878.el6.x86_64 | grep stub_execve
ffffffff8100b4e0 T stub_execve
cat /boot/System.map-2.6.32-220.23.2.ali878.el6.x86_64 | grep sys_execve
ffffffff810095b0 T sys_execve

//在sys_call_table中搜索系統調用函數地址
cat info | grep 8100b4e0: [10298.905575] 59:  the address is:         8100b4e0
cat info | grep 810095b0: no result

//對於64bit的Linux系統來說,在系統調用外層使用了stub(wrapper functions)
\linux-3.15.5\arch\x86\kernel\entry_64.S
ENTRY(stub_execve)
    CFI_STARTPROC
    addq $8, %rsp
    PARTIAL_FRAME 0
    SAVE_REST
    FIXUP_TOP_OF_STACK %r11
    call sys_execve
    movq %rax,RAX(%rsp)
    RESTORE_REST
    jmp int_ret_from_sys_call
    CFI_ENDPROC
END(stub_execve)

在Linux 64bit下,stub_execve就是sys_execve的wrapper函數

/source/arch/x86/um/sys_call_table_64.c

#define stub_execve sys_execve

這也意味着在Linux 64bit下,sys_execeve在sys_call_table里不存在了,而是用stub_execve取代了,我們的hook對象也就是stub_execve

2. sys_socketcall

sys_socketcall 只適用於x86-32平台下適用,在非x86-32平台下,sys_socketcall是不存在的,Linux 64bit將sys_socketcall的"系統調用派發機制"拆分成了分別獨立的系統調用,例如sys_socket、sys_bind、 sys_connect

//找到Linux 64bit對應的unistd_64.h文件
find /usr/src/kernels/`uname -r` -name unistd_64.h
vim /usr/src/kernels/2.6.32-220.23.2.ali878.el6.x86_64/arch/x86/include/asm/unistd_64.h

1. sys_socket
cat /boot/System.map-2.6.32-220.23.2.ali878.el6.x86_64 | grep sys_socket
ffffffff8140a210 T sys_socket
cat info | grep 8140a210
[924227.139549] 41:  the address is:         8140a210
cat /usr/src/kernels/2.6.32-220.23.2.ali878.el6.x86_64/arch/x86/include/asm/unistd_64.h | grep __NR_socket
#define __NR_socket                             41
__SYSCALL(__NR_socket, sys_socket)


2. sys_connect
cat /boot/System.map-2.6.32-220.23.2.ali878.el6.x86_64 | grep sys_connect
ffffffff8140bfb0 T sys_connect
[924227.139550] 42:  the address is:         8140bfb0
cat /usr/src/kernels/2.6.32-220.23.2.ali878.el6.x86_64/arch/x86/include/asm/unistd_64.h | grep __NR_connect
#define __NR_connect                42
__SYSCALL(__NR_connect, sys_connect)


3. sys_bind
cat /boot/System.map-2.6.32-220.23.2.ali878.el6.x86_64 | grep sys_bind
ffffffff8140c0a0 T sys_bind
[924227.139558] 49:  the address is:         8140c0a0
cat /usr/src/kernels/2.6.32-220.23.2.ali878.el6.x86_64/arch/x86/include/asm/unistd_64.h | grep __NR_bind
#define __NR_bind                49
__SYSCALL(__NR_bind, sys_bind)

在Linux 64bit環境下,可以直接針對sys_connect(即TCP_CONNECT動作進行監控)

3. sys_init_module

//找到Linux 64bit對應的unistd_64.h文件
find /usr/src/kernels/`uname -r` -name unistd_64.h
vim /usr/src/kernels/2.6.32-220.23.2.ali878.el6.x86_64/arch/x86/include/asm/unistd_64.h

cat /boot/System.map-2.6.32-220.23.2.ali878.el6.x86_64 | grep sys_init_module
ffffffff810afe50 T sys_init_module
cat info | grep 810afe50
[924227.139712] 175:  the address is:         810afe50

cat /usr/src/kernels/2.6.32-220.23.2.ali878.el6.x86_64/arch/x86/include/asm/unistd_64.h | grep __NR_init_module
#define __NR_init_module                        175
__SYSCALL(__NR_init_module, sys_init_module)

Relevant Link:

http://stackoverflow.com/questions/9940391/looking-for-a-detailed-document-on-linux-system-calls

 

4. Linux 32bit、64bit環境下sys_call_table replace hook:建立通用兼容性的sys_call_table Replace Hook Engine

0x1: Linux 32/64bit Hook Point

1. 32bit
    1) sys_execve
    2) sys_socketcall
    3) sys_init_module
2. 64bit
    1) stub_execve
    2) sys_connect
    3) sys_init_module

0x2: Linux 32/64bit __NR_XX定義的異同

在進行sys_call_table replace hook的時候,我們往往需要借助系統頭文件<asm/unistd.h>的__NR_XX宏定義來定位尋址到我們要hook的目標系統調用處理函數,需要注意的是,這個宏定義在32/64bit的Linux上存在着一些差異,我們在編寫sys_call_table hook engine的時候需要特別注意這塊的兼容性

print_NR.c

#include <asm/unistd.h>
#include <linux/module.h>    // included for all kernel modules
#include <linux/kernel.h>    // included for KERN_INFO
#include <linux/init.h>        // included for __init and __exit macros
 
static int __init hello_init(void)
{ 
    //在32bit Linux下編譯(未做跨平台兼容)
    /*
    printk("__NR_execve: %d\n", __NR_execve);
    printk("__NR_socketcall: %d\n", __NR_socketcall);
    printk("__NR_init_module: %d\n", __NR_init_module);
    */

    //在64bit Linux下編譯(未做跨平台兼容)
    printk("__NR_execve: %d\n", __NR_execve); 
    printk("__NR_connect: %d\n", __NR_connect);
    printk("__NR_init_module: %d\n", __NR_init_module);
 
    printk(KERN_INFO "Hello world!\n"); 
    return 0;    // Non-zero return means that the module couldn't be loaded.
}
 
static void __exit hello_cleanup(void)
{
    printk(KERN_INFO "Cleaning up module.\n");
}
 
module_init(hello_init);
module_exit(hello_cleanup);

在Linux 32bit、Linux 64bit環境下分別作編譯,結果如下

1. 32 bit
[22726.762562] __NR_execve: 11: sys_execve
[22726.762570] __NR_socketcall: 102: sys_socketcall
[22726.762573] __NR_init_module: 128: sys_init_module

2. 64 bit
[ 2295.036784] __NR_execve: 59: stub_execve
[ 2295.036785] __NR_connect: 42: sys_connect
[ 2295.036786] __NR_init_module: 175: sys_init_module

從結果上來看,_NR_XX宏定義的打印結果和我們的調研結果是一致的,所不同的是在32、64環境下系統調用對應的__NR_XX宏定義名字不同了

0x3: Linux 64bit 環境下 sys_execve hook特殊處理

為了充分利用Linux 64bit下的寄存器資源、以及提高Linux 64bit針對進程執行系統調用的執行效率,Linux 64bit內核針對sys_execve進行了特殊處理,使用了"wrapper function":stub_execve,對sys_execve進行了包裝

\linux-3.15.5\arch\x86\kernel\entry_64.S
ENTRY(stub_execve)
    /*
    匯編代碼對rsp,堆棧參數尋址寄存器進行了修正
    說明內核在進入stub_execve之前,rsp本身就是"不准確"的,需要進行修正,而rsp不准確也意味着棧上參數尋址是不准確的,這直接帶來一個問題就是我們進行replace hook的fake_xxx_function不能簡單的直接使用函數聲明中傳遞進來的參數
    */
    CFI_STARTPROC
    addq $8, %rsp 
    PARTIAL_FRAME 0
    SAVE_REST
    FIXUP_TOP_OF_STACK %r11

    //修復棧、寄存器狀態之后,進入真正的sys_execve系統調用
    call sys_execve

    movq %rax,RAX(%rsp)
    RESTORE_REST
    jmp int_ret_from_sys_call
    CFI_ENDPROC
END(stub_execve)

在Linux 64bit環境下,我們對sys_call_table[__NR_execve]進行replace hook之后,我們在fake_sys_execve中得到的參數不是准確的,因為這個時候rsp是不准確的,解決這個問題的思路有兩個

1. 在fake_sys_execve中使用"inline asm 內聯匯編"的方式,模仿stub_execve在進入sys_execve之前所做的事情
/*
這種方式需要在內核代碼中插入大量的匯編
並且承當更大的兼容性風險
*/

2. 直接對sys_execve進行"inline hook"
    1) 通過kprobe監控sys_execve的系統調用,使用爭奪自旋鎖的方式強制當前所有CPU等待"inline hook"的地址替換動作完成
    2) 通過kprobe獲取到sys_execve在內核中的函數地址
    3) 直接拷貝sys_execve入口點開始的9字節的字節碼,將這9字節字節碼替換為:jmp fake_sys_execve(總共9字節)
    4) 在fake_sys_execve中,將竊取的原始的sys_execve入口點的匯編字節碼重新執行一次
    5) 由於fake_sys_execve是inline hook到sys_execve中的,所以這個時候fake_sys_execve可以直接使用sys_execve的棧上的參數,這個時候,我們就可以正常執行fake_sys_execve的主體代碼
    5) 當fake_sys_execve執行完畢之后,直接跳回到之前sys_execve開頭那段被替換的地址之后的第一條指令,繼續執行即可
/*
使用inline hook需要重點關注的問題就是:
    1) "inline hook"的關鍵動作是一段內核內存地址的替換過程
    2) 大多數情況下這個地址替換過程需要消耗超過1條的CPU指令去完成
    3) 在多線程/多CPU情況下,CPU在執行多條指令的期間可能會被打斷,從而破壞"inline hook"這個過程的一致性,可能導致地址替換失敗
    4) 需要使用自旋鎖的機制強制保證這個地址替換(hook)的過程的"原子性"
*/

0x4: 模塊卸載時舊的函數調用的返回導致的"bad memory address access"問題

模塊在卸載的時候有可能有之前舊的用戶態習系統調用請求hung在當前我們的hook模塊中,不能直接粗暴的rmmod,否則會引起原始函數返回后ret到一塊"not valid memory"中,解決這個問題的方案是采用內聯匯編,構造直接返回的棧狀態,下圖解釋

因為Linux GCC不支持nick裸函數,所以我們不能直接push origin_func、ret的方式構造特殊的棧狀態,跳轉到原始系統調用函數中

if(sizeof(void*)==4)
{ 
    asm volatile ("movl %1,%%eax \n movl %%eax,%0":"=r"(old_func):"r"(old_func));
    asm volatile (".intel_syntax");//這里換用intel語法,gas語法簡直不是給人用的
    asm volatile ("mov %esp,%ebp");
    asm volatile ("pop %ebp");//現在ebp的原始值已經被恢復了
    asm volatile (".att_syntax");//換回gas的att語法
    asm volatile ("pushl %eax");
    asm volatile ("ret");
}else
{ 
    asm volatile ("movq %1,%%rax \n movq %%rax,%0":"=r"(old_func):"r"(old_func));
    asm volatile (".intel_syntax");//這里換用intel語法,gas語法簡直不是給人用的
    asm volatile ("mov %rsp,%rbp");
    asm volatile ("pop %rbp");
    asm volatile (".att_syntax");//換回gas的att語法
    asm volatile ("pushq %rax");
    asm volatile ("ret");
}

0x5:  動態獲取系統調用函數在sys_call_table中的索引號

1. 獲取"kallsyms_lookup_name"的函數地址
    1) 如果linux內核直接導出了這個函數,則可以直接使用
    2) 或者使用kprobe機制去獲取這個函數的地址
        2.1) kprobe注冊"kallsyms_lookup_name"
        2.2) 獲取kprobe注冊后的函數地址
        2.3) kprobe解除注冊
2. 調用kallsyms_lookup_name()獲取我們要HOOK的函數在內核符號導出表的地址: hook_func_address
3. 使用kallsyms_lookup_name()獲取sys_call_table的內核地址
3. 將hook_func_address在sys_call_table中逐行遍歷,得到對應的偏移索引號
4. 使用動態獲取的索引號進行sys_call_table replace hook

0x6: 總結

/*
sys_call_table replace hook: 要解決的問題是讓原始系統調用直接返回用戶態系統調用的入口點之后
inline hook: 要解決的問題是保證地址替換的過程的原子性
*/
1. 32 bit
sys_execve: sys_call_table replace hook
sys_socketcall: sys_call_table replace hook
sys_init_module: sys_call_table replace hook

2. 64 bit
stub_execve: inline hook
sys_connect: sys_call_table replace hook
sys_init_module: sys_call_table replace hook

 

Copyright (c) 2014 LittleHann All rights reserved

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM