第 4 章 16 位汇编应用举例

68
第 4 第 16 第第第第第第第 如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如如

description

第 4 章 16 位汇编应用举例. 如何用汇编去实现高级语言的功能。 如何在底层实现键盘控制。 如何在底层实现视频控制。 如何在底层实现磁盘扇区操作。 如何在底层实现定时器应用。. 模拟 C 语言函数实现. 1. 把数据转换为字符串 在 C 语言下有这样一个函数: char *_ltoa(long value , char *string , int radix) ; 它把数值 value 按 radix 进制转换到字符串 string ,为了简单起见,我们只实现最复杂的一种,即转换为用 10 进制表示的字符串。算法为:. - PowerPoint PPT Presentation

Transcript of 第 4 章 16 位汇编应用举例

Page 1: 第 4 章  16 位汇编应用举例

第 4 章 16 位汇编应用举例如何用汇编去实现高级语言的功能。如何在底层实现键盘控制。如何在底层实现视频控制。如何在底层实现磁盘扇区操作。如何在底层实现定时器应用。

Page 2: 第 4 章  16 位汇编应用举例

模拟 C 语言函数实现 1. 把数据转换为字符串在 C 语言下有这样一个函数:char *_ltoa(long value , char *string ,int radix) ; 它把数值 value 按 radix 进制转换到字符串 string ,为了简单起见,我们只实现最复杂的一种,即转换为用 10 进制表示的字符串。算法为:

Page 3: 第 4 章  16 位汇编应用举例

(1) 设置标志 FLAG ,以决定是否显示负号;(2) SOURCE 和 0 比较,为负则取负数的绝对值,FLAG 置 1 ;(3) 将 SOURCE 送 AX , AX 循环除以 10 ,余数(DX) 为要显示的位值,加’ 0’ 变为字符压入堆栈。一直循环到 AX 为 0 为止,入栈次数存 DI ;(4) 若 FLAG=1 ,负号入栈;(5) 按入栈次数依次出栈,送 DL ,用 INT 21H 功能 2 显示。

Page 4: 第 4 章  16 位汇编应用举例

.MODEL SMALL , C _LTOA PROTO :WORD ;过程声明.DATA CR = 13 ;定义回车键值常量,等于 13 LF = 10 ;定义换行键值常量,等于 10 DATA1 DD -8654.CODE ;子程序 _LTOA 是按十进制输出 16 位二进制数值 SOURCE .CODE .STARTUPINVOKE _LTOA , DATA1 INVOKE _LTOA , -2345 .EXIT 0

Page 5: 第 4 章  16 位汇编应用举例

_LTOA PROC USES DI DX SI BX SOURCE:WORD LOCAL FLAG:BYTE ;用来描述正负 MOV FLAG , 0 ;初始化 MOV AX , SOURCE XOR DI , DI MOV SI , 10 CMP AX , 0 JGE NEXT ;有符号比较指令, AX 大于等于 0 则跳 NEXT MOV FLAG , 1 ; FLAG=1 ,负数 NOT AX ;取反 ADD AX , 1 ;上两条指令把 AX 变为绝对值,如 -1234 1234 INC DI

Page 6: 第 4 章  16 位汇编应用举例

NEXT: .REPEAT ;本循环把 16 位二进制数转换成十进制 XOR DX , DX ;能省掉么?不能,后面要用它放余数 DIV SI ADD DL , '0' PUSH DX INC DI .UNTIL AX==0 ; FLAG=1 ,为负,负号入堆栈 .IF FLAG == 1 MOV DL , '-' PUSH DX .ENDIF MOV CX , DI ;入栈的次数送给 CX

Page 7: 第 4 章  16 位汇编应用举例

;本循环把堆栈中的字符串显示出来 .REPEAT POP DX ;显示字符送 DL MOV AH , 2 ; DOS 功能 2 INT 21H .UNTILCXZ ; CX=0 ,退出;下面六条指令显示回车、换行MOV DL , CR MOV AH , 2 INT 21H MOV DL , LF MOV AH , 2 INT 21H RET_LTOA ENDPEND

Page 8: 第 4 章  16 位汇编应用举例

字符串操作 计算字符串长度在 C 语言中有函数 strlen ,格式如下:size_t strlen( const char *string ) ;它用来计算字符串长度,输入参数 string 为 0 结尾的字符串,返回值为长度。我们用 _strlen模拟它,算法为:从第一个字符开始计数,依次检查其是否为 0 ; 为 0 则将计数值送 AX ,然后返回,否则检查下一个字符。

Page 9: 第 4 章  16 位汇编应用举例

_strlen PROC USES BX CX _string:WORD ; _STRING为字符串的偏移地址MOV BX , _stringXOR CX , CX AGAIN:MOV AL , [BX] CMP AL , 0 ; AL 为 0 ,到结尾JZ _OKINC CX INC BX MOV AL , [BX] JMP AGAIN_OK:MOV AX , CX ;返回的长度送 AXRET_strlen ENDP

Page 10: 第 4 章  16 位汇编应用举例

4.2 键盘中断 键盘控制原理 键盘数据的接收由 PC 机 8255 可编程芯片来实现的。在键盘内部有一个微处理器 INTEL8048 ,它从系统板接收时钟信号,读取每个键入的键值,将键的扫描码送到 8255 的 PA端口 (60H)内,同时产生一个中断号为 9的中断。 PB端口(61H) 的第 7位用来控制 PA端口数据的接收,该位为 0 时表示允许键盘输入,为 1 时表示禁止键盘输入。中断9的任务是,读取扫描码并把应答信号送到键盘、把扫描码转换为字符码或控制变换键和将字符码放入键盘缓冲区内。

Page 11: 第 4 章  16 位汇编应用举例

将 PB端口的第 7位设置为 1 ,键盘将不能接收数据IN AL , 61HOR AL , 80HOUT 61H , AL 下面的代码恢复键盘的输入功能IN AL , 61HAND AL , 7FHOUT 61H , AL

Page 12: 第 4 章  16 位汇编应用举例

不依靠中断,直接从芯片读键盘信息 下面的代码读取键盘的扫描码并向键盘发送应答信号:IN AL , 60H ;从 PA端口读取键盘扫描码PUSH AX ;存到堆栈IN AL , 61H ;读取 PB端口信息OR AL , 80H ;位 7置 1OUT 61H , AL ;设置 PB端口位 7为 1AND AL , 7FH ;位 7置 0OUT 61H , AL ;复位键盘应答位

Page 13: 第 4 章  16 位汇编应用举例

从键盘缓冲区直接读键盘扫描码 键盘缓冲区是一个先进先出的环形队列,其所占内存区域如下: 缓冲区头指针: WORD类型,其内存地址为0000:041AH 。 缓冲区尾指针: WORD类型,其内存地址为0000:041CH 。 键盘信息缓冲区:其内存地址为 0000:041EH~0000:003DH ,该缓冲区的缺省长度为 16 个字。

Page 14: 第 4 章  16 位汇编应用举例

.MODEL SMALL

.STACK

.DATA

.CODE .STARTUP

MOV BX , 0MOV DS , BX ; DS=0MOV BX , 4000H MOV ES , BX ; ES=4000HMOV CX , 30H ;循环 30H 次XOR BX , BX

Page 15: 第 4 章  16 位汇编应用举例

AGAIN:MOV AX , 0000H INT 16H ;等待键盘输入MOV AX , DS:[041AH]MOV ES:[BX] , AX ; 4000H:[BX] DS:[040AH]ADD BX , 2MOV AX , DS:[041CH]MOV ES:[BX] , AX ; 4000H:[BX] DS:[040CH]ADD BX , 2LOOP AGAIN ; CX=CX-1 , CX=0 则退出.EXIT 0END

Page 16: 第 4 章  16 位汇编应用举例

通过中断获取键盘信息 1. 使用 INT 16H该中断由 BIOS提供实现键盘输入操作。检测键盘状态的过程 KBSTATUS如下:KBSTATUS PROC MOV AX , 0100H INT 16H ;取键盘状态信息 JNZ HAD_KEY ; ZF=0 ,有键输入 MOV AX , 0 ;无键输入,返回 0 RETHAD_KEY : ;取键值 XOR AX , AX INT 16H ;返回键值, AH 为扫描码, AL 为字符码 RETKBSTATUS ENDP

Page 17: 第 4 章  16 位汇编应用举例

通过 DOS 的 INT 21HDOS 的 INT 21H 中的相关功能如下: 01H——带回显的键盘输入; 06H——控制台的输入 /输出:当 DL=0FFH ,表示键盘输入; 07H——不回显、不过滤的键盘输入; 08H——不回显的键盘输入; 0AH——键盘输入字符串; 0BH——检查键盘输入状态; 0CH——清除输入缓冲区的输入功能。

Page 18: 第 4 章  16 位汇编应用举例

例如判断按键是 Y还是 N代码如下:GET_KEY: MOV AH , 1INT 21HCMP AL ,‘ Y’JE IS_YCMP AL , ‘ N’JE IS_N……IS_Y:……IS_N:……

Page 19: 第 4 章  16 位汇编应用举例

4.3 视频控制程序 显示器是计算机的输出外部设备之一,它通过插在主板卡槽上的显示适配器和计算机连接。屏幕上的显示分为图形方式和文本方式,每种方式可能又分为若干模式,例如图形方式有 800*600 和 1024*768象素点阵等。通过直接操作显存、BIOS 中断 10H 和 DOS 的功能可以实现视频操作

Page 20: 第 4 章  16 位汇编应用举例

直接控制显存 在视频控制器上有描述屏幕图象数据的显示缓冲区,显示器扫描缓冲区中的数据,在屏幕上显示出相应的字符或图形。如果缓冲区中有多幅图象,我们把每幅图象称之为一页。不同显示模式的显示缓冲区在内存中的地址不同,不同显卡的地址也不同。因此虽然直接往显示缓冲区写数据可以获得较快的速度,但兼容性很差。

Page 21: 第 4 章  16 位汇编应用举例

使用 BIOS BIOS 用 INT 10H提供了设置显示模式、显示字符或图象、取屏幕字符或图象等功能。列举常用功能如下: 设置显示模式输入信息:AH = 0 ;AL = 模式号。例如, AL=4 为彩色图形方式 (320*200) , AL=1 为 40列 *25 行文本方式;输出信息:无。 设置光标大小输入信息:AH = 1 ;CH = 光标起始行号;CL = 光标终止行号。输出信息:无。

Page 22: 第 4 章  16 位汇编应用举例

设置光标位置输入信息:AH = 2 ;BH = 页号;DH = 行号;DL = 页号;输出信息:无。 在屏幕上写点输入信息:AH = 12 ;DX = 行号;CX = 列号;AL = 前景色号 写字符并光标进一格输入信息:AH = 14 ;AL = 字符 ASCII码;BH = 页号;BL = 前景色。输出信息:无。

Page 23: 第 4 章  16 位汇编应用举例

例 2 :设置屏幕为 320x200 的点阵,然后从左上角 (100 , 100) 到 (140 , 140)画一条红线。 程序首先需将屏幕设置为要求的显示模式( AH=0),然后使用写点功能往屏幕上写点

Page 24: 第 4 章  16 位汇编应用举例

.MODEL SMALL.DATAX1 DW 100 ;起始值为 (100 , 100)Y1 DW 100.CODE.STARTUP; AH=0 ,设置图形模式; AL=13H ,为 320x200 的 256色模式MOV AH , 0 MOV AL , 13HINT 10H

Page 25: 第 4 章  16 位汇编应用举例

AGAIN: ; AH=0CH 为向屏幕写点模式 ; AL 为颜色值,等于 12 为红色; DX 为像素行值, CX 为像素列值 MOV AH , 0CH MOV AL , 12 MOV DX , X1 MOV CX , Y1 INT 10H INC X1 INC Y1 CMP X1 , 140 JB AGAIN.EXIT 0END

Page 26: 第 4 章  16 位汇编应用举例

使用 DOS 功能 使用 DOS 功能可以显示一个字符或一个字符串,功能如下: 在当前光标位置输出一个字符输入信息:AH = 2 ;DL = 字符 ASCII码; ● 在当前光标位置输出一个字符串输入信息:AH = 9;DS:DX = 字符串地址,必须以 $结束;输出信息:无。

Page 27: 第 4 章  16 位汇编应用举例

例:编写一个显示字符串的宏 COUT.MODEL SMALLCOUT MACRO STRING ;定义宏MOV AH , 9MOV DX , OFFSET STRINGINT 21HENDM.DATAS1 DB "ABCDEFG$".CODE .STARTUPCOUT S1 ;调用宏.EXIT 0END

Page 28: 第 4 章  16 位汇编应用举例

4.4 磁盘控制程序 常用磁盘为软盘和硬盘。前者读取数据速度慢、存储容量大。硬盘的盘面一般以铝合金为基体,软盘以聚酯塑料为基片,在它们的表面涂有磁性材料。硬盘有多个盘片固定在同一个主轴上。为了方便存储和检索数据,盘片被划分为磁道和扇区。磁道是从盘片外圈到里排序的同心圆,每个磁道分为若干扇区,将几个扇区组合成一组叫簇。扇区是磁盘数据操作的最小单位,簇是文件操作的最小单位。每个盘片上同一编号的磁道组成柱面。磁盘控制器解释来自主机的指令并向磁盘驱动器发出相应的控制信号。

Page 29: 第 4 章  16 位汇编应用举例

常用 INT 13H 功能 磁盘复位输入信息:AH = 0 ;输出信息:AH = 磁盘状态,为以下值:00H—无错;01H-- 送驱动器命令非法;02H-- 地址标记未找到;03H-- 磁盘写保护;04H--未找到要求扇区;08H—DMA运行超时;10H—CRC错;20H—控制器错;40H—寻道错80H—磁盘未响应。

Page 30: 第 4 章  16 位汇编应用举例

读取磁盘状态输入信息:AH = 1 ;输出信息:AH = 磁盘状态,同上。

Page 31: 第 4 章  16 位汇编应用举例

读磁盘扇区数据到内存缓冲区AH = 2 ;AL = 要读的扇区数;CH = 柱面号(低 8 位); CL = 扇区号( 0-5 位); 6-7位为柱面号; DH = 磁头号;DL = 驱动器号,软盘 A , B 为 0 , 1 ,对第一块硬盘 80H ,第二块 81H ,……;ES:BX = 数据缓冲区的地址。输出信息:CF=0 ,操作成功, AH=0 , AL=读出的扇区数;CF=1 ,操作失败, AH= 出错状态,同前。

Page 32: 第 4 章  16 位汇编应用举例

内存缓冲区内容写入磁盘输入信息:同读盘;输出信息:同读盘。检验指定扇区输入信息:不要求 ES:BX ,其它同读盘;输出信息:同读盘。 格式化磁盘输入信息: ES:BX= 格式化参数首址,其它同读盘;输出信息:同读盘。

Page 33: 第 4 章  16 位汇编应用举例

设计一个简单钥匙软盘程序 设计程序 key.exe ,在它运行时只有软驱上插有钥匙盘才能正确运行,否则提示错误信息。其原理是在软盘上设置一个特殊的信息,如特殊的扇区、坏扇区等办法。我们这里是利用引导扇区的空域设置密码,程序 key.exe执行时会读该密码,正确则顺利执行,否则出错。

Page 34: 第 4 章  16 位汇编应用举例

观察软盘引导扇区

Page 35: 第 4 章  16 位汇编应用举例

程序将软盘的 0 面 0 磁道 1 扇区(面和道从 0 开始排,扇区从 1 开始排,这里是引导扇区)。可见,在 4000:4020处有几个字节为 0 ,我们用这段空间来存放密码。设密码为字符串“ 12345”,用命令 E修改内存数据,用 D4000:4000再验证修改结果。

Page 36: 第 4 章  16 位汇编应用举例
Page 37: 第 4 章  16 位汇编应用举例

命令 W 行表示将内存 4000:4000 开始的数据写入 0驱 (A:) 的第 0 个逻辑扇区(引导扇区)开始共 1 个扇区。当然也可以编一段程序写入。 为查看修改引导扇区内容后软盘能否正常工作,可以尝试磁盘文件操作,若无误则可以。

Page 38: 第 4 章  16 位汇编应用举例

编写识别程序 .MODEL SMALL , CCMPCODE PROTO ;声明比较字符串的子程序.DATASEC_CODE DB "12345", 0COUNT EQU $-OFFSET SEC_CODE-1 ;取密码字符串的长度; $表示当前偏移地址SECTOR DB 512 DUP(0)INF1 DB " 读软盘失败 ", 0DH , 0AH , '$'INF2 DB " 请插入钥匙盘 ", 0DH , 0AH , '$'INF3 DB " 密码正确,谢谢使用 ", 0DH , 0AH , '$‘.CODE .STARTUP

Page 39: 第 4 章  16 位汇编应用举例

MOV AX , 0201H ;读引导扇区 MOV CX , 1 MOV DX , 0 MOV BX , SEG SECTOR MOV ES , BX MOV BX , OFFSET SECTOR INT 13H CMP AH , 0 ; AH =0 读成功,否则失败 JE READ_OK MOV AH , 9 MOV DX , OFFSET INF1 INT 21H .EXIT 0

Page 40: 第 4 章  16 位汇编应用举例

READ_OK: ;读成功 CALL CMPCODE CMP AX , 0 ;返回值为 0 ,相等 JZ CMP_OK ;比较读出的相应位置内容是否和密码相等 MOV AH , 9 MOV DX , OFFSET INF2 ;不相等,提示插入软盘 INT 21H .EXIT 0CMP_OK: ;相等 MOV AH , 9 MOV DX , OFFSET INF3 INT 21H.EXIT 0

Page 41: 第 4 章  16 位汇编应用举例

;比较 sector+20h 和 SEC_CODE 是否相等,返回值为 AXCMPCODE PROC LOCAL FLAGS:WORD MOV FLAGS , 0 ;初始化 MOV SI , OFFSET SEC_CODE MOV DI , OFFSET SECTOR ADD DI , 20H ;在扇区偏移 20H 的地方放密码 MOV CX , COUNT ;设置循环的最大次数AGAIN: MOV AL , [SI] CMP AL , [DI] JNZ NO_EQUAL INC SI INC DI LOOP AGAIN JMP _EXIT_NO_EQUAL: MOV FLAGS , 1 ;不相等_EXIT_: MOV AX , FLAGSRETCMPCODE ENDPEND

Page 42: 第 4 章  16 位汇编应用举例

4.4.3 设计软盘扫描程序 我们在用 Format命令格式化软盘时,如果软盘上有坏扇区,该命令能提示出来。我们设计一个类似的程序,程序在数据段定义 2 个 512 字节的缓冲区,循环读磁盘的每个扇区,每个扇区同时读 2次。如果第一次读失败,则认为该扇区为坏扇区。如果读两次成功了,比较两次读取的数据不相同也认为该扇区是坏的。

Page 43: 第 4 章  16 位汇编应用举例

4.4.4 读写大硬盘扇区数据 使用中断 INT 13H 的扩展功能可以读写大硬盘扇区数据。前面介绍的 INT 13H中断只能采用 10 位二进制来表示磁道,所以对于大于 8.4G 的硬盘它已无能为力了。扩展 INT 13H又称为 INT 13 EXTENSION APIS ,它主要就是用来对超过 1024 个磁道的硬盘进行读写的。

Page 44: 第 4 章  16 位汇编应用举例

首先要介绍一个与逻辑扇号相关的结构为扩展 INT 13H使用,描述如下:DISK_ADDR_PKT STRUCT ;磁盘地址包PACKET_SIZE DB 16 ;磁盘参数包的尺寸,必须为10HRESERVED DB 0 ;保留,必须为零BLOCK_COUNT DW ? ;传输的扇区数BUFFER_ADDR DD ? ;内存缓冲区地址(段:偏移)BLOCK_NUM DQ ? ;起始绝对扇区号(即起始扇区的 LBA 号码)DISK_ADDR_PKT ENDS

Page 45: 第 4 章  16 位汇编应用举例

结构中前两项是固定的,用到的是后三项。起始绝对扇区号即前面讲到的逻辑扇区号,从 0开始编号。扩展功能如下:(1) 扩展读的功能 入口: AH= 42H DL=驱动器号(硬盘是 80H) DS:SI= DISK_ADDR_PKT 的地址 出口:成功则 CF= 0 , AH= 0 ; 失败则 CF= 1 , AH=错误码

Page 46: 第 4 章  16 位汇编应用举例

(2) 扩展写的功能 入口: AH= 43H AL = 0 ( 数据不校验 ) = 1(数据校验) DL=驱动器号 DS:SI=磁盘地址包 出口:成功则 CF= 0 , AH= 0 失败则 CF= 1 , AH=错误码 注意:一般取 AL= 0 。

Page 47: 第 4 章  16 位汇编应用举例

(3) 获得驱动器参数入口: AH= 48H DL=驱动器号 DS:SI=返回结果的地址 出口:成功则 CF= 0 , AH= 0 DS:SI 指向返回数据结构的地址:失败则 CF= 1 , AH=错误码成功时指向如下的结构地址:DISK_INFO STRUCTINFO_SIZE DW 26 ;缓冲区的大小FLAGS DW ? ;信息标志CYLINDERS DD ? ;磁道数目HEADS DD ? ;磁头数目SEC_PER_TRACK DD ? ;每磁道扇区数目SECTORS DQ ? ;磁盘扇区总数SECTOR_SIZE DW ? ;每扇区字节数DISK_INFO ENDS

Page 48: 第 4 章  16 位汇编应用举例

4.5 中断程序设计 设计自己使用的中断程序 在程序设计时,有时为了方便,使用某个中断号来设置自己的中断,在程序退出时恢复原来的中断程序。该种中断程序和子程序很相似,只不过使用寄存器传参数,中断程序第一条指令为 sti ,中断返回时使用指令 iret ,而不是子程序的 ret 。在主程序中的调用方式为 INT n(n 为中断号 ) 。

Page 49: 第 4 章  16 位汇编应用举例

(1) 定义中断程序,格式为:MYINTERUPT PROC

STI……IRET ;不同于子程序的 RET

MYINTERUPT ENDP

Page 50: 第 4 章  16 位汇编应用举例

(2) 获取要设置的中断号的原来入口地址,使用DOS 中断的功能 35h :功能号: AH=35h 。入口参数: AL= 要设置的中断号。出口参数: ES 为中断服务程序段地址, BX 为中断服务程序的偏移地址。 获取原来的地址是为了在结束使用自己的中断后,恢复原来的入口地址。也可以根据中断号直接从中断向量表中取入口地址。

Page 51: 第 4 章  16 位汇编应用举例

(3) 设置新的中断入口地址,使用 DOS 中断的功能 25h :功能号: AH=25h 。入口参数: AL= 要设置的中断号; DS 为中断服务程序myinterupt 的段地址, BX 为中断服务程序myinterupt 的偏移地址。

Page 52: 第 4 章  16 位汇编应用举例

4.6 引导程序设计 引导程序原理 每一个软盘和硬盘逻辑分区的第一个逻辑扇区上为引导扇区,物理硬盘的第一个物理扇区上还有主引导扇区。引导程序的作用是让系统识别磁盘格式和启动别的程序,它位于引导扇区。

Page 53: 第 4 章  16 位汇编应用举例

软盘和硬盘的引导程序都有一定的格式,在 Debug 下用 L命令可以读出引导扇区的引导程序,命令“ L4000 : 0 2 0 1”表示将 C :( 0 表示 A :, 1 表示 B :, 2 表示 C :)的逻辑 0 扇区开始的 1 个扇区读到内存 4000:0 。命令“ D4000:0”以 16进制方式显示 4000:0 开始内存数据,命令“ U4000:0”从 4000:0 反汇编代码。

Page 54: 第 4 章  16 位汇编应用举例

由于 Debug 的命令只能管理逻辑分区,而主引导扇区是位于逻辑分区之外的。一般情况下,物理硬盘的第一个磁道的第一个扇区是主引导扇区,从第二个磁道开始是 C :分区。 扇区数据的最后两个字节“ 55 AA”为引导扇区标志。机器启动后 BIOS 上程序开始执行,自我检查结束后开始读主引导扇区。

Page 55: 第 4 章  16 位汇编应用举例

由于一个扇区只有 512 字节,我们编写的显示字符串的程序也有几十行,原来的主引导程序已经 512 字节,装不下我们的代码。我们注意到,在物理硬盘的第一个磁道只有主引导扇区,其它扇区是空闲的。可以将原来的主引导扇区代码移动到其它空闲的扇区,将我们的主引导程序放在第一个扇区。我们的引导程序运行后会显示一行字符串,然后再读原来的主引导程序,并跳转到原来的主引导程序运行。

Page 56: 第 4 章  16 位汇编应用举例

实现步骤 (1) 准备系统盘 选择一张软盘,在 DOS 下执行 Format A:/S ,表示格式化软盘且向它复制 DOS系统文件。 (2) 备份主引导扇区数据到软盘 可以编写一个程序实现,也可以用 Debug 实现。这样做的目的是,万一系统崩溃了,还可以用软盘启动恢复。如果用 Debug ,步骤如下: ① 建立一个文件,如 ddd.txt ,随便敲入几个字母,如“ aaaaaaaaaaaaaa”。 ② 用命令 Debug ddd.txt ,将该文件装载到内存。用命令 d 可以看到文件在内存中位置为 126C:0100H~126C:010DH ,如图 4-24所示。

Page 57: 第 4 章  16 位汇编应用举例

③ 读主引导扇区数据到内存 126C:0100H 开始的区域。因为偏移地址 100H~2FFH 要用来放引导扇区数据,故代码从 300H 开始。④ 保存内存数据到文件 ddd.txt 。操作如图 4-26 。注意这样几点: ● 寄存器 BX.CX保存文件 ddd.txt 的大小,我们要将新的数据写入,必须修改它们。 ● CX修改前的大小为 0Eh ,这是原来 ddd.txt 的大小。主引导扇区长 512 字节,故修改为 200H 。 ● 命令 W 用于将当前位置开始 (100H) ,长度为 BX.CX的数据写入文件。

Page 58: 第 4 章  16 位汇编应用举例

(3) 移动主引导扇区数据 .(4) 安装新的主引导程序 方法与前面类似。可以编写一个独立程序,先读文件 boot.com的 7C00H 开始的 200H 字节数据到分配的内存,然后将其写入主引导扇区。

Page 59: 第 4 章  16 位汇编应用举例

4.7 定时器应用程序 产生时钟原理 中断 INT 8 为时钟中断,每秒发生 18.2 次,用以刷新系统时间,在 INT 8 中要调用中断 1Ch 。 INT 1Ch 入口地址在逻辑地址为 0000:0000h开始的中断向量表中。每个中断占用 4 个字节,因此 1Ch 的入口地址在 0000:0070h 到 0000:0073h 。命令 d0:0070 可以看到,它的入口地址的 CS 为 D000h , IP 为 001Dh 。

Page 60: 第 4 章  16 位汇编应用举例

要定时执行某个程序,一般使用接管中断 1Ch 实现。始终要显示时间,其时分秒在不停地变化,意味着每隔相等的时间就要刷新显示的数据。显示的数据来自于系统时间。中断 1Ah提供了获取系统时间的功能,以其功能 2 为例,使用方法如下:功能描述: 读取时间。入口参数: AH= 02H 。出口参数: CH= BCD码格式的小时。CL= BCD码格式的分钟。DH= BCD码格式的秒。DL= 00H——标准时间,否则,夏令时。CF= 0——时钟在走,否则,时钟停止。

Page 61: 第 4 章  16 位汇编应用举例

4.8 用 Debug 修改程序结构 修改代码原理 我们知道,对一般 com格式文件是从偏移地址 100H开始运行的。如果要先运行我们的代码,只有两个办法,一个是把原来的代码往后移,把我们的代码放在前面。另一个办法是将我们的代码附加在原程序后面,然后修改第一条指令,让它先跳到我们的代码运行,运行结束后再跳回去 对于第一种方法,代码往后移,涉及到同时要修改偏移地址,如前面的 MOV DX , 10C 。第二种方法要先将第一条指令修改为 JMP XXX ,其中 XXX 为我们附加代码的地方。运行完附加代码后,再将原来的指令改回去,然后跳转到原来的地方运行。

Page 62: 第 4 章  16 位汇编应用举例

步骤如下:(1) 使用 JMP 120H ,则占用 2 个字节,记住原来偏移 100H处的字节“ BA 0C”。 COM 格式程序从第 1 条指令开始执行,运行完我们的程序后,还要返回运行原来的程序。跳回运行前必须恢复原来的代码。(2) 修改第 1 条指令修改为 JMP 120 。使用命令a 实现。(3) 从要附加代码的 120H处开始添加代码。也可以从更后面些开始,只要在一个段内即可。

Page 63: 第 4 章  16 位汇编应用举例

(4) 因为在 MOV DX , 136H 指令设字符串从 136H 开始,故用 F命令从该处开始添加字符串。也可以用命令 E逐个添加字符。(5) 写入的长度由寄存器 CX 决定,程序被修改后变长了,要修改到新的值。计算从 100H 到字符串的最后程序占用 50H 字节,用命令 R CX修改要写入的字节数。(6) 使用 W 指令保存。 W命令后可以带明确的写入开始地址,也可以不带。装入 deb.com时,开始位置为 100H ,所以此处的缺省开始位置为 100H 。

Page 64: 第 4 章  16 位汇编应用举例
Page 65: 第 4 章  16 位汇编应用举例

4.9 加密一个 EXE 文件 我们用简单的方法加密,对字符串和显示字符串的代码分别进行异或,让静态反汇编者看不到直接的字符串和代码。但是程序运行时必须先将字符串和代码再异或一次,以恢复本来的状态。

Page 66: 第 4 章  16 位汇编应用举例

加密方法的实现 ;文件名: Crypto.asm.MODEL SMALL .DATA STRING DB "I AM A STUDENT!",0DH,0AH,"$"LEN EQU $-STRING ; LEN 为字符串长度.CODE .STARTUP ;与 78H 异或,解密字符串MOV BX, OFFSET STRINGMOV CX,LENAGAIN1: XOR BYTE PTR[BX],78H INC BX LOOP AGAIN1

Page 67: 第 4 章  16 位汇编应用举例

;与 78H 异或,解密显示字符串的代码MOV BX,ADDR1MOV CX,ADDR2-ADDR1AGAIN2: XOR BYTE PTR[BX],78H INC BX LOOP AGAIN2 ADDR1 EQU $ ; ADDR1 等于当前的偏移地址MOV DX, OFFSET STRINGMOV AH,9INT 21HADDR2 EQU $ ; ADDR2 等于当前的偏移地址 .EXIT 0 END

Page 68: 第 4 章  16 位汇编应用举例

加密 EXE 文件中的代码与字符串 生成 Crypto.exe 后反汇编,首先要找到字符串和显示字符串代码在文件中的位置,记下相应的 16 进制串 WinHex 是一款二进制编辑工具。运行 WinHex.exe ,查找对应的 16 进制代码,找到在文件偏移中对应的位置 选中要异或的数据部分,运行菜单“编辑”“数据修改”,在异或的值中添入 78H ,选择确定,即所有选中字节与 78H 进行了异或,保存该文件即可