The task is to replace some syscalls in linux 2.6.x kernel. In the 2.4.x kernel it's easy to
do, but in 2.6.x system call table is not in exported symbols. It may be done for x86 in the
hackish way via sys_call_table address calculation:
----------||----------
/* System call table address calculation.
*/
ptr=(unsigned long *)((init_mm.end_code + 4) & 0xfffffffc);
printk (KERN_INFO"Searching for sys_call_table address...\n");
/* Lookup for the table in the data section. */
while((unsigned long )ptr < (unsigned long)init_mm.end_data) {
if (*ptr == (unsigned long *)sys_open) { /* The hit has happend! */
printk (KERN_INFO" -> matching detected at %p\n", ptr);
/* The pointers mast point to kernel code section... */
for(i = 0; i < 4 ;i++)
{
arr[i]=*(ptr+i);
arr[i]=(arr[i] >> 16) & 0x0000ffff;
}
/* And they does not mast match... */
if(arr[0] != arr[2] || arr[1] != arr[3])
{
sys_call_table=(ptr-__NR_open);
break;
}
}
ptr++; /* The next one... */
}
printk (KERN_INFO"sys_call_table base found at: %p\n",sys_call_table);
/* Saving pointers to original
* system call handlers.
*/
original_sys_write = sys_call_table[__NR_write];
original_sys_open = sys_call_table[__NR_open];
original_sys_close = sys_call_table[__NR_close];
printk (KERN_INFO"Starting patching!\n");
/* Remapping write, open and close syscall
* entries syscall table with to our functions.
*/
sys_call_table[__NR_write] = fake_sys_write;
sys_call_table[__NR_open] = fake_sys_open;
sys_call_table[__NR_close] = fake_sys_close;
...
----------||----------
Is there a clear way to system calls replacement (for example via audit API)?
Why would you want to do that
Why would you want to do that? Aren't you trying to solve a problem the wrong way? You can intercept systemcalls in userspace easily for all dynamically linked programs. In the kernel you can make a LSM module or something, or your own wrapper filesystem or whatever. But simply replacing existing systemcalls with your own at runtime isn't the way to go.
your view seems good could y
your view seems good could you give me a brief idea over this, i am also trying to intercept system calls but i am getting error
unresolved symbol sys_call_table in linux 2.4.21
i found from others that redhat has removed the option of exporting sys_call_table from version 2.4.18
ok bye ..
rajkaman
The question is what you want
The question is what you want to do, not how.
If it's just some stupid college assignment, then you don't have much choice I guess. But if you want to achieve something useful and more long term then think very carefully what the right way is to reach your goal.
So the question is, what do you want to do? And think about the big picture, not the implementation details.
Could you point me how to int
Could you point me how to intercept all system calls in userspace ?
See http://kerneltrap.org/nod
See http://kerneltrap.org/node/5802
As strcmp said, you can also use ptrace, depending on what exactly your goal is. The preload thing only works with programs dynamically linked to libc (in practice almost all), but isn't really suitable for security related things as programs can always call systemcalls directly.
Improper System call table address calculation
If you need to calculate the syscall table (sys_call_table), here is the function you can use within a lkm (kernel 2.6.x). You can verify the address is correct by comparing it with:
grep sys_call_table /boot/System.map*
The complete code is here:
http://www.gnome.org/~lcolitti/gnome-startup/linux-iolog/readlog.c
finding sys_call_table: alternate method
somewhere in the linux-kernel, sys_call_table has to be called. now where is this place? we find near the int 0x80 vector, which points to "system_call", which, in "syscall_call", does a "call *sys_call_table(,eax,4)". the file is named "entry.S" in linux/arch/i386/kernel/. so, tell the compiler to generate an assembly listing when compiling entry.S and lookup the machine code generated for the instruction. the adress of sys_call_table should be about 1 or 2 bytes away from the "syscall_call" label.
unfortunately, allthough both symbols are in kallsyms:
hr@clio$ grep system_call /proc/kallsyms
c0102300 T system_call
hr@clio$ grep syscall_call /proc/kallsyms
c0102332 t syscall_call
the compiler cannot find it at compile time. so either you have to search /proc/kallsyms yourself, or ask the CPU via the SIDT machine instruction to store a pointer to the descriptor table. In memory of M$-DOS, I've written (for demonstration purposes) an LKM which implements the old "get_vector" "set_vector" DOS-function calls - maybe some of you remember "mov ax,2509h" "int 21".
the implementation seems straight forward enough, but if you find any bug, please tell me. I hope it is bugfree :-}.
at module_init, SIDT is executed and the int 0x80 vector is modified.
unfortunately, this site shortens my article, so check the full source-code at the URL below.
static int __init sysmon_init(void) {
int n;
...
asm("sidt idt_descr");
n=SYSCALL_VECTOR;
saved_vec=get_vector(n);
set_vector(n,new_syscall);
return 0;
}
you can look at the complete code here: http://wildsau.enemy.org/SYSMON
once the module is loaded, you can view /proc/sysmon which accumulates how often systemcalls are executed. there's a also a userspace program to show a statistic (./sysmon-txt | sort -nr +1 | head gives the 10 most frequently executed syscalls)
I'm aware, that this does not solve your problem, but you can use "get_vector(0x80)" to start scanning the for the "call *sys_call_table(,eax,4)" opcode. it will probably look like this:
hr@clio$ cat foo.s
call *0xdeadbeef(,%eax,4)
hr@clio$ as -al foo.s
GAS LISTING foo.s page 1
1
2
3 0000 FF1485EF call *0xdeadbeef(,%eax,4)
3 BEADDE
kind regards,
h.rosmanith
PS: but please write a follow-up to this article if you know another alternate solution
Due to some error, the webpag
Due to some error, the webpage http://wildsau.enemy.org/SYSMON was not available. This is fixed now - it's possible to access it now.
sorry for the inconvenience.
'grep sys_call_table
'grep sys_call_table /boot/System.map*' & address returned by find_sys_call_table(), did not match. When I used the address from the grep command, I am able to interrupt a system call. Can I use the value returned from grep? What is the disadvantage?
Thank you