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

Posted fengbingchun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux下C++中可使用的3种Hook方法相关的知识,希望对你有一定的参考价值。

      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消息或特定事件。钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。

      GitHubhttps://github.com/fengbingchun/Linux_Code_Test

以上是关于Linux下C++中可使用的3种Hook方法的主要内容,如果未能解决你的问题,请参考以下文章

怎么hook linux open函数

Linux内核中的下半部机制之tasklet

Linux内核中的下半部机制之tasklet

Hook CreateProcess

Linux下使用C++解析json文件

如何hook某一个shell命令