系統調用表

系統調用表

系統調用表(System call Table),是一張由指向實現各種系統調用的核心函式的函式指針組成的表,該表可以基於系統調用編號進行索引,來定位函式地址,完成系統調用。

掛載驅動通過修改系統調用表的函式地址可對常用處理函式進行Hook,從而實現對一些核心的系統動作進行過濾、監控的目的。

基本介紹

  • 中文名:系統調用表
  • 外文名:System Call Table
  • 定義:系統調用編號索引,定位地址
  • 系統:Linux
  • 套用學科計算機科學
內容簡介,核心源碼定義,獲取地址,系統調用表掛鈎,

內容簡介

系統調用表是Linux核心中的一個數據結構,在系統調用過程中,最終會在核心態中查找系統調用表,藉此定位相應系統服務函式的地址。
Linux的系統調用是預先定義好的,每一個系統調用都有一個編號,在核心中有一個對應的服務函式。在Linux的發展過程中,它提供的系統調用也在不斷變化,從Linux.0的135個系統調用發展到Linux3.0的347個系統調用,系統調用表也不斷擴大。
需要注意的是,系統調用表及與其相關的若干機制並非是在CPU中實現的,而是由作業系統提供的。在Linux作業系統中,應用程式通常使用SYSENTER、SYSCALL或INT 0x80進入系統調用,核心態程式system_call(位置linux4.20版本)根據EAX中的系統調用號查找系統調用表,獲得調用號對應的服務函式,調用該函式完成系統調用的服務處理工作,如圖1所示。
系統調用表
圖1 系統調用過程

核心源碼定義

系統調用表在核心中定義為sys_call_table,由Linux核心在初始化的時候填充,從核心原始碼中可以得到它的聲明和定義,基於Linux4.20核心源碼,其定義在檔案arch\x86\um\sys_call_table_64.c中。
const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = {
       /*
        * 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>
};
系統調用號定義在 linux-4.20.4\arch\sh\include\uapi\asm\unistd_64.h,共395個系統調用。
#define __NR_restart_syscall      0
#define __NR_exit          1
#define __NR_fork          2
#define __NR_read          3
#define __NR_write          4
#define __NR_open          5
#define __NR_close          6
#define __NR_waitpid          7
#define __NR_creat          8
#define __NR_link          9
#define __NR_unlink         10
#define __NR_execve         11
#define __NR_chdir         12
#define __NR_time         13
#define __NR_mknod         14
#define __NR_chmod         15
#define __NR_lchown         16
                 /* 17 was sys_break */
#define __NR_oldstat         18
#define __NR_lseek         19
#define __NR_getpid         20
#define __NR_mount         21
#define __NR_umount         22
#define __NR_setuid         23
#define __NR_getuid         24
#define __NR_stime         25
#define __NR_ptrace         26
#define __NR_alarm         27
#define __NR_oldfstat         28
#define __NR_pause         29
#define __NR_utime         30
系統調用地址在核心編譯階段被指定,不會更改,地址在編譯階段被寫入兩個檔案,System.map: 該檔案包含所有的符號地址,系統調用也包含在內,vmlinux: 系統初始化時首先被讀入記憶體的核心映像檔案。
Linux x86_64有兩套調用模式:Long模式和兼容模式,對應有兩套調用表:system_call,ia32_syscall。
系統服務調用從系統擴展性角度而言是重要的,核心執行系統調用的方式使得新的服務可被動態地加入今後推出的作業系統中,核心通過擴充系統調用表即可支持新的系統服務,而無需改變系統或應用程式。編寫完新的服務後,系統管理員只需運行工具程式即可動態創建一個新的調度表。在新的表中將包含指向新的系統服務的另一個入口點。

獲取地址

使用命令行查看地址
cat /proc/kallsyms| grep sys_call_table
cat /boot/System.map-xx
系統調用表
核心sys_call_table地址查看

系統調用表掛鈎

可以通過修改核心符號表,替換函式地址,使其跳轉到我們自己的函式上,就可以完成劫持。Linux Rootkit多數基於修改系統調用表的系統調用掛鈎。但系統調用表所在記憶體是有防寫的,需要先去掉防寫,再做修改。
防寫指的是寫入唯讀記憶體時出錯,這個特性可以通過CR0暫存器控制:開啟或關閉,只需要修改一個比特,也就是從0開始的第16個比特。
unsigned int close_cr(void){
    unsigned int cr0 = 0;
    unsigned int ret;
    asm volatile("movq %%cr0,%%rax":"=a"(cr0));
    ret = cr0;
    cr0 &= 0xfffeffff;
    asm volatile("movq %%rax,%%cr0"::"a"(cr0));
    return ret;
}
void open_cr(unsigned int oldval){
    asm volatile("movq %%rax,%%cr0"::"a"(oldval));
}

相關詞條

熱門詞條

聯絡我們