push,你到底做了啥事情????

来源:互联网 发布:淘宝上的快排能买吗 编辑:程序博客网 时间:2024/04/30 05:00

事情要一件一件来说,就像吃饭要一口一口吃一样。一共有两件事情,这节就先讲push的事情。

问一句,push, what the hell are u doing?

启动bochs,开始push stack之旅。

截取一部分源码:

protect:;[7].进入到保护模式后,为了给予内核最大的访问内存能力,ds段寄存器使用4G段描述符;初始化dsmov eax, 0x00000008 mov ds, eax;初始化堆栈段mov eax, 0x00000018mov ss, eaxxor esp, esp;8.将sector1的kernel代码拷贝到0x040000处的内存中来;1)由于目前不知道kernel的代码尺寸,先拷贝一个扇区看看;  根据约定,第一个扇区的前4个字节应该就是kernel的总尺寸,可以根据这个尺寸知道后面还要加载多少扇区;@input: DI:SI 起始扇区号  DS:BX 写入的内存地址mov ebx, 0x40000 ;段内偏移mov di, 0x0000mov si, 0x0001call read_from_harddisk
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@function read_from_harddisk;@input: DI:SI 起始扇区号;@input: DS:BX 写入的内存地址;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;[bits 32]read_from_harddisk:push eaxpush ebxpush ecxpush edx

目前我所知道的就只有:push eax, 就是把当前的esp值-4,然后把[ss:esp]的内存空间写上eax内这4字节的内容。

看上去挺简单的,但是,事实上就是这么简单吗????

首先先看下整个程序gdt表项,堆栈段位于0x03号选择子,内存扩展方式是expand-down,所以栈底是高位,从0x7c00开始向下扩展

<bochs:5> info gdtGlobal Descriptor Table (base=0x0000000000007e00, limit=39):GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000GDT[0x01]=Data segment, base=0x00000000, limit=0xffffffff, Read/WriteGDT[0x02]=Code segment, base=0x00007c00, limit=0x00000200, Execute-Only, Non-Conforming, 32-bitGDT[0x03]=Data segment, base=0x00007c00, limit=0xf1000fff, Read/Write, Expand-downGDT[0x04]=Data segment, base=0x000b8000, limit=0x00008000, Read/WriteYou can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'<bochs:6>


在保护模式下,下面代码主要就是初始化数据段以及堆栈段寄存器:

;[7].进入到保护模式后,为了给予内核最大的访问内存能力,ds段寄存器使用4G段描述符;初始化dsmov eax, 0x00000008 mov ds, eax;初始化堆栈段mov eax, 0x00000018mov ss, eaxxor esp, esp


执行完成后,各个寄存器的值为:注意 esp为0x00000000

<bochs:18> regrax: 0x00000000_00000018 rcx: 0x00000000_00098000rdx: 0x00000000_00000000 rbx: 0x00000000_0000000brsp: 0x00000000_00000000 rbp: 0x00000000_00000000rsi: 0x00000000_000e7e20 rdi: 0x00000000_00000092r8 : 0x00000000_00000000 r9 : 0x00000000_00000000r10: 0x00000000_00000000 r11: 0x00000000_00000000r12: 0x00000000_00000000 r13: 0x00000000_00000000r14: 0x00000000_00000000 r15: 0x00000000_00000000rip: 0x00000000_000000b3eflags 0x00000046: id vip vif ac vm rf nt IOPL=0 of df if tf sf ZF af PF cf
之后调用函数后,有push动作,那么会进行相关操作的内存区域肯定是<0x7c00,先dump一段内存看看,后面可以做一个push前后比较:

<bochs:20> xp /40bx 0x7bf0[bochs]:0x0000000000007bf0 <bogus+       0>:    0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x000x0000000000007bf8 <bogus+       8>:    0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x000x0000000000007c00 <bogus+      16>:    0xb8    0x00    0x00    0x8e    0xd8    0xb8    0x00    0x000x0000000000007c08 <bogus+      24>:    0xbb    0x00    0x00    0xb9    0x00    0x00    0xba    0x000x0000000000007c10 <bogus+      32>:    0x00    0xbf    0x00    0x00    0x8b    0x36    0xf7    0x7d<bochs:21> sNext at t=17825139(0) [0x0000000000007d5f] 0010:000000000000015f (unk. ctxt): push eax                  ; 50<bochs:22>Next at t=17825140(0) [0x0000000000007d60] 0010:0000000000000160 (unk. ctxt): push ebx                  ; 53<bochs:23>Next at t=17825141(0) [0x0000000000007d61] 0010:0000000000000161 (unk. ctxt): push ecx                  ; 51<bochs:24>Next at t=17825142(0) [0x0000000000007d62] 0010:0000000000000162 (unk. ctxt): push edx                  ; 52<bochs:25>Next at t=17825143(0) [0x0000000000007d63] 0010:0000000000000163 (unk. ctxt): mov al, 0x01              ; b001<bochs:26> xp /60bx 0x7be0[bochs]:0x0000000000007be0 <bogus+       0>:    0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x000x0000000000007be8 <bogus+       8>:    0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x000x0000000000007bf0 <bogus+       0>:    0x00    0x80    0x09    0x00    0x00    0x00    0x04    0x000x0000000000007bf8 <bogus+       8>:    0x18    0x00    0x00    0x00    0xc5    0x00    0x00    0x000x0000000000007c00 <bogus+      16>:    0xb8    0x00    0x00    0x8e    0xd8    0xb8    0x00    0x000x0000000000007c08 <bogus+      24>:    0xbb    0x00    0x00    0xb9    0x00    0x00    0xba    0x000x0000000000007c10 <bogus+      32>:    0x00    0xbf    0x00    0x00    0x8b    0x36    0xf7    0x7d<bochs:27> regrax: 0x00000000_00000018 rcx: 0x00000000_00098000rdx: 0x00000000_00000000 rbx: 0x00000000_00040000rsp: 0x00000000_ffffffec rbp: 0x00000000_00000000rsi: 0x00000000_000e0001 rdi: 0x00000000_00000000r8 : 0x00000000_00000000 r9 : 0x00000000_00000000r10: 0x00000000_00000000 r11: 0x00000000_00000000r12: 0x00000000_00000000 r13: 0x00000000_00000000r14: 0x00000000_00000000 r15: 0x00000000_00000000rip: 0x00000000_00000163eflags 0x00000046: id vip vif ac vm rf nt IOPL=0 of df if tf sf ZF af PF cf<bochs:28>


执行完后,可以发现,内存变化如下:标颜色的这四段刚好对应上被push的 eax(0x00000018), ebx(0x00040000), ecx(0x00098000), edx(0x00000000)。可是,起始地址是从0x7c00开始的呀,从0x7bfc - 0x7bff之间还存在4个字节的空位,这个是啥鸟?为啥空了4个字节啊,在缺少系统的学习堆栈原理之前,这空着4个字节让人很匪夷所思。

没有办法的情况下,大胆的猜想是应该的,先看看这4个字节是啥内容吧,具体的值是0x000000c5。


没啥特殊。无奈之下,把编译好的代码打印出来看看吧:

<bochs:20> u /2000007cb3: (                    ): mov ebx, 0x00040000       ; bb0000040000007cb8: (                    ): mov di, 0x0000            ; 66bf000000007cbc: (                    ): mov si, 0x0001            ; 66be010000007cc0: (                    ): call .+154                ; e89a00000000007cc5: (                    ): mov eax, dword ptr ds:[ebx] ; 8b0300007cc7: (                    ): mov ecx, 0x00000200       ; b90002000000007ccc: (                    ): div eax, ecx              ; f7f100007cce: (                    ): mov ecx, eax              ; 89c100007cd0: (                    ): cmp eax, 0x00000000       ; 83f80000007cd3: (                    ): jz .+29                   ; 741d00007cd5: (                    ): cmp edx, 0x00000000       ; 83fa0000007cd8: (                    ): jnz .+3                   ; 750300007cda: (                    ): sub ecx, 0x00000001       ; 83e90100007cdd: (                    ): add ebx, 0x00000200       ; 81c30002000000007ce3: (                    ): mov di, 0x0000            ; 66bf000000007ce7: (                    ): add si, 0x0001            ; 6683c60100007ceb: (                    ): call .+111                ; e86f00000000007cf0: (                    ): loop .-21                 ; e2eb00007cf2: (                    ): mov eax, dword ptr ds:0x40004 ; a10400040000007cf7: (                    ): mov ecx, dword ptr ds:0x40008 ; 8b0d08000400
发现有点意思,有一个地方和c5有一点点的相似,那就是下面的最后一行指令的地址:00007cc5,会不会是和这个c5是同样的东西?如果你稍微与实模式打过一些交道,相信你肯定会有这种直觉,那就是不自然的把段基址*10+c5做一个联系。这里的c5应该是和代码段相关的。

00007cbc: (                    ): mov si, 0x0001            ; 66be010000007cc0: (                    ): call .+154                ; e89a00000000007cc5: (                    ): mov eax, dword ptr ds:[ebx] ; 8b03
而且刚好,sreg一把,发现cs的段基址起始就是0x7c00,那么显而易见,c5就应该是eip的值吧~ 看看:注意cs段的base=0x7c00

是的,那么c5其实就是等于代码段的段内偏移!

<bochs:27> sreges:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1        Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessedcs:0x0010, dh=0x00409900, dl=0x7c000200, valid=1        Code segment, base=0x00007c00, limit=0x00000200, Execute-Only, Non-Conforming, Accessed, 32-bitss:0x0018, dh=0x00cf9700, dl=0x7c001000, valid=1        Data segment, base=0x00007c00, limit=0xf1000fff, Read/Write, Expand-down, Accessedds:0x0008, dh=0x00cf9300, dl=0x0000ffff, valid=1        Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessedfs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1        Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessedgs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1        Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessedldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1gdtr:base=0x0000000000007e00, limit=0x27idtr:base=0x0000000000000000, limit=0x3ff


原归正状:那么从0x7bfc - 0x7bff之间还存在4个字节的空位,而且刚好就是call完后return回来继续执行的代码首地址,那么push eax,你到底还干了啥,这个答案就有了一个比较完整的解释:

push eax干了啥?

1.不用怀疑:肯定就是

sub esp, 4

mov ebx, esp

mov [ss:ebx], eax

2.经过上面验证,在做1之前,他肯定还做了下面这鸟事情:

sub esp, 4

mov ebx, esp

mov [ss:ebx], 返回地址

然后才开始做上面的1.


目前还有一个疑问没有想明白:

进入call之后,你会惊奇的发现,esp由之前的0x0变成了下面的:0xfffffffc。这个值不得了,当然你会说,这个不简单吗,就是数值翻转了嘛,0-4成了负数,变成了0xfffffffc。


<bochs:30> regrax: 0x00000000_00000018 rcx: 0x00000000_00098000rdx: 0x00000000_00000000 rbx: 0x00000000_00040000rsp: 0x00000000_fffffffc rbp: 0x00000000_00000000rsi: 0x00000000_000e0001 rdi: 0x00000000_00000000r8 : 0x00000000_00000000 r9 : 0x00000000_00000000r10: 0x00000000_00000000 r11: 0x00000000_00000000r12: 0x00000000_00000000 r13: 0x00000000_00000000r14: 0x00000000_00000000 r15: 0x00000000_00000000rip: 0x00000000_0000015feflags 0x00000046: id vip vif ac vm rf nt IOPL=0 of df if tf sf ZF af PF cf<bochs:31>

话是没错,我的疑问是,如果你后面再push一个ebx,那么执行mov [ss:ebx], eax, 这一句,它的实际地址会是啥呀?莫非也会翻转,翻转+翻转 = 正确了? 明天得继续研究下翻转的原理。基础不好,汗一个。。。什么都要从零学起。。。。。


今天就到此为止吧。困了,洗漱、睡觉。

原创粉丝点击