netlink+kprobe实现linux下进程监控

#include <linux/kernel.h>  
#include <linux/module.h>  
#include <linux/kprobes.h>  
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include<linux/vmalloc.h>
#define NETLINK_USER 31
struct sock *nl_sk = NULL;
struct nlmsghdr *nlh;
int pid;
static struct kprobe kp = {  
    .symbol_name    = "sys_execve",  
};  
  
/* kprobe pre_handler: called just before the probed instruction is executed */  
static int handler_pre(struct kprobe *p, struct pt_regs *regs)  
{  
#ifdef CONFIG_X86  
        printk(KERN_INFO "pre_handler: p->addr = 0x%p, ip = %lx,"  
            " flags = 0x%lx,pid=%d,comm=%s,name=%s\n",  
        p->addr, regs->ip, regs->flags,current->pid,current->comm,*((char **)regs->si+1));  
        char ** argv = (char **) regs->si;
        size_t exec_line_size=0;
        while(NULL!=*argv)
        {
          exec_line_size=exec_line_size+strlen(*argv)+1;
          argv++;
        }
        char *str = vmalloc(exec_line_size);
        if (NULL!=str)
        {
           memset(str,0,exec_line_size);
           argv = (char **) regs->si;
           while (NULL != *argv) 
			   {
			
			     snprintf(str, exec_line_size,
					"%s%s",str, *argv);
			      argv++;	
		       }
        }		 
		if(pid!=0)
		{
			 struct sk_buff *skb_out;
			 int msg_size;
			 int res;
			 if(NULL!=str)
			 {
			   msg_size=strlen(str);
			   skb_out = nlmsg_new(msg_size,0);
			   if(!skb_out)
			   {
				   printk(KERN_ERR "Failed to allocate new skb\n");
				   vfree(str);
				   return 0;
			   } 
			   nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);  
			   NETLINK_CB(skb_out).dst_group = 0; 
			   strncpy(nlmsg_data(nlh),str,msg_size);
			   res=nlmsg_unicast(nl_sk,skb_out,pid);
			   vfree(str);
			   return 0;
			 }
         }
         vfree(str);
#endif  
#ifdef CONFIG_PPC  
    printk(KERN_INFO "pre_handler: p->addr = 0x%p, nip = 0x%lx,"  
            " msr = 0x%lx\n",  
        p->addr, regs->nip, regs->msr);  
#endif  
#ifdef CONFIG_MIPS  
    printk(KERN_INFO "pre_handler: p->addr = 0x%p, epc = 0x%lx,"  
            " status = 0x%lx\n",  
        p->addr, regs->cp0_epc, regs->cp0_status);  
#endif  
  
    /* A dump_stack() here will give a stack backtrace */  
    return 0;  
}  
  
/* kprobe post_handler: called after the probed instruction is executed */  
static void handler_post(struct kprobe *p, struct pt_regs *regs,  
                unsigned long flags)  
{  
#ifdef CONFIG_X86  
    printk(KERN_INFO "post_handler: p->addr = 0x%p, flags = 0x%lx,pid=%d,comm=%s,name=%s\n",  
        p->addr, regs->flags,current->pid,current->comm,(char *)regs->di);  
#endif  
#ifdef CONFIG_PPC  
    printk(KERN_INFO "post_handler: p->addr = 0x%p, msr = 0x%lx\n",  
        p->addr, regs->msr);  
#endif  
#ifdef CONFIG_MIPS  
    printk(KERN_INFO "post_handler: p->addr = 0x%p, status = 0x%lx\n",  
        p->addr, regs->cp0_status);  
#endif  
}  
  
/* 
 * fault_handler: this is called if an exception is generated for any 
 * instruction within the pre- or post-handler, or when Kprobes 
 * single-steps the probed instruction. 
 */  
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)  
{  
    printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",  
        p->addr, trapnr);  
    /* Return 0 because we don't handle the fault. */  
    return 0;  
}  
static void hello_nl_recv_msg(struct sk_buff *skb) {
		//struct nlmsghdr *nlh;
		struct sk_buff *skb_out;
		int msg_size;
		char *msg="init";
		int res;
		printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
		msg_size=strlen(msg);
		nlh=(struct nlmsghdr*)skb->data;
		printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(nlh));
		pid = nlh->nlmsg_pid; /*pid of sending process */
		skb_out = nlmsg_new(msg_size,0);
		if(!skb_out)
		{
			printk(KERN_ERR "Failed to allocate new skb\n");
			return;
		} 
		nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);  
		NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
		strncpy(nlmsg_data(nlh),msg,msg_size);
		res=nlmsg_unicast(nl_sk,skb_out,pid);
		if(res<0)
			printk(KERN_INFO "Error while sending bak to user\n");
}
  
static int __init kprobe_init(void)  
{  
		struct netlink_kernel_cfg cfg = {
			.input = hello_nl_recv_msg,
		};
		nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
		if(!nl_sk)
		{
			printk(KERN_ALERT "Error creating socket.\n");
			return -1;
		}
		int ret;  
		kp.pre_handler = handler_pre;  
		kp.post_handler = handler_post;  
		kp.fault_handler = handler_fault;  
		  
		ret = register_kprobe(&kp);  
		if (ret < 0)
		{  
	    	printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);  
			return ret;  
		}  
		printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);  
		return 0;  
}  
  
static void __exit kprobe_exit(void)  
{  
    unregister_kprobe(&kp);  
    printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);  
    netlink_kernel_release(nl_sk);
}  
  
module_init(kprobe_init)  
module_exit(kprobe_exit)  
MODULE_LICENSE("GPL"); 

用户态代码如下

#include <sys/socket.h>
#include <linux/netlink.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
int main()
{
		sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
		if(sock_fd<0)
		return -1;
		memset(&src_addr, 0, sizeof(src_addr));
		src_addr.nl_family = AF_NETLINK;
		src_addr.nl_pid = getpid(); 
		bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
		memset(&dest_addr, 0, sizeof(dest_addr));
		memset(&dest_addr, 0, sizeof(dest_addr));
		dest_addr.nl_family = AF_NETLINK;
		dest_addr.nl_pid = 0; /* For Linux Kernel */
		dest_addr.nl_groups = 0; /* unicast */
		nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
		memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
		nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
		nlh->nlmsg_pid = getpid();
		nlh->nlmsg_flags = 0;
		strcpy(NLMSG_DATA(nlh), "Hello");
		iov.iov_base = (void *)nlh;
		iov.iov_len = nlh->nlmsg_len;
		msg.msg_name = (void *)&dest_addr;
		msg.msg_namelen = sizeof(dest_addr);
		msg.msg_iov = &iov;
		msg.msg_iovlen = 1;
		printf("Sending message to kernel\n");
		sendmsg(sock_fd,&msg,0);
		printf("Waiting for message from kernel\n");
		/* Read message from kernel */
		while(1)
		{
		   recvmsg(sock_fd, &msg, 0);
		   printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh));
		}
		close(sock_fd);
}



Makefile

ifneq ($(KERNELRELEASE),) # after ifneq ,there is a space! or,will get an error
obj-m := process.o 
else 
KERNELDIR := /lib/modules/$(shell uname -r)/build 
PWD := $(shell pwd) 
default: 
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
	gcc user.c -o user 
clean: 
	rm -rf *.o *.ko *mod.c [mM]odule* .*.cmd *.o.d .tmp_versions 
endif  




通过这种方式能够获得内核中启动的进程信息。通过ioctl会占用很多的cpu资源,所以这种方式能够满足需求。





  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值