c语言Linux钩子函数,在Linux C/C++中对现有函数添加Hook的方法

#include

#include

#include

#include

#include

#include

#include

#include

#define PAGE_SIZE         sysconf(_SC_PAGESIZE)

#define PAGE_MASK         (~(PAGE_SIZE-1))

#define PAGE_ALIGN(addr)  (unsigned char *)(((uintptr_t)(addr) + PAGE_SIZE - 1) & PAGE_MASK)

#define BYTES_SIZE_REL (1 + sizeof(uint32_t))

#define BYTES_SIZE     (5 + sizeof(uint64_t))

static void ConstructJmpRel(void* x, void* target) {

((uint8_t*)x)[0] = 0xe9;

*(uint32_t*)((uint8_t*)x + 1) = (uintptr_t)target - ((uintptr_t)x + 5);

}

static void ConstructJmp(void* x, void* target) {

((uint8_t*)x)[0] = 0x49;

((uint8_t*)x)[1] = 0xbb;

*(uint64_t*)((uint8_t*)x + 2) = (uint64_t)target;

((uint8_t*)x)[10] = 0x41;

((uint8_t*)x)[11] = 0xff;

((uint8_t*)x)[12] = 0xe3;

}

static int CodeCopy(void* dst, void* src, int min_len) {

ZydisDecoder decoder;

ZydisDecodedInstruction instruction;

int offset = 0;

const char* data = (const char*)src;

ZydisFormatter formatter;

ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);

ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_ADDR_FORMAT,

ZYDIS_ADDR_FORMAT_RELATIVE_SIGNED);

ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);

while (ZYDIS_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, data + offset, 4096, 0, &instruction))) {

memcpy((char*)dst + offset, (char*)src + offset, instruction.length);

char buffer[256];

ZydisFormatterFormatInstruction(&formatter, &instruction, buffer, sizeof(buffer));

if (strstr(buffer, "[rip+0x") != NULL) {

if (instruction.length == 7 &&

(strncmp(buffer, "lea", 3) == 0 || strncmp(buffer, "mov", 3) == 0) &&

strstr(buffer, ", [rip+0x") != NULL) {

// need to patch things like 'lea rax, [rip+0x13BCE]', which

// happens a lot at the beginning of func

int reladdr = *(int*)(data + offset + 3);

int64_t new_reladdr = (uint64_t)src + reladdr - (uint64_t)dst;

if (new_reladdr > 0xFFFFFFFFLL || new_reladdr < -0xFFFFFFFFLL) {

return 0; // cannot patch this

}

*(int*)((char*)dst + offset + 3) = (int)new_reladdr;

} else {

return 0; // not supported yet

}

} else if (buffer[0] == 'j') {

return 0; // jump instructions not supported

}

offset += instruction.length;

if (offset >= min_len) {

return offset;

}

}

return 0; // failed

}

void* InstallHook(void* func, void* new_func) {

static int num_hooks = 0;

static unsigned char* hook_buf = NULL;

if (num_hooks >= 65536 / 64) {

return NULL; // too many hooks

}

if (hook_buf == NULL) {

hook_buf = (unsigned char*)mmap(NULL, 65536, PROT_READ | PROT_WRITE | PROT_EXEC,

MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

}

void* buf = (void*)(hook_buf + num_hooks * 64);

mprotect(hook_buf, 65536, PROT_READ | PROT_WRITE | PROT_EXEC);

int64_t size_diff = (int64_t)buf - (int64_t)func;

int prot_size = PAGE_SIZE;

if ((unsigned char*)func + BYTES_SIZE > PAGE_ALIGN(func)) {

prot_size *= 2;

}

if (size_diff > 0xFFFFFFF0LL || size_diff < -0xFFFFFFF0LL) {

int len = CodeCopy(buf, func, BYTES_SIZE);

if (len == 0) {

mprotect(hook_buf, 65536, PROT_READ | PROT_EXEC);

return NULL;

}

mprotect(PAGE_ALIGN(func) - PAGE_SIZE, prot_size,

PROT_READ | PROT_WRITE | PROT_EXEC);

ConstructJmp((unsigned char *)buf + len, (unsigned char*)func + len);

ConstructJmp(func, new_func);

mprotect(PAGE_ALIGN(func) - PAGE_SIZE, prot_size, PROT_READ | PROT_EXEC);

} else {

int len = CodeCopy(buf, func, BYTES_SIZE_REL);

if (len == 0) {

mprotect(hook_buf, 65536, PROT_READ | PROT_EXEC);

return NULL;

}

mprotect(PAGE_ALIGN(func) - PAGE_SIZE, prot_size,

PROT_READ | PROT_WRITE | PROT_EXEC);

ConstructJmpRel((unsigned char *)buf + len, (unsigned char*)func + len);

ConstructJmpRel(func, new_func);

mprotect(PAGE_ALIGN(func) - PAGE_SIZE, prot_size, PROT_READ | PROT_EXEC);

}

mprotect(hook_buf, 65536, PROT_READ | PROT_EXEC);

num_hooks++;

return buf;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要明确一点:Linux hook函数是一类内核函数,它们被用来拦截并处理一些系统调用或硬件断等事件。因此,要实现在write和read设备文件时操作某个寄存器,就需要编写hook函数,将其注册到相应的系统调用。 以下是一个示例代码,用于在write和read设备文件时访问某个寄存器: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <asm/uaccess.h> #define DEVICE_NAME "mydevice" #define DEVICE_MAJOR 240 /* 定义寄存器地址 */ #define REG_ADDR 0x1234 /* 定义hook函数 */ static ssize_t mydevice_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { int value; /* 读取寄存器的值 */ value = inw(REG_ADDR); /* 将寄存器的值写入用户空间 */ if (copy_to_user(buf, &value, sizeof(value))) { return -EFAULT; } return sizeof(value); } static ssize_t mydevice_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) { int value; /* 从用户空间读取数据 */ if (copy_from_user(&value, buf, sizeof(value))) { return -EFAULT; } /* 写入寄存器 */ outw(value, REG_ADDR); return count; } /* 定义file_operations结构体 */ static struct file_operations mydevice_fops = { .owner = THIS_MODULE, .read = mydevice_read, .write = mydevice_write, }; /* 模块初始化函数 */ static int __init mydevice_init(void) { int ret; /* 注册字符设备 */ ret = register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &mydevice_fops); if (ret < 0) { printk(KERN_ERR "Failed to register device.\n"); return ret; } printk(KERN_INFO "Device registered with major number %d.\n", DEVICE_MAJOR); return 0; } /* 模块卸载函数 */ static void __exit mydevice_exit(void) { unregister_chrdev(DEVICE_MAJOR, DEVICE_NAME); printk(KERN_INFO "Device unregistered.\n"); } module_init(mydevice_init); module_exit(mydevice_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple device driver with hook function."); ``` 上述代码,我们定义了两个hook函数:mydevice_read和mydevice_write。在mydevice_read函数,我们使用inw函数读取寄存器的值,并将其写入用户空间;在mydevice_write函数,我们使用outw函数将从用户空间读取到的数据写入寄存器。 需要注意的是,我们使用了两个内联汇编函数inw和outw来读写寄存器。这些函数会将指定地址处的数据读取到寄存器,或将寄存器的数据写入指定地址。这些寄存器通常是与硬件设备相关的寄存器,具体的操作方式和寄存器地址需要根据硬件设备的设计进行调整。 最后,我们将定义好的file_operations结构体注册到字符设备,并在模块初始化函数和卸载函数分别调用register_chrdev和unregister_chrdev函数来完成设备的注册和卸载。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值