This project provides a simple method to intercept various kernel methods on the fly by using ftrace.
main.c includes a complete example hooking 2 kernel functions, implementing a bare bones RDTSC timer based VM detection evasion.
The most important parts are as follows:
A list of functions to hook:
static const fthinit_t hook_list[] = {
HLIST_NAME_ENTRY(kvm_emulate_cpuid),
HLIST_GETTER_ENTRY(kvm_vcpu_run)
};
HLIST_NAME_ENTRY retrieves the address of the function using kallsyms, while HLIST_GETTER_ENTRY requires the user to define a getter function that returns a uintptr_t. It is done this way:
DEFINE_HOOK_GETTER(kvm_vcpu_run)
{
return (uintptr_t)kvm_x86_ops->run;
}
To initialize the hook list call start_hook_list
function. Also, end_hook_list
function removes the hooks.
Every hook has to be defined using DEFINE_FUNCTION_HOOK and DEFINE_INTERCEPT_HOOK macros. For FUNCTION type, there is DEFINE_STATIC_FUNCTION_HOOK macro if it is possible to define the function in the same file. Otherwise, use DEFINE_FUNCTION_HOOK and DECLARE_FUNCTION_HOOK. The syntax is all the same, like this:
DEFINE_STATIC_FUNCTION_HOOK(int, kvm_emulate_cpuid, struct kvm_vcpu *vcpu)
To access the original function use the DEFINE_ORIGINAL macro inside the function.
DEFINE_INTERCEPT_HOOK macros work in a similar way, but you do not need to specify the function parameters, they are always as follows: unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs
. Example definition:
DEFINE_STATIC_INTERCEPT_HOOK(int, vmx_handle_exit)
If the hook hangs the system, disable sibling and tail call optimizations by adding this at the top of each file containing the hooks:
#pragma GCC optimize("-fno-optimize-sibling-calls")