A Linux kernel function to insert a command to play craft?

Last night Mr. Anderson began to trouble most of the night, completely sleep, after the grandmother took away Mr. Anderson, I wrote an article:
https://blog.csdn.net/dog250/article/details/105093969
However, no one how can do practical things.

Although it is difficult, but it can be simple.

I mean, I want to choose a simple kernel function, wherein the insertion, the function simply does not require correction to the relative offset. But I did not find such a function test for me. So I am ready to write one. The following is an example kernel module:

#include <linux/module.h>
#include <linux/proc_fs.h>

// 足够简单的函数!
static ssize_t hook_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
{
	int n = 0;
	return n;
}

static struct file_operations hook_ops = {
	.owner = THIS_MODULE,
	.read = hook_read,
};

static struct proc_dir_entry *ent;
static int __init hookstat_init(void)
{
	ent=proc_create("test",0660,NULL,&hook_ops);
	if (!ent)
		return -1;

	return 0;
}

static void __exit hookstat_exit(void)
{
	proc_remove(ent);
}

module_init(hookstat_init);
module_exit(hookstat_exit);
MODULE_LICENSE("GPL");

Load of.

Next, we look at this hook_read function:

crash> dis hook_read
0xffffffffa0374000 <hook_read>: nopl   0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffffa0374005 <hook_read+5>:       push   %rbp
0xffffffffa0374006 <hook_read+6>:       xor    %eax,%eax
0xffffffffa0374008 <hook_read+8>:       mov    %rsp,%rbp
0xffffffffa037400b <hook_read+11>:      pop    %rbp
0xffffffffa037400c <hook_read+12>:      retq

I would like to insert a line instructions before retq, its role is to increment the value system of panic_on_oops!

We increment the value of the instruction code panic_on_oops by asm inline assembly to the dump:

asm ("incl 0xffffffff81977890" :::);

0xffffffff81977890 which is panic_on_oops address I found in / proc / kallsyms, of course, you can also directly check symbol with API.

dump out a total of seven bytes of instruction code:

	incl[0] = 0xff;
	incl[1] = 0x04;
	incl[2] = 0x25;
	incl[3] = 0x90;
	incl[4] = 0x78;
	incl[5] = 0x97;
	incl[6] = 0x81;
	incl[7] = 0xc3;

We need to put seven bytes into the front retq.

The following code to complete this process:

#include <linux/module.h>
#include <linux/cpu.h>

char *p;
static struct mutex *_text_mutex;

void test_sub1(void) __attribute__ ((aligned (1024))); // 提供足够大的空间容纳原始函数
void test_sub2(void) __attribute__ ((aligned (1024)));
void test_sub1(void)
{
	printk("yes\n");
}
void test_sub2(void)
{
	printk("yes yes\n");
}

static void *(*_text_poke_smp)(void *addr, const void *opcode, size_t len);
static int __init hotfix_init(void)
{
	unsigned char e9_jmp[5];
	unsigned char incl[8];
	char *addr;
	s32 offset;

	_text_poke_smp = (void *)0xffffffff8163e1f0;
	_text_mutex = (void *)0xffffffff81984920;

	p = test_sub1;
	addr = 0xffffffffa0374000; // 该地址是通过hook_read符号查到地址。

	_text_poke_smp(p, addr, 20); // 通过crash dis指令,20个字节够了

	offset = (s32)((long)p - (long)addr - 5);

	incl[0] = 0xff;
	incl[1] = 0x04;
	incl[2] = 0x25;
	incl[3] = 0x90;
	incl[4] = 0x78;
	incl[5] = 0x97;
	incl[6] = 0x81;
	incl[7] = 0xc3;
	incl[8] = 0xc3; // 原有的retq指令往后移7个字节
	_text_poke_smp(&p[12], incl, 8); // 在retq前插入incl指令

	e9_jmp[0] = 0xe9;
	(*(s32 *)(&e9_jmp[1])) = offset;
	get_online_cpus();
	mutex_lock(_text_mutex);
	_text_poke_smp(addr, e9_jmp, 5); // 替换原始函数的前面5个字节
	mutex_unlock(_text_mutex);
	put_online_cpus();

	return 0;
}

static void __exit hotfix_exit(void)
{
}

module_init(hotfix_init);
module_exit(hotfix_exit);
MODULE_LICENSE("GPL");

Load of this time, we continue to cat / proc / test, and then look at the value of panic_on_oops:

[root@localhost ~]# cat /proc/test
[root@localhost ~]# sysctl -a|grep panic_on_oops
kernel.panic_on_oops = 9
[root@localhost ~]# cat /proc/test
[root@localhost ~]# sysctl -a|grep panic_on_oops
kernel.panic_on_oops = 10
[root@localhost ~]# cat /proc/test
[root@localhost ~]# sysctl -a|grep panic_on_oops
kernel.panic_on_oops = 11

The effect is like that.

Now talk about the complexity of the case, if we go to hook a normal function? If our hook_read function becomes the following way:

static ssize_t dump_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
{
	char kbuf[16] = {0};

	if (*ppos != 0) {
		return 0;
	}

	n = snprintf(kbuf, 16, "%d\n", 1234);
	memcpy(ubuf, kbuf, n);
	*ppos += n;

	return n;
}

I like to see the original function:

crash> dis hook_read
0xffffffffa0365000 <hook_read>: nopl   0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffffa0365005 <hook_read+5>:       push   %rbp
0xffffffffa0365006 <hook_read+6>:       mov    %rsp,%rbp
0xffffffffa0365009 <hook_read+9>:       push   %r13
0xffffffffa036500b <hook_read+11>:      push   %r12
0xffffffffa036500d <hook_read+13>:      push   %rbx
0xffffffffa036500e <hook_read+14>:      mov    %rcx,%rbx
0xffffffffa0365011 <hook_read+17>:      sub    $0x18,%rsp
0xffffffffa0365015 <hook_read+21>:      mov    %gs:0x28,%rax
0xffffffffa036501e <hook_read+30>:      mov    %rax,-0x20(%rbp)
0xffffffffa0365022 <hook_read+34>:      xor    %eax,%eax
0xffffffffa0365024 <hook_read+36>:      cmpq   $0x0,(%rcx)
0xffffffffa0365028 <hook_read+40>:      jne    0xffffffffa036505f <hook_read+95>
0xffffffffa036502a <hook_read+42>:      lea    -0x30(%rbp),%rdi
0xffffffffa036502e <hook_read+46>:      mov    %rsi,%r13
0xffffffffa0365031 <hook_read+49>:      mov    $0x4d2,%ecx
0xffffffffa0365036 <hook_read+54>:      mov    $0xffffffffa0366024,%rdx
0xffffffffa036503d <hook_read+61>:      mov    $0x10,%esi
0xffffffffa0365042 <hook_read+66>:      callq  0xffffffff812fd8f0 <snprintf>
0xffffffffa0365047 <hook_read+71>:      lea    -0x30(%rbp),%rsi
0xffffffffa036504b <hook_read+75>:      movslq %eax,%r12
0xffffffffa036504e <hook_read+78>:      mov    %r13,%rdi
0xffffffffa0365051 <hook_read+81>:      mov    %r12,%rdx
0xffffffffa0365054 <hook_read+84>:      callq  0xffffffff812ff530 <__memcpy>
0xffffffffa0365059 <hook_read+89>:      add    %r12,(%rbx)
0xffffffffa036505c <hook_read+92>:      mov    %r12,%rax
0xffffffffa036505f <hook_read+95>:      mov    -0x20(%rbp),%rdx
0xffffffffa0365063 <hook_read+99>:      xor    %gs:0x28,%rdx
0xffffffffa036506c <hook_read+108>:     jne    0xffffffffa0365079 <hook_read+121>
0xffffffffa036506e <hook_read+110>:     add    $0x18,%rsp
0xffffffffa0365072 <hook_read+114>:     pop    %rbx
0xffffffffa0365073 <hook_read+115>:     pop    %r12
0xffffffffa0365075 <hook_read+117>:     pop    %r13
0xffffffffa0365077 <hook_read+119>:     pop    %rbp
0xffffffffa0365078 <hook_read+120>:     retq
0xffffffffa0365079 <hook_read+121>:     callq  0xffffffff81074510 <__stack_chk_fail>

Then we look at it hook like:

crash> dis 0xffffffffa0374000 100
0xffffffffa0374000 <test_sub1>: nopl   0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffffa0374005 <test_sub1+5>:       push   %rbp
0xffffffffa0374006 <test_sub1+6>:       mov    %rsp,%rbp
0xffffffffa0374009 <test_sub1+9>:       push   %r13
0xffffffffa037400b <test_sub1+11>:      push   %r12
0xffffffffa037400d <test_sub1+13>:      push   %rbx
0xffffffffa037400e <test_sub1+14>:      mov    %rcx,%rbx
0xffffffffa0374011 <test_sub1+17>:      sub    $0x18,%rsp
0xffffffffa0374015 <test_sub1+21>:      mov    %gs:0x28,%rax
0xffffffffa037401e <test_sub1+30>:      mov    %rax,-0x20(%rbp)
0xffffffffa0374022 <test_sub1+34>:      xor    %eax,%eax
0xffffffffa0374024 <test_sub1+36>:      incl   0xffffffff81977890
0xffffffffa037402b <test_sub1+43>:      retq
0xffffffffa037402c <test_sub1+44>:      jge    0xffffffffa0373ffe
0xffffffffa037402e <test_sub1+46>:      mov    %rsi,%r13
0xffffffffa0374031 <test_sub1+49>:      mov    $0x4d2,%ecx
0xffffffffa0374036 <test_sub1+54>:      mov    $0xffffffffa0366024,%rdx
0xffffffffa037403d <test_sub1+61>:      mov    $0x10,%esi
0xffffffffa0374042 <test_sub1+66>:      callq  0xffffffff8130c8f0 <zlib_inflate+2384>
0xffffffffa0374047 <test_sub1+71>:      lea    -0x30(%rbp),%rsi
0xffffffffa037404b <test_sub1+75>:      movslq %eax,%r12
0xffffffffa037404e <test_sub1+78>:      mov    %r13,%rdi
0xffffffffa0374051 <test_sub1+81>:      mov    %r12,%rdx
0xffffffffa0374054 <test_sub1+84>:      callq  0xffffffff8130e530 <lzo1x_1_do_compress+672>
0xffffffffa0374059 <test_sub1+89>:      add    %r12,(%rbx)
0xffffffffa037405c <test_sub1+92>:      mov    %r12,%rax
0xffffffffa037405f <test_sub1+95>:      mov    -0x20(%rbp),%rdx
0xffffffffa0374063 <test_sub1+99>:      xor    %gs:0x28,%rdx
0xffffffffa037406c <test_sub1+108>:     jne    0xffffffffa0374079 <test_sub1+121>
0xffffffffa037406e <test_sub1+110>:     add    $0x18,%rsp
0xffffffffa0374072 <test_sub1+114>:     pop    %rbx
0xffffffffa0374073 <test_sub1+115>:     pop    %r12
0xffffffffa0374075 <test_sub1+117>:     pop    %r13
0xffffffffa0374077 <test_sub1+119>:     pop    %rbp
0xffffffffa0374078 <test_sub1+120>:     retq
0xffffffffa0374079 <test_sub1+121>:     callq  0xffffffff81083510 <exit_ptrace+128>

Jump hell broke loose, because there is no offset correction ah.

However, and assign a separate instruction compared to a memory copy function, the entire function directly in the vicinity of the translation would be better, in general retq after the tail, there will be some free space, after the function pan down, down the empty space can be inserted instruction.

In fact, you only need to insert a relative jump, space enough, you can jump jmp somewhere else and then come back ah!

Well, sleep.


Wenzhou shoes wet, rain water will not be fat.

Released 1580 original articles · won praise 5111 · Views 11,130,000 +

Guess you like

Origin blog.csdn.net/dog250/article/details/105129254