Skip to content
yuanzhubi edited this page Apr 7, 2017 · 3 revisions

MACRO API:

LOCAL_HOOK(src_function_name, dest_function_name) : use it out of function LOCAL_HOOK_CPP(src_function_name, dest_function_name) : use it out of function LOCAL_HOOK_INIT(src_function_name) : use it out of function LOCAL_HOOK_START(src_function_name, dest_function_ptr) : use it in a function and the second argument is a function pointer! LOCAL_HOOK_FUNCTIONPOINTER_SYNC(src_function_name) : use it out of function

local_hook is to help you hook a exported "C" function that was compiled into a dynamic library at x86 or x64 platform in elf format "locally" ! Your process space can be separated into following space models: an executable file, several dynamic libraries. Here "locally" means you can hook the exported function only in one unit.

局部“挂钩”可以让你“局部”地对一个elf动态库导出的C函数进行“挂钩”。 我们可以把进程地址空间划分为以下地址模块:一个可执行文件,多个动态库。 这里我们所说的“局部”即是让“挂钩行为”仅在一个地址模块中生效。

#include <stdio.h> LOCAL_HOOK(puts, myputs)

That's all! 这就完了!

You have to use LOCAL_HOOK out of function filed. The hook will happen before the main function, or after dlopen finish if the codes is compiled into a dynamic library. If your version of GCC does not support attribute ((constructor)), you can use LOCAL_HOOK_CPP in a c++ source file instead.

你得在函数体外使用LOCAL_HOOK,这样“挂钩”行为会在main函数执行之前生效,在dlopen完成之后(如果你这个代码是被编译进了动态库)生效。 如果你的GCC版本不支持__attribute__ ((constructor)), 那么你可以在一个C++代码文件里使用LOCAL_HOOK_CPP来代替LOCAL_HOOK。

For more flexible, you can use LOCAL_HOOK_INIT out of function and LOCAL_HOOK_START in any proper function. Then the hook will happen after LOCAL_HOOK_START executed. Either the first hook happened in LOCAL_HOOK or LOCAL_HOOK_CPP or LOCAL_HOOK_START, you can call LOCAL_HOOK_START anywhere to hook second times or more in any function.

如果需要更灵活的使用,你可以在函数体外使用LOCAL_HOOK_INIT而在某个合适的函数中使用LOCAL_HOOK_START。“挂钩”行为会在LOCAL_HOOK_START执行后生效。 不管第一次的“挂钩”行为发生在LOCAL_HOOK 或 LOCAL_HOOK_CPP 或者 LOCAL_HOOK_START之中,你可以在任何函数中第二次调用或者更多次的调用LOCAL_HOOK_START来重新“挂钩”。

Attention: You can use it in CC++ language. Local hook can be only used to hook a exported "C" function that was compiled into a dynamic library at x86 or x64 platform in elf format. Large code models(SYSTEM V AMD64 ABI) is not supported. (Your GOT is greater than 2GB? The total linked ".so" files should be greater than 50GB in size!) How to remove the hook? You need to use dlsym to get the original function address first(after hook you do not have other method to get the original function address), and use LOCAL_HOOK_START with the address as 2rd argument. Take care of the function pointer problem in next sections.

注意: 你可以在CC++中使用。 局部挂钩只能对一个在x86或者x64的平台下编译进elf格式的动态库并导出的C函数进行挂钩。 “大型代码模式”(见 SYSTEM V AMD64 ABI) 是不支持的。(简单说吧,难道你链接的动态库超过50G了?) 需要移除“挂钩”?你需要先通过dlsym获取函数的原始地址("挂钩"之后你没有别的方法获取他的原始地址了),再把他作为第二个参数调用LOCAL_HOOK_START。 仔细阅读下一小节中提到的函数指针的问题。

Function pointer problem: But this is not all. If other models use function pointer of puts, our hook may affects them. The reason is due to the dynamic library linker wants the function pointer of the one function in every models are same, implemented by copy GOT of same function. But seldom did programmers use function pointer in GLIBC to call a function ? Most of our hook goals are there. If you face such dyniamic library, if it is used not by dlopen function but dynamic link, please use LOCAL_HOOK_INIT out of function filed and use LOCAL_HOOK_START after entering main function, then the we will not affect the function pointer of thedynamic library; else if it is used by dlopen function, you need to remove the hook first by the way mentioned in previous section, then dlopen, then LOCAL_HOOK_START again. A suggestion of the dlopen case, is to implement the remove hook, dlopen, restart hook via local hook the dlopen function.

但是这并不是全部。如果其它模块使用puts的函数指针,我们的“挂钩”行为有可能会影响到他们的取值, 原因是动态链接器希望程序在不同模块对于同一个函数获得相同的函数指针值, 所以后加载的模块总是从先加载的模块中拷贝有重叠的GOT内容。 不过话说回来,很少有人通过函数指针去调用GLIBC里的函数吧?我们绝大多数挂钩行为的目标都是在GLIBC那里。 如果你真的足够不幸遇上这样的动态库, 如果他是通过动态链接而不是通过dlopen函数进入你的进程空间的, 那么请在函数体外使用LOCAL_HOOK_INIT并且在main函数执行之后使用LOCAL_HOOK_START。这样动态库里的函数指针就不会受到影响了; 如果他是通过dlopen的,请使用上一小节提到的移除“挂钩”方法先移除“挂钩”,再dlopen,再重新“挂钩”。 有一个对上面所述的dlopen情况的建议:请把上面所述的移除“挂钩”、再dlopen、再重新“挂钩”的行为,直接通过局部挂钩dlopen函数来封装解决。

Clone this wiki locally