Closed alichtman closed 5 years ago
Hey, thank you for using KHOOK.
As for hooking system calls you have to hook sys_XXX
symbols like sys_kill
. See the example below:
KHOOK_EXT(long, sys_kill, long, long);
static long khook_sys_kill(long pid, long sig) {
printk("sys_kill -- %s pid %ld sig %ld\n", current->comm, pid, sig);
return KHOOK_ORIGIN(sys_kill, pid, sig);
}
Just use the right prototype for this sys_kill
...
Oh, whoops. My brain was not working correctly last night. Thanks for the help!
However, the example did not work for me. When I run $ kill <some_pid>
in bash, this debug statement isn't printed.
I tried changing the first parameter to a pid_t
type, and that did not solve the problem either.
I'm pretty sure that $ kill
calls sys_kill()
, but I'm not sure if that's true.
It's weird. I've tried to kill -9 1
and the dmesg shows me:
[ 4630.052329] sys_kill -- bash pid 1 sig 9
By the way, my kernel is 4.8.0-53-generic
I'm working on 4.18.0-17-generic
. Still not seeing the same behavior you're describing. Hmm.
OK, it makes sense then. From some point they changed syscalls notation and argument passing. So, now you have to look for __x64_sys_kill
with long (*)(const struct pt_regs *)
proto instead of sys_kill
. The code may look like this (didn't test):
KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *);
static long khook___x64_sys_kill(const struct pt_regs *regs) {
printk("sys_kill -- %s pid %ld sig %ld\n", current->comm, regs->di, regs->si);
return KHOOK_ORIGIN(__x64_sys_kill, regs);
}
Oh, alright, cool! I'll try this out when I have a minute.
Worked perfectly. Thanks for the help!
Updated the README with this example. Thank you for the question.
Can you explain where you found this new function signature?
KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *);
static long khook___x64_sys_kill(const struct pt_regs *regs)
I'm having trouble reproducing this with other syscalls.
For example, I have this hook for msgctl
, and it's not being tripped.
KHOOK_EXT(long, __x64_ksys_msgctl, int, int, struct msqid_ds __user *);
static long khook___x64_ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
Here is a relevant LKML email: https://lore.kernel.org/lkml/tip-d5a00528b58cdb2c71206e18bd021e34c4eab878@git.kernel.org/
But I can't figure out where you found the prototype for the updated sys_kill function. As far as I can tell, it's not in the source code. But I also know that can't be right, so I'm a little stuck. Google has turned up nothing so far.
Edit: I found this: https://github.com/torvalds/linux/blob/618d919cae2fcaadc752f27ddac8b939da8b441a/arch/x86/include/asm/syscall_wrapper.h#L125
and updated my code to:
KHOOK_EXT(long, __x64_ksys_msgctl, const struct pt_regs *);
static long khook___x64_ksys_msgctl(const struct pt_regs * regs) {
// int msqid, int cmd, struct msqid_ds __user *buf
action_task* task;
// Read first two arguments
if (regs->di == -1 && regs->si == -1) {
if (condition) {
printk(KERN_EMERG "sys_msgctl -- preparing...\n");
...
return 0;
} else {
printk(KERN_EMERG "sys_msgctl\n");
task = (action_task*) regs->dx;
...
return 0;
}
} else {
return KHOOK_ORIGIN(__x64_ksys_msgctl, regs);
}
}
However, this still does not hook msgctl
calls.
TLDR: __x64_ksys_msgctl
-> __x64_sys_msgctl
https://elixir.bootlin.com/linux/latest/source/ipc/msg.c#L614
SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
{
return ksys_msgctl(msqid, cmd, buf);
}
You could ether hook ksys_msgctl(int, int, struct msqid_ds *)
as a kernel function (in case if it is exported as a ksym with name -- check by grepping /proc/kallsyms) or hook __x64_sys_msgctl/sys_msgctl
as a system call handler.
ksys_msgctl
does appear in /proc/kallsyms
, and I've made this change: __x64_ksys_msgctl -> __x64_sys_msgctl
.
It's still not being hooked properly.
The syscall definition you pasted in was the reason I initially had sys_msgctl
hooked like this:
KHOOK_EXT(long, __x64_ksys_msgctl, int, int, struct msqid_ds __user *); static long khook___x64_ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
Should I change that ^ to __x64_sys_msgctl
?
I feel like I’m missing some core understanding of what I’m doing. Do you have any recommendations for topics I should read up on?
Should I change that ^ to __x64_sys_msgctl?
YES (but I didn't test it)
This works well for me:
KHOOK_EXT(long, __x64_sys_msgctl, const struct pt_regs *);
static long khook___x64_sys_msgctl(const struct pt_regs *regs)
{
printk("%s -- msqid:%ld cmd:%ld ptr:%p\n", current->comm, regs->di, regs->si, (void *)regs->dx);
return KHOOK_ORIGIN(__x64_sys_msgctl, regs);
}
main.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(int argc, const char *argv[])
{
msgctl(100, 200, (void *)300);
return 0;
}
$ dmesg
[108112.452874] a.out -- msqid:100 cmd:200 ptr:000000008b1f8f3d
What you posted did work for me. Funny enough, I actually posted that signature in a previous comment. I think my error was that the line below was never hit. I passed a -1
in to msgctl
for the first two parameters and it was turned into INT_MAX
(although I don't understand why, since ints
are signed...):
if (regs->di == -1 && regs->si == -1) {
Anyways, the issue is now resolved. Thank you again for the help.
hi, I am trying to hook sys_open and some other syscalls to intercept the file system activity, on kernel 4.17/4.18 on x86_64.
/proc/kallsyms shows x64_sys_open, but not ksys_open. Not sure if I need to hook ksys_open or x64_sys_open I am getting compilation error of 'undelcared identifier' for sys_open & __x64_sys_open.
What are the right headers I need to include ?
Along with sys_open, I need to hook sys_creat, sys_openat, sys_execve, sys_truncate, sys_ftruncate, sys_write, etc...
Before kernel 4.17, I was able to find the symbol for sys_xyz, but from Kernel 4.17 onward, I am not sure if I need to hook __x64_sys_xyz or ksys_xyz or sys_xyz.
In syscalls.h Some system call are declared with /__ARCH_WANT_SYSCALL_DEPRECATED/
Please help, thank you, Kumar T
@KTalinki Use the following code for every "modern" syscall handler (replace XXX
with open
or so):
KHOOK_EXT(long, __x64_sys_XXX, const struct pt_regs *);
static long khook___x64_sys_XXX(const struct pt_regs *regs)
{
// do the job
return KHOOK_ORIGIN(__x64_sys_XXX, regs);
}
Thank you milabs.
If I were to use hook in a traditional way of finding a specific syscall table address and hook it, which specific syscall API to hook sys_open or x64_sys_open or ksys_open sys_open or x64_sys_creat or ksys_creat sys_openat or x64_sys_openat or ksys_openat sys_execve or x64_sys_exeeve or ksys_execve etc ...
and what are the header files x64_sys_creat or x64_sys_openat are declared ?
It will be great if someone can share a sample with what is needed to hook syscalls on kernels from 4.17 onward.
thank you, Kumar T
Dear @KTalinki, you don't need to have headers to hook __x64_sys_XXX
as they all have the same prototype (like I shown before). As for the ksys_xxx()
symbols I'd suggest you to look for the Linux kernel source code to see how they are used. Finally, you're the kernel developer and you have to be able to dig the source code.
thank you @milabs , the way our existing code is structured, it uses the declaration of the syscalls from .../include/linux/syscalls.h
But on kernel 4.17 with x64_sys_open, is not declared in
The issue I am running in to is compilation errors for x64_sys_open and SYSCALL_64. Including <arch/x85/include/generated/asm/syscalls_64.h> is not helping.
Any help is appreciated, thank you, Kumar
@KTalinki Again, you don't have to include ANY header to hook __x64_XXX, just use the KHOOK_EXT
macro:
KHOOK_EXT(long, __x64_sys_XXX, const struct pt_regs *);
static long khook___x64_sys_XXX(const struct pt_regs *regs)
{
// do the job
return KHOOK_ORIGIN(__x64_sys_XXX, regs);
}
Which is the error with using this code?
@milabs hello,I want to hook sys_exevce. I'm using the KHOOK_EXT macro,which work well on the 64-bit machines,for example Redhat6.8 x86_64 or CentOS8 x86_64.The code is as follows: Linux Redhat6.8 2.6.32-642.el6.x86_64:
KHOOK_EXT(long, sys_execve, char __user *, char __user * __user *, char __user * __user *, struct pt_regs *);
static long khook_sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp, struct pt_regs *regs)
{
long ret = 0;
ret = KHOOK_ORIGIN(sys_execve, name, argv, envp, regs);
return ret;
}
CentOS8 x86_64:
KHOOK_EXT(long, __x64_sys_execve, const struct pt_regs *);
static long khook___x64_sys_execve(const struct pt_regs *regs)
{
long ret = 0;
ret = KHOOK_ORIGIN(__x64_sys_execve, regs);
return ret;
}
BUT,I have a problem on the 32-bit machine. I test it on Linux Redhat 6.8 2.6.32-642.el6.i686.The code is as follows:
KHOOK_EXT(int, sys_execve, struct pt_regs *);
static int khook_sys_execve(struct pt_regs *regs)
{
int ret = 0;
ret = KHOOK_ORIGIN(sys_execve, regs);
return ret;
}
I Found the sys_execve() symbols from the source code as follow:
After I insmod, I execute "ls" or any other commands. ERROR as following:
I suspect there is a problem with this code executing on a 32-bit machine.I hope you can take a look in your busy schedule. Thanks for your help!
@wbt165 I'd recommend you to hook do_execve
instead of sys_execve
for exec case. Could you try to hook it that way?
@milabs Thanks for your response!
I test do_execve
,and the results as follows:
[do_execve
work well on Linux Redhat6.8 2.6.32-642.el6.x86_64 ]
#include <linux/sched.h>
KHOOK(do_execve);
static int khook_do_execve(const char * filename,
char __user *__user *argv,
char __user *__user *envp,
struct pt_regs * regs)
{
int ret = 0;
ret = KHOOK_ORIGIN(do_execve, filename, argv, envp, regs);
pr_info("%s - Pass %s = %d\n", __func__, filename, ret);
return ret;
}
[do_execve
CANNOT hook on CentOS8 4.18.0-147.8.1.el8_1.x86_64, because the debug info is not printed out]
#include <linux/binfmts.h>
KHOOK(do_execve);
static int khook_do_execve(struct filename *filename,
const char __user *const __user *__argv,
const char __user *const __user *__envp)
{
int ret = 0;
ret = KHOOK_ORIGIN(do_execve, filename, __argv, __envp);
pr_info("%s - Pass %s = %d\n", __func__, filename->name, ret);
return ret;
}
[ do_execve
CANNOT work on Linux Redhat6.8 2.6.32-642.el6.i686]
#include <linux/sched.h>
KHOOK(do_execve);
static int khook_do_execve(const char * filename,
char __user *__user *argv,
char __user *__user *envp,
struct pt_regs * regs)
{
int ret = 0;
ret = KHOOK_ORIGIN(do_execve, filename, argv, envp, regs);
pr_info("%s - Pass %s = %d\n", __func__, filename, ret);
return ret;
}
After I insmod, I execute "ls" or any other commands. ERROR as following: The debug info is as follow:
Thanks for your help!
@wbt165 Unfortunately, 32-bit stub is not implemented as I never had such requirement for myself (see https://github.com/milabs/khook/blob/master/khook/x86/stub.S#L24). It would be great if you'll try to implement missing part of the macro.
If you could test that code on 32-bit system?
.macro CALL_COPY_N_ARGS n
sub $(\n * 4), %esp
.set i, 0
.rept \n
mov ((\n + i + 1) * 4)(%esp), %eax
mov %eax, (i * 4)(%esp)
.set i, i + 1
.endr
mov $0xcacacaca, %eax
call *%eax
add $(\n * 4), %esp
.endm
If you could test that code on 32-bit system?
.macro CALL_COPY_N_ARGS n sub $(\n * 4), %esp .set i, 0 .rept \n mov ((\n + i + 1) * 4)(%esp), %eax mov %eax, (i * 4)(%esp) .set i, i + 1 .endr mov $0xcacacaca, %eax call *%eax add $(\n * 4), %esp .endm
@milabs Unfortunately,this code has NO effect……
@milabs Unfortunately,this code has NO effect……
Made a branch for you to test: https://github.com/milabs/khook/tree/i686-fix Could you please test it?
@milabs Thank you for creating a branch! I tested it on Linux Redhat6.8 2.6.32-642.el6.i686, but it didn't work. The code is as follow:
#include <linux/uaccess.h>
#include <linux/slab.h>
static char *duplicate_filename(const char __user *filename)
{
char *kernel_filename;
int nRet;
kernel_filename = kmalloc(4096, GFP_KERNEL);
if (!kernel_filename)
{
pr_info("%s - NULL!\n", __func__);
return NULL;
}
nRet = strncpy_from_user(kernel_filename, filename, 4096);
if (nRet < 0) {
pr_info("%s - nRet = %d!\n", __func__, nRet);
kfree(kernel_filename);
return NULL;
}
return kernel_filename;
}
KHOOK_EXT(int, sys_execve, struct pt_regs *);
static int khook_sys_execve(struct pt_regs *regs)
{
int ret = 0;
char *filename;
filename = duplicate_filename((char __user *)regs->bx);
pr_info("%s - %s!\n", __func__, filename);
ret = KHOOK_ORIGIN(sys_execve, regs);
pr_info("%s ret = %d\n", __func__, ret);
kfree(filename);
return ret;
}
After I insmod, I execute "ls" or any other commands. ERROR as following: The debug info is as follow:
Just wanted to start out by saying this is an awesome project! Nice work!
I'm having a problem hooking
sys_kill
, and I was hoping you'd be able to help me out.sys_kill
is defined here inlinux/syscalls.h
.I have been trying to hook this function for a while and can not get anything to compile. I was able to hook
kill_pid
, however, that did not hook thekill
syscall.Is there a way to hook the actual kill syscall? Or can it not be done since the syscall table is no longer exported, post-Kernel 2.6?