一般情况有四个部分 pre_probe, post_probe, kprobe_ init, kprobe_exit.

probe addr 两种方式获得,一种直接调用kallsyms_lookup_name(“you_function”), 另外一种是直接给地址 0xabcd. 可用的函数和地址都是通过cat /proc/kallsyms 找到。

例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
#INCLUDE <linux/kprobes.h>
#include <linux/kallsyms.h>
#include "asm/ptrace.h"
#include "asm/current.h"
#include "linux/utsname.h"

/* global probe object */
struct kprobe probe;

/*
 * enter the probe pointer
 */
static int pre_probe(struct kprobe *probe, struct pt_regs *regs)
{
	printk("Hit it\n");
	return 0;
}
/*
 * exit the probe pointer
 */
static void post_probe(struct kprobe *probe, struct pt_regs *regs, unsigned long flags)
{}

static int __init kprobe_ init(void)
{
	probe.pre_handler = pre_probe;
	probe.post_handler = post_probe;

	//probe.addr = (kprobe_opcode_t *) 0xaddress;
	probe.addr = (kprobe_opcode_t *) kallsyms_lookup_name("you_function");
	if (probe.addr == NULL) {
		return 1;
	}

	register_kprobe(&probe);
	printk("register probe driver.\n");
	return 0;
}

static void __exit kprobe_exit(void)
{
	unregister_kprobe(&probe);
	printk("unregister probe driver.\n");
	return;
}

module_init(kprobe_ init);
module_exit(kprobe_ exit);
MODULE_LICENSE("GPL");

如果想拿到函数中的参数,在X86_64平台上, 对于Linux-2.6.23版本,Linux的参数传递 通过如下9个寄存器完成,分别为:RDI,RSI,RDX,RCX,RAX,R8,R9,R10,R11。 对于Linux-3.2版本之后,名字改变为 di, si, dx… 这样获得参数的值就为

1
2
3
4
5
static int pre_probe(struct kprobe *probe, struct pt_regs *regs)
{
	printk("first param is %d.\n", regs->di);
	return 0;
}

Reference:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

#ifdef __i386__

struct pt_regs {
	unsigned long bx;
	unsigned long cx;
	unsigned long dx;
	unsigned long si;
	unsigned long di;
	unsigned long bp;
	unsigned long ax;
	unsigned long ds;
	unsigned long es;
	unsigned long fs;
	unsigned long gs;
	unsigned long orig_ax;
	unsigned long ip;
	unsigned long cs;
	unsigned long flags;
	unsigned long sp;
	unsigned long ss;
};

#else /* __i386__ */

struct pt_regs {
/*
 * C ABI says these regs are callee-preserved. They aren't saved on kernel entry
 * unless syscall needs a complete, fully filled "struct pt_regs".
 */
	unsigned long r15;
	unsigned long r14;
	unsigned long r13;
	unsigned long r12;
	unsigned long bp;
	unsigned long bx;
/* These regs are callee-clobbered. Always saved on kernel entry. */
	unsigned long r11;
	unsigned long r10;
	unsigned long r9;
	unsigned long r8;
	unsigned long ax;
	unsigned long cx;
	unsigned long dx;
	unsigned long si;
	unsigned long di;
/*
 * On syscall entry, this is syscall#. On CPU exception, this is error code.
 * On hw interrupt, it's IRQ number:
 */
	unsigned long orig_ax;
/* Return frame for iretq */
	unsigned long ip;
	unsigned long cs;
	unsigned long flags;
	unsigned long sp;
	unsigned long ss;
/* top of stack page */
};

#endif /* !__i386__ */