Chinaunix首页 | 论坛 | 博客
  • 博客访问: 616764
  • 博文数量: 201
  • 博客积分: 3076
  • 博客等级: 中校
  • 技术积分: 2333
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-02 19:44
文章分类

全部博文(201)

文章存档

2010年(118)

2009年(83)

我的朋友

分类:

2010-05-09 15:06:45

http://blog.chinaunix.net/u/12592/showart_1421096.html



直接上代码吧,就是sidt之后,通过kmem字符设备搜索指纹。

测试环境: Debian Lenny 2.6.26-2-686

091020:实在是不好意思,之前的代码稍 微有一些问题,已经改正了;-)

#include
#include
#include
#include
#include
#include
#include
#include
#include

#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\");
    return 0;
  }
 
  if (read(fd, buf,size)!=size)
  {
    //perror(\"fd read\");
    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;
}
 
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%X\n",(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=%X\n", (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,"\xff\x14\x85",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%x\n", sct, p);
 }
 
 close(kmem_fd);
 return 0;
}

注意:
ubuntu等发行版已经禁用了/dev /kmem,可以查看/boot/config-2.6.xx,grep一下DEV_KMEM,可以发现是no set。

参考:
http://www.phpweblog.net/GaRY/archive/2007/06/17/get_sys_call_table_address.html
http://blog.chinaunix.net/u2/73704/showart_1089555.html
阅读(826) | 评论(0) | 转发(0) |
0

上一篇:sizeof

下一篇:hash function

给主人留下些什么吧!~~