eip的问题,还要再请教一下tb01412(tb)
我在进入内核之后、系统调用之前的处理函数中,先获得内核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




