在Linux上Hook系统函数execve获取执行参数-Rootkit

在Linux上Hook系统函数execve获取执行参数

根据linux系统在32位平台还是64位平台分别进行了hook代码的编写和测试,该功能是常见的rootkit技术

针对32位平台的Hook代码如下,已经在ubuntu12.04上测试过:

/*
* 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);

ubuntu 16.04 64位 ,内核版本:4.15.0-38-generic,Hook代码如下:hook.c

/*
* 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);

Makefile编写

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

在linux内核中编译依赖该模块,进行execve函数的参数的Hook,并打印参数内容

 
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/

你可能感兴趣的:(linux,c/c++,rookit,syscall,hook)