You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否将进程系统调用重定向至其他动态库?Ubuntu下能否劫持读写调用转存MySQL?

当然可以!在Ubuntu这类Linux系统下,LD_PRELOAD 就是实现这种系统调用劫持的绝佳工具,能帮你把应用A的read/write操作无缝转接到MySQL数据库。下面我一步步给你讲具体怎么做:

核心思路:用LD_PRELOAD劫持动态链接函数

Linux的动态链接器会优先加载LD_PRELOAD环境变量指定的动态库,这意味着我们可以编写自己的read和write函数,覆盖系统默认的实现,在函数里把原本的文件读写逻辑替换成MySQL操作。

具体实现步骤

1. 编写自定义劫持库

我们需要写一个C语言的动态库,里面实现自己的read和write函数,同时要保留调用原系统函数的能力(用于处理非目标文件的读写操作)。示例代码如下:

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <mysql/mysql.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

// 保存原系统函数的指针
ssize_t (*original_read)(int fd, void *buf, size_t count) = NULL;
ssize_t (*original_write)(int fd, const void *buf, size_t count) = NULL;

MYSQL *conn;

// 初始化MySQL连接,程序启动时自动执行
__attribute__((constructor)) void init() {
    // 获取原系统函数的地址
    original_read = dlsym(RTLD_NEXT, "read");
    original_write = dlsym(RTLD_NEXT, "write");

    // 初始化并建立MySQL连接
    conn = mysql_init(NULL);
    if (!mysql_real_connect(conn, "localhost", "your_username", "your_password", "your_dbname", 0, NULL, 0)) {
        fprintf(stderr, "MySQL连接失败: %s\n", mysql_error(conn));
        exit(1);
    }
}

// 清理MySQL连接,程序退出时自动执行
__attribute__((destructor)) void cleanup() {
    if (conn) {
        mysql_close(conn);
    }
}

// 自定义read函数:拦截目标文件的读操作,从MySQL读取数据
ssize_t read(int fd, void *buf, size_t count) {
    struct stat st;
    if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
        char path[256];
        snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
        char real_path[256];
        if (readlink(path, real_path, sizeof(real_path)-1) != -1) {
            // 替换成你要拦截的目标文件路径
            if (strcmp(real_path, "/path/to/your/target/file") == 0) {
                MYSQL_RES *res;
                MYSQL_ROW row;
                if (mysql_query(conn, "SELECT data FROM your_table LIMIT 1") == 0) {
                    res = mysql_store_result(conn);
                    if (res && (row = mysql_fetch_row(res))) {
                        size_t data_len = strlen(row[0]);
                        size_t return_len = data_len < count ? data_len : count;
                        memcpy(buf, row[0], return_len);
                        mysql_free_result(res);
                        return return_len;
                    }
                    mysql_free_result(res);
                }
            }
        }
    }
    // 非目标文件,调用原read函数处理
    return original_read(fd, buf, count);
}

// 自定义write函数:拦截目标文件的写操作,将数据写入MySQL
ssize_t write(int fd, const void *buf, size_t count) {
    struct stat st;
    if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
        char path[256];
        snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
        char real_path[256];
        if (readlink(path, real_path, sizeof(real_path)-1) != -1) {
            // 替换成你要拦截的目标文件路径
            if (strcmp(real_path, "/path/to/your/target/file") == 0) {
                char escaped_data[2048];
                // 转义特殊字符,防止SQL注入
                mysql_real_escape_string(conn, escaped_data, buf, count);
                char query[2048];
                snprintf(query, sizeof(query), "INSERT INTO your_table (data) VALUES ('%s')", escaped_data);
                if (mysql_query(conn, query) == 0) {
                    return count; // 模拟原函数返回写入的字节数
                } else {
                    fprintf(stderr, "MySQL写入失败: %s\n", mysql_error(conn));
                }
            }
        }
    }
    // 非目标文件,调用原write函数处理
    return original_write(fd, buf, count);
}

2. 编译动态库

用gcc将代码编译成共享库,需要链接MySQL客户端库和动态链接库:

gcc -shared -fPIC -o libmysqlhook.so hook.c -ldl -lmysqlclient

如果提示找不到mysqlclient库,先安装依赖包:

sudo apt-get install libmysqlclient-dev

3. 运行应用A

设置LD_PRELOAD环境变量,让应用A优先加载我们的自定义库:

LD_PRELOAD=./libmysqlhook.so ./appA

如果应用A是系统级程序,可能需要加上sudo,同时确保库的路径正确(或者把库放到/usr/lib这类系统库目录)。

关键注意事项
  • 精准拦截目标文件:一定要通过文件路径准确判断哪些read/write操作需要拦截,否则会破坏应用A的其他正常功能(比如日志、配置文件读写)。
  • SQL注入防护:插入MySQL的数据必须用mysql_real_escape_string转义特殊字符,避免安全风险。
  • 错误处理:要处理MySQL连接失败、读写失败等异常情况,必要时可以回退到原函数行为,防止应用A崩溃。
  • 静态编译应用的限制:如果应用A是静态编译的(不依赖动态链接库),LD_PRELOAD会失效,这种情况需要用ptrace工具劫持系统调用,但实现复杂度会高很多。
  • 安全性与权限:自定义库要确保没有漏洞,运行应用的用户需要拥有MySQL的读写权限。

内容的提问来源于stack exchange,提问作者Sreram

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:21:08