根据linux系统在32位平台还是64位平台分别进行了hook代码的编写和测试,该功能是常见的rootkit技术
/*
* This kernel module locates the sys_call_table by scanning
* the system_call interrupt handler (int 0x80)
*/
#include
#include
#include
#include
#include
/*
** module macros
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("geeksword");
MODULE_DESCRIPTION("hook sys_execve");
/*
** module constructor/destructor
*/
typedef void (*sys_call_ptr_t)(void);
sys_call_ptr_t *_sys_call_table = NULL;
typedef asmlinkage int (*orig_execve)(const char __user *filename, const char __user *const __user *argv, const char __user *const __user *envp);
orig_execve old_execve = NULL;
// hooked mkdir function
asmlinkage int hooked_execve(const char __user *filename, const char __user *const __user *argv, const char __user *const __user *envp) {
size_t exec_line_size;
char * exec_str = NULL;
char ** p_argv = (char **) argv;
static char* msg = "hooked sys_execve(): ";
exec_line_size = (strlen(filename) + 1);
/* Iterate through the execution arguments, to determine the final
size of the execution string. */
while (NULL != *p_argv) {
exec_line_size += (strlen(*p_argv) + 1);
(char **) p_argv++;
}
/* Allocate enough memory for the execution string */
exec_str = vmalloc(exec_line_size);
if (NULL != exec_str) {
snprintf(exec_str, exec_line_size, "%s", filename);
/* Iterate through the execution arguments */
p_argv = (char **) argv;
while (NULL != *p_argv) {
/* Concatenate each argument with our execution line */
snprintf(exec_str, exec_line_size,
"%s %s", exec_str, *p_argv);
(char **) p_argv++;
}
/* Send execution line to the user app */
//COMM_nl_send_exec_msg(exec_str);
printk("%s,%s\n", msg, exec_str);
}
//printk("%s%s---%s:%s\n", msg, filename, argv[0], envp[0]);
return old_execve(filename, argv, envp);
}
// memory protection shinanigans
unsigned int level;
pte_t *pte;
// initialize the module
static int hooked_init(void) {
printk("+ Loading hook_mkdir module\n");
// struct for IDT register contents
struct desc_ptr idtr;
// pointer to IDT table of desc structs
gate_desc *idt_table;
// gate struct for int 0x80
gate_desc *system_call_gate;
// system_call (int 0x80) offset and pointer
unsigned int _system_call_off;
unsigned char *_system_call_ptr;
// temp variables for scan
unsigned int i;
unsigned char *off;
// store IDT register contents directly into memory
asm ("sidt %0" : "=m" (idtr));
// print out location
printk("+ IDT is at %08x\n", idtr.address);
// set table pointer
idt_table = (gate_desc *) idtr.address;
// set gate_desc for int 0x80
system_call_gate = &idt_table[0x80];
// get int 0x80 handler offset
_system_call_off = (system_call_gate->a & 0xffff) | (system_call_gate->b & 0xffff0000);
_system_call_ptr = (unsigned char *) _system_call_off;
// print out int 0x80 handler
printk("+ system_call is at %08x\n", _system_call_off);
// scan for known pattern(0xff1485xx) in system_call (int 0x80) handler
// pattern is just before sys_call_table address
for(i = 0; i < 128; i++) {
off = _system_call_ptr + i;
if(*(off) == 0xff && *(off+1) == 0x14 && *(off+2) == 0x85) {
_sys_call_table = *(sys_call_ptr_t **)(off+3);
break;
}
}
// bail out if the scan came up empty
if(_sys_call_table == NULL) {
printk("- unable to locate sys_call_table\n");
return 0;
}
// print out sys_call_table address
printk("+ found sys_call_table at %08x!\n", _sys_call_table);
// now we can hook syscalls ...such as uname
// first, save the old gate (fptr)
old_execve = (orig_execve) _sys_call_table[__NR_execve];
// unprotect sys_call_table memory page
pte = lookup_address((unsigned long) _sys_call_table, &level);
// change PTE to allow writing
set_pte_atomic(pte, pte_mkwrite(*pte));
printk("+ unprotected kernel memory page containing sys_call_table\n");
// now overwrite the __NR_uname entry with address to our uname
_sys_call_table[__NR_execve] = (sys_call_ptr_t) hooked_execve;
printk("+ sys_execve hooked!\n");
return 0;
}
static void hooked_exit(void) {
if(old_execve != NULL) {
// restore sys_call_table to original state
_sys_call_table[__NR_execve] = (sys_call_ptr_t) old_execve;
// reprotect page
set_pte_atomic(pte, pte_clear_flags(*pte, _PAGE_RW));
}
printk("+ Unloading hook_execve module\n");
}
/*
** entry/exit macros
*/
module_init(hooked_init);
module_exit(hooked_exit);
/*
* This kernel module locates the sys_call_table by kallsyms_lookup_name("sys_call_table");
*/
#include
#include
#include
#include
#include
#include
/*
** module macros
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("geeksword");
MODULE_DESCRIPTION("hook sys_execve");
/*
** module constructor/destructor
*/
//typedef void (*sys_call_ptr_t)(void);
//sys_call_ptr_t *_sys_call_table = NULL;
unsigned long sys_call_table_addr = 0;
typedef asmlinkage long (*orig_execve)(const char __user *filename, const char __user *const __user *argv, const char __user *const __user *envp);
orig_execve old_execve = NULL;
// hooked mkdir function
asmlinkage long hooked_execve(const char __user *filename, const char __user *const __user *argv, const char __user *const __user *envp) {
size_t exec_line_size;
char * exec_str = NULL;
char ** p_argv = (char **) argv;
static char* msg = "hooked sys_execve(): ";
exec_line_size = (strlen(filename) + 1);
/* Iterate through the execution arguments, to determine the final
size of the execution string. */
while (NULL != *p_argv) {
exec_line_size += (strlen(*p_argv) + 1);
(char **) p_argv++;
}
/* Allocate enough memory for the execution string */
exec_str = vmalloc(exec_line_size);
if (NULL != exec_str) {
snprintf(exec_str, exec_line_size, "%s", filename);
/* Iterate through the execution arguments */
p_argv = (char **) argv;
while (NULL != *p_argv) {
/* Concatenate each argument with our execution line */
snprintf(exec_str, exec_line_size,
"%s %s", exec_str, *p_argv);
(char **) p_argv++;
}
/* Send execution line to the user app */
//COMM_nl_send_exec_msg(exec_str);
printk("%s,%s\n", msg, exec_str);
}
//printk("%s%s---%s:%s\n", msg, filename, argv[0], envp[0]);
return old_execve(filename, argv, envp);
}
/*******************************************************************
* Name: obtain_sys_call_table_addr
* Description: Obtains the address of the `sys_call_table` in the
* system.
*******************************************************************/
static int obtain_sys_call_table_addr(unsigned long * sys_call_table_addr) {
int ret = 1;
unsigned long temp_sys_call_table_addr;
temp_sys_call_table_addr = kallsyms_lookup_name("sys_call_table");
/* Return error if the symbol doesn't exist */
if (0 == sys_call_table_addr) {
ret = -1;
goto cleanup;
}
printk("Found sys_call_table: %p", (void *) temp_sys_call_table_addr);
*sys_call_table_addr = temp_sys_call_table_addr;
cleanup:
return ret;
}
// memory protection shinanigans
unsigned int level;
pte_t *pte;
// initialize the module
static int hooked_init(void) {
printk("+ Loading hook_mkdir module\n");
int ret = -1;
ret = obtain_sys_call_table_addr(&sys_call_table_addr);
if(ret != 1){
printk("- unable to locate sys_call_table\n");
return 0;
}
// print out sys_call_table address
printk("+ found sys_call_table at %08lx!\n", sys_call_table_addr);
// now we can hook syscalls ...such as uname
// first, save the old gate (fptr)
old_execve = ((unsigned long * ) (sys_call_table_addr))[__NR_execve];
// unprotect sys_call_table memory page
pte = lookup_address((unsigned long) sys_call_table_addr, &level);
// change PTE to allow writing
set_pte_atomic(pte, pte_mkwrite(*pte));
printk("+ unprotected kernel memory page containing sys_call_table\n");
// now overwrite the __NR_uname entry with address to our uname
((unsigned long * ) (sys_call_table_addr))[__NR_execve]= (unsigned long) hooked_execve;
printk("+ sys_execve hooked!\n");
return 0;
}
static void hooked_exit(void) {
if(old_execve != NULL) {
// restore sys_call_table to original state
((unsigned long * ) (sys_call_table_addr))[__NR_execve] = (unsigned long) old_execve;
// reprotect page
set_pte_atomic(pte, pte_clear_flags(*pte, _PAGE_RW));
}
printk("+ Unloading hook_execve module\n");
}
/*
** entry/exit macros
*/
module_init(hooked_init);
module_exit(hooked_exit);
obj-m += hook.o
all:
make -C /lib/modules/`uname -r`/build M=$(PWD) modules
clean:
make -C /lib/modules/`uname -r`/build M=$(PWD) clean
make
sudo insmod hook.o
ls -al
sudo rmmod hook.ko
dmesg | tail
[13945.375592] hooked sys_execve(), filename: /usr/bin/powerline-render---powerline-render:LC_MEASUREMENT=zh_CN.UTF-8
[13956.157147] hooked sys_execve(), filename: /usr/bin/awk---awk:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/sbin:/usr/sbin:/usr/local/sbin
[13956.160118] hooked sys_execve(), filename: /sbin/lsmod---lsmod:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/sbin:/usr/sbin:/usr/local/sbin:/sbin
[13956.725097] hooked sys_execve(), filename: /usr/bin/awk---awk:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/sbin:/usr/sbin:/usr/local/sbin
[13956.726811] hooked sys_execve(), filename: /sbin/lsmod---lsmod:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/sbin:/usr/sbin:/usr/local/sbin:/sbin
[13957.079773] hooked sys_execve(), filename: /usr/bin/awk---awk:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/sbin:/usr/sbin:/usr/local/sbin
[13957.081903] hooked sys_execve(), filename: /sbin/lsmod---lsmod:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/sbin:/usr/sbin:/usr/local/sbin:/sbin
[13962.067052] hooked sys_execve(), filename: /usr/bin/sudo---sudo:LC_MEASUREMENT=zh_CN.UTF-8
[13962.074011] hooked sys_execve(), filename: /sbin/rmmod---rmmod:LC_MEASUREMENT=zh_CN.UTF-8
[13962.081164] + Unloading hook_execve module
https://my.oschina.net/macwe/blog/603583
https://github.com/kfiros/execmon/blob/master/kmod/syscalls.c
http://onestraw.github.io/linux/lkm-and-syscall-hook/