温习一下当年的汇编

假设和说明

本文以32Bit的X86 Windows为原型进行说明。栈的增长方向为高地址向低地址。

开发环境为Visual Studio,语言是C++。没有涉及到Delphi、Borland C++、Visual Basic等。

文中的任何栈地址、寄存器值以及内存址,都会与大家的环境不同。这些值是基于笔者当前环境的当前镜像。

另外一篇文章会介绍C call、Standard call、Fast call和This call。本文默认基于C call。

示例代码

C++代码

int FuncOne(int a, int b)

{

int sum;

sum = a + b;

return sum;

}

void main()

{

FuncOne(0x100, 0x200);

}

对应的汇编代码

操作方式

· 用Visual Studio建立一个Visual C++的Win32 Console工程,在主文件中,删除所有代码,把上述C++代码粘贴上。

· 设置端点在main下面的左括号上,如下图

· 按F5运行程序,当断点触发时,如下图

· 点击Visual Studio的主菜单“Debug”,点击Windows子菜单,然后分别选择Memory1、Disassembly和Registers。如下图红色部分。

· 修改你的Visual Studio窗口布局,如下图(这是我喜好的风格)

首先修改右上角的Columns列,这里我修改为4,以便于每次stack的操作,我们能更清楚地看到。

其次在Address对应的那个输入框上,输入@esp,然后按回车。

上面的窗口为Disassembly窗口,当前断点所在处为push ebp

上面的窗口为Registers窗口,显示几个重要的寄存器。

代码说明

代码由Prologue、代码call和Epilogue组成。

Prologue


PUSH EBP


保存old Frame Pointer地址到栈上


MOV EBP,ESP


保存当前栈地址,因为下面要修改栈地址


SUB ESP, 0C0H


预留出C0个字节的空间,供本地变量及其他使用。如编译器的对栈的检查,如Edit & Continue。后面我们修改这些设置,就会发现预留空间的变化。


PUSH EBX


这三个寄存器经常用,所以不管下面代码是否实际使用,都保留上。这是编译器的行为。


PUSH ESI


PUSH EDI

Epilogue


POP EDI


恢复寄存器的原址


POP ESI


POP EBX


ADD ESP, 0CH


清理栈


MOV ESP,EBP


恢复栈地址


POP EBP


恢复Frame Pointer地址

栈的变化

01031440 push ebp

执行前:ESP = 003FFD50。执行后:EIP = 01031441 ESP = 003FFD4C

我们可以看到,在入栈操作后,ESP减少了4,即我们开始提到的,栈的空间是高地址向低地址增长的。EIP的始终指向当前要执行的代码的地址。

继续按F10,一直走到下面这行:

此时,ESP = 002AF954

在Memory窗口,输入@esp,然后回车

在灰色光标闪烁的地方,就是当前的栈顶,里面的值为0。按F10,此时代码进行到下一行:

观察此时的栈情况,首先ESP = 002AF950

然后看memory窗口

最下面一行显示0x200已经入栈了,表示为一个DWORD类型的00 02 00 00。

继续按F10,ESP = 002AF94C

然后看Memory窗口

第二个参数0x100也已经入栈了,表示为一个DWORD类型的00 01 00 00。

这时要注意,代码运行到了func call的地方。

在这里,我们要按F11,同时记住当前的ESP是002AF94C,该call下一行要执行的代码是add esp, 8,地址是0103146D。

按F11进入到call中后,首先观察寄存器的情况:ESP = 002AF948

ESP又减少了4,为什么?我们要观察Memory窗口

当前ESP指向的地址是什么?就是上面的add esp,8的地址。

所以在当前环境下,我们可以总结出:

· 右面参数入栈

· 左面参数入栈

· 返回地址入栈

(这个与call方式有关,我们在下一篇文章中再谈)

上面的add esp,8 代表什么?因为我们push了两个参数,共占用了栈的8个字节,所以我们需要恢复栈的原始状态。加8即代表回到了原来的地址。如果是1个参数,则就是加4了。

Prologue的说明

Q: 为什么要ebp-0C0h,而不是其他的数字?

A: 看下面一行的30h,乘以sizeof(DWORD)之后,即是0C0h。这段空间包含了参数使用的栈空间、Edit&Continue的空间和编译器对于栈保护的空间。

Q: move ax, 0CCCCCCCCh什么意思?

A: CC代表了int 3。所以上述代码实际上是填充了0C0h个int3在该栈空间内。如果代码“不小心”运行到了这里,则会立刻中断。

Edit & Continue

在Visual Studio中右击project,选择Property,修改General中的Debug Information Format为下图(默认为:Program Database for Edit And Continue (/ZI)

重新debug,我们会看到汇编代码如下:

上面的填充CC以及sub esp的操作已经没有了。如果修改代码如下:

则汇编代码变化为:

注意962BC3地址的sub esp,8,因为我们有两个local变量,所以栈预留了8个字节。那么如果我们有很多个变量呢?大家可以自己试验一下。

FQQ

时间: 2024-10-12 20:08:04

温习一下当年的汇编的相关文章

税务案例(作者单位:山东鲁信税务师事务所)

目录公司董事领取报酬可筹划新办商业企业慎选优惠年度减免期多分利可以少补税委托开会可避免会议费被认定为是价外费用巧签投资合同享受节税收益合理设置机构享受最低税率合理利用资源综合利用税收优惠政策个人独资企业财产出租转让的筹划策略醋酸制法不同 节税效果迥异房地产开发经营与资产管理活动税务筹划思维与方法废旧物资收购.加工可筹划合法避税:纳税人“辩护律师”不要忽视所得税优惠政策影响关联企业借款利息扣除的筹划打包出售:变资产转让为资本转让薪酬激励可筹划用转让定价法进行纳税筹划 28企业重组不可忽视契税筹划

《格蠹汇编》调试笔记

以前也就是把Windbg作为一个调试所写驱动的调试器.只进行源码级的调试,运用的比较浅显. 最近研读张银奎老师的<软件调试>获益良多,刚好与之配套的<格蠹汇编>提供了老师大量的调试经验以及实验环境.不拿来好好实践一番简直浪费. 0X01调试笔记之侦查广告插件 俗话说:工欲善其事,必先利其器.对于调试领域来说,更是如此.我们不但要在自己的计算机中安装有WinDbg,还应当使用JIT调试的方法.因为对于Windows系统中的应用程序的崩溃问题,JIT调试是非常有效的办法,而且JIT调试

win32汇编实现一个简单的TCP服务端程序(WinSock的简单认知应用)

Windows网络编程,相信好多人都知道,但是我们一般都是用其他语言编写,例如C,C++,JAVA,python等等,这些语言都可以,但是汇编语言比较底层,利用它,我们可以更清晰的了解到网络编程的内在部分,这是其他语言不能相比的,好了,废话不多说,这其实就是这次的目的(毕竟水平欠缺,还是先来按照罗云斌老师的WIN32汇编书上的例子加以学习,举一反三吧). 说道网络编程,现在我所接触到的程序开发,工具软件的使用,库等等都是基于Windows平台的,想要了解Windows的网络编程就必须要知道Win

ATT 汇编语法

在研华的pc104上使用看门狗要使用汇编.使用汇编来修改CMOS里面的参数.也就是内联汇编.linux下gcc只支持ATT汇编.所以这儿有必要将ATT语法学习学习.以后需要的时候翻出来温习温习. 1,操作数的长度         操作数的长度用加在指令后的符号表示 b(byte, 8-bit), w(word, 16-bits), l(long, 32-bits),如“movb %al, %bl”,“movw %ax, %bx”,“movl %eax, %ebx ”.        如果没有指定

2星|陈春花《顺德40年》:各种官宣的汇编,内容太虚,新信息太少

顺德40年:一个中国改革开放的县域发展样板 基本是顺德各方官宣的汇编整理,内容比较虚.企业的故事讲的太少,内容还都基本见过. 总体评价2星,不推荐阅读. 以下是书中一些内容的摘抄: 1:1978年5月,一位名叫杨钊的香港客商通过罗湖口岸来到了珠三角腹地的顺德县.三个月后,设在顺德容奇镇的“大进制衣厂”正式开工.顺德人普遍认为,这是中国内地第一家真正的“三来一补”企业.P2 2:在顺德的观感和体会,极大地改变了费孝通对“珠江模式”的认识.在中国城镇化研究领域,费孝通最早提出了“苏南模式”和“温州模

自制操作系统-使用汇编显示 hello world

Windows (开机)读软盘第一个扇区的读法的具体表格 Hello World汇编版 就是将16进制编写的代码使用汇编语言编写出来 ; cherry-os ORG 0x7c00 ;指定程序装载的位置 ;下面用于描述FAT12格式的软盘 JMP entry DB 0x90 DB "CHRRYIPL" ;启动区的名称可以是任意的字符串,但长度必须是8字节 DW 512; 每一个扇区的大小,必须是512字节 DB 1 ;簇的大小(必须为1个扇区) DW 1 ;FAT的起始位置(一般从第一个

GCC在C语言中内嵌汇编 asm __volatile__ 【转】

转自:http://blog.csdn.net/pbymw8iwm/article/details/8227839 在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可, GCC会自动插入代码完成必要的操作. 1.简单的内嵌汇编 例: __asm__ __volatile__("hlt"); "__asm__"表示后面的

Linux C中内联汇编的语法格式及使用方法(Inline Assembly in Linux C)

在阅读Linux内核源码或对代码做性能优化时,经常会有在C语言中嵌入一段汇编代码的需求,这种嵌入汇编在CS术语上叫做inline assembly.本文的笔记试图说明Inline Assembly的基本语法规则和用法(建议英文阅读能力较强的同学直接阅读本文参考资料中推荐的技术文章 ^_^). 注意:由于gcc采用AT&T风格的汇编语法(与Intel Syntax相对应,二者的区别参见这里),因此,本文涉及到的汇编代码均以AT&T Syntax为准. 1. 基本语法规则 内联汇编(或称嵌入汇

汇编第五日

mov ax, offset 标号:取得标号相对于伪代码后第一条指令地址0的相对偏移量即标号地址 可以发现汇编指令中的idata会直接反映在机器码中 jmp指令可以修改IP或CS和IP的值,具体格式如下: ①jmp short 标号(段内转移) (IP) = (IP)+ 8位位移 8位位移含义是:标号地址减去jmp指令的下一条指令地址即为相对位移地址(可正可负,但是范围必须在8位数据能表示之内)并不是直接目的地址 8位位移范围为-128 - 127 例如: JMP 0008即跳到0BBD:000