首页 > 系统相关 >Function Interposition in Linux(hook)

Function Interposition in Linux(hook)

时间:2022-08-19 11:36:14浏览次数:73  
标签:Function real malloc 函数 dlsym Interposition hook 加载 size

你是否想多改变库代码的工作方式,不替换整个库或者重新编译它。例如,你想包裹一层mallocfree函数来记录分配的日志,为了查找内存泄露。你可以重写那段使用了malloc/free的代码,或者修改libc,这两者听起来都不是很吸引人的方式

这个教程将告诉你用自己实现的wrapper来代替库中的函数,这被叫做函数打桩(function interposition),它可以在任何程序中完成,而无需重新编译程序或库。

首先,一些背景知识:动态链接。当一个程序使用动态链接库编译时,有一列表记录未定义的符号(symbol)包含在二进制中的,还有一个列表记录程序所链接的库(library)。符号和库两者没什么关联,这两个列表仅仅用来告诉loader那些库需要被加载、那些符号需要被解析。在运行时(Runtime),每个符号用提供的第一个库来解析,这意味着如果我们将包含我们wrapper函数的库在其他库的前面加载,程序中的未定义符号表将解析到我们的wrapper函数,而不是真正的函数

我们如何让一个程序加载它没有链接的库?幸运的是,这是最简单的部分。环境变量LD_PRELOAD为加载器提供了一个库列表,以便在其他任何操作之前加载。假设我们有一个名为libjmalloc的共享库。因此包括mallocfree的替换。我们想在程序foo中使用它,所以我们像这样运行它:

LD_PRELOAD=/home/jay/libjmalloc.so   ./foo

这个loader将表现的像foo链接了libmalloc.so一样,我们给它一个到库的绝对路径,这样它就不会去搜索/usr/lib这样的普通位置。如果要预加载多个库,请使用冒号分隔它们的名称。

到目前为止都很好,但是如果我们想在自己实现的版本中使用原版的malloc呢?例如,我们仅仅想在调用malloc/free时打印一条信息,但是内存管理仍然用原来的malloc/free。然而我们不能在wrapper中直接调用libc版的malloc,因为编译器会将它解释为对wrapper本身的递归调用。解决方案是使用dlsym动态加载指向malloc的指针

#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>

void* malloc(size_t size)
{
    static void* (*real_malloc)(size_t) = NULL;
    if (!real_malloc)
        real_malloc = dlsym(RTLD_NEXT, "malloc");

    void *p = real_malloc(size);
    fprintf(stderr, "malloc(%d) = %p\n", size, p);
    return p;
}

我们编译一下:

gcc -shared -ldl -fPIC jmalloc.c -o libjmalloc.so

dlfcn.h 申明函数将动态加载符号表,而不是链接到程序中。这些函数的一个主要用法就是加载plugins。例如在这里,我们认为libc是一个提供了malloc(我们把它赋给real_malloc)的插件。我们使用dlsym加载这个符号,它有两个参数:(a library handle, a symbol name)。通常情况下,我们使用dlopen获取一个有效的库句柄,但是因为malloc所在的libc库默认就是被链接,所以我们只需要传一个RTLD_NEXT它告诉动态链接器:在下一个支持它的库中解析符号(而不是在当前调用dlsyum的这个库)RTLD_NEXTGNU特有的,所以记得在include dlfcn.h 之前定义_GNU_SOURCE

此时,您可以替换大部分的库函数。但是,有一些函数不能使用此方法插入。例如,如果您想为dlsym本身创建一个包装器,该怎么办?您还不能在内部包装任何库函数dlsym调用。

如果你确实需要包装这些函数,GNU链接器提供了一个有用的选项 --wrap。如果你给它一个符号dlsym,它会将所有的dlsym调用替换成__wrap_dlsym,用real_dlsym调用真正的dlsym,这种方法的缺点是,您需要重新链接使用wrapper任何程序。上面的例子可以被写成这样:

#include <stdint.h>
#include <stdio.h>

void* __real_malloc(size_t);
void* __wrap_malloc(size_t size)
{
    void *p = __real_malloc(size);
    fprintf(stderr, "malloc(%d) = %p\n");
    return p;
}

写在最后的一点东西。首先,LD_PRELOAD会因为安全原因被SUID权限的程序忽略,由于函数插入可以让程序执行任何您想要的操作,因此Linux阻止您修改代表其他用户或组运行的程序的行为。其次,您不能插入静态链接库的函数调用,因为这些调用在运行时之前已解析。例如,如果libc中的某个函数调用malloc,它将永远不会调用其他库中的包装函数。

除了这些限制之外,函数插入是一种非常强大的技术,可用于监控程序或修改其行为。愉快的介入!

ref:
https://jayconrod.com/posts/23/tutorial-function-interposition-in-linux

标签:Function,real,malloc,函数,dlsym,Interposition,hook,加载,size
From: https://www.cnblogs.com/lfri/p/16601431.html

相关文章

  • function 和mapped function的区别
    1--在函数定义上使用mapped前缀将此函数标记为自动映射到集合上。这意味着,如果将集合作为函数的第一个参数,则该函数将在集合的元素上自动重复调用。这允许您定义脚本化......
  • React报错之Unexpected default export of anonymous function
    正文从这开始~总览当我们尝试使用默认导出来导出一个匿名函数时,会导致"Unexpecteddefaultexportofanonymousfunction"警告。为了解决该错误,在导出函数之前,为函数赋......
  • Function eregi() is deprecated (解决方法)
    在php升级到php5.3之后后,在使用的过程经常发现有的程序会出现Functioneregi()isdeprecated的报错信息。是什么原因呢?这是因为php5.3中不再支持eregi()函数,而使用preg_m......
  • React Hooks
    Hooks概念Hook是一个特殊的函数,它可以让你“钩入”React的特性。Hook是React16.8(当前版本18,项目使用17)的新增特性,它可以让你在不编写class的情况下使用state以......
  • React报错之Expected `onClick` listener to be a function
    正文从这开始~总览当我们为元素的onClick属性传递一个值,但是该值却不是函数时,会产生"Expected onClick listenertobeafunction"报错。为了解决该报错,请确保只为元......
  • function plotter
    1#include<stdio.h>2#include<math.h>3#include<stdlib.h>4#include<stdbool.h>5#definemax(x,y)((x)>(y)?(x):(y))67#defineXDIM1024/......
  • 如何绑定 Webhook 推送
    近几年Webhook在前后端对接的开发模式中变得越来越流行,我们能用事件描述的事物越多,Webhook的作用范围也就越大。Webhook作为一个轻量的事件处理应用,正变得越来越实用。......
  • 报错:FUNCTION .to_char does not exist(to_char与date_format)
    错误代码:<iftest="startDate!=nullandstartDate!=''">ANDto_char(o.order_time,'yyyy-mm-dd')<![CDATA[>=]]>#{startDate}</if><iftest="endDate!=nulland......
  • React报错之Type '() => JSX.Element[]' is not assignable to type FunctionComponen
    正文从这开始~总览当我们尝试从函数组件中返回元素组成的数组时,会产生"Type'()=>JSX.Element[]'isnotassignabletotypeFunctionComponent"错误。为了解决该错误......
  • pytest常用hook函数
    pytest_runtest_makereport说明:收集每个用例三个阶段的执行结果先执行when='setup'返回前置的执行结果然后执行when='call'返回用例步骤的执行结果最后执行when='t......