CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  Linux/Unix社区 >  内核及驱动程序研究区

eip的问题,还要再请教一下tb01412(tb)

楼主amazonking(你好)2006-03-04 17:27:02 在 Linux/Unix社区 / 内核及驱动程序研究区 提问

 
  我在进入内核之后、系统调用之前的处理函数中,先获得内核sp,然后把sp开始的20个long都显示出来,可我却找不到eip的位置了。我节选了连续的输出如下:  
  (截获的ftpd的系统调用,sc_eax是系统调用号,sp++是从sp开始的一个个long的值,加“”的数字是我认为是eip,在接下来的分析中却导致find_vma(eip,current->mm)  
    ->vm_file为空)  
   
  Mar   4   15:22:45   localhost   kernel:sc_eax   =   6,sp++=  
  4,2348612,3515684,4,165830716,-1078846040,  
  6,123,123,6,4469762,115,66118,“-1078846072”,123,0,0,-20486,-20486,-20486  
   
  Mar   4   15:22:46   localhost   kernel:sc_eax   =   175,sp++=  
  1,-1078846420,0,8,2338804,-1078846440,  
  175,123,123,175,4469762,115,66118,“-1078846596”,123,0,0,-20486,-20486,-20486  
   
  Mar   4   15:22:46   localhost   kernel:sc_eax   =   175,sp++=  
  1,-1078846420,0,8,2338804,-1078846440,  
  175,123,123,175,4469762,115,66118,“-1078846596”,123,0,0,-20486,-20486,-20486  
   
  Mar   4   15:22:46   localhost   kernel:sc_eax   =   102,sp++=  
  5,-1078846272,3515684,0,-1078846092,-1078846040,  
  102,123,123,102,4469762,115,66118,“-1078846280”,123,0,0,-20486,-20486,-20486  
  我自己push的顺序如下:  
  "pushl   %%eax\n"  
  "pushl   %%es\n"  
  "pushl   %%ds\n"  
  "pushl   %%eax\n"  
  "pushl   %%ebp\n"  
  "pushl   %%edi\n"  
  "pushl   %%esi\n"  
  "pushl   %%edx\n"  
  "pushl   %%ecx\n"  
  "pushl   %%ebx\n"  
  "call   my_handler   \n"  
  到底哪一个才是eip呢? 问题点数:20、回复次数:18Top

1 楼tb01412(tb)回复于 2006-03-04 20:24:38 得分 20

你push了十个寄存器,你就定义一个结构,包含十二个整型字段,倒数第二个就是你的EIP,倒数第一个是CSTop

2 楼amazonking(你好)回复于 2006-03-04 20:42:20 得分 0

问题是怎么会对一个进程所有的系统调用得到的eip一模一样?你可以看得到的数据里的结果,都是4469762Top

3 楼tb01412(tb)回复于 2006-03-04 20:59:57 得分 0

首先你的结构体是怎么样定义的,我不太清楚  
  还有就是有个问题:如果你用的是动态链接库,那么动态链接库中的系统调用发出时的EIP应该是一个定值,你需要捕捉不同的系统调用时的EIP,看是不是一样的值就明白了Top

4 楼amazonking(你好)回复于 2006-03-04 22:22:33 得分 0

我现在不通过结构体获得eip了,就想直接获得sp,算到eip的地址,读取。  
   
  动态库在运行时被系统加载到进程的虚拟空间中,使用从调用进程的虚拟地址空间分配的内存,成为调用进程的一部分。  
  比如下面的进程  
  $   cat   /proc/$$/maps  
  08048000-08057000   r-xp   00000000   03:05   357756   /bin/ash  
  08057000-08058000   rw-p   0000e000   03:05   357756   /bin/ash  
  08058000-0805b000   rw-p   00000000   00:00   0  
  4a2a8000-4a2bb000   r-xp   00000000   03:05   422661   /lib/ld-2.1.3.so  
  4a2bb000-4a2bc000   rw-p   00012000   03:05   422661   /lib/ld-2.1.3.so  
  4a2bc000-4a2bd000   rw-p   00000000   00:00   0  
  4a2c0000-4a3ad000   r-xp   00000000   03:05   422668   /lib/libc-2.1.3.so  
  4a3ad000-4a3b1000   rw-p   000ec000   03:05   422668   /lib/libc-2.1.3.so  
  4a3b1000-4a3b5000   rw-p   00000000   00:00   0  
  bff7c000-bff7f000   rw-p   ffffe000   00:00   0  
  它的动态链接库/lib/ld-2.1.3.so中系统调用的地址也不应该是同一个值吧(4a2a8000-4a2bb000),只是可能在不同的时候有不同的地址。  
  为什么说eip是定值呢?如果是定值,那么这个定值在系统调用结束后让进程返回到了同一个地方?  
  Top

5 楼tb01412(tb)回复于 2006-03-04 22:32:37 得分 0

在不同时刻运行的进程时,它的值不一定相同,但在运行起来后,任何时候在相应库中的系统调用时,它的EIP是个定值!!!!Top

6 楼tb01412(tb)回复于 2006-03-04 22:42:07 得分 0

而不同的进程使用同一个库,那个库被映射成了不同的虚拟地址,但在物理地址上却只有一份!!!  
  所以你看到的同一个库有不同的虚拟地址,但是一个进程一旦使用了一个动态库,并运行后,在这个进程的任何一个地方去调动态库中的函数,接着动态库中发出系统调用时,它的EIP就是相同的Top

7 楼amazonking(你好)回复于 2006-03-06 15:59:57 得分 0

看到资料说:  
  在Linux中,为了达到更好的共享性能,使用了与Windows不一样的策略:浮动代码(Po    
  sition   Independent   Code,简称PIC)。具体说,使用的转移指令都是相对于当前程序    
  计数器(IP)的偏移量;代码中引用变量、函数的地址都是相对于某个基地址的偏移量    
  。总之,从不引用一个绝对地址。  
  后面的不怎么看得懂啊!郁闷  
  某一个动态链接库加载后,eip保持不变了?那变的是什么?  
   
  一个进程每个运行模块都有GOT表,这个运行模块是什么概念?  
  是不是下面的进程就是3个模块??  
  08048000-08057000   r-xp   00000000   03:05   357756   /bin/ash  
  08057000-08058000   rw-p   0000e000   03:05   357756   /bin/ash  
  08058000-0805b000   rw-p   00000000   00:00   0  
  4a2a8000-4a2bb000   r-xp   00000000   03:05   422661   /lib/ld-2.1.3.so  
  4a2bb000-4a2bc000   rw-p   00012000   03:05   422661   /lib/ld-2.1.3.so  
  4a2bc000-4a2bd000   rw-p   00000000   00:00   0  
  4a2c0000-4a3ad000   r-xp   00000000   03:05   422668   /lib/libc-2.1.3.so  
  4a3ad000-4a3b1000   rw-p   000ec000   03:05   422668   /lib/libc-2.1.3.so  
  4a3b1000-4a3b5000   rw-p   00000000   00:00   0  
  bff7c000-bff7f000   rw-p   ffffe000   00:00   0  
  如果是,我怎么判断一个系统调用发生在哪一个模块,以及它在这个模块内部的相对地址??  
  Top

8 楼tb01412(tb)回复于 2006-03-06 22:49:38 得分 0

你想一下嘛:你在你的应用程序中写了一个函数,在连接之后,你这个地址相对固定了,在加载到操作系统以后,它不就是一个定值了吗??除非你把它KILL掉了,再重新运行这个进程!!!  
  你把动态模块中的函数也当成一个普通函数来看嘛,这不是一样的吗??????  
  模块加载之后,对它的定位是相对的,也就是由操作系统决定的,但一旦对它定位之后,它其中的某个函数地址不就固定了吗??相应函数内部某条代码的EIP地址不就是固定了的吗????  
  你如果要取得一个系统调用时的EIP,你可以在两个进程中分别调用相应的函数,你就应该看出这两个EIP会不一样的Top

9 楼amazonking(你好)回复于 2006-03-07 10:23:19 得分 0

动态链接库加载后,每一条语句的在进程虚拟内存中的绝对地址都是确定的,这我知道。  
  好像搞错了,我以为你之前说:一个动态链接库内的所有系统调用的eip都一样  
  fun(){  
      sys_call_1();  
      sys_call_2();  
  }  
  以为你说sys_call_1和sys_call_2的eip一样。  
  问题是,我在获得eip的时候,对不同的系统调用eip就是一样?所以我搞不清楚怎么回事了  
  我的目的就是想能像/proc/**/maps里那样,把一个系统调用根据它发生的eip判断它是哪个模块里发生的,是某个动态链接库或者进程本身。  
   
  Top

10 楼tb01412(tb)回复于 2006-03-07 12:08:12 得分 0

哦,你把你全部的代码贴出来嘛Top

11 楼amazonking(你好)回复于 2006-03-07 14:10:41 得分 0

#define   NULL   0  
  /*   The   necessary   header   files   */    
  #include   <linux/tty.h>  
  #include   <linux/mm.h> //GFP_KERNEL  
  #include   <asm/unistd.h>  
  #include   <linux/slab.h> //kmalloc  
  #include   <linux/fs.h>  
  #include   <linux/fcntl.h>  
  #include   <linux/sched.h>  
  #include   <linux/thread_info.h>  
  //#include   <asm-i386/unistd.h>  
  #include   <asm/msr.h>  
  #include   <asm/pgtable.h>  
  #include   <asm/uaccess.h> //get_fs(),set_fs(),KERNEL_DS  
  #include   <linux/file.h> //fput();  
  #include   <linux/string.h> //strcpy();  
  /*   Standard   in   kernel   modules   */    
  #include   <linux/kernel.h>       /*   We're   doing   kernel   work   */ //sprintf()  
  #include   <linux/module.h>       /*   Specifically,   a   module   */    
  #include   <linux/init.h>  
   
  struct   descriptor_idt  
  {  
  unsigned   short   offset_low,seg_selector;  
  unsigned   char   reserved,flag;  
  unsigned   short   offset_high;  
  };  
  struct   {  
  unsigned   short   limit;  
  unsigned   long   base;  
  }__attribute__   ((packed))   idtr;  
   
  //variable   declaration  
  static   unsigned   long   old_stub;  
   
  unsigned   long   *sp_kernel;  
   
  //the   information   to   gather,including    
  unsigned   long   cur_pid; //progress   id  
  unsigned   long   idt_elf; //identity   of   the   execution   image  
  unsigned   long   rela_ip_addr; //sc   relative   ip   address,可执行文件或者so的相对地址  
  unsigned   long   sc_eax; //sc   id   number  
  unsigned   long   sc_ebx,sc_ecx,sc_edx,sc_esi,sc_edi; //sc   parameters  
  unsigned   long   *cstack_head; //call   stack   information   list   head  
   
  //function   declaration  
  int   my_handler();  
  extern   asmlinkage   void   my_stub_int80(void);  
   
  void   stub_kad(void)  
  {  
  __asm__   (  
  ".globl   my_stub_int80\n"  
  ".align   4,0x90\n"  
  "my_stub_int80:\n"  
  "pushl   %%eax\n"  
  "pushl   %%es\n"  
  "pushl   %%ds\n"  
  "pushl   %%eax\n"  
  "pushl   %%ebp\n"  
  "pushl   %%edi\n"  
  "pushl   %%esi\n"  
  "pushl   %%edx\n"  
  "pushl   %%ecx\n"  
  "pushl   %%ebx\n"  
                    "movl   %%eax,%0\n"  
  "movl   %%ebx,%1\n"  
  "movl   %%ecx,%2\n"  
  "movl   %%edx,%3\n"  
  "movl   %%esi,%4\n"  
  "movl   %%edi,%5\n"  
  "movl   %%esp,%6\n"  
  "call   my_handler   \n"  
  "popl   %%ebx\n"  
  "popl   %%ecx\n"  
  "popl   %%edx\n"  
  "popl   %%esi\n"  
  "popl   %%edi\n"  
  "popl   %%ebp\n"  
  "popl   %%eax\n"  
  "popl   %%ds\n"  
  "popl   %%es\n"  
  "popl   %%eax\n"  
  "jmp   *old_stub"  
  ::"m"(sc_eax),"m"(sc_ebx),"m"(sc_ecx),"m"(sc_edx),"m"(sc_esi),"m"(sc_edi),"m"(sp_kernel)  
  );  
  }  
  int   get_block_addr(unsigned   long   addr,unsigned   long   *block,unsigned   long   *rela_addr)//通过给的系统调用返回地址,获得该系统调用所在的block及其内部pc  
  {  
  struct   vm_area_struct   *block_area   =   NULL;  
  unsigned   long   block_start   =   0;  
  unsigned   long   block_end   =   0;  
  struct   file   *image   =   NULL;  
  if((block_area   =   find_vma(current->mm,addr))) //获得add的vmarea  
  {  
  block_start   =   block_area->vm_start;  
  block_end   =   block_area->vm_end;  
  *rela_addr   =   (addr   -   block_start);  
  if(!(image   =   block_area->vm_file))  
  {  
  printk("the   addr   %ld   block   image   file   doesn't   exist\n",addr);  
  return   1;  
  }  
  *block   =   image->f_dentry->d_inode->i_ino;  
  return   0;  
  }  
  printk("find_vma   failured");  
  return   1;  
  }  
  int   my_handler() //处理函数,用来获得相关信息  
  {  
  //如果当前pid是vsftpd相关的,则current->comm是vsftpd  
  if(   strcmp(current->comm,"vsftpd")   !=   0   )  
                    {  
            return   1;  
  }  
  cur_pid   =   current->pid;  
                    //问题就在这个curr_addr!!  
  unsigned   long   curr_addr   =   sp_kernrl+10;//根据sp,获得系统调用发生时刻的eip  
                    if(get_block_addr(curr_addr,&idt_elf,&rela_ip_addr))//获得当前ip的详细信息  
  {  
  printk("WARNING:wrong   eip   information!!!\n");  
  return   2;  
  }  
                    ...  
                    return   0;  
  }  
  static   int   mod_init_func(void)    
  {    
  /*deal   with   the   int80   syscall*/  
  printk("start   get_addr_idt");  
  __asm__   volatile   ("sidt   %0":   "=m"   (idtr));  
  printk("the   idt   address   is   %ld\n",idtr.base);  
  struct   descriptor_idt   *idte=(struct   descriptor_idt   *)(idtr.base+8*0x80);  
  old_stub=(idte->offset_high<<16|idte->offset_low);  
  unsigned   long   new_addr=(unsigned   long)my_stub_int80;  
  idte->offset_high   =   (unsigned   short)   (new_addr   >>   16);  
  idte->offset_low   =   (unsigned   short)   (new_addr   &   0x0000FFFF);  
  /*   If   we   return   a   non   zero   value,   it   means   that   init_module    
  failed   and   the   kernel   module   can't   be   loaded   */    
  return   0;    
  }    
   
   
  /*   Cleanup   -   undid   whatever   init_module   did   */    
  static   void   mod_exit_func(void)    
  {    
  /*deal   with   the   int80   syscall*/  
  printk("destroy...b..\n");  
  __asm__   volatile   ("sidt   %0":   "=m"   (idtr));  
  struct   descriptor_idt   *idte=(struct   descriptor_idt   *)(idtr.base+8*0x80);  
  idte->offset_high   =   (unsigned   short)   (old_stub   >>   16);  
  idte->offset_low   =   (unsigned   short)   (old_stub   &   0x0000FFFF);  
  /*clearup   finished*/  
  printk("exited   !!\n");  
  }    
   
  module_init(mod_init_func);  
  module_exit(mod_exit_func);Top

12 楼tb01412(tb)回复于 2006-03-08 23:56:13 得分 0

第一个地方:  
  将asmlinkage也要写在my_stub_int80实现函数的前面(不仅是用在声明的时候)  
   
   
  第二个地方:   unsigned   long   curr_addr   =   sp_kernrl+10;//根据sp,获得系统调用发生时刻的eip  
   
  sp_kernrl就是那个my_handler函数调用my_handler时的EIP,好像要将sp_kernrl加上  
  11*4才行吧(因为操作系统在进你的函数时已经由CPU将EIP压入了ESP中),要改成这样:  
  unsigned   long   curr_addr   = (unsigned   long)((int)sp_kernel   +   44);Top

13 楼tb01412(tb)回复于 2006-03-09 00:03:57 得分 0

纠正一下,把asmlinkage写在my_handler前面,不过这个东东在你此时的代码里面没有什么多大的实际用处,可能是以前的时候留下来的Top

14 楼amazonking(你好)回复于 2006-03-09 10:58:16 得分 0

还是不对啊,unsigned   long   *sp_kernel;  
  sp_kernel+11和(unsigned   long)((int)sp_kernel   +   44)就是一样的地址了  
   
  关键问题就是一开始我贴出来的结果,我把sp_kernel一直到sp_kernel+20都打印出来,  
  结果sp_kernel+6等于sp_kernel+9等于eax,到这儿为止都是对的。  
  但是sp_kernel+10和sp_kernel+11,对一个进程的每个系统调用都是相同的值了。  
  Top

15 楼amazonking(你好)回复于 2006-03-09 13:52:03 得分 0

晕倒了,我把我的程序放到一个p4的机器上,获得的eip都是对的  
  但是在我的笔记本上获得的eip就不对了,难道是pm的cpu变了?Top

16 楼tb01412(tb)回复于 2006-03-10 13:15:51 得分 0

你的笔记本上是不是64位处理器?Top

17 楼amazonking(你好)回复于 2006-03-10 17:10:46 得分 0

不是阿,32位的,我又弄了一台p4的机器也有问题。  
  结果我又试了几次正确的那台机器,都是正确的。那台机器是超线程的。Top

18 楼tb01412(tb)回复于 2006-03-11 08:57:03 得分 0

这个问题太高深了,实在是不懂了Top

相关问题

  • 谁和我说一下学完了JAVASCRIPT!还要学什么?
  • 网站做好上传以后还要不要配置一下
  • 请教,关于eip
  • 怎样读取EIP?
  • 婷婷感冒了,明天还要考试!大家祝福一下吧,偶给分!
  • 既然有了copy assingment operator 为何还要 copy constructor ?谁给讲解一下?最好有个示例
  • 学习delphi还要看那些书?谢谢各位了,帮忙指点一下了!!!!!
  • 请问一下ORACLE8i装好以后要启动OEM之前还要干哪些事???
  • 元旦还要出差!郁闷,散分顺便帮我看一下这个问题!
  • 请大虾指导一下.学了DELPHI以后还要学点什么好找工作?

关键词

  • 函数
  • 模块
  • 系统
  • 虚拟
  • 动态库
  • 代码
  • eip
  • idte
  • 进程
  • 系统调用

得分解答快速导航

  • 帖主:amazonking
  • tb01412

相关链接

  • CSDN Blog
  • 技术文档
  • 代码下载
  • 第二书店
  • 读书频道

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo