int main(int argc, char **argv) { asm("cmpl $284, %eax \n\t"); return 0; }
编译后使用objdump得到了3d 1c 01 00 00 cmp $0x11c,%eax这样的机器码/汇编码,于是我们可以断定,机器特征码为3d 1c 01 00 00 。类似的,sys_call_table的地址也可以这样来求得,不过记住,没有必要,既然你有root权限了,还有必要这样吗?
那么到底怎么做到的呢?请看模块dynamic_add_syscall:
#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/fs.h> #include <linux/proc_fs.h> unsigned long entry_addr, table_addr; unsigned long nowa_num, want_num; module_param(entry_addr, long, S_IRUSR); MODULE_PARM_DESC(entry_addr, "system call entry"); //参数保存system_call的地址 module_param(table_addr, long, S_IRUSR); MODULE_PARM_DESC(table_addr, "syscall table"); //参数保存sys_call_table的地址 module_param(nowa_num, long, S_IRUSR); MODULE_PARM_DESC(nowa_num, "system calls number"); //参数保存现有的系统调用数量 module_param(want_num, long, S_IRUSR); MODULE_PARM_DESC(want_num, "system calls number"); //参数保存希望扩充到的系统调用数量 unsigned int table_new[500] = {0x00}; //新的系统调用表 unsigned int old_table; //保存原有的系统调用表,以备恢复 unsigned int old_num; //��存原有系统调用数量,以备恢复 unsigned int old_table_i; //保存系统调用表机器码命中的偏移地址 unsigned int old_num_i; //保存系统调用数量机器码命中的偏移地址 unsigned char *entry; unsigned char *table; unsigned int orig_table; unsigned char *nowa_num_addr; unsigned int appendi; //以下的procfs文件展示了一些地址信息,包括新的系统调用表地址以及当前到达哪个系统调用号了。 static int read_syscall_info(char *page, char **start, off_t off, int count, int *eof, void *data) { int len; len = sprintf(page, "[table_addr:%p] [nowa number:%d] [please inc the value at address %p, thank you!]\n", table_new, appendi, &appendi); len -= off; *start = page + off; if (len > count) len = count; else *eof = 1; if (len < 0) len = 0; return len; } int __init rm_init(void){ unsigned int new_table = table_new; unsigned char *ntp = &new_table; unsigned char num_test_op[5] = {0}; //定义一个数组,包含了匹配的检测系统调用号范围的机器码 :3d 1c 01 00 00。 int i, j = 0, k = 0; entry = entry_addr; table = table_addr; nowa_num_addr = &nowa_num; unsigned char *want_num_addr = &want_num; orig_table = table; unsigned char *otp = &orig_table; num_test_op[0] = 0x3d; num_test_op[1] = *(nowa_num_addr+0); //这两行初始化匹配机器码 num_test_op[2] = *(nowa_num_addr+1); num_test_op[3] = 0x00; num_test_op[4] = 0x00; for (i = 0; i < nowa_num; i ++) { unsigned int *p = table+i*4; table_new[i] = *p; } appendi = i; j = 0; for (i = 0; i < 256; i ++) { if ( !j && *(entry+i+0) == num_test_op[0] && *(entry+i+1) == num_test_op[1] && *(entry+i+2) == num_test_op[2] && *(entry+i+3) == num_test_op[3] && *(entry+i+4) == num_test_op[4] ) { old_num_i = i; j = 1; *(entry+i+1) = *(want_num_addr+0); //这两行修改系统调用号的范围 *(entry+i+2) = *(want_num_addr+1); } if ( !k && *(entry+i+0) == *(otp+0) && *(entry+i+1) == *(otp+1) && *(entry+i+2) == *(otp+2) && *(entry+i+3) == *(otp+3) ) { old_table_i = i; k = 1; *(entry+i+0) = *(ntp+0); //这四行修改系统调用表的地址 *(entry+i+1) = *(ntp+1); *(entry+i+2) = *(ntp+2); *(entry+i+3) = *(ntp+3); } } //在procfs中导出一些信息,供实现新系统调用的模块参考 create_proc_read_entry("new_syscall", S_IFREG, NULL, read_syscall_info, NULL); return 0; } void __exit rm_exit(void){ //针对init的修改进行还原 unsigned char *otp = &orig_table; *(entry+old_table_i+0) = *(otp+0); *(entry+old_table_i+1) = *(otp+1); *(entry+old_table_i+2) = *(otp+2); *(entry+old_table_i+3) = *(otp+3); *(entry+old_num_i+1) = *(nowa_num_addr+0); *(entry+old_num_i+2) = *(nowa_num_addr+1); remove_proc_entry("new_syscall", NULL); } EXPORT_SYMBOL(appendi); //导出现在已经到哪个系统调用号了 module_init(rm_init); module_exit(rm_exit); MODULE_LICENSE("GPL");