If your hook function is located within the same file being modified by plthook_open(), calling the original function by name will cause an infinite recursion (the hook calls itself), leading to a stack overflow and process crash.
To avoid this, you must capture the address of the original function and call it via a function pointer.
Platform Differences:
- Windows: The fourth argument of
plthook_replace() provides the address of the original function. - Unix/Linux: The fourth argument of
plthook_replace() does not set the address. You must use dlsym(RTLD_DEFAULT, "function_name") to retrieve the original function's address.
static ssize_t (*recv_func)(int sockfd, void *buf, size_t len, int flags);
/* This function is called instead of recv() called by libfoo.so.1 */
static ssize_t my_recv(int sockfd, void *buf, size_t len, int flags)
{
ssize_t rv;
... do your task: logging, etc. ...
rv = (*recv_func)(sockfd, buf, len, flags); /* call real recv(). */
... do your task: logging, check received data, etc. ...
return rv;
}
int install_hook_function()
{
plthook_t *plthook;
if (plthook_open_by_address(&plthook, &recv_func) != 0) {
printf("plthook_open error: %s\n", plthook_error());
return -1;
}
if (plthook_replace(plthook, "recv", (void*)my_recv, (void**)&recv_func) != 0) {
printf("plthook_replace error: %s\n", plthook_error());
plthook_close(plthook);
return -1;
}
#ifndef WIN32
// The address passed to the fourth argument of plthook_replace() is
// available on Windows. But not on Unixes. Get the real address by dlsym().
recv_func = (ssize_t (*)(int, void *, size_t, int))dlsym(RTLD_DEFAULT, "recv");
#endif
plthook_close(plthook);
return 0;
}