table(Linux系统调用表)的地址

一.方法一:常用方式

我们首先需要找到call table-with-offset的特征,先看下面的代码

syscall_call:
        call *sys_call_table(,%eax,4)
假设我们没有vmlinux可供gdb反汇编,那也只有采用模拟的方式了,模拟出一个call *sys_call_table(,%eax,4),然后看其机器码,然后在system_call的附近基于这个特征进行寻找 :

void fun1()    {            printf("fun1\n");    }    void fun2()    {            printf("fun2\n");    }    unsigned int sys_call_table[2] = {fun1, fun2};    int main(int argc, char **argv)    {            asm("call *sys_call_table(,%eax,4) \n\t");    }  

然后用objdump进行dump可见下面一行:
080483ac <main>:
...
 80483bc:       ff 14 85 1c 95 04 08    call   *0x804951c(,%eax,4)
...


于是ff 14 85 后面就是sys_call_table的地址,注意大小端,x86机器是小端机器,因此是反着的。如果system_call也不知道,比如不能挂载procfs,并且也没有System.map,那么就只有通过中断描述符来先获取system_call的地址了,方法如下:
0.你必须知道中断描述符的结构以及有中断描述符寄存器这么一回事。不过就算不知道也比较好查,google即可;
1.通过sidt指令获取中断描述符的基地址;
2.将这个地址加上8*0x80就是系统调用描述符的地址了;

3.从这个描述符中取出系统调用处理程序即system_call地址的高16位和低16位,拼接在一起即可。

二.方法二:使用dump_stack
写一个很简单的内核模块,内部调用dump_stack ,然后就可以看到:
 [<f88f300b>] init_module+0xb/0x53 [gettable]
 [<c013adc4>] sys_init_module+0x104/0x250
 [<c010620b>] syscall_call+0x7/0xb

既然看到了syscall_call+0x7的地址,那么也就知道了标号syscall_call的地址,而我们需要找的sys_call_table的地址就在它下面地址的指令中 ,对于2.6.8内核而言,就是它下面的第一条指令:
syscall_call:
        call *sys_call_table(,%eax,4)
实际上syscall_call这个标号可以在/proc/kallsym中取到的,如果没有procfs再使用dump_stack的方法。为了不让人说我是胡扯的,贴上代码:

int __init rm_init(void){        dump_stack();            unsigned char *ptr=0xc010620b-0x7;   //0xc010620b这个地址是从dump_stack中取到的,这里将两个模块合并成了一个            int i;            for (i = 0; i < 8; i ++) {                    printk("%02x ", (unsigned char)*(ptr+i));            }            return 0;    }    void __exit rm_exit(void){    }    module_init(rm_init);    module_exit(rm_exit);    MODULE_LICENSE("GPL");  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwfxgj.html