520 likes | 686 Views
第 5 ç« 32 使±‡ç¼–程åºè®¾è®¡. 80186 ä»¥åŽ CPU 在 8086 åŸºç¡€ä¸Šå¢žåŠ çš„å¸¸ç”¨æŒ‡ä»¤ã€‚ 在 DOS 下和 Windows 下如何使用 32 使Œ‡ä»¤è®¾è®¡ç¨‹åºã€‚ 区别于 DOS 下的 Debug ,如何用 W32Dasm 调试 Windows 程åºã€‚. 5.1 32 使Œ‡ä»¤ç³»ç»Ÿ.
E N D
第5章 32位汇编程序设计 80186以后CPU在8086基础上增加的常用指令。 在DOS下和Windows下如何使用32位指令设计程序。 区别于DOS下的Debug,如何用W32Dasm调试Windows程序。
5.1 32位指令系统 • Intel公司于1985年正式公布了32位微处理器80386。80386采用32位指令系统的结构,被Intel公司称为英特尔结构,简称IA(1ntel Architecture)结构,并明确宣布作为后续80x86微处理器的标准。在此基础上,Intel公司又相继推出了80486、Pentium、MMX Pentium 、Pentium Pro、Pentium II、Pentium III、Pentium Ⅳ等微处理器,它们都继承了80386的32位指令系统,同时又新增了若干条专用指令;另外还在32位整数指令系统的基础上加入了浮点指令、整数多媒体MMX指令和浮点多媒体SSE指令,极大地丰富了Intel 80x86微处理器的指令系统,有效地增强了Intel 80x86微处理器的功能。
32位的寻址方式 • Intel 80x86系列的微处理器32位CPU相对于16位CPU寻址方式的主要区别有: (1) 32位寻址方式的操作数可以是8位、16位或32位,包括32位的立即数。 例如: MOV EAX,12345678H ;源操作数为32位立即数 MOV EAX,EBX ;两个寄存器均为32位 MOV EAX,[2000H] ;因为EAX为32位,从DS:[2000H]处取4字节
(2) 在使用寄存器间接寻址、寄存器相对寻址或相对的基址变址寻址时,既可以用16位的寄存器,又可以使用32位的寄存器。 例如: MOV AX,[BX] MOV DX,[EBX] MOV EAX,[EBX+80H] MOV EAX,[EBX+ESI+0400H]
(3) 80386的所有32位通用寄存器都可以作为偏移地址参加寻址,而在8086/8088/80186/80286中的AX、DX、CX寄存器不能用来存放存储器操作数的偏移地址。 例如: MOV AX,[ECX] ;正确 MOV BX,[EAX] ;正确 MOV BX,[AX] ;在16位下错误
(4) 80386的所有32位通用寄存器都可以作为基地址寄存器使用,除了ESP寄存器以外都可以作为变址寄存器使用。
(5) 32位变址寄存器的值可以乘上一个比例常数(如1,2,4,8),乘上比例常数的变址方式对于访问数组等数据结构特别有效。 例如: MOV EAX,[ESI*2] MOV EAX,[EBX+ESI*8] MOV EAX,[EBX+ESI*4+0400H]
由此可见,16位存储器操作数的寻址方式的组成公式为: 16位有效地址=基址寄存器(BX/BP)+变址寄存器(SI/DI)+8/16位的偏移量 其中基址寄存器只能是BX或BP,变址寄存器只能是SI或DI。 而32位存储器操作数的寻址方式的组成公式为: 32位有效地址=基址寄存器+(变址寄存器*比例)+8/32位的偏移量 其中基址寄存器为任何8个32位通用寄存器之一,变址寄存器为除ESP之外的任何32位通用寄存器之一,比例可以是1、2、4或8,代表操作数的长度是1、2、4或8字节,位移量可以是8或32位的值。
32位扩展指令 • 1.数据传送指令的扩展 (1) 堆栈操作 a. 进栈指令PUSH和出栈指令POP b.16位通用寄存器进栈指令PUSHA和出栈指令POPA 从80186开始引入了如下指令: PUSHA ;顺序将AX/CX/DX/BX/SP/BP/SI/DI的内容 压入堆栈,SP←SP-16 POPA ;功能和PUSHA指令功能相反,SP←SP+16
c. 32位通用寄存器进栈指令PUSHAD和出栈指令POPAD. 这两条指令是32位CPU新扩展的指令: PUSHAD ;顺序将 EAX/ECX/EDX/EBX/ESPEBP/ESI/EDI的内容压入堆栈,SP←SP-32 POPAD ;功能和PUSHAD指令功能相反,SP←SP+32
(2) 标志传送 标志传送指令增加了两条: PUSHFD ;将EFLAGS的内容压入堆栈,堆栈中D16D17两位被清0 POPFD ;将堆栈内容弹出到EFLAGS,堆栈中D20D19两位被清0,D16保持不变
(3) 地址传送 地址传送指令增加了三条: LFS r16/r32, mem ;FS:r16/r32←存储单元的32/48位远指针 LGS r16/r32, mem ;GS:r16/r32←存储单元的32/48位远指针 LSS r16/r32, mem ;SS:r16/r32←存储单元的32/48位远指针
2. 算术运算指令的扩展 (1) 乘除法指令 IMUL r16,r16/m16/i8/i16 ;r16← r16*r16/m16/i8/i16 IMUL r16,r16/m16,i8/i16 ;r16← r16/m16*i8/i16 IMUL r32,r32/m32/i8/i32 ;r32← r32*r32/m32/i8/i16 IMUL r32,r32/m32,i8/i32 ;r16← r32/m32*i8/i16 指令说明:新增的这些指令要求目的操作数和源操作数的长度要相同。对于8位立即数i8要进行符号扩展,扩展后为16/32位。
(2) 符号扩展指令 80386 新扩展的指令有: CWDE ;将AX符号扩展为EAX CDQ ;将EAX符号扩展为EDX.EAX MOVSX r16,r8/m8 ;r16←将r8/m8符号扩展 MOVZX r16,r8/m8 ;r16←将r8/m8零位扩展 MOVSX r32,r8/m8/r16/m16 ;r32←将r8/m8/r16/m16符号扩展 MOVZX r32,r8/m8/r16/m16 ;r32←将r8/m8/r16/m16零位扩展
3. 位操作指令扩展 移位指令从80186开始支持一个立即数做移位次数,其指令格式为: SHL/SHR/SAL/SAR/ROL/ROR/RCL/RCR reg/mem,1/cl/i8
4. 串操作指令扩展 从80186开始支持端口的串操作,配合重复前缀指令就能够实现用一条指令连续进行输入或输出操作,大大提高了CPU的I/O操作能力。
(1) 串输入 指令格式及功能: INSB/INSW/INSD ;ES:[DI/EDI] ←DX指定的输入端口,DI/EDI←DI/EDI±1/2/4 指令说明:INS指令从由DX指定的输入端口中输入一 个字节(INSB)或一个字(INSW)或一个双字INSD) 数据到由ES:[DI/EDI]指定的存储单元中,且能使 DI/EDI自动±1或±2或±4;DX内容保持不变。ES段寄 存器不能被段超越。
(2) 串输出 指令格式及功能: OUTSB/OUTSW/OUTSD ;DX指定的输出端口←DS:[SI/ESI],SI/ESI←SI/ESI±1/2/4 指令说明:该指令实现从由DS:[SI/ESI]指定的内存单元中的一个字节(OUTSB)或一个字(OUTSW)或一个双字(OUTSD)数据到由DX指定输出端口中,且能使SI/ESI自动±1或±2或±4;DX内容保持不变。DS段寄存器可以被段超越。
80386新增指令 • 80386CPU中通用寄存器由32位寄存器组成,因此所有16位指令都有其相应的32位指令形式,以支持32位数据类型的操作。操作数可为8位、16位或32位,并且可以使用32位寻址方式。80386的执行单元中新增了一个“桶型”移位器,所以可以实现快速移位操作,新增的指令主要是有关位操作的。另外,80386还增加了条件设置指令,以及对控制、调试和测试寄存器的传送指令。
80486新增指令 • 80486CPU不仅包括80386CPU的结构,还包括了80387协处理器FPU的结构,且在此基础上增加了8KB的Cache高速缓冲存储器,它的最高内部时钟频率达到了100MHZ。采用了精简指令系统集计算机技术RISC和指令流水线方式,使指令的执行速度及其他性能有了更大的提高,且可以直接执行8087的所有浮点运算指令。 • 80486的指令系统在80386指令系统的基础上增加了6条指令,其中,INVLPG、INVD及WBINVD三条专用于Cache管理,一般用户不需使用,另外三条XADD、CMPXCHG和BSWAP指令是可供系统应用程序使用的指令。
Pentium新增指令 • Pentium CPU仍为32位结构,地址总线为32位,但外部数据线为64位,内部时钟频率为60MHZ~200MHZ。Pentium CPU对浮点处理单元进行了重大改进,增加了专用的加法、乘法和除法单元;采用具有两条流水线的超标量技术;对常用的简单指令用硬件实现等,进一步提高了Pentium CPU的整体性能。 • Pentium CPU指令系统中新增加了一条8字节比较交换指令CMPXCHG8B,一条处理器识别指令CPUID,4条系统专用指令RDTSC、RDMSR、WRMSR、RSM。
Pentium pro新增指令 • Pentium Pro CPU的地址总线为36位,可以寻址的主存空间可达64GB。Pentium Pro CPU内含一级Cache 为16 KB,二级Cache 为256/512KB;扩展了超标量技术,具有三个整数处理单元和一个浮点处理单元,能同时执行三条指令,并对32位指令进行了优化处理。 • Pentium Pro CPU在Pentium指令系统的基础上新增了3条实用的指令CMOV、RDPMC、UD2。
DOS下32位汇编程序 • 32位程序编写规范 32位指令的程序设计方法和我们在前面讲过的16位指令的程序设计方法基本相同。但在编写完整的汇编程序时,需注意以下问题:
指定汇编程序识别新指令 • 处理16位段和32位段 • 注意有些指令在16位段和32位段的差别
DOS 32位程序举例 例1:将一个64位数据算术左移4位 分析:本例采用EDX.EAX保存64位数据,用4次循环实现移位。 .MODEL SMALL .386 ;采用32位指令,16位段模式 .STACK .DATA QVAR DQ 1234567887654321H .CODE .STARTUP MOV EAX,DWORD PTR QVAR MOV EDX DWORD PTR QVAR [4] MOV ECX,4 NEXT: SHL EAX,1 RCL EDX,1 LOOP NEXT MOV DWORD PTR QVAR,EAX MOV DWORD PTR QVAR[4],EDX .EXIT 0 END
Windows下32位汇编程序 • 若较好地掌握了Windows下的汇编程序开发,可以让我们深刻地理解高级语言是怎么来的,而且在学习反病毒技术、软件的加密解密方面这是必须的。在高级语言的开发中涉及到程序的调试,也要用到汇编语言。 • Windows下汇编语言的开发使用软件Masm32或Tasm32,本书使用的是Masm32。程序的调试使用W32dasm、Soft-Ice等软件。
Windows汇编语言特点 • DOS下的汇编程序是“指令+中断”,而Windows下32位汇编程序是“指令+API+消息”。 • API函数:API是“Application Programming Interface”的英文缩写,很象DOS下的中断。中断是系统提供的功能,在操作系统运行后就被装载在内存中,而API函数是通过将函数所在的动态连接库装载到内存后调用函数的。
在Windows下设计应用程序不使用API是不可能的,有些高级语言看似没有使用API,只不过它们提供的模块对API进了封装。在Windows下设计应用程序不使用API是不可能的,有些高级语言看似没有使用API,只不过它们提供的模块对API进了封装。 • API是Windows的基础,API包含在众多扩展名为dll的动态连接库中,三个关键的动态连接库文件是:
Kernel32.dll:系统服务功能。包含内存管理、任务管理和文件操作等API函数。一般情况下都要使用该动态连接库。也许一个程序什么功能也没有,但不能没有类似DOS下退出内存的.EXIT 0指令,在Windows下为API函数ExitProcess。 • Gui32.dll:图形设备接口。提供显示文本和图形等API函数。Windows程序最大的一个特点是窗口,如果设计的程序要包含窗口,则需要该库中的函数,包括窗口的建立、显示、事件处理和销毁。 • User32.dll:用户接口服务。提供建立窗口和传送消息的API函数。用户点击按钮或拖动窗口,界面之所以出现相应的变化,因为系统对不同的用户操作用消息来描述,不同的消息又对应不同的函数,由它们去处理。
消息:消息是指Windows发出的一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。
消息本身是作为一个用MSG命名的结构传递给应用程序的,这个结构中包含了消息的类型等信息。其定义如下:消息本身是作为一个用MSG命名的结构传递给应用程序的,这个结构中包含了消息的类型等信息。其定义如下: MSG struct Hwnd dword ? ;消息目的窗口句柄 Message dword ? ;消息常量标识符,是用WM_开头的预定义常量 wParam dword ? ;32位消息带的参数1 lParam dword ? ;32位消息带的参数2 Time dword ? ;消息创建时的时间 Pt POINT <> ;消息创建时的鼠标位置 MSG ends
MASM32开发环境 Steve Hutchesson的免费软件包 • 编辑器geditor.exe • MASM 6.14汇编程序和链接程序 • 相当完整的Win32的包含文件、库文件以及教程和示例等
MASM32的网络资源 • Hutch的32位MASM第8版(masm32v82r.zip) http://www.movsd.com/ • Iczelion的Win32教程 http://spiff.tripnet.se/~iczelion http://asm.yeah.net/ • API文档 http://www.microsoft.com/msdn
Win32ASM程序结构 .386 ;伪指令,还可以是.486 .586 .MODEL Flat, STDCALL ;内存模式伪指令 .DATA ; STDCALL告诉编译器参数的传递约定。 ;初始化数据定义于此 ...... .DATA? ;未初始化数据定义于此 ...... .CONST ;常量定义于此 ...... .CODE ;标号 ;start: ;代码部分 ..... end <label> ;end start
Win32ASM程序示例 • 一个最简单的Win32汇编语言程序 • 显示标准Windows消息窗口的程序 • 消息框显示:汇编语言并不难 • 标题:欢迎进入32位Windows世界 • 将下面的代码存为aa.asm,然后选择菜单“Project”“Assemble & Link”,如果没有错误的话,会生成aa.exe。双击aa.exe就可以执行它。
API区别大小写 包含API函数的库文件 包含对系统常量和API函数等的声明 .386 .model flat,stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib
返回操作系统API调用 显示消息框API调用 .data szCaption db “欢迎进入32位Windows世界”,0 szText db “汇编语言并不难!”,0 .code start: invoke MessageBox,NULL,\ offset szText, addr szCaption,MB_OK invoke ExitProcess,NULL end start
W32Dasm反汇编工具简介 • W32Dasm是著名的静态反汇编工具,它能把PE等格式的文件反汇编为易于阅读的文本文件。所谓的静态反汇编是有别于动态反汇编工具,一次完成反汇编,不能一条指令一条指令的跟踪执行的一种反汇编方式。W32Dasm只有简单的调试功能。
W32Dasm的主要功能 • 保存反汇编文本文件和创建方案文件 • 跳转到代码的某个位置 • 查看导入、导出函数 • 以二进制方式查看数据段和代码段数据 • 资源定位 • 简单的动态调试功能
W32Dasm 的反汇编代码阅读 • 我们以上个例子生成的可执行文件进行反汇编,然后分析其反汇编文件结构。下面按行进行说明: • 反汇编的文件名为test.exe。 • 代码段在文件中偏移地址为400h,大小为200h。 • 数据段在文件中偏移地址为800h,大小为200h。 • 节个数为3,程序内存中装载的虚拟地址为00400000h。节是可执行文件中代码、数据和资源的基本单位。 节:性质相同的数据放在一个连续区域内,该区域叫节
节名.text,内存中相对于ImageBase的偏移值为1000h,文件中偏移为400h,大小为200h,节属性值为60000020h。属性表明该节是可执行、可读和可写等特征的。该节一般包含可执行的代码。节名.text,内存中相对于ImageBase的偏移值为1000h,文件中偏移为400h,大小为200h,节属性值为60000020h。属性表明该节是可执行、可读和可写等特征的。该节一般包含可执行的代码。 • 节名.rdata,内存中相对于ImageBase的偏移值为2000h,文件中偏移为600h,大小为200h,节属性值为40000040h。
节名.data,内存中相对于ImageBase的偏移值为3000h,文件中偏移为800h,大小为200h,节属性值为0c0000040h。定义的全局变量一般在该节。节名.data,内存中相对于ImageBase的偏移值为3000h,文件中偏移为800h,大小为200h,节属性值为0c0000040h。定义的全局变量一般在该节。 • 节名.rsrc,内存中相对于ImageBase的偏移值为4000h,文件中偏移为0a00h,大小为600h,节属性值为0c0000040h。文件中使用到的资源一般在该节。
程序有一个菜单资源,但格式不清楚。 • 程序无对话框资源。 • 导入函数信息。 • 有两个导入模块。 • 导入模块1为kernel32.dll,模块2为user32.dll。 • 调用模块1中函数ExitProcess,在内存中地址为0040205ch,函数序号为0075h。 • 调用模块2中函数MessageBoxA,在内存中地址为00402078h,函数序号为01bbh。
导出函数个数为0。一般只有dll文件才有导出模块。导出函数个数为0。一般只有dll文件才有导出模块。 • 汇编代码列表。 • 代码部分在节.text。 • 程序入口在内存00401000h,在文件偏移位置1600h。
后面部分为汇编代码部分。在原程序中调用 MessageBox的方法为: invoke MessageBox,0,offset text1,offset text2,MB_OK 在反汇编中,我们可以看出实际的代码为: push 00000000h ;实际为常量MB_OK push 0040300Fh ;字符串的偏移地址 push 00403000h ;字符串的偏移地址 push 00000000h ;窗口句柄 call 00401020h ;跳转到MessageBox
Windows程序的调试 • 本节通过举例怎样反汇编一个程序并进行调试和修改。可以使用Soft-Ice调试Windows程序,我们这里使用W32dasm实现对test.exe的修改,对照图5-8,修改后的结果如图5-19。其原理是将调用MessageBox传递的参数进行修改,修改后如下: push 00000000h ;不变 push 00403000h ;修改 push 00403000h ;修改 push 00000000h ;不变 call 00401020h ;不变
修改的步骤 (1) 从菜单“Open File to Disassemble”选择文件test.exe,反汇编结束后从菜单“Debug”选择“Load Process”,点击“Load”,生成受W32dasm控制的进程test.exe。
(2) 选择对话框,此时焦点定位在程序的第一条指令,偏移地址为00401000h。我们要修改00401002h处的指令,但直接点击该行不管用。点击“Goto Address”,在弹出的界面中点击“OK”,焦点会跳到第二条指令,