Linux Module to Hook Process Functions

Linux module to hook process functions

Be aware that there are several different syscalls which could be used - not just recv().

Assuming the application in question does its kernel interaction via the C library (instead of crafting syscalls by hand), and that you can restart it to set up the test, a fairly straightforward idea could be to use the LD_PRELOAD environment variable to first load a custom library which replaces the syscall wrappers of interest with intercepting ones.

Or you could set up syscall interception the way strace does, and monkey with the ones of interest.

Another option is to not let the application connect directly to the remote system, but instead create a proxy, have it connect to the proxy, and have the proxy connect to the remote system. A major advantage of this is that it's quite portable, requiring little in the way of platform specific details.

Linux module: being notified about task creation and destruction

You can use Kprobes, which enables you to dynamically hook into code in the kernel. You will need to find the right function among the ones involves in creating and destroying processes that give you the information you need. For instance, for tasks created, do_fork() in fork.c would be a good place to start. For tasks destroyed, do_exit. You would want to write a retprobe, which is a kind of kprobe that additionally gives you control at the end of the execution of the function, before it returns. The reason you want control before the function returns is to check if it succeeded in creating the process by checking the return value. If there was an error, then the function will return a negative value or in some cases possibly 0.

You would do this by creating a kretprobe struct:

static struct kretprobe do_fork_probe = {
.entry_handler = (kprobe_opcode_t *) my_do_fork_entry,
.handler = (kprobe_opcode_t *) my_do_fork_ret,
.maxactive = 20,
.data_size = sizeof(struct do_fork_ctx)
};

my_do_fork_entry gets executed when control enters the hooked function, and my_do_fork_ret gets executed just before it returns. You would hook it in as follows:

do_fork_probe.kp.addr =
(kprobe_opcode_t *) kallsyms_lookup_name("do_fork");

if ((ret = register_kretprobe(&do_fork_probe)) <0) {
// handle error
}

In the implementation of your hooks, it's a bit unwieldy to get the arguments and return value. You get these via the saved registers pt_regs data structure. Let's look at the return hook, where on x86 you get the return value via regs->ax.

static int my_do_fork_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
{
struct do_fork_ctx *ctx = (struct do_fork_ctx *) ri->data;
int ret = regs->ax; // This is on x86
if (ret > 0) {
// It's not an error, probably a valid process
}
}

In the entry point, you can get access to the arguments via the registers. e.g. on x86, regs->di is the first argument, regs->si is the second etc. You can google to get the full list. Note that you shouldn't rely on these registers for the arguments in the return hook as the registers may have been overwritten for other computations.

You will surely have to jump many hoops in getting this working, but hopefully this note should set you off in the right direction.

How to add a hook in memcpy function of linux kernel?

thanks to @Basile Starynkevitch
I solve the problem, yes, 'Sometimes, the compiler is optimizing memcpy to __builtin_memcpy'

Can multiple kernel modules use the same netfilter hook without affecting each other?

As you know, the hooks are just places in the TCP/IP stack that you can insert some functions to do whatever with the skbs. Each function usually return one of the following (see include/uapi/linux/netfilter.h)

  • NF_DROP ----- This is the end of this skb. Drop this skb and do not pass it to rest of hooks (and of course higher layers).
  • NF_ACCEPT -- I am done with this skb, forward the skb to the next hook
  • NF_STOLEN -- I hijacked this skb (the module queued the skb for later processing)

IPtables uses these hooks to implement the required firewall rules. You can of course exist with IPtables (and any other hooks), but if for some reason your function is called before IPtables hooks and returns NF_DROP, the skb will not be forwarded to IPtables. On the other hand, if you always return NF_ACCEPT, then IPtables and other hooks in the system will not be affected at all.

As for the order of the hooks, the following priorities are used when the netfilter system traverses the hooks (from include/uapi/linux/netfilter_ipv4.h):

enum nf_ip_hook_priorities {
NF_IP_PRI_FIRST = INT_MIN,
NF_IP_PRI_CONNTRACK_DEFRAG = -400,
NF_IP_PRI_RAW = -300,
NF_IP_PRI_SELINUX_FIRST = -225,
NF_IP_PRI_CONNTRACK = -200,
NF_IP_PRI_MANGLE = -150,
NF_IP_PRI_NAT_DST = -100,
NF_IP_PRI_FILTER = 0,
NF_IP_PRI_SECURITY = 50,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_SELINUX_LAST = 225,
NF_IP_PRI_CONNTRACK_HELPER = 300,
NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
NF_IP_PRI_LAST = INT_MAX,};

This means that IPtables mangle table hooks will be executed before FILTER hooks. You can use any of these values or your own when you register with nf_register_hooks().



Related Topics



Leave a reply



Submit