IT猫扑网:您身边最放心的安全下载站! 最新更新| 软件分类| 专题汇总| 手机版

您当前所在位置:IT猫扑网 > 操作系统 > LINUX > Linux用户空间获取系统调用表地址

Linux用户空间获取系统调用表地址

时间:2015-06-28 00:00 来源:IT猫扑网|http://www.itmop.com/ 作者:网管联盟 我要评论(0)

  一、代码及实现

  (一)用户空间源代码

  #include <stdio.h>

  #include <stdlib.h>

  #include <string.h>

  #include <sys/types.h>

  #include <sys/stat.h>

  #include <fcntl.h>

  #include <unistd.h>

  #include <errno.h>

  #include <sys/mman.h>

  #define CALLOFF 100 //读取100字节

  struct {

  unsigned short limit;

  unsigned int base;

  } __attribute__ ((packed)) idtr;  //这个结构表示IDTR寄存器,这个寄存器中保存中断描述符表 的地址

  struct {

  unsigned short off1;

  unsigned short sel;

  unsigned char none,flags;

  unsigned short off2;

  } __attribute__ ((packed)) idt;  //中断描述符表中的内容:中断门描述符

  unsigned int old_readkmem (int fd, void * buf,size_t off,unsigned int size) //用read方式读取kmem中一定长度内容

  {

  if (lseek64(fd, (unsigned long long)off,SEEK_SET)!=off)

  {

  perror(&fd lseek error&);

  return 0;

  }

  if (read(fd, buf,size)!=size)

  {

  perror(&fd read error&);

  return 0;

  }

  }

  unsigned long readkmem (int fd, void * buf, size_t off, unsigned int size)//用mmap方式从kmem中读取一定长度内容

  {

  size_t  moff, roff;

  size_t   sz = getpagesize();

  char * kmap;

  unsigned long ret_old = old_readkmem(fd, buf, off, size); //先用老方法读取,不行再用mmap

  if (ret_old != 0)

  return ret_old;

  moff = ((size_t)(off/sz)) * sz;

  roff = off - moff;

  kmap = mmap(0, size+sz, PROT_READ, MAP_PRIVATE, fd, moff);

  if (kmap == MAP_FAILED)

  {

  perror(&readkmem: mmap&);

  return 0;

  }

  memcpy (buf, &kmap[roff], size);

  if (munmap(kmap, size) != 0)

  {

  perror(&readkmem: munmap&);

  return 0;

  }

  return size;

  }

#p#副标题#e#

  int main (int argc, char **argv)

  {

  unsigned sys_call_off;

  int kmem_fd;  // /dev/kmem文件描述符

  unsigned sct;

  char sc_asm[CALLOFF],*p;

  /* 获得IDTR寄存器的值 */

  asm (&sidt %0& : &=m& (idtr));

  printf(&idtr base at 0x%Xn&,(int)idtr.base);

  /* 打开kmem */

  kmem_fd = open (&/dev/kmem&,O_RDONLY);

  if (kmem_fd<0)

  {

  perror(&open&);

  return 1;

  }

  /* 从IDT读出0x80向量 (syscall) */

  readkmem (kmem_fd, &idt,idtr.base+8*0x80,sizeof(idt)); //idtr.base+8*0x80 表示80中断描述符的偏移

  sys_call_off = (idt.off2 << 16) | idt.off1;    //idt.off2 表示地址的前16位,得到syscall地址

  printf(&idt80: flags=%X sel=%X off=%Xn&, (unsigned)idt.flags,(unsigned)idt.sel,sys_call_off);

  /* 寻找sys_call_table的地址 */

  readkmem (kmem_fd, sc_asm,sys_call_off,CALLOFF);

  p = (char*)memmem (sc_asm,CALLOFF,&xffx14x85&,3); //只要找到邻近int $0x80入口点system_call的call sys_call_table(,eax,4)指令的机器指令就可以了,call something(,eax,4)指令的机器码是0xff 0x14 0x85,因此搜索这个字符串。

  sct = *(unsigned*)(p+3); //sys_call_table地址就在0xff 0x14 0x85之后

  if (p)

  {

  printf (&sys_call_table at 0x%x, call dispatch at 0x%xn&, sct, p);

  }

  close(kmem_fd);

  return 0;

  }

  (二)编译及实践

  该程序就是用户空间的普通应用程序,编译之后执行即可。我这里同时列出在虚拟机上和物理机上的执行结果,以作对比。

  虚拟机上的执行结果如下:

  idtr base at 0xFFC18000

  fd read error: Success

  readkmem: mmap: Input/output error

  idt80: flags=0 sel=0 off=0

  fd read error: Bad address

  readkmem: mmap: Input/output error

  Segmentation fault

  物理机上的执行结果:

  idtr base at 0xC1334000

  idt80: flags=EF sel=60 off=C1003CC4

  sys_call_table at 0xc124d4e0, call dispatch at 0xbfc2b330

  可见,虚拟机环境中并没有正确的获取到系统调用表,而物理机上的程序则正确的执行了。为什么虚拟机上执行有问题呢?我会在第二部分的分析总结中进行解释。

  二、总结

  (一)实现原理

  内核态获取系统调用表的实现原理,请参看本人的博文《Linux下实现劫持系统调用的总结》。用户态的实现原理,从本质上应该是和内核一致的。有区别的地方就在于,内核态可以直接访问内核地址空间,而用户态是不可以的。

  因此,用户态实现的时候就需要解决如何访问内核地址空间的问题。我们同样可以通过sidt指令获取到中断向量表的地址,然后通过读取/dev/kmem来定位到该地址。对于文件/dev/kmem,可以通过直接read或者mmap的方式操作即可。接下来的工作就是一步一步的去定位到系统调用表的地址了。

  (二)虚拟机环境的问题

  我们上面谈到在虚拟机执行该程序的时候出错了,经查找,其原因见参考链接3,这里列出其解释:

  在大多数的虚拟机中将无法顺利的读取IDTR。因为lidt指令是一个特权指令,将会产生一个异常,并被VM所捕获。这样可以使VM为每一个操作系统维持 一个虚拟的IDTR。因为sidt指令没有被处理,它将会返回一个伪造的IDTR地址,通常会大于0xFFC00000。

  我们在虚拟机执行这个程序返回的idtr的地址是0xFFC18000,正好印证了该解释。

  以上是对用户空间获取系统调用表地址的总结。如有遗漏不妥之处,请大家多多指教。

关键词标签:Linux

相关阅读 安装红帽子RedHat Linux9.0操作系统教程 Tomcat9.0如何安装_Tomcat9.0环境变量配置方法 多种操作系统NTP客户端配置 Linux操作系统修改IP Linux实现SCSI硬盘热插拔及在线识别 Linux下用CDMA modem拨号上网

文章评论
发表评论

热门文章 安装红帽子RedHat Linux9.0操作系统教程 安装红帽子RedHat Linux9.0操作系统教程 Linux服务器:设计高性能网站架构-LLMP Linux服务器:设计高性能网站架构-LLMP 使用Clonezilla迁移到虚拟Linux环境 使用Clonezilla迁移到虚拟Linux环境 Linux上的MRTG流量监控中心 Linux上的MRTG流量监控中心 Linux 双网卡绑定一个IP原理及实现 Linux 双网卡绑定一个IP原理及实现 linux和windows等系统远程控制ubuntu桌面 linux和windows等系统远程控制ubuntu桌面

相关下载

人气排行 Linux下获取CPUID、硬盘序列号与MAC地址 dmidecode命令查看内存型号 linux tc实现ip流量限制 安装红帽子RedHat Linux9.0操作系统教程 linux下解压rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 关机、重启、注销 命令 查看linux服务器硬盘IO读写负载 linux命令行浏览器的使用方法 Linux NFS服务固定端口及防火墙配置 U盘安装Ubuntu 10.04 Linux清除用户登录记录和命令历史方法