`
zzc1684
  • 浏览: 1190412 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

学 Win32 汇编[18]: 关于压栈(PUSH)与出栈(POP) 之二

 
阅读更多

由于 "栈" 是由高到低使用的, 所以新压入的数据的位置更低.
ESP 中的指针将一直指向这个新位置, 所以 ESP 中的地址数据是动态的.

每次 PUSH, ESP = ESP - x; 每次 POP, ESP = ESP + x;
其中的 x 只能是 4 或 2, 因为 Win32 的 PUSH 只可以压入 32 位(默认)或 16 位的数据.

ESP 有个名字叫 "栈顶", 其实它指向的是栈中最低位置的数据.



实例查看 ESP 的变化:


; Test18_1.asm
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.data
    ddVal1 dd 1
    ddVal2 dd 2
    dwVal1 dw 3
    dwVal2 dw 4
.code
main proc
    PrintHex esp  ;0012FFA4
    
    push ddVal1
    PrintHex esp  ;0012FFA0
    push ddVal2
    PrintHex esp  ;0012FF9C
    push dwVal1
    PrintHex esp  ;0012FF9A
    push dwVal2
    PrintHex esp  ;0012FF98
    
    pop dwVal2
    PrintHex esp  ;0012FF9A
    pop dwVal1
    PrintHex esp  ;0012FF9C
    pop ddVal2
    PrintHex esp  ;0012FFA0
    pop ddVal1
    PrintHex esp  ;0012FFA4
    ret
main endp
end main


使用参数压栈的方式调用函数, 同时揭示 invoke 的本质:


; Test18_2.asm
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
;include    masm32.inc
;include    debug.inc
includelib kernel32.lib
;includelib masm32.lib
;includelib debug.lib

include    user32.inc
includelib user32.lib

.data
    szMsg     db 'Hello World!', 0
    szCaption db 'Hi', 0
.code
main proc
    ;invoke MessageBox, NULL, addr szMsg, addr szCaption, MB_OK
    ;用压栈的方式调用 MessageBox 函数; 本来就是如此, invoke 只是简化了这个步骤
    push MB_OK ;C 函数和系统函数读取参数的顺序是: 从右到左; 最左边的参数最后使用, 要先压入
    push offset szCaption
    push offset szMsg
    push NULL  ;一个常数会默认当作 32 位数据压入
    call MessageBox
    pop edx    ;随便出栈到一个地方, 已经没用了, 相当于进回收站
    pop edx    ;尽管没用, 不出是不行的, 因为 push 和 pop 要成对出现
    pop edx
    pop edx
    
    ;invoke ExitProcess, NULL
    ;用压栈的方式调用 ExitProcess 函数
    push NULL
    call ExitProcess
    pop edx
main endp
end main


从上面的例子看出, 函数调用是需要先压栈(PUSH)参数的;

PUSH 另一重要作用是保护数据, 调用函数前, 最先需要保护的就是 EIP, 这是执行完函数后的下一条指令的地址.
call 指令会先把 EIP 传给 ESP; ret 指令最后把 ESP 恢复给 EIP. 所以, 压栈出栈保护的是 ESP.
但因 ESP 是动态的, 所以一般先 mov ebp, esp, 然后 push ebp ... 像这样:



mov ebp, esp
push ebp
;...函数或子过程
pop ebp
mov esp, ebp
;leave ;可以使用 leave 指令代替上面两行, 它是对上面两行的简化


从调试器中查看编译器添加的保护 ESP 的代码:


; Test18_3.asm; 这是用于调试的例子
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.code
;求和函数
sumProc proc v1:dword, v2:dword, v3:dword
    mov eax, v1
    add eax, v2
    add eax, v3
    ret
sumProc endp
;
main proc
    invoke sumProc, 11, 22, 33
    PrintDec eax ;66
    ret
main endp
end main
;--------------------------

;Ctrl + T 是设置或取消断点
;Ctrl + D 是调试运行
;从调试器中看到 sumProc 函数的代码变成了:

PUSH EBP
MOV EBP,ESP
MOV EAX,DWORD PTR SS:[EBP+8]
ADD EAX,DWORD PTR SS:[EBP+C]
ADD EAX,DWORD PTR SS:[EBP+10]
LEAVE

;看来保护 ESP 的工作是由编译器做的
;从这里也看出了 EBP 寄存器的主要用途就是中转 ESP 中的数据


利用 ESP 的地址偏移读取栈中的数据:


; Test18_4.asm
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.code
main proc
    push 111
    push 222
    push 333
    push 444
    
    mov eax, [esp]
    PrintDec eax     ;444
    mov eax, [esp+4]
    PrintDec eax     ;333
    mov eax, [esp+12]
    PrintDec eax     ;111
    
    pop edx
    pop edx
    pop edx
    pop edx
    ret
main endp
end main


总结 PUSH 和 POP 的主要用途: 1、暂存与恢复数据; 2、处理函数参数.



压栈、出栈指令汇总:



PUSH(PUSHWPUSHD)  / POP   ;进出 16 位或 32 位操作数, 默认 32 位

PUSHAD              / POPAD ;进出 EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI
PUSHA               / POPA  ;进出  AX、 CX、 DX、 BX、 SP、 BP、 SI、 DI

PUSHFD              / POPFD ;进出 EFLAGS
PUSHF               / POPF  ;进出 EFLAGS 的低 16 位
分享到:
评论

相关推荐

    单片机课程设计汇编语言程序.doc

    出栈 LJMP MAIN FX1:JNB P1.1 ,FX2 MOV A,#4 ADD A,R2 PUSH Acc LCALL XS POP Acc LJMP MAIN FX2: JNB P1.2 , FX3 MOV A,#8 ADD A,R2 PUSH Acc LCALL XS POP Acc LJMP MAIN FX3: MOV A,#12 ADD A,R2 PUSH Acc LCALL ...

    c语言 Day1 入门知识,程序

    语言发展史: 机器语言→汇编语言→高级语言 ...push压栈 pop 出栈 call 调用 eax 32位寄存器 简单加法计算 { __asm mov a, 10 mov b, 20 mov eax,a add eax,b mov c, eax } 断点和单步调试:

    微型计算机原理和汇编语言 8086/8088 汇编语言指令表

    附录 B 8086/8088 汇编语言...POP POP dst 出栈一个字数据,送到操作数dst确定的位置- - - - - - - - - XCHG XCHG 把dst、src两个操作数中的内容互换- - - - - - - - - XLAT XLAT 以BX+AL的和作为偏移地址,从数据段

    万年历源码 汇编版(带源码)

    一个很好的汇编学习例程。 ;;;;;;;;;;;;;;;;;;;;;;;;;;将数值转换为字符型数据,进入函数之前ax保存年份,结果转换完了将字符放到year表示的数据段中;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; itoa: mov si,10 ;将ax传进来的...

    汇编常用命令

     PUSH 入栈指令及POP出栈指令: 堆栈操作是以"后进先出"的方式进行数据操作.  PUSH SRC //Word  入栈的操作数除不允许用立即数外,可以为通用寄存器,段寄存器(全部)和存储器.  入栈时高位字节先入栈,低位字节后...

    单片机计时器(汇编)

    置光标位置 ,AH=2,BH=0,DH跟DL分别为行号与列号,并入栈保护BX mov ah,2 mov bh,0 mov dh,3 mov dl,8 int 10h pop bx lea dx,t_buff ;送t_buff偏移地址到DX,并调用DOS显示功能,功能号为9 mov ah,9 int 21h ...

    汇编速查手册

    POPD 32位标志出栈. 二、算术运算指令 ─────────────────────────────────────── ADD 加法. ADC 带进位加法. INC 加 1. AAA 加法的ASCII码调整. DAA 加法的十进制调整. SUB...

    exe文件脱壳步骤txt下载

    pop xx:xx 出栈 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。 我们搜索 Possible Reference to String Resource ID=00122 因为对E...

    汇编指令

     PUSH 入栈指令及POP出栈指令: 堆栈操作是以"后进先出"的方式进行数据操作.  PUSH SRC //Word  入栈的操作数除不允许用立即数外,可以为通用寄存器,段寄存器(全部)和存储器.  入栈时高位字节先入栈,低位...

    汇编指令(chm格式)

    8088 汇编速查手册 一、数据传输指令 ─────────────────────────────────────── 它们在存贮器和寄存器、寄存器和输入输出端口之间传送数据. 1. 通用数据传送指令. ...

    8086 汇编指令 微型计算机原理

    MOV(Move)传送 PUSH(Push onto the stack)进栈...POP(Pop from the stack)出栈 XCHG(Exchange)交换 .MOV指令 格式为: MOV DST,SRC 执行的操作:(DST)(SRC) .PUSH进栈指令 格式为:PUSH SRC 执行的操作:(SP)(SP)-2

    字母排序与输入输出显示

    loop1:push cx;保存外循环次数 mov bx,0 loop2: mov al,data+2[bx];备份 cmp al,data+2[bx+1];相邻两个数比较 jl next xchg al,data+2[bx+1];相邻两个数交换 mov data+2[bx],al next:inc bx loop loop2 pop ...

    od脱壳软件破解工具

    但愿大家互相进修进修,大家对于破解都不是很了解,人们想学破解,可是去无从入手,所以决议为大家写1个破解初级读物的教程,但愿能大家了解破解有一些帮忙,但愿能有更多的人踏入破解的大门  1.低级,修改步伐,用...

    单片机期末考试题目及答案详解

    调用返回时再进行出栈操作,把保护的断点送回 。 3.某程序初始化时使(SP)=40H,则此堆栈地址范围为 ,若使(SP)=50H,则此堆栈深度为 。 4.在相对寻址方式中,“相对”两字是指相对于 ,寻址得到的结果是 。...

Global site tag (gtag.js) - Google Analytics