2.6内核系统调用劫持段错误segment fault等问题的解决方法

news/2024/7/6 6:33:12

在网上搜了很多关于2.6内核系统调用劫持的文章,流传的最多的可能就是那个以mkdir系统调用为例子的文章,自己按照源码敲进去,写好Makefile后也编译通过了,但是加载时却出现了Segment fault的错误,后来调试了一下,发现sys_call_table找得不对,后面却用了返回的一个非法地址,结果出现访问错误。看来这个segment fault是由于非法访问内存引起的,添加了返回值判断后,再次加载模块,没有出现段错误,但是后来发现查找sys_call_table的结果为NULL。后来在网上找了一下,发现系统调用劫持时需要更改一下cr0的标志位(以前Windows系统中进行系统调用劫持时也是要操作这个寄存器)。修改了以后的模块代码如下:
/*
*
*
*       Filename: syscallhook.c
*
*    Description:
*
*        Version: 1.0
*        Created: 2009年10月02日 14时32分39秒
*       Revision: none
*       Compiler: gcc
*
*         Author: YOUR NAME (),
*        Company:
*
*

=======================================================================

==============
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/unistd.h>

MODULE_LICENSE("GPL");

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

unsigned long *sys_call_table=NULL;
asmlinkage int (*orig_mkdir)(const char *,int);
unsigned int orig_cr0;

struct _idt
{
    unsigned short offset_low;
unsigned short segment_sel;
    unsigned char reserved, flags;
    unsigned short offset_high;
}__attribute__((packed));

unsigned int clear_and_ret_cr0(void)
{
    unsigned int cr0 = 0;
    unsigned int ret = 0;

    asm volatile ("movl %%cr0, %%eax"
            :"=a"(cr0));

    ret = cr0;
    cr0 &= 0xfffeffff;

    asm volatile ("movl %%eax, %%cr0"
            :
            :"a"(cr0));

    return ret;
}

void setback_cr0(unsigned int val)
{
    asm volatile("movl %%eax, %%cr0"
            :
            :"a"(val));
}

char* findoffset(char *start)
{
char *ptr = start;
int i = 0;
for(; i < 100; i++)
{
if(*(ptr+i) == '/xff'
   && *(ptr+ i + 1) == '/x14'
   && *(ptr+ i + 2) == '/x85')
{
   return ptr + i;
}
}

return NULL;
}

unsigned long getscTable(void)
{
    struct _idt *idt;
    unsigned long system_call = 0, sct = 0;
    unsigned short offset_low,offset_high;
    char *p = NULL;

orig_cr0 = clear_and_ret_cr0();   //注意在这里设置一下cr0
    /* get the interrupt descriptor table */
    __asm__("sidt %0" : "=m" (idtr));
setback_cr0(orig_cr0);
              
    /* get the address of system_call */
    idt = (void *)(idtr.base + 8 * 0x80);
    offset_low = idt->offset_low;
    offset_high = idt->offset_high;
    system_call = (offset_high<<16)|offset_low;

printk("idt:%x system_call:%x/n", idt, system_call);   

p = findoffset((char*)system_call);
if(NULL != p)
{
sct = *(unsigned long*)(p+3);
}
return (unsigned long*)sct;
}

asmlinkage int hacked_mkdir(const char * pathname, int mode)
{
    printk("PID %d called sys_mkdir, path: %s!/n", current->pid,

pathname);
    return orig_mkdir(pathname,mode);
}

static int find_init(void)
{
    sys_call_table = getscTable();
printk("sys_call_table find:0x%x/n", sys_call_table);
if(NULL != sys_call_table)
{
orig_mkdir=(int(*)(const char*,int))sys_call_table

[__NR_mkdir];
     orig_cr0 = clear_and_ret_cr0();
     sys_call_table[__NR_mkdir]=(unsigned long)hacked_mkdir;
     setback_cr0(orig_cr0);
}
    return 0;
}

void find_cleanup(void)
{
    orig_cr0 = clear_and_ret_cr0();
    if(sys_call_table)
    {
        sys_call_table[__NR_mkdir]=(unsigned long)orig_mkdir;
    }
    setback_cr0(orig_cr0);
    return;
}

module_init(find_init);
module_exit(find_cleanup);

Makefile如下:
obj-m := syscallhook.o
KERNELDIR := /home/done/linux-2.6.27.18/
PWD := $(shell pwd)
EXTRA_CFLAGS += -ggdb
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
ls | egrep -v "Makefile|syscallhook.c" | xargs $(RM) -rf
下面是在2.6.27.18内核下的测试图:


http://www.niftyadmin.cn/n/4464080.html

相关文章

Linux2.6内核中劫持系统调用隐藏进程

网上很多类似的文章,其中很多示例程序都是在比较老的内核版本上测试过,很多在新的内核下根本无法运行,我收集了一些相关的资料,并给出一个在linux内核2.6.28(ubuntu9.04)上可以运行的程序代码.相比其他一些文章,修改如下:1.增加了两个函数,清CR0的第20位,不然在替换sys_call_ta…

windows和linux下如何远程获取操作系统版本和主机名

远程获取windows和linux操作系统版本和主机名需要具备以下条件&#xff1a; 假设 主机A(windows 7)&#xff0c;ip:192.168.12.2 主机B(centos 6.3)&#xff0c;ip:192.168.12.3 主机C(windows 2008)-为远程要获取信息的主机&#xff0c;ip:192.168.12.4 主机D(centos 6.3…

shell脚本-利用check_snmp查看远程linux操作系统版本

说明&#xff1a; 脚本通过本地执行check_snmp命令&#xff0c;获取远程linux操作系统版本&#xff0c;并将信息写入文本中 #!/bin/bash awk {print $1} list.txt |while read line do echo $line info/usr/local/nagios/libexec/check_snmp -H $line -C public -o sysDescr…

实现Linux系统调用劫持

关于系统调用劫持如果一个木马要隐藏起来&#xff0c;不被系统管理员发现。截获系统调用似乎是必须的。大部分情况下&#xff0c;通过修改系统调用表来实现系统调用的劫持。下面是一个典型的截获系统调用的模块&#xff1a;模块一&#xff1a;#include #include #include #incl…

获取Linux 2.6.x sys_call_table

在linux中所有的syscall都是调用int 0x80, int 0x80的中断服务程序为system_call(arch/x86/kernel/traps_32.c:set_system_gate(SYSCALL_VECTOR,&system_call). system_call (arch/x86/entry_32.S)最终call *sys_call_table(,%eax,4)来完成一个syscall调用. 即 int 0x80…

当访问php遇到空白页时

当访问php页面遇到返回空白页时&#xff0c;请在检查语法有无问题时&#xff0c;多多关注php.ini配置中是不是把disable_functions phpinfo启用了。

转:Before main() 分析(gdb的使用)

main()的堆栈内容演示。预备知识&#xff1a;1. 常用命令(gdb) b * 0x80483d8 # 在地址处设置断点(gdb) b main# 在标号处设置断点(gdb) disass 0x80483d8# 反汇编(gdb) si执行1条汇编指令&#xff0c;ni执行整个汇编函数&#xff1b;s执行1条C语句&#xff0c;n执行整…

python批量操作Linux服务器脚本,ssh密码登录(执行命令、上传、下载)(一)

#-*- coding: utf-8 -*-#批量操作linux服务器&#xff08;执行命令&#xff0c;上传&#xff0c;下载&#xff09;#!/usr/bin/pythonimport paramikoimport datetimeimport osimport threadingdef ssh2(ip,username,passwd,cmd):try:paramiko.util.log_to_file(paramiko_______…