# System call hooking
###### tags: `learning`
## Things to do
:::info
1. 找到system call table的位置
2. 把system call table所在的segment標為可寫
- 原本是read only
3. 找到要hook的system call在syscall table中的offset
4. 把該offset中的ptr改成自己寫的function ptr
5. 把syscall table改回read only
:::
## Kernel Module Programming
[ref](https://ithelp.ithome.com.tw/articles/10157922)
### Hello world
- `hook.c`
```c=
#include <linux/kernel.h> /* for KERN_INFO */
#include <linux/module.h> /* for all modules*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Minyeon");
MODULE_DESCRIPTION("test");
int init_module(void)
{
pr_info("Hello\n");
return 0;
}
void exit_module(void)
{
pr_info("Goodbye\n");
}
```
- `Makefile`
```c=
obj-m += hook.o //obj-m : 將module編成.ko檔,以便之後可以進行載入
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
```
- `modinfo hook.ko`可查看module資訊
![](https://i.imgur.com/70hGiar.png =500x)
`insmod hook.ko`把module載入kernel
![](https://i.imgur.com/7FqgIi3.png =500x)
`lsmod`可以查看已載入的module
![](https://i.imgur.com/w2PmO0V.png =500x)
`rmmod hook.ko`把module從kernel中移除
![](https://i.imgur.com/SlJxxBF.png =500x)
### 從command line傳參數
- 借助`module_param`這個macro傳參數(定義在`linux/moduleparam.h` 中)
```c=
module_param(param_name, param_type, permission)
//param_name: 變數名稱
//param_type: 變數的資料型態(int, bool, charp...)
//permission: 變數對sysfs的存取權限
```
在Command line利用`param_name = our_name`傳入參數
![](https://i.imgur.com/lsZ0Wp1.png)
### 呼叫`call_usermodehelper`
- 執行一個新process(ps),並把結果導至一個檔案(ps_out)中
```c=
#include <linux/kernel.h> /* for KERN_INFO */
#include <linux/module.h> /* for all modules*/
#include <linux/sched.h> /* for task struct*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Minyeon");
MODULE_DESCRIPTION("test");
int init_hook(void)
{
int ret = -1;
char path[] = "/bin/bash";
char *argv[] = {path, "-c", "/bin/ps -ef >> /home/minyeon/my_sys_hook/ps_out", NULL};
char *envp[] = {"HOME=/", "PATH=/sbin:/bin:/usr/bin", NULL};
pr_info("[*] Start call_usermodehelper...\n");
ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);
pr_info("ret=%i\n", ret);
pr_info("Process: %s, Pid: %d\n", current->comm, current->pid);
//pr_info("Hello %s\n", name);
return 0;
}
void exit_hook(void)
{
pr_info("Goodbye\n");
}
module_init(init_hook);
module_exit(exit_hook);
```
### 執行自己的程式
```c=
int init_hook(void)
{
int ret = -1;
char path[] = "/bin/bash";
char *argv[] = {path, "-c", "/home/minyeon/my_sys_hook/test >> /home/minyeon/my_sys_hook/test_out", NULL};
char *envp[] = {"HOME=/", "PATH=/sbin:/bin:/usr/bin", NULL};
pr_info("[*] Start call_usermodehelper...\n");
ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);
pr_info("ret=%i\n", ret);
pr_info("Process: %s, Pid: %d\n", current->comm, current->pid);
//pr_info("Hello %s\n", name);
return 0;
}
```
### Get sys_call_table
```c
#include <linux/kernel.h> /* for KERN_INFO */
#include <linux/module.h> /* for all modules*/
#include <linux/sched.h> /* for task struct*/
#include <linux/kprobes.h> /* for kprobe*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Minyeon");
MODULE_DESCRIPTION("test");
static struct kprobe kp = {
.symbol_name = "kallsyms_lookup_name"
};
int init_hook(void)
{
/* find syscall_table*/
register_kprobe(&kp);
pr_alert("Syscall table found at 0x%px \n", kp.addr);
return 0;
}
void exit_hook(void)
{
unregister_kprobe(&kp);
pr_info("Goodbye\n");
}
module_init(init_hook);
module_exit(exit_hook);
```
## 問題
- Linux kernel 5.7.0之後,`kallsyms_lookup_name`不再export
- 編譯會跳出`ERROR: modpost: "kallsyms_lookup_name" undefined!`
![](https://i.imgur.com/qih9MjE.png)
- `/proc/kallsyms`每次開機就會random一次,所以無法直接hard coded
- [solve by](https://github.com/zizzu0/LinuxKernelModules/blob/main/FindKallsymsLookupName.c)