c - 是否可以在没有 LD_PRELOAD 的情况下覆盖打开的 C 系统调用?
问题描述
源被打印,但没有open:
或被open64:
打印。如何解决这个问题?谢谢!
/*
gcc -o emload emload.c -ldl
./emload
*/
// emload.c
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <stdarg.h>
typedef int (*orig_open_func_type)(const char *__file, int flags, ...);
typedef int (*orig_openat_func_type)(int dirfd, const char *__file, int flags, ...);
int open(const char *__file, int __oflag, ...)
{
orig_open_func_type orig_func;
orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open");
int res = 0;
if (__oflag & O_CREAT) {
va_list ap;
va_start(ap, __oflag);
int mode = va_arg(ap, unsigned);
res = orig_func(__file, __oflag, mode);
va_end(ap);
}
else
res = orig_func(__file, __oflag);
printf("open: %d (%s)\n", res, __file);
return res;
}
int open64(const char *__file, int __oflag, ...)
{
orig_open_func_type orig_func;
orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open64");
int res = 0;
if (__oflag & O_CREAT) {
va_list ap;
va_start(ap, __oflag);
int mode = va_arg(ap, unsigned);
res = orig_func(__file, __oflag, mode);
va_end(ap);
}
else
res = orig_func(__file, __oflag);
printf("open64: %d (%s)\n", res, __file);
return res;
}
int openat(int dirfd, const char *__file, int __oflag, ...)
{
orig_openat_func_type orig_func = (orig_openat_func_type)dlsym(RTLD_NEXT, "openat");
int res = 0;
if (__oflag & O_CREAT) {
va_list ap;
va_start(ap, __oflag);
int mode = va_arg(ap, unsigned);
res = orig_func(dirfd, __file, __oflag, mode);
va_end(ap);
}
else
res = orig_func(dirfd, __file, __oflag);
printf("openat: %d (%s)\n", res, __file);
return res;
}
char source[2 << 20];
int main(int argc, char **argv, char **env)
{
FILE* f = fopen("emload.c", "r");
fread(source, sizeof(source), 1, f);
puts(source);
fclose(f);
return 0;
}
解决方案
GLIBCfopen
直接调用系统调用包装器,没有任何地址解析,所以你在这里不走运。您的其他选择是:
ptrace(2)
从单独的进程中使用,通过PTRACE_SYSCALL
请求跟踪系统调用。这将在任何系统调用上停止,而不仅仅是您需要的系统调用,因此可能会降低性能。- 修补内存中的包装以跳转到您的覆盖。但是,这可能会使执行原始代码变得更加困难,因为您需要分析它的前几条指令(您覆盖)以重现它们的效果。或者,您可以完全重新实现包装器,避免返回到原始版本。
推荐阅读
- unity3d - 无图层和剔除蒙版
- c# - Asp.Net Razor 页面处理程序未正确调用方法 C#
- php - Composer 包在哪里放置客户端配置?
- python - 有什么有效的方法可以循环遍历带有其值列表的列以在熊猫中进行条件过滤?
- javascript - amCharts 中 x 轴上的标签缺失
- xamarin - 使用带有 XF 的 ZXingScannerPage,我的内容页面有奇怪的行为
- c# - 如何在 c# 中替换 IndexOutOfRangeException 错误并改用 BadRequest()?
- r - 在R中评估非常大的阶乘
- hive - 实时 Hive 数据转换?
- php - Laravel 路由组 - Controller 中的使用价值