本文的目标是学习如何使用获取系统调用表,通过替换系统调用,可以做很多事情;想要替换系统函数首要的问题就是获取系统调用表 system call table。
演示环境:
uname -ra
Linux localhost.localdomain 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)
系统调用表,根据名字就可以猜到是一个表(实现是数组)里面放了很多的系统调用函数。
获取之后,就可以通过数组下标来寻找对用的系统函数。
下标可以通过查看内核源码得知:arch/x86/include/generated/uapi/asm/unistd_32.h
第一种:通过内核导出函数kallsyms_lookup_name获取:
- 条件:需要内核开启CONFIG_KALLSYMS配置
cat /boot/config-3.10.0-693.el7.x86_64 | grep CONFIG_KALLSYMS
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
核心代码:
//kallsyms_lookup_name need be export, need CONFIG_KALLSYMS when compile kernel
void* sys_table_addr = (void*) kallsyms_lookup_name("sys_call_table");
完整代码:
#include <linux/init.h> // 模块初始化和退出
#include <linux/module.h>
#include <linux/kallsyms.h>
// 内核的一些基本信息,主要是modinfo显示
MODULE_AUTHOR("andy");
MODULE_DESCRIPTION("test");
MODULE_LICENSE("GPL");
MODULE_VERSION("v1.1.0");
void getsystab()
{
void *sys_table_addr = (void *) kallsyms_lookup_name("sys_call_table");
if (sys_table_addr)
{
printk("addr:%p \n", sys_table_addr);
}
}
static int patch_init(void)
{
printk("[testkern]init\n");
getsystab();
return 0;
}
static void patch_exit(void){
printk("[testkern]exit\n");
return ;
}
// 入口
module_init(patch_init);
// 退出
module_exit(patch_exit);
dmesg查看执行结果:
[535528.128860] [testkern]init
[535528.131788] addr:ffffffff816beee0
第二种:通过读取system.map文件获取
本质是通过下面的命令获取
cat /boot/System.map-3.10.0-693.el7.x86_64 | grep sys_call_table
完整代码:
#include <linux/init.h> // 模块初始化和退出
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include<linux/slab.h> //kfree
#define PROC_V "/proc/version"
#define BOOT_PATH "/boot/System.map-"
#define MAX_VERSION_LEN 256
// 内核的一些基本信息,主要是modinfo显示
MODULE_AUTHOR("andy");
MODULE_DESCRIPTION("test");
MODULE_LICENSE("GPL");
MODULE_VERSION("v1.1.0");
// 主要是通过读取文件 获取内核的版本信息
char *acquire_kernel_version (char *buf) {
struct file *proc_version;
char *kernel_version;
mm_segment_t oldfs;
oldfs = get_fs();
set_fs (KERNEL_DS);
// 打开版本信息
proc_version = filp_open(PROC_V, O_RDONLY, 0);
if (IS_ERR(proc_version)