动态模块和篡改系统调用

内核模块工作在内核空间(supervisor space),而应用程序工作在用户空间(user space)。内核模块是一个由多个回调函数组成的“被动”代码集合体,采用了“事件驱动模型”;而应用程序总是从头至尾的执行单个任务。内核模块不能调用C标准函数库(glibc库),只能调用linux内核导出的内核函数 内核模块在编程时必须考虑可重入性(reentrant),内核模块可使用的栈很小(一般只有4096字节) 。

内核驱动模块的创建与加载

创建动态模块源码 修改Makefile文件生成编译规则 编译创建的模块源码,生成驱动模块 安装驱动模块 查看是否安装成功 使用驱动模块 卸载驱动模块 在编写驱动程序的时候,需要注意的一点是,老版本的内核驱动编译可以允许不写入modinfo数据。高版本内核是需要进行填写的,如果不写,那么将会编译不能通过。

MODULE_AUTHOR(""); 模块作者MODULE_DESCRIPTION(""); 模块描述MODULE_ALIAS(""); 模块别名MODULE_LICENSE(""); 开源协议

模块的操作

模块的编译

V2.4 #gcc −O2 −g −Wall −DMODULE −D KERNEL −c filename.c // filename.c为自己编写的模块程序源代码文件

V2.6 当前目录建立Makefile文件 执行make即可按照Makefile的规定进行编译,形成.ko模块文件

模块的加载 insmod命令 如: insmod filename.ko 或insmod filename.o

模块的查看 lsmod more /proc/modules dmesg ——查看日志(printk)

模块的卸载 rmmod命令 如:rmmod filename

编写简单模块mymodules.c

#include <linux/init.h>                                            /*必须要包含的头文件*/ 
#include <linux/kernel.h> 
#include <linux/module.h>                                    /*必须要包含的头文件*/ 
static int mymodule_init(void)                                //模块初始化函数 
{   
    printk("hello,my module wored! \n");
    /*输出信息到内核日志*/   
    return 0; 
} 
static void mymodule_exit(void) //模块清理函数 
{    
    printk("goodbye,unloading my module.\n");         
    /*输出信息到内核日志*/ 
}   
module_init(mymodule_init);                                //注册初始化函数 
module_exit(mymodule_exit);                              
//注册清理函数 
MODULE_LICENSE("GPL");                              
//模块许可声明 

makefile文件

ifneq ($(KERNELRELEASE),) 
obj-m := mymodules.o       
#obj-m指编译成外部模块 
else 
KERNELDIR := /lib/modules/$(shell uname -r)/build  
#定义一个变量,指向内核目录 
PWD := $(shell pwd)  
modules:         
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
#编译内核模块  
endif 

编译模块

#make

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hCMCBR5X-1639148863375)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=YjY1YTUzMzA1YmU2ZjBjMzNhZmIxNWJjNjVhOTU0OTVfWmdQRHF5c1B6OElhaVFQT3J4SDRJYWJYWUNHQjkzV2ZfVG9rZW46Ym94Y25IS2o4RGF6ZmVpdGo5cFdtbklXdTB6XzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

#ls

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lYcI8BGg-1639148863376)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=Yjg2NGU1YzNmN2RkYzg2ZTA4MmVjYjU1ZmE2YWU5MTFfUWF1aHQwS1J2MXh5bGZKVEhhdENCckVxQnFtSElYamJfVG9rZW46Ym94Y244dmhtRThUdkV5c2J1a0ROa0I5V0NnXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

文件列表包含 mymodules.ko

加载内核模块

#insmod ./mymodules.ko

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SVzuAd9P-1639148863377)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=NmZjMGQwNDJhOWZkYWJmYzUwYmVhYWVkMGY4MDUxYTJfdm90VWVndXBkR3c3MDlLNXV3UWV3aTg4MW5DUWhUMjdfVG9rZW46Ym94Y25SZnladkJKZ2hDVnVDalllR2tmOW9oXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

需要root权限

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bHKxKdHq-1639148863377)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=ODEyM2NmM2UwN2RjZjFlYWMxY2ZlZGVhNjZlZDAwZGJfNVFtcjBBQkZrc2RoMU41cGxxZkhjT3hXOUh5SkFXUDhfVG9rZW46Ym94Y25ldnlDVnZERVZCV3ZCamdPQUk3dnNmXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

使用 lsmod 命令来查看系统内的模块列表,以观察新设计的模块加载情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0p9tcuHr-1639148863378)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=Y2ZhODYxYTNhNTM3NTA1YjM5NjYyZDdjNzRiMzRmZWZfeGRNVkZOZk1HaFNFWWFHWGo0TG1yMFhrd05LaldSUXlfVG9rZW46Ym94Y24zdmpveTl5c3hhRVJHdlR6TEpWZkJiXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

mymodules 即为新加载的内核动态模块

或者查看内核日志信息,执行:

#dmesg –c

此时可以看到内核日志信息:hello,my module was loaded!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UoqMTb8M-1639148863378)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=NWNhNDM0NTE5MmQyY2FmMGMxZTk1NmViMTE2YjJlMDdfNU0za25tdEVZb2JLRHoycHV1MjZXdTlQRmlxYXpzeUZfVG9rZW46Ym94Y25lYm0yMWVkZnZCM0JNQUNsc3pPZUZnXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

卸载动态模块

#rmmod mymodules

lsmod查看,已经没有了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-83FTBuLa-1639148863379)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=MjIzMzc2Y2VjOTVkMGQ2MGZlZWU1MDE4MDBhMTMyNjVfcVR0bjZHV3pENGJMQjZJbVk4WEt0RmcwUnZ4TFlQNUdfVG9rZW46Ym94Y25LQmdXVlJhVENyTkNJelRRamo2b3FlXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

查看dmesg,已经卸载。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-esJQn2jv-1639148863379)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=OGQ1ODZlZjA4MWIwZjFkOWU2ZmZlMjQ3NTRhZTdkNzdfZDVtbUVUMFNKS09xVlFISWd1QzdQNWhoQnMzOTFYdmtfVG9rZW46Ym94Y25Fc3NFVnB6T2gyQmhyakxZWkh1M1JlXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

篡改系统调用

(39条消息) Linux 系统调用(二)——使用内核模块添加系统调用(无需编译内核)_金荣的个人技术博客-CSDN博客_内核模块添加系统调用

本实验在Ubuntu12.04下进行。

系统调用号

Linux操作系统利用系统调用号来标识系统调用,每一个系统调用对应唯一的一个系统调用号。使用sudo find / -name unistd_64.h查找预留系统调用号。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lLMx6SuE-1639148863380)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=ZTEyZmM5ZmI3ODYwMjk0YjE3MWMxYmExMjUzMmNlYTdfVGk2bUN6WWVOT0JQSnloV1diOWlNMWp0WmpEaHY1bERfVG9rZW46Ym94Y25FdHlJQVEyb3c2QllwS2h6TE1LRVFoXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

使用uname -r查看内核版

打开unistd_64.h,内容如下。

#ifndef __ASM_SH_UNISTD_64_H
#define __ASM_SH_UNISTD_64_H

/*
 * include/asm-sh/unistd_64.h
 *
 * This file contains the system call numbers.
 *
 * Copyright (C) 2000, 2001  Paolo Alberelli
 * Copyright (C) 2003 - 2007 Paul Mundt
 * Copyright (C) 2004  Sean McGoogan
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#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
                                 /* 31 was sys_stty */
                                 /* 32 was sys_gtty */
#define __NR_access                 33
#define __NR_nice                 34
                                 /* 35 was sys_ftime */
#define __NR_sync                 36
#define __NR_kill                 37
#define __NR_rename                 38
#define __NR_mkdir                 39
#define __NR_rmdir                 40
#define __NR_dup                 41
#define __NR_pipe                 42
#define __NR_times                 43
                                 /* 44 was sys_prof */
#define __NR_brk                 45
#define __NR_setgid                 46
#define __NR_getgid                 47
#define __NR_signal                 48
#define __NR_geteuid                 49
#define __NR_getegid                 50
#define __NR_acct                 51
#define __NR_umount2                 52
                                 /* 53 was sys_lock */
#define __NR_ioctl                 54
#define __NR_fcntl                 55
                                 /* 56 was sys_mpx */
#define __NR_setpgid                 57
                                 /* 58 was sys_ulimit */
                                 /* 59 was sys_olduname */
#define __NR_umask                 60
#define __NR_chroot                 61
#define __NR_ustat                 62
#define __NR_dup2                 63
#define __NR_getppid                 64
#define __NR_getpgrp                 65
#define __NR_setsid                 66
#define __NR_sigaction                 67
#define __NR_sgetmask                 68
#define __NR_ssetmask                 69
#define __NR_setreuid                 70
#define __NR_setregid                 71
#define __NR_sigsuspend                 72
#define __NR_sigpending                 73
#define __NR_sethostname         74
#define __NR_setrlimit                 75
#define __NR_getrlimit                 76        /* Back compatible 2Gig limited rlimit */
#define __NR_getrusage                 77
#define __NR_gettimeofday         78
#define __NR_settimeofday         79
#define __NR_getgroups                 80
#define __NR_setgroups                 81
                                 /* 82 was sys_select */
#define __NR_symlink                 83
#define __NR_oldlstat                 84
#define __NR_readlink                 85
#define __NR_uselib                 86
#define __NR_swapon                 87
#define __NR_reboot                 88
#define __NR_readdir                 89
#define __NR_mmap                 90
#define __NR_munmap                 91
#define __NR_truncate                 92
#define __NR_ftruncate                 93
#define __NR_fchmod                 94
#define __NR_fchown                 95
#define __NR_getpriority         96
#define __NR_setpriority         97
                                 /* 98 was sys_profil */
#define __NR_statfs                 99
#define __NR_fstatfs                100
                                /* 101 was sys_ioperm */
#define __NR_socketcall                102        /* old implementation of socket systemcall */
#define __NR_syslog                103
#define __NR_setitimer                104
#define __NR_getitimer                105
#define __NR_stat                106
#define __NR_lstat                107
#define __NR_fstat                108
#define __NR_olduname                109
                                /* 110 was sys_iopl */
#define __NR_vhangup                111
                                /* 112 was sys_idle */
                                /* 113 was sys_vm86old */
#define __NR_wait4                114
#define __NR_swapoff                115
#define __NR_sysinfo                116
#define __NR_ipc                117
#define __NR_fsync                118
#define __NR_sigreturn                119
#define __NR_clone                120
#define __NR_setdomainname        121
#define __NR_uname                122
#define __NR_cacheflush                123
#define __NR_adjtimex                124
#define __NR_mprotect                125
#define __NR_sigprocmask        126
                                /* 127 was sys_create_module */
#define __NR_init_module        128
#define __NR_delete_module        129
                                /* 130 was sys_get_kernel_syms */
#define __NR_quotactl                131
#define __NR_getpgid                132
#define __NR_fchdir                133
#define __NR_bdflush                134
#define __NR_sysfs                135
#define __NR_personality        136
                                /* 137 was sys_afs_syscall */
#define __NR_setfsuid                138
#define __NR_setfsgid                139
#define __NR__llseek                140
#define __NR_getdents                141
#define __NR__newselect                142
#define __NR_flock                143
#define __NR_msync                144
#define __NR_readv                145
#define __NR_writev                146
#define __NR_getsid                147
#define __NR_fdatasync                148
#define __NR__sysctl                149
#define __NR_mlock                150
#define __NR_munlock                151
#define __NR_mlockall                152
#define __NR_munlockall                153
#define __NR_sched_setparam                154
#define __NR_sched_getparam                155
#define __NR_sched_setscheduler                156
#define __NR_sched_getscheduler                157
#define __NR_sched_yield                158
#define __NR_sched_get_priority_max        159
#define __NR_sched_get_priority_min        160
#define __NR_sched_rr_get_interval        161
#define __NR_nanosleep                162
#define __NR_mremap                163
#define __NR_setresuid                164
#define __NR_getresuid                165
                                /* 166 was sys_vm86 */
                                /* 167 was sys_query_module */
#define __NR_poll                168
#define __NR_nfsservctl                169
#define __NR_setresgid                170
#define __NR_getresgid                171
#define __NR_prctl              172
#define __NR_rt_sigreturn        173
#define __NR_rt_sigaction        174
#define __NR_rt_sigprocmask        175
#define __NR_rt_sigpending        176
#define __NR_rt_sigtimedwait        177
#define __NR_rt_sigqueueinfo        178
#define __NR_rt_sigsuspend        179
#define __NR_pread64                180
#define __NR_pwrite64                181
#define __NR_chown                182
#define __NR_getcwd                183
#define __NR_capget                184
#define __NR_capset                185
#define __NR_sigaltstack        186
#define __NR_sendfile                187
                                /* 188 reserved for getpmsg */
                                /* 189 reserved for putpmsg */
#define __NR_vfork                190
#define __NR_ugetrlimit                191        /* SuS compliant getrlimit */
#define __NR_mmap2                192
#define __NR_truncate64                193
#define __NR_ftruncate64        194
#define __NR_stat64                195
#define __NR_lstat64                196
#define __NR_fstat64                197
#define __NR_lchown32                198
#define __NR_getuid32                199
#define __NR_getgid32                200
#define __NR_geteuid32                201
#define __NR_getegid32                202
#define __NR_setreuid32                203
#define __NR_setregid32                204
#define __NR_getgroups32        205
#define __NR_setgroups32        206
#define __NR_fchown32                207
#define __NR_setresuid32        208
#define __NR_getresuid32        209
#define __NR_setresgid32        210
#define __NR_getresgid32        211
#define __NR_chown32                212
#define __NR_setuid32                213
#define __NR_setgid32                214
#define __NR_setfsuid32                215
#define __NR_setfsgid32                216
#define __NR_pivot_root                217
#define __NR_mincore                218
#define __NR_madvise                219

/* Non-multiplexed socket family */
#define __NR_socket                220
#define __NR_bind                221
#define __NR_connect                222
#define __NR_listen                223
#define __NR_accept                224
#define __NR_getsockname        225
#define __NR_getpeername        226
#define __NR_socketpair                227
#define __NR_send                228
#define __NR_sendto                229
#define __NR_recv                230
#define __NR_recvfrom                231
#define __NR_shutdown                232
#define __NR_setsockopt                233
#define __NR_getsockopt                234
#define __NR_sendmsg                235
#define __NR_recvmsg                236

/* Non-multiplexed IPC family */
#define __NR_semop                237
#define __NR_semget                238
#define __NR_semctl                239
#define __NR_msgsnd                240
#define __NR_msgrcv                241
#define __NR_msgget                242
#define __NR_msgctl                243
#define __NR_shmat                244
#define __NR_shmdt                245
#define __NR_shmget                246
#define __NR_shmctl                247

#define __NR_getdents64                248
#define __NR_fcntl64                249
                                /* 250 is reserved for tux */
                                /* 251 is unused */
#define __NR_gettid                252
#define __NR_readahead                253
#define __NR_setxattr                254
#define __NR_lsetxattr                255
#define __NR_fsetxattr                256
#define __NR_getxattr                257
#define __NR_lgetxattr                258
#define __NR_fgetxattr                269
#define __NR_listxattr                260
#define __NR_llistxattr                261
#define __NR_flistxattr                262
#define __NR_removexattr        263
#define __NR_lremovexattr        264
#define __NR_fremovexattr        265
#define __NR_tkill                266
#define __NR_sendfile64                267
#define __NR_futex                268
#define __NR_sched_setaffinity        269
#define __NR_sched_getaffinity        270
                                /* 271 is reserved for set_thread_area */
                                /* 272 is reserved for get_thread_area */
#define __NR_io_setup                273
#define __NR_io_destroy                274
#define __NR_io_getevents        275
#define __NR_io_submit                276
#define __NR_io_cancel                277
#define __NR_fadvise64                278
                                /* 279 is unused */
#define __NR_exit_group                280

#define __NR_lookup_dcookie        281
#define __NR_epoll_create        282
#define __NR_epoll_ctl                283
#define __NR_epoll_wait                284
#define __NR_remap_file_pages        285
#define __NR_set_tid_address        286
#define __NR_timer_create        287
#define __NR_timer_settime        (__NR_timer_create+1)
#define __NR_timer_gettime        (__NR_timer_create+2)
#define __NR_timer_getoverrun        (__NR_timer_create+3)
#define __NR_timer_delete        (__NR_timer_create+4)
#define __NR_clock_settime        (__NR_timer_create+5)
#define __NR_clock_gettime        (__NR_timer_create+6)
#define __NR_clock_getres        (__NR_timer_create+7)
#define __NR_clock_nanosleep        (__NR_timer_create+8)
#define __NR_statfs64                296
#define __NR_fstatfs64                297
#define __NR_tgkill                298
#define __NR_utimes                299
#define __NR_fadvise64_64        300
                                /* 301 is reserved for vserver */
                                /* 302 is reserved for mbind */
                                /* 303 is reserved for get_mempolicy */
                                /* 304 is reserved for set_mempolicy */
#define __NR_mq_open            305
#define __NR_mq_unlink          (__NR_mq_open+1)
#define __NR_mq_timedsend       (__NR_mq_open+2)
#define __NR_mq_timedreceive    (__NR_mq_open+3)
#define __NR_mq_notify          (__NR_mq_open+4)
#define __NR_mq_getsetattr      (__NR_mq_open+5)
                                /* 311 is reserved for kexec */
#define __NR_waitid                312
#define __NR_add_key                313
#define __NR_request_key        314
#define __NR_keyctl                315
#define __NR_ioprio_set                316
#define __NR_ioprio_get                317
#define __NR_inotify_init        318
#define __NR_inotify_add_watch        319
#define __NR_inotify_rm_watch        320
                                /* 321 is unused */
#define __NR_migrate_pages        322
#define __NR_openat                323
#define __NR_mkdirat                324
#define __NR_mknodat                325
#define __NR_fchownat                326
#define __NR_futimesat                327
#define __NR_fstatat64                328
#define __NR_unlinkat                329
#define __NR_renameat                330
#define __NR_linkat                331
#define __NR_symlinkat                332
#define __NR_readlinkat                333
#define __NR_fchmodat                334
#define __NR_faccessat                335
#define __NR_pselect6                336
#define __NR_ppoll                337
#define __NR_unshare                338
#define __NR_set_robust_list        339
#define __NR_get_robust_list        340
#define __NR_splice                341
#define __NR_sync_file_range        342
#define __NR_tee                343
#define __NR_vmsplice                344
#define __NR_move_pages                345
#define __NR_getcpu                346
#define __NR_epoll_pwait        347
#define __NR_utimensat                348
#define __NR_signalfd                349
#define __NR_timerfd_create        350
#define __NR_eventfd                351
#define __NR_fallocate                352
#define __NR_timerfd_settime        353
#define __NR_timerfd_gettime        354
#define __NR_signalfd4                355
#define __NR_eventfd2                356
#define __NR_epoll_create1        357
#define __NR_dup3                358
#define __NR_pipe2                359
#define __NR_inotify_init1        360
#define __NR_preadv                361
#define __NR_pwritev                362
#define __NR_rt_tgsigqueueinfo        363
#define __NR_perf_event_open        364
#define __NR_recvmmsg                365
#define __NR_accept4                366
#define __NR_fanotify_init        367
#define __NR_fanotify_mark        368
#define __NR_prlimit64                369
#define __NR_name_to_handle_at        370
#define __NR_open_by_handle_at        371
#define __NR_clock_adjtime        372
#define __NR_syncfs                373
#define __NR_sendmmsg                374
#define __NR_setns                375
#define __NR_process_vm_readv        376
#define __NR_process_vm_writev        377
#define __NR_kcmp                378
#define __NR_finit_module        379

#define NR_syscalls 380

#endif /* __ASM_SH_UNISTD_64_H */

其中321号系统调用没有使用,可以篡改此调用号。

系统调用表

Linux操作系统利用函数指针数组保存系统调用服务程序的地址,这个数组成为系统调用表(sys_call_table)。使用/proc/kallsyms获取系统调用表的首地址,命令为sudo cat /proc/kallsyms | grep sys_call_table,结果如图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xn130guP-1639148863380)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=ZDU0NDY5MGUzOGU0MDFjMGExNDUxOTA4NGNhM2Q2OGZfdk5ocUNrZm9GZEhQMHdhY2htVDVZcm9lNUR4N05KcG5fVG9rZW46Ym94Y25kOTBNM1J3b2tWdXhTTDJ0UEk2TmhmXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

可以看到地址为ffffffff81801420

建立模块源

编写程序 modify_syscall.c

修改控制寄存器

在上面符号表中查阅sys_call_table的地址时,c1630060 R sys_call_table里面的R代表的是可读属性,所以为了能顺利篡改系统调用的地址,需要提前对控制寄存器CR0 的第16 位WP(写保护位)进行修改,在程序退出时则进行还原。

修改控制寄存器的函数为clear_cr0,代码如下。

unsigned int clear_cr0(void)        
{
        unsigned int cr0 = 0;
        unsigned int ret;
        //move the value in reg cr0 to reg rax
        //movl moves a 32-bits operand
        //movq moves a 64-bits operand
        //rax is a 64-bits register
        //an assembly language code
        //asm volatile ("movl %%cr0, %%eax" : "=a"(cr0));//32-bits        
        asm volatile ("movq %%cr0, %%rax" : "=a"(cr0));        //64-bits
        ret = cr0;
        //var cr0 is rax        
        cr0 &= 0xfffeffff; //set 0 to the 17th bit
        //asm volatile ("movl %%eax, %%cr0" :: "a"(cr0));//32-bits
        //note that cr0 above is a variable while cr0 below is a reg.        
        asm volatile ("movq %%rax, %%cr0" :: "a"(cr0));        
        return ret;
}

注意32位和64位的汇编代码部分指令不一样。

还原控制寄存器

修改系统调用后要还原控制寄存器,还原代码如下。

//recover the value of WP 
void setback_cr0(unsigned int val)
{        
        //asm volatile ("movl %%eax, %%cr0" :: "a"(val));//32-bits
        asm volatile ("movq %%rax, %%cr0" :: "a"(val));//64-bits
}

自己的系统调用函数

编写自己的系统调用函数my_sys_func,输出我的班级学号,返回输入参数之和。

static int my_sys_func(int a,int b,int c)
{
        printk("Change syscall successfully!\nReturn a+b+c\nBy cwj-class 93-No 2194214336\n");
        return a+b+c;
}

模块初始化

编写模块初始化函数init_sys_call,包括获取系统调用表、备份原系统调用函数地址、修改写保护位、修改系统调用地址、改回写保护位。

注意这里没有直接写入系统调用表地址,而是使用了kallsyms_lookup_name("sys_call_table");自动获取地址。

static int __init init_sys_call(void)
{
        printk("Begin changing syscall...\n");
        //Automatically get sys_call_table address
        sys_call_table = (unsigned long *)kallsyms_lookup_name("sys_call_table");
        //print sys_call_table address
           printk("sys_call_table: 0x%p\n", sys_call_table);
        //save original syscall func
        old_sys_call_func = (int(*)(void))(sys_call_table[__NR_syscall]);        
        //modify the value of WP in CR0 
        orig_cr0 = clear_cr0();        
        //change the syscall address
        sys_call_table[__NR_syscall] = (unsigned long)&my_sys_func;        
        //setback the value of WP in CR0 
        //to read only
        setback_cr0(orig_cr0);        
        return 0;
}

退出模块

编写退出模块函数exit_sys_call,包括修改写保护位、恢复系统调用函数、恢复写保护位。

static void __exit exit_sys_call(void)
{
        //modify the value of WP in CR0
        orig_cr0 = clear_cr0();        
        //change the syscall address
        sys_call_table[__NR_syscall] =old_sys_call_func;        
        //setback the value of WP in CR0 
        //to read only
        setback_cr0(orig_cr0);
        printk("Recovering syscall...\n");        
}

完整模块代码

综合以上部分形成完整代码如下。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/time.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/kallsyms.h>
//using syscall 321
#define __NR_syscall 321        
unsigned long *sys_call_table;
unsigned int clear_cr0(void);
void setback_cr0(unsigned int val);
static int sys_mycall(int a, int b, int c);
//to save the original value of the register cr0
unsigned long orig_cr0;        
unsigned long *sys_call_table = 0;
//to save the original syscall func
unsigned long old_sys_call_func; 
//set 0 to the 17th bit (WP) in reg cr0
unsigned int clear_cr0(void)        
{
        unsigned int cr0 = 0;
        unsigned int ret;
        //move the value in reg cr0 to reg rax
        //movl moves a 32-bits operand
        //movq moves a 64-bits operand
        //rax is a 64-bits register
        //an assembly language code
        //asm volatile ("movl %%cr0, %%eax" : "=a"(cr0));//32-bits        
        asm volatile ("movq %%cr0, %%rax" : "=a"(cr0));        //64-bits
        ret = cr0;
        //var cr0 is rax        
        cr0 &= 0xfffeffff; //set 0 to the 17th bit
        //asm volatile ("movl %%eax, %%cr0" :: "a"(cr0));//32-bits
        //note that cr0 above is a variable while cr0 below is a reg.        
        asm volatile ("movq %%rax, %%cr0" :: "a"(cr0));        
        return ret;
}

//recover the value of WP 
void setback_cr0(unsigned int val)
{        
        //asm volatile ("movl %%eax, %%cr0" :: "a"(val));//32-bits
        asm volatile ("movq %%rax, %%cr0" :: "a"(val));//64-bits
}

//my syscall function
static int sys_mycall(int a,int b,int c)
{
        printk("Change syscall successfully!\nReturn a+b+c\nBy cwj-class 93-No 2194214336\n");
        return a+b+c;
}

static int __init init_addsyscall(void)
{
        printk("Begin changing syscall...\n");
        //Automatically get sys_call_table address
        sys_call_table = (unsigned long *)kallsyms_lookup_name("sys_call_table");
        //print sys_call_table address
        printk("sys_call_table: 0x%p\n", sys_call_table);
        //save original syscall func
        old_sys_call_func = (int(*)(void))(sys_call_table[__NR_syscall]);        
        //modify the value of WP in CR0 
        orig_cr0 = clear_cr0();        
        //change the syscall address
        sys_call_table[__NR_syscall] = (unsigned long)&sys_mycall;        
        //setback the value of WP in CR0 
        //to read only
        setback_cr0(orig_cr0);        
        return 0;
}


static void __exit exit_addsyscall(void)
{
        //modify the value of WP in CR0
        orig_cr0 = clear_cr0();        
        //change the syscall address
        sys_call_table[__NR_syscall] =old_sys_call_func;        
        //setback the value of WP in CR0 
        //to read only
        setback_cr0(orig_cr0);
        printk("Recovering syscall...\n");        
}

module_init(init_addsyscall);
module_exit(exit_addsyscall);
MODULE_LICENSE("GPL");

建立makefile文件

建立makefile文件如下

ifneq ($(KERNELRELEASE),) 
obj-m := modify_syscall.o 
else 
KERNELDIR := /lib/modules/$(shell uname -r)/build 
PWD := $(shell pwd) 
modules: 
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
endif 
clean: 
        $(MAKE) -C $(KERNELDIR) M=$(PWD) clean

编译模块

使用make编译模块

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N78pwTkb-1639148863381)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=ZDFkMjE4NDU5ZGQyM2JmYzQzODMxN2ZiMjZiMDc0NGZfTllyNG1BVDRXeEl6RDM0OHBEejVFd0laMXZaMDZSWnNfVG9rZW46Ym94Y25yRWJFM1VIS0xIUW16ZWlidk5Xb29mXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

编写测试程序test.c

#include<stdio.h>
#include<unistd.h>
#include<sys/syscall.h>
#include<time.h>
int main()
{
        printf("Set parameters 78,10,20\nReturn:");        
        int ret=syscall(321,78,10,20); 
        if(ret == -1)
                printf("syscall failed!\n");
        else
                printf("%d\n",ret);
        return 0;
}

编译运行得到下图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-haFzPOkR-1639148863381)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=MTc3NDlkMTAyOTJkZDk0NTNmNGIzYmQ5ZGM3NmY2N2FfM0N4dzV0NWRqVkRUWXlvM0lON1BsTXF2VkFNREUxQWtfVG9rZW46Ym94Y25WT0R2MEU2SHh5WGlmUTFWMmJPRVhhXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

安装模块

使用sudo insmod modify_syscall.ko安装模块,安装完后使用test文件测试,结果如图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZHYI5q94-1639148863381)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=ZDQwM2RmNDI0OWVhMjE3ODZmM2YyYTVkZWY3YTcyYmNfbFV3c2plcDFjaW5KbWlWMUF6M1JUM0xUNVV1WXkyeWFfVG9rZW46Ym94Y25uSkEwZUZyRlcwRlY5MEd0Tm8zVE9iXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

可以看到返回值为108,是输入参数之和,说明系统调用篡改成功。

卸载模块

使用sudo rmmod modify_syscall卸载模块,卸载后再次使用test测试如图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OlGbx4VZ-1639148863382)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=ZDFjMjY2Nzk0MGZhODIyZmVhM2Q3YTliNTY4NjM4MzVfaGM2SEdUdURjbzBybkZlQjRjZEZnbHpzYjhIQjJRUFBfVG9rZW46Ym94Y25SMm1pUDF2Y09KSmlGQ1NXamo1enhlXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

可见这是系统调用已经恢复。

使用dmesg -c查看日志如图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qEl3aUXJ-1639148863382)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=YmZlYmQzYzA5ZmM3Y2MyYTcwMDgzNWM4ZTczNzMxODNfZ2dOZE54YTB0dG1LZWVXYmliSlYySllJalY5S2RJTzJfVG9rZW46Ym94Y25uQlVXeHU5SFpTaWJXVG1FSGg1MGxjXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

可以看到日志中打印出了篡改过程,说明实验成功。

出现的问题

Make时错误

make时出现如下报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WmWXg0PO-1639148863382)(https://xz2k2i3v0u.feishu.cn/space/api/box/stream/download/asynccode/?code=YjMwNjQzN2RkZDMzN2Q4MmQ4YWY1ZGVkOWIzNDQzZTlfRFlqekEzaHJEY3d0Wm5xSUZPYUozWVVzUmJ6SGJKZkpfVG9rZW46Ym94Y25MRk1WT3l4TnVuMnhyM3E2RUNtMkJUXzE2MzkxNDg4Mjk6MTYzOTE1MjQyOV9WNA)]

这是因为sys_call_table的地址是一个十六进制数,需要在前面加上0x。将modify_syscall.c中的地址改为unsigned long p_sys_call_table=0xffffffff81801420;

    int ret=syscall(321,78,10,20); 
    if(ret == -1)
            printf("syscall failed!\n");
    else
            printf("%d\n",ret);
    return 0;

}


编译运行得到下图。

[外链图片转存中...(img-haFzPOkR-1639148863381)]

### 安装模块

使用`sudo insmod modify_syscall.ko`安装模块,安装完后使用test文件测试,结果如图。

[外链图片转存中...(img-ZHYI5q94-1639148863381)]

可以看到返回值为108,是输入参数之和,说明系统调用篡改成功。

### 卸载模块

使用`sudo rmmod modify_syscall`卸载模块,卸载后再次使用test测试如图。

[外链图片转存中...(img-OlGbx4VZ-1639148863382)]

可见这是系统调用已经恢复。

使用`dmesg -c`查看日志如图。

[外链图片转存中...(img-qEl3aUXJ-1639148863382)]

可以看到日志中打印出了篡改过程,说明实验成功。

# 出现的问题

## Make时错误

make时出现如下报错

[外链图片转存中...(img-WmWXg0PO-1639148863382)]

这是因为sys_call_table的地址是一个十六进制数,需要在前面加上0x。将modify_syscall.c中的地址改为`unsigned long p_sys_call_table=0xffffffff81801420; `

## 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值