Linux函数调用劫持方法

Posted 造夢先森

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux函数调用劫持方法相关的知识,希望对你有一定的参考价值。

  • Ring3中劫持:
    1,基于环境变量LD_PRELOAD的动态库劫持
  • Ring0中劫持:
    1,Kernel Inline Hook
    2,syscall table修改
    3,内核调试机制Kprobe

基于环境变量LD_PRELOAD的动态库劫持

​ 在Linux中,动态库加载的时候,会按照以下顺序进行搜索:LD_PRELOAD >LD_LIBRARY_PATH >/etc/ld.so.cache>/lib>/usr/lib

方法原理:通过LD_PERELOAD设置编写自己的so库函数在原正常函数前执行

例子:劫持fputs()函数
整个调用过程如下:

编写自定义的动态链接库源码hook.c:

#include<stdio.h>
#include<dlfcn.h> //用于搜索原函数

/* 要求:函数的形式必须和原函数一样(返回类型,函数名,函数参数)*/
int fputs(const char*s, FILE *stream) 
    /* 自定义的操作区域 */
    printf("hook puts! str: ");

    /* 调用原函数*/
    typeof(fputs)  *func;//函数指针
    func=dlsym(RTLD_NEXT,"fputs");//查找fputs函数位置  dlsym:在打开的动态库里找一个函数
    return (*func)(s, stream); //调用原函数执行


编译成共享库:

gcc hook.c -fPIC -shared -ldl -D_GNU_SOURCE -o hook.so
  • -fPIC: 编译器就输出位置无关目标码.适用于动态连接
  • -shared: 生成共享目标文件

3.设置LD_PRELOAD
通过设置环境变量的方法

临时设置: export LD_PRELOAD=$YOUR PATH/hook.so
取消:unset LD_PRELOAD
 
永久设置:
修改profile文件 加入 export LD_PRELOAD=$YOUR PATH/hook.so
修改.bashrc文件 加入 export LD_PRELOAD=$YOUR PATH/hook.so

编写一个测试程序test.c

#include <stdio.h>

int main()
    char str[20]="\\0";

    printf("input:");
    fgets(str, 20, stdin);
    printf("output:");
    fputs(str, stdout);
    return 0;


测试结果 :

# ./a.out
input:123
output:123

# export LD_PRELOAD=/root/hook.so

# ./a.out
input:123
output:hook puts! str: 123

内核调试机制kprobe进行系统调用劫持

  • Kprobe介绍
    轻量级内核调试机制
  • Kprobe两种使用方法
    模块加载
    debugfs接口
  • Kprobe三种探测手段
    kprobe 基本的探测手段 基础 可以在函数内任意位置放置探测点
    jprobe 探测在函数的入口,可以方便的获得函数参数,但是每个函数只能有一个探针
    Kretprobe 探测在函数的返回值
  • 例子:劫持execve()

hook.c:


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>

int jsys_execve(const char __user *filename,
		const char __user *const __user *__argv,
		const char __user *const __user *__envp)

  	pr_info("jprobe: execve: %s\\n", filename);

	/* Always end with a call to jprobe_return(). */
  	jprobe_return();
  	return 0;


static struct jprobe jprobe_execve = 
	.entry= jsys_execve,
	.kp = 
		.symbol_name	= "sys_execve",
	,
;

static int __init mymodule_init(void)
    int ret;

	/* 挂载 hook */
	ret = register_jprobe(&jprobe_execve);
	if (ret < 0) 
		pr_info("register_jprobe failed, returned %d\\n", ret);
		return -1;
	
	pr_info("Planted jprobe execve at %p, handler addr %p\\n",
	       jprobe_execve.kp.addr, jprobe_execve.entry);
    
    return 0;


static void __exit mymodule_exit(void)

	unregister_jprobe(&jprobe_execve);



module_init(mymodule_init)
module_exit(mymodule_exit)
MODULE_LICENSE("GPL");

Makefile:

KO_NAME:= # 传入生成的ko文件的名字
PWD=$(shell pwd) # Makefile文件所在目录
KDIR:=/lib/modules/$(shell uname -r)/build
obj-m:=$(KO_NAME).o
$(KO_NAME)module-objs:=$(KO_NAME).o # 此处.o文件的名字必须与源码的.c文件保持一致
MAKE:=make
default:
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) EXTRA_CLFAGS+="" modules
clean:
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean

编译ko:

make KO_NAME="hook"

参考:https://blog.csdn.net/weixin_38371073/article/details/106235404

以上是关于Linux函数调用劫持方法的主要内容,如果未能解决你的问题,请参考以下文章

Linux函数调用劫持方法

Linux下利用动态链接劫持库函数并注入代码

黑客技术之移花接木(劫持)

lkm func劫持BUG

linux lkm rootkit常用技巧

阿里云PCDN新亮点 自动调用HTTPDNS 解决域名劫持困扰