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

x33g5p2x  于2021-12-05 转载在 C/C++  
字(4.2k)|赞(0)|评价(0)|浏览(392)

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

    1. 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环境变量:可以设置共享库的路径,并且该库将在任何其它库之前加载,即这个动态库中符号优先级是最高的。如果系统库函数使用内联优化,如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++ test.cpp
echo -e "**** start run ****\n"
LD_PRELOAD=${PWD}/libhook.so ./a.out

**     **执行结果如下:


 

**     **3. 使用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

**     **执行结果如下:


 

**     **Windwos上的Hook是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其它进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理Windows消息或特定事件。钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。

**      GitHub**:https://github.com/fengbingchun/Linux_Code_Test

相关文章

最新文章

更多