Linux下C++中可使用的3中Hook方法

      Hook即钩子,截获API调用的技术,是将执行流程重定向到你自己的代码,类似于hack。如使程序运行时调用你自己实现的malloc函数代替调用系统库中的malloc函数。这里介绍下Linux下C++中可使用的3中Hook方法:

1. GNU C库给部分函数预留Hook接口的

GNU C库中有一部分函数允许用户通过指定适当的钩子函数(hook function)来修改。主要是malloc、realloc和free的行为,钩子函数的声明在malloc.h文件中,如__malloc_hook, __free_hook,你可以使用这些钩子来帮助你调试使用动态内存分配的程序,但是用GCC编译时会提示这些接口已被废弃(不影响使用)。

      测试代码如下:

#include <malloc.h>
#include <stdio.h>
 
/* reference:
    http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html
    https://stackoverflow.com/questions/11356958/how-to-use-malloc-hook
*/
void* (*old_malloc_hook)(size_t, const void*);
void (*old_free_hook)(void* __ptr, const void*);
void my_free_hook(void* ptr, const void* caller);
 
void* my_malloc_hook(size_t size, const void* caller)
{
    void *result;
    // Restore all old hooks
    __malloc_hook = old_malloc_hook;
    __free_hook = old_free_hook;
    // Call recursively
    result = malloc(size);
    // Save underlying hooks
    old_malloc_hook = __malloc_hook;
    old_free_hook = __free_hook;
    // printf might call malloc, so protect it too.
    printf("malloc (%u) returns %p\n", (unsigned int) size, result);
    // Restore our own hooks
    __malloc_hook = my_malloc_hook;
    __free_hook = my_free_hook;
    return result;
}
 
void my_free_hook(void *ptr, const void *caller)
{
    // Restore all old hooks
    __malloc_hook = old_malloc_hook;
    __free_hook = old_free_hook;
    // Call recursively
    free(ptr);
    // Save underlying hooks
    old_malloc_hook = __malloc_hook;
    old_free_hook = __free_hook;
    // printf might call free, so protect it too.
    printf("freed pointer %p\n", ptr);
    // Restore our own hooks
    __malloc_hook = my_malloc_hook;
    __free_hook = my_free_hook;
}
 
void my_init(void)
{
    old_malloc_hook = __malloc_hook;
    old_free_hook = __free_hook;
    __malloc_hook = my_malloc_hook;
    __free_hook = my_free_hook;
}
 
int main()
{
    my_init();
 
    void* p = malloc(10);
    free(p);
 
    fprintf(stdout, "test finish\n");
    return 0;
}

     build.sh内容如下:

#! /bin/bash
 
g++ test.cpp
echo -e "**** start run ****\n"
./a.out

      执行结果如下:

 2. 使用LD_PRELOAD优先加载以替换系统库里的函数

     使用LD_PRELOAD环境变量可以设置共享库的路径,并且该库将在任何其它库之前加载,即这个动态库中符号优先级是最高的。如果系统库函数使用内联优化,如strcmp,则在编译程序时,可能需添加-fno-builtin-strcmp。

      测试代码test.cpp如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
 
int main()
{
    srand(time(NULL));
    for (int i = 0; i < 2; ++i)
        fprintf(stdout, "value: %02d\n", rand() % 100);
 
    const char* str1 = "https://blog.csdn.net/fengbingchun";
    const char* str2 = "https://github.com/fengbingchun";
    fprintf(stdout, "are they equal: %d\n", strcmp(str1, str2));
 
    fprintf(stdout, "test finish\n");
    return 0;
}

      测试代码hook.cpp如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int rand()
{
    fprintf(stdout, "_^_ set rand function to a constant: 88 _^_\n");
    return 88;
}
 
int strcmp(const char* str1, const char* str2)
{
    fprintf(stdout, "_^_ set strcmp function to a constant: 0 _^_\n");
    return 0;
}

      build.sh内容如下:

#! /bin/bash
 
g++ -shared -fPIC -o libhook.so hook.cpp
或者g++ -shared -fPIC -fno-builtin-strcmp -o libhook.so hook.cpp
g++ test.cpp
echo -e "**** start run ****\n"
LD_PRELOAD=${PWD}/libhook.so ./a.out

      执行结果如下:

 3. 使用gcc的封装选项

      使用GCC的--wrap选项可以对symbol使用包装函数(wrapper function),任何对symbol未定义的引用(undefined reference)会被解析成__wrap_symbol,而任何对__real_symbol未定义的引用会被解析成symbol。

        即当一个名为symbol符号使用wrap功能时,程序中任何用到symbol符号的地方实际使用的是__wrap_symbol符号,任何用到__real_symbol的地方实际使用的是真正的symbol。

        注意:当__wrap_symbol是使用C++实现时,一定要加上extern “C”,否则将会出现”undefined reference to __wrap_symbol”。

      测试代码test.cpp如下:

#include <stdio.h>
#include <stdlib.h>
 
extern "C" {
 
void* __real_malloc(size_t size);
void __real_free(void* ptr);
extern void foo();
void __real_foo();
 
void* __wrap_malloc(size_t size)
{
    fprintf(stdout, "_^_ call wrap malloc function _^_\n");
    return __real_malloc(size);
}
 
void __wrap_free(void* ptr)
{
    fprintf(stdout, "_^_ call wrap free function _^_\n");
    __real_free(ptr);
}
 
void __wrap_foo()
{
    fprintf(stdout, "_^_ call wrap foo function _^_\n");
}
 
} // extern "C"
 
int main()
{
    foo();
    __real_foo();
 
    void* p1 = malloc(10);
    free(p1);
 
    fprintf(stdout, "test finish\n");
    return 0;
}

      测试代码foo.cpp如下:

#include <stdio.h>
 
extern "C" {
 
void foo()
{
    fprintf(stdout, "call foo function\n");
}
 
} // extern "C"

      build.sh内容如下:

#! /bin/bash
 
g++ foo.cpp test.cpp -Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=foo
echo -e "**** start run ****\n"
./a.out

      执行结果如下:


原文链接:https://blog.csdn.net/fengbingchun/article/details/121730082

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值