当前位置:   article > 正文

抓取sys_call_table 地址 x86_64_windows x64应用层获取syscall内存地址

windows x64应用层获取syscall内存地址

在网上看到很多文章是通过驱动内联汇编拿到idt地址,但是在x86_64上确跑不起来,还宕机,来一起唠唠。

先说说网上同行说自己使用以下代码去解析sys_call_table 地址
lkm.c

//lkm.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 <linux/sched.h>
#include <linux/kallsyms.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <asm/current.h>
 
	
unsigned long *sys_call_table;
 
struct 
{
	unsigned short size;
	unsigned int addr;
}__attribute__((packed)) idtr;
 
struct
{
	unsigned short offset_1;
	unsigned short selector;
	unsigned char zero;
	unsigned char type_attr;
	unsigned short offset_2;
}__attribute__((packed)) idt;
 
unsigned long  *find_sys_call_table(void)
{
	unsigned int sys_call_off;
	char *p;
	int i;
	unsigned int ret;
 
	asm("sidt %0":"=m"(idtr)); //通过idtr获取IDT表的地址
	printk("Arciryas:idt table-0x%x\n", idtr.addr);
 
	//将0x80处sys_call_table的地址存放到idt中
	memcpy(&idt, idtr.addr+8*0x80, sizeof(idt));//IDT表一行占8个字节,所以8*0x80
	sys_call_off = ((idt.offset_2<<16) | idt.offset_1);
 
	p = sys_call_off;
	for(i=0; i<100; i++)
	{
		if(p[i]=='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85')  //sys_call_table的call硬编码
			ret = *(unsigned int *)(p+i+3);
	}
	printk("Arciryas:sys_call_table-0x%x\n", ret);
	return (unsigned long**)ret;
}
 
asmlinkage long (*real_mkdir)(const char __user *pathname,umode_t mode);
asmlinkage long fake_mkdir(const char __user *pathname, umode_t mode)
{
	printk("Arciryas:mkdir-%s\n", pathname);
	
	return (*real_mkdir)(pathname, mode);
}
 
static int lkm_init(void)
{
	sys_call_table = find_sys_call_table();
 
	write_cr0(read_cr0() & (~0x10000));
	real_mkdir = (void *)sys_call_table[__NR_mkdir];
	sys_call_table[__NR_mkdir] = fake_mkdir;
	write_cr0(read_cr0() | 0x10000);
 
	printk("Arciryas:module loaded\n");
 
	return 0;
}
 
static void lkm_exit(void)
{
	write_cr0(read_cr0() & (~0x10000));	
	sys_call_table[__NR_mkdir] = real_mkdir;
	write_cr0(read_cr0() | 0x10000);
	printk("Arciryas:module removed\n");
}
 
module_init(lkm_init);
module_exit(lkm_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxxxxx");
MODULE_DESCRIPTION("hook mkdir");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

这个程序会直接让系统宕机的原因是因为这个结构体对addr的赋int,在64位系统应该改成long,这里仅仅是解决代码执行内联汇编asm宕机问题,除了此处修改,相应的变量也应该修改成Long型,改完之后代码可以跑,但是得到的结果确是错误!

struct 
{
	unsigned short size;
	unsigned int addr; // 高32位为idt表地址
}__attribute__((packed)) idtr; // idtr是48位6字节寄存器
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
//lkm.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 <linux/sched.h>
#include <linux/kallsyms.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <asm/current.h>
 
	
unsigned long *sys_call_table;
 
struct 
{
	unsigned short size;
	unsigned long addr;
}__attribute__((packed)) idtr;
 
struct
{
	unsigned short offset_1;
	unsigned short selector;
	unsigned char zero;
	unsigned char type_attr;
	unsigned short offset_2;
}__attribute__((packed)) idt;
 
unsigned long  *find_sys_call_table(void)
{
	unsigned long sys_call_off;
	long *p;
	int i;
	unsigned long ret;
 
	asm("sidt %0":"=m"(idtr)); //通过idtr获取IDT表的地址
	printk("Arciryas:idt table-0x%lx\n", idtr.addr);
 
	//将0x80处sys_call_table的地址存放到idt中
	memcpy(&idt, idtr.addr+8*0x80, sizeof(idt));//IDT表一行占8个字节,所以8*0x80
	sys_call_off = ((idt.offset_2<<16) | idt.offset_1);
 
	p = sys_call_off;
	for(i=0; i<100; i++)
	{
		if(p[i]=='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85')  //sys_call_table的call硬编码
			ret = *(unsigned long *)(p+i+3);
	}
	printk("Arciryas:sys_call_table-0x%lx\n", ret);
	return (unsigned long**)ret;
}
 
asmlinkage long (*real_mkdir)(const char __user *pathname,umode_t mode);
asmlinkage long fake_mkdir(const char __user *pathname, umode_t mode)
{
	printk("Arciryas:mkdir-%s\n", pathname);
	
	return (*real_mkdir)(pathname, mode);
}
 
static int lkm_init(void)
{
	sys_call_table = find_sys_call_table();
 
	write_cr0(read_cr0() & (~0x10000));
	real_mkdir = (void *)sys_call_table[__NR_mkdir];
	sys_call_table[__NR_mkdir] = fake_mkdir;
	write_cr0(read_cr0() | 0x10000);
 
	printk("Arciryas:module loaded\n");
 
	return 0;
}
 
static void lkm_exit(void)
{
	write_cr0(read_cr0() & (~0x10000));	
	sys_call_table[__NR_mkdir] = real_mkdir;
	write_cr0(read_cr0() | 0x10000);
	printk("Arciryas:module removed\n");
}
 
module_init(lkm_init);
module_exit(lkm_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxxxxx");
MODULE_DESCRIPTION("hook mkdir");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

其实也没有改什么,只是把所有变量类型改为long型。
看下面结果还是错误!!!!

curtis@curtis-virtual-machine:~/Desktop/fail$ uname -a
Linux curtis-virtual-machine 4.2.0-42-generic #49~14.04.1-Ubuntu SMP Wed Jun 29 20:22:11 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
  • 1
  • 2

dmesg查看打印信息和从/proc/kallsyms抓出的数据进行比对,验证数据的正确性。

curtis@curtis-virtual-machine:~/Desktop/fail$ sudo cat /proc/kallsyms | grep idt_table
ffffffff81eb5000 B idt_table
ffffffff81eb6000 B debug_idt_table
ffffffff81eb8000 B trace_idt_table
curtis@curtis-virtual-machine:~/Desktop/fail$ sudo cat /proc/kallsyms | grep sys_call_table
ffffffff818001c0 R sys_call_table
ffffffff81801580 R ia32_sys_call_table
curtis@curtis-virtual-machine:~/Desktop/fail$
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

驱动安装成功,也不会宕机,但是抓到的数据是有问题的!!!!!

curtis@curtis-virtual-machine:~/Desktop/fail$ sudo insmod lkm.ko 
curtis@curtis-virtual-machine:~/Desktop/fail$ dmesg | tail -n 3
[ 3749.769517] Arciryas:idt table-0xffffffffff578000
[ 3749.769520] Arciryas:sys_call_table-0xffffffff81c15080
[ 3749.769523] Arciryas:module loaded
curtis@curtis-virtual-machine:~/Desktop/fail$ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

主要问题在以下两点:
1.x86_64系统获得idtr是通过读寄存器的值得来的;
2.x86_64系统对call的硬编码也是不一样的"\xff\x14\xc5"

修改之后代码以及makefile:
get_sct.c

#include <linux/module.h>
#include <linux/kernel.h>

unsigned long *sys_call_table;

struct {
    unsigned short limit;
    unsigned long base;
} __attribute__ ((packed))idtr;

struct {
    unsigned short off1;
    unsigned short sel;
    unsigned char none, flags;
    unsigned short off2;
} __attribute__ ((packed))idt;


void *memmem ( const void *haystack, size_t haystack_size, const void *needle, size_t needle_size )
{
    char *p;

    for ( p = (char *)haystack; p <= ((char *)haystack - needle_size + haystack_size); p++ )
        if ( memcmp(p, needle, needle_size) == 0 )
            return (void *)p;

    return NULL;
}


// http://bbs.chinaunix.net/thread-2143235-1-1.html
unsigned long *find_sys_call_table ( void )
{
    char **p;
    unsigned long sct_off = 0;
    unsigned char code[512];

    rdmsrl(MSR_LSTAR, sct_off);
    memcpy(code, (void *)sct_off, sizeof(code));

    p = (char **)memmem(code, sizeof(code), "\xff\x14\xc5", 3);

    if ( p )
    {
        unsigned long *sct = *(unsigned long **)((char *)p + 3);

        // Stupid compiler doesn't want to do bitwise math on pointers
        sct = (unsigned long *)(((unsigned long)sct & 0xffffffff) | 0xffffffff00000000);

        return sct;
    }
    else
        return NULL;
}


// 模块载入时被调用
static int __init init_get_sys_call_table(void)
{
      sys_call_table = find_sys_call_table();
      printk("The sys_call_table address is:%lx\n",(unsigned long)sys_call_table);
      return 0;
}


// 模块卸载时被调用
static void __exit exit_get_sys_call_table(void)
{
	printk("Get sys_call_table finish!\n");
}

module_init(init_get_sys_call_table);
module_exit(exit_get_sys_call_table);

// 模块信息

MODULE_LICENSE("GPL2.0");
MODULE_AUTHOR("curits");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

Makefile:

obj-m += get_sct.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出结果:

curtis@curtis-virtual-machine:~/Desktop/get_system_call_x86_64$ ./auto.sh 
#########make file##########
make -C /lib/modules/4.2.0-42-generic/build M=/home/curtis/Desktop/get_system_call_x86_64 modules
make[1]: Entering directory `/usr/src/linux-headers-4.2.0-42-generic'
  Building modules, stage 2.
  MODPOST 1 modules
make[1]: Leaving directory `/usr/src/linux-headers-4.2.0-42-generic'
#########insmod ko file########
#########rmmod ko file#########
##########make clean###########
make -C /lib/modules/4.2.0-42-generic/build M=/home/curtis/Desktop/get_system_call_x86_64 clean
make[1]: Entering directory `/usr/src/linux-headers-4.2.0-42-generic'
  CLEAN   /home/curtis/Desktop/get_system_call_x86_64/.tmp_versions
  CLEAN   /home/curtis/Desktop/get_system_call_x86_64/Module.symvers
make[1]: Leaving directory `/usr/src/linux-headers-4.2.0-42-generic'
##########dmesg info###########
[ 4033.613719] Arciryas:module removed
[ 4044.225868] get_sct: module license 'GPL2.0' taints kernel.
[ 4044.225871] Disabling lock debugging due to kernel taint
[ 4044.226165] The sys_call_table address is:ffffffff818001c0
[ 4045.244574] Get sys_call_table finish!
curtis@curtis-virtual-machine:~/Desktop/get_system_call_x86_64$ sudo cat /proc/kallsyms | grep sys_call_table
ffffffff818001c0 R sys_call_table
ffffffff81801580 R ia32_sys_call_table
curtis@curtis-virtual-machine:~/Desktop/get_system_call_x86_64$ 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

成功拿到x86_64系统sys_call_table!!!!!!!!!!!!

这是因为在高版本内核中系统调用的方式发生了改变,如果要进行系统调用,则必须将所需的系统调用号存储到rax寄存器中,然后使用软件中断调用内核syscall。在使用中断之前,系统调用所需的所有参数都必须加载到某些寄存器中,并且返回值几乎总是放在rax。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/183421
推荐阅读
相关标签
  

闽ICP备14008679号