您的位置:首页 > 运维架构 > Linux

get system call table in x86-64 Linux

2012-07-19 16:36 465 查看

get system call table in x86-64 Linux

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/module.h>

#include <asm/uaccess.h>

#include <asm/fcntl.h>

#include <asm/unistd.h>

#include <asm/ia32_unistd.h>

#include <asm/msr.h>

#define THIS_DESCRIPTION "Dynamically get sys_call_table/ia32_sys_call_table in kernel module.\n\t\tI don't think there would be anyone who won't enable CONFIG_IA32_EMULATION these days.\n\t\tso you can add the unessary check if you really want to."

MODULE_DESCRIPTION( THIS_DESCRIPTION );

MODULE_AUTHOR("albcamus <albcamus@gmail.com>");

MODULE_LICENSE("GPL");

/**

* TODO: if you want shut this up, comment the following line.

*/

#define BY_IDT_DEBUG

#ifdef BY_IDT_DEBUG

#define dbgprint(format,args...) \

printk("get_syscall: function:%s-L%d: "format, __FUNCTION__, __LINE__, ## args);

#else

#define dbgprint(format,args...)  do {} while(0);

#endif

/**

* sys call table

*/

void ** my_ia32_syscall_table;

void ** my_syscall_table;

/**

* 10 bytes  -- please refer to AMD64 Architecture Programmer's

*         Manuals for more information.

*/

struct idtr {

unsigned short limit;

unsigned long base; //in 64bit mode, base address is 8 bytes

} __attribute__ ((packed));

/**

* in long mode -- 64bit mode and compatity mode,

* every IDT entry has a 16-byte size

*/

struct idt {

u16 offset_low;

u16 segment;

unsigned ist : 3, zero0 : 5, type : 5, dpl :2, p : 1;

u16 offset_middle;

u32 offset_high;

u32 zero1;

} __attribute__ ((packed));

/**

* Return the first appearence of NEEDLE in HAYSTACK.  -- copied from PHRACK

* */

static void *memmem(const void *haystack, size_t haystack_len,

const void *needle, size_t needle_len)

{/*{{{*/

const char *begin;

const char *const last_possible

= (const char *) haystack + haystack_len - needle_len;

if (needle_len == 0)

/* The first occurrence of the empty string is deemed to occur at

the beginning of the string.  */

return (void *) haystack;

/* Sanity check, otherwise the loop might search through the whole

memory.  */

if (__builtin_expect(haystack_len < needle_len, 0))

return NULL;

for (begin = (const char *) haystack; begin <= last_possible;

++begin)

if (begin[0] == ((const char *) needle)[0]

&& !memcmp((const void *) &begin[1],

(const void *) ((const char *) needle + 1),

needle_len - 1))

return (void *) begin;

return NULL;

}/*}}}*/

/**

* Find the location of ia32_sys_call_table

*/

static unsigned long get_syscall_table_ia32(void)

{/*{{{*/

#define OFFSET_SYSCALL 100    /* from system_call/ia32_syscall, we'll read first 150 bytes */

struct idtr idtr;

struct idt idt;

unsigned long sys_call_off;

unsigned long retval;

char sc_asm[OFFSET_SYSCALL], *p;

/* well, let's read IDTR */

asm("sidt %0"

:"=m"(idtr)

: );

dbgprint("idtr base at %p\n", (void *)idtr.base);

/**

* Read in IDT for vector 0x80 (syscall)

*/

memcpy(&idt, (char *) idtr.base + 16 * 0x80, sizeof(idt));

sys_call_off =  ( ( (unsigned long)idt.offset_high ) << 32 ) |

( ((idt.offset_middle << 16 ) | idt.offset_low) & 0x00000000ffffffff );

dbgprint("sys_call_off at %p\n", (void *)sys_call_off);

/* we have syscall routine address now, look for syscall table

dispatch (indirect call) */

memcpy(sc_asm, (void *)sys_call_off, OFFSET_SYSCALL);

/**

* ia32_call > ia32_tracesys > ia32_do_syscall > 'call *ia32_sys_call_table(,%rax,8)'

* Find callq *ia32_sys_call_table(,%rax,8)

*

* (gdb) disassemble ia32_syscall

* Dump of assembler code for function ia32_syscall:

* 0xffffffff81066b98 <ia32_syscall+0>:    swapgs

* 0xffffffff81066b9b <ia32_syscall+3>:    sti

* 0xffffffff81066b9c <ia32_syscall+4>:    mov    %eax,%eax

* 0xffffffff81066b9e <ia32_syscall+6>:    push   %rax

* 0xffffffff81066b9f <ia32_syscall+7>:    cld

* 0xffffffff81066ba0 <ia32_syscall+8>:    sub    $0x48,%rsp

* 0xffffffff81066ba4 <ia32_syscall+12>:   mov    %rdi,0x40(%rsp)

* 0xffffffff81066ba9 <ia32_syscall+17>:   mov    %rsi,0x38(%rsp)

* 0xffffffff81066bae <ia32_syscall+22>:   mov    %rdx,0x30(%rsp)

* 0xffffffff81066bb3 <ia32_syscall+27>:   mov    %rcx,0x28(%rsp)

* 0xffffffff81066bb8 <ia32_syscall+32>:   mov    %rax,0x20(%rsp)

* 0xffffffff81066bbd <ia32_syscall+37>:   mov    %gs:0x10,%r10

* 0xffffffff81066bc6 <ia32_syscall+46>:   sub    $0x1fd8,%r10

* 0xffffffff81066bcd <ia32_syscall+53>:   orl    $0x2,0x14(%r10)

* 0xffffffff81066bd2 <ia32_syscall+58>:   testl  $0x181,0x10(%r10)

* 0xffffffff81066bda <ia32_syscall+66>:   jne    0xffffffff81066c04 <ia32_tracesys>

* End of assembler dump.

* (gdb) disassemble ia32_tracesys

* Dump of assembler code for function ia32_tracesys:

* 0xffffffff81066c04 <ia32_tracesys+0>:   sub    $0x30,%rsp

* 0xffffffff81066c08 <ia32_tracesys+4>:   mov    %rbx,0x28(%rsp)

* 0xffffffff81066c0d <ia32_tracesys+9>:   mov    %rbp,0x20(%rsp)

* 0xffffffff81066c12 <ia32_tracesys+14>:  mov    %r12,0x18(%rsp)

* 0xffffffff81066c17 <ia32_tracesys+19>:  mov    %r13,0x10(%rsp)

* 0xffffffff81066c1c <ia32_tracesys+24>:  mov    %r14,0x8(%rsp)

* 0xffffffff81066c21 <ia32_tracesys+29>:  mov    %r15,(%rsp)

* 0xffffffff81066c25 <ia32_tracesys+33>:  movq   $0xffffffffffffffda,0x50(%rsp)

* 0xffffffff81066c2e <ia32_tracesys+42>:  mov    %rsp,%rdi

* 0xffffffff81066c31 <ia32_tracesys+45>:  callq  0xffffffff81073a02 <syscall_trace_enter>

* 0xffffffff81066c36 <ia32_tracesys+50>:  mov    0x30(%rsp),%r11

* 0xffffffff81066c3b <ia32_tracesys+55>:  mov    0x38(%rsp),%r10

* 0xffffffff81066c40 <ia32_tracesys+60>:  mov    0x40(%rsp),%r9

* 0xffffffff81066c45 <ia32_tracesys+65>:  mov    0x48(%rsp),%r8

* 0xffffffff81066c4a <ia32_tracesys+70>:  mov    0x58(%rsp),%rcx

* 0xffffffff81066c4f <ia32_tracesys+75>:  mov    0x60(%rsp),%rdx

* 0xffffffff81066c54 <ia32_tracesys+80>:  mov    0x68(%rsp),%rsi

* 0xffffffff81066c59 <ia32_tracesys+85>:  mov    0x70(%rsp),%rdi

* 0xffffffff81066c5e <ia32_tracesys+90>:  mov    0x78(%rsp),%rax

* 0xffffffff81066c63 <ia32_tracesys+95>:  mov    (%rsp),%r15

* 0xffffffff81066c67 <ia32_tracesys+99>:  mov    0x8(%rsp),%r14

* 0xffffffff81066c6c <ia32_tracesys+104>: mov    0x10(%rsp),%r13

* 0xffffffff81066c71 <ia32_tracesys+109>: mov    0x18(%rsp),%r12

* 0xffffffff81066c76 <ia32_tracesys+114>: mov    0x20(%rsp),%rbp

* 0xffffffff81066c7b <ia32_tracesys+119>: mov    0x28(%rsp),%rbx

* 0xffffffff81066c80 <ia32_tracesys+124>: add    $0x30,%rsp

* 0xffffffff81066c84 <ia32_tracesys+128>: jmpq   0xffffffff81066bdc <ia32_do_syscall>

* End of assembler dump.

* (gdb) disassemble ia32_do_syscall

* Dump of assembler code for function ia32_do_syscall:

* 0xffffffff81066bdc <ia32_do_syscall+0>: cmp    $0x13d,%eax

* 0xffffffff81066be1 <ia32_do_syscall+5>: ja     0xffffffff81066c89 <ia32_badsys>

* 0xffffffff81066be7 <ia32_do_syscall+11>:        mov    %edi,%r8d

* 0xffffffff81066bea <ia32_do_syscall+14>:        mov    %ebp,%r9d

* 0xffffffff81066bed <ia32_do_syscall+17>:        xchg   %ecx,%esi

* 0xffffffff81066bef <ia32_do_syscall+19>:        mov    %ebx,%edi

* 0xffffffff81066bf1 <ia32_do_syscall+21>:        mov    %edx,%edx

* 0xffffffff81066bf3 <ia32_do_syscall+23>:        callq  *0xffffffff812e7c70(,%rax,8)

* End of assembler dump.

* (gdb) x/xw ia32_do_syscall+23

* 0xffffffff81066bf3 <ia32_do_syscall+23>:        0x70c514ff

* (gdb)

*

*/

p = (char *) memmem(sc_asm, OFFSET_SYSCALL, "\xff\x14\xc5", 3);

if (p == NULL) {

printk("opcode not found, meats that we cannot find sys_call_table.\n");

return 0;

}

retval = *(unsigned long *) (p + 3);

return retval;

#undef OFFSET_SYSCALL

}/*}}}*/

/**

* Find the location of long-mode sys_call_table

*/

static unsigned long get_syscall_table_long(void)

{/*{{{*/

#define OFFSET_SYSCALL 150

unsigned long syscall_long, retval;

char sc_asm[OFFSET_SYSCALL];

rdmsrl(MSR_LSTAR, syscall_long);

dbgprint("long mode: system_call is at %p\n", (void *)syscall_long);

memcpy(sc_asm, (char *)syscall_long, OFFSET_SYSCALL);

/**

* Find callq *sys_call_table(,%rax,8)

* -------------------------------------

* (gdb) disassemble system_call

* Dump of assembler code for function system_call:

* 0xffffffff81063750 <system_call+0>:     swapgs

* 0xffffffff81063753 <system_call+3>:     mov    %rsp,%gs:0x18

* 0xffffffff8106375c <system_call+12>:    mov    %gs:0x10,%rsp

* 0xffffffff81063765 <system_call+21>:    sti

* 0xffffffff81063766 <system_call+22>:    sub    $0x50,%rsp

* 0xffffffff8106376a <system_call+26>:    mov    %rdi,0x40(%rsp)

* 0xffffffff8106376f <system_call+31>:    mov    %rsi,0x38(%rsp)

* 0xffffffff81063774 <system_call+36>:    mov    %rdx,0x30(%rsp)

* 0xffffffff81063779 <system_call+41>:    mov    %rax,0x20(%rsp)

* 0xffffffff8106377e <system_call+46>:    mov    %r8,0x18(%rsp)

* 0xffffffff81063783 <system_call+51>:    mov    %r9,0x10(%rsp)

* 0xffffffff81063788 <system_call+56>:    mov    %r10,0x8(%rsp)

* 0xffffffff8106378d <system_call+61>:    mov    %r11,(%rsp)

* 0xffffffff81063791 <system_call+65>:    mov    %rax,0x48(%rsp)

* 0xffffffff81063796 <system_call+70>:    mov    %rcx,0x50(%rsp)

* 0xffffffff8106379b <system_call+75>:    mov    %gs:0x10,%rcx

* 0xffffffff810637a4 <system_call+84>:    sub    $0x1fd8,%rcx

* 0xffffffff810637ab <system_call+91>:    testl  $0x181,0x10(%rcx)

* 0xffffffff810637b2 <system_call+98>:    jne    0xffffffff81063889 <tracesys>

* 0xffffffff810637b8 <system_call+104>:   cmp    $0x117,%rax

* 0xffffffff810637be <system_call+110>:   ja     0xffffffff8106387b <badsys>

* 0xffffffff810637c4 <system_call+116>:   mov    %r10,%rcx

* 0xffffffff810637c7 <system_call+119>:   callq  *0xffffffff812e6d60(,%rax,8)

* 0xffffffff810637ce <system_call+126>:   mov    %rax,0x20(%rsp)

* End of assembler dump.

* (gdb) x/xw system_call+119

* 0xffffffff810637c7 <system_call+119>:   0x60c514ff

* (gdb)

*/

retval = (unsigned long) memmem(sc_asm, OFFSET_SYSCALL, "\xff\x14\xc5", 3);

if ( retval != 0 ) {

dbgprint("long mode : sys_call_table is at %p\n",

(void *) (* (unsigned long *)(retval+3)) ) ;

retval = (unsigned long) ( * (unsigned long *)(retval+3) );

} else {

printk("long mode : memmem found nothing, returning NULL:( \n");

retval = 0;

}

#undef OFFSET_SYSCALL

return retval;

}/*}}}*/

static int get_syscall_init_module(void)

{/*{{{*/

printk(KERN_DEBUG "get_syscall: Hi, you fucking linux!\n");

my_ia32_syscall_table = (void **) get_syscall_table_ia32();

if (my_ia32_syscall_table == 0)

return -1;

my_syscall_table = (void **) get_syscall_table_long();

if (my_syscall_table == 0)

return -1;

dbgprint("ia32_sys_call_table address : %p\n", (void *) my_ia32_syscall_table);

dbgprint("long mode : sys_call_table address : %p\n", (void *) my_syscall_table);

#define REPLACE_IA32(x) o_sys_##x = my_ia32_syscall_table[__NR_ia32_##x];\

my_ia32_syscall_table[__NR_ia32_##x] = my_sys_##x

#define GET_OLD_IA32_SYSCALL_ADDR(x) my_ia32_syscall_table[__NR_ia32_##x]

//    dbgprint("sys_read at %p, my_read at %p\n", (void *)GET_OLD_IA32_SYSCALL_ADDR(read), (void *)my_sys_read);

//    REPLACE_IA32(read);

#undef REPLACE_IA32

return 0;

}/*}}}*/

static void get_syscall_exit_module(void)

{/*{{{*/

printk(KERN_DEBUG "get_syscall: bye, you fucking linux!\n");

#define RESTORE_IA32(x) my_ia32_syscall_table[__NR_ia32_##x] = o_sys_##x

//    RESTORE_IA32(read);

#undef RESTORE_IA32

}/*}}}*/

module_init(get_syscall_init_module);

module_exit(get_syscall_exit_module);


Reference :
http://phrack.org/archives/58/p58-0x07
[ 本帖最后由 albcamus 于 2007-1-19 09:33 编辑 ]

langue 回复于:2007-01-18 20:38:22

不错。

朱熹之 回复于:2007-01-18 20:48:44

不错,顶了:em02:

albcamus 回复于:2007-01-19 09:33:10

这个程序前天刚刚做完, 没怎么测试, 我仅仅在linux-2.6.18 Turion64 X2上测试过, 欢迎大家测试, 把BUG发给我:em02:

anhongkui 回复于:2008-02-16 09:55:52

直接oops,在替换系统调用的时候

我好像看过i386的一篇文章,应该也是你写的吧,在替换之前清掉cr0的第20位, 这个64位的不用清吗?

anhongkui 回复于:2008-02-16 09:56:42

我现在是能够找到syscall_table的地址,但是,一替换就死机

anhongkui 回复于:2008-02-17 08:50:02

我查了查,cr0的第5-30位都必须为0,第31位为PE位,

不知道第20位是干什么的,望解惑

谢谢

albcamus 回复于:2008-02-18 09:30:43

引用:原帖由 anhongkui 于 2008-2-17 08:50 发表


我查了查,cr0的第5-30位都必须为0,第31位为PE位,

不知道第20位是干什么的,望解惑

谢谢


看手册卷三图2-6

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=374669]anhongkui
回复于:2008-02-18 15:06:33

请问是什么手册?

哪里能够找到这个手册?

我只找到了一个关于讲保护模式的

谢谢

albcamus 回复于:2008-02-18 17:45:48
http://www.intel.com/products/processor/manuals/index.htm http://developer.amd.com/documentation/guides/Pages/default.aspx
anhongkui 回复于:2008-02-19 11:56:09

谢谢

看了两个文档,讲cr0寄存器,

主要就是将WP位清为0,这时候可以改写只读的page,即可以修改syscall_table的page

不知道这么理解对不对。

anhongkui 回复于:2008-02-19 11:57:21

还是amd的讲的清楚一些,intel的太难懂了

caravsapm70 回复于:2008-12-20 12:18:46

64位下需要修改cr0寄存器的第16位。

楼主的代码找的地址,后32位是正确的,与/boot/System.map中一致。但是前32位就有问题了。

dreamice 回复于:2008-12-20 22:11:16

引用:原帖由 anhongkui 于 2008-2-19 11:57 发表


还是amd的讲的清楚一些,intel的太难懂了


能提供AMD相关详细手册么?

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=601724]rtable
回复于:2008-12-20 22:26:07

这个工作似乎进一步,用户程序能够不通过Socket接口直接从网卡抓包,就有了非纸上的意义。

albcamus 回复于:2008-12-22 14:31:19

引用:原帖由 caravsapm70 于 2008-12-20 12:18 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=6856970&ptid=885248]


64位下需要修改cr0寄存器的第16位。

楼主的代码找的地址,后32位是正确的,与/boot/System.map中一致。但是前32位就有问题了。


cr0.WP和32位、64位没什么关系, 都一样。

哪个符号的前32位错了? sys_call_table还是ia32_sys_call_table?

PS, 这个例子就是当时刚买了一台AMD64的笔记本, 练手的。 真正想知道这两个syscall table的地址,简单的无以复加: 直接读MSR_LSTAR和MSR_CSTAR这两个MSR寄存器就行了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux X86_64 syscall_table