Hi. In this brief post I’ll show you another way to get the syscall table address dinamically.

This post is only an expansion of this one.

The idea is very trivial: we can find this address by a brute-force scan on the kernel reserved memory, in order to find the syscall table address. The kernel memory ranges from 0xc0000000 to 0xd0000000 (in 32-bit architecture).

We can compare the known locations with exported system calls, so finding the syscall table address. Even if the syscall table address is no longer exported, a few system calls (like sys_close) are still exported and available in the kernel modules.

I don’t like very much this method because scanning all the memory is computationally expensive. But, it works! :)

This is the “find()” function that takes care of the task:

... #define START_MEM 0xc0000000 #define END_MEM 0xd0000000 ... unsigned long **find() { unsigned long **sctable; unsigned long int i = START_MEM; while ( i < END_MEM) { sctable = (unsigned long **)i; if ( sctable[__NR_close] == (unsigned long *) sys_close) { return &sctable[0]; } i += sizeof(void *); } return NULL; }

Simply it scans the memory from START_MEM to END_MEM: when the “__NR_close”-th address of “sctable” is equals to the “sys_close()” address, we are sure that “sctable” is pointing to the syscall table. So we have only to return this address and use it as usual.

Follows the LKM source code (“bruteforce.c”):

#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/unistd.h> #include <asm/current.h> #include <linux/sched.h> #include <linux/syscalls.h> #include <asm/system.h> MODULE_LICENSE("GPL"); #define START_MEM 0xc0000000 #define END_MEM 0xd0000000 unsigned long *syscall_table; unsigned long **find() { unsigned long **sctable; unsigned long int i = START_MEM; while ( i < END_MEM) { sctable = (unsigned long **)i; if ( sctable[__NR_close] == (unsigned long *) sys_close) { return &sctable[0]; } i += sizeof(void *); } return NULL; } static int init(void) { printk("

Module starting...

"); syscall_table = (unsigned long *) find(); if ( syscall_table != NULL ) { printk("Syscall table found at %x

", (unsigned ) syscall_table); } else { printk("Syscall table not found!

"); } return 0; } static void exit(void) { printk("Module ending

"); return; } module_init(init); module_exit(exit);

Here is the Makefile:

obj-m := bruteforce.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

We can compile it:

spaccio@spaccio:~/Hijack/bruteforce$ make make -C /lib/modules/2.6.35-22-generic/build SUBDIRS=/home/spaccio/Hijack/bruteforce modules make[1]: Entering directory `/usr/src/linux-headers-2.6.35-22-generic' CC [M] /home/spaccio/Hijack/bruteforce/bruteforce.o /home/spaccio/Hijack/bruteforce/bruteforce.c:19: warning: function declaration isn’t a prototype Building modules, stage 2. MODPOST 1 modules CC /home/spaccio/Hijack/bruteforce/bruteforce.mod.o LD [M] /home/spaccio/Hijack/bruteforce/bruteforce.ko make[1]: Leaving directory `/usr/src/linux-headers-2.6.35-22-generic' spaccio@spaccio:~/Hijack/bruteforce$

Finally we can run it:

spaccio@spaccio:~/Hijack/bruteforce$ sudo insmod bruteforce.ko spaccio@spaccio:~/Hijack/bruteforce$

Now we check if the address found is correct or not:

spaccio@spaccio:~/Hijack/bruteforce$ dmesg | tail ... [ 725.653763] Module starting... [ 725.988959] Syscall table found at c05d2180 spaccio@spaccio:~/Hijack/bruteforce$ spaccio@spaccio:~/Hijack/bruteforce$ cat /boot/System.map-2.6.35-22-generic | grep sys_call_table c05d2180 R sys_call_table spaccio@spaccio:~/Hijack/bruteforce$

As expected, the syscall address is correct.

You can include the “find()” function in your LKM, so finding dinamically the syscall table address.

Bye.