首页 > 其他分享 >chapter5------编写主引导扇区代码

chapter5------编写主引导扇区代码

时间:2024-08-02 11:51:30浏览次数:13  
标签:number 字节 chapter5 al 扇区 mov ------ byte es

主引导扇区 (Main Boot Sector, MBR)

  • 什么是主引导扇区:
    处理器加电或者复位之后(简单来说就是启动计算机),如果硬盘是首选的启动设备,那么ROM-BIOS(基本输入输出系统)将试图读取硬盘的0面0道1扇区(简单来说就是第一个扇区),这就是主引导扇区
  • 主引导扇区的特点:
    • 扇区数据仅有512字节
    • MBR应该以0x550xAA这两个字节结尾来确保有效性(可以理解为这个结束标志表示这个文件是MBR,大家有兴趣可以去了解魔数)
    • ROM-BIOS程序首先检测文件最后的两个字节(0x55, 0xAA),若有效则将MBR加载到逻辑地址0x0000:0x7c00处,即物理地址0x07c00

在屏幕上显示文字

  • 文字如何显示在屏幕上

    • 显卡:为显示器提供内容,并控制显示器的显示模式和状态
    • 显示器:将显卡提供的内容以视觉可见的方式呈现在屏幕上
    • 显示存储器(VRAM,显存):显卡控制显示器的最小单位是像素,一个像素对应着屏幕上的一个点,要显示的内容预先写入显存
  • 显示器的工作模式

    • 图形模式:显存里的内容---> 比特0---像素不亮,比特1--像素亮
      图形模式
      显卡周期性地从显存中提取比特,并按顺序显示在屏幕上

    • 文本模式:
      在图形模式下控制像素的明暗以显示字符非常麻烦。所以就有了文本模式。我们只需将字符的ASCII代码存放到显存中,然后显卡提取,显示器打印就行了,控制像素的工作就交给字符发生器
      文本模式

    • 不论是哪种工作模式,要让屏幕显示文字,我们只需关注将要显示的内容写入显存中即可

  • 访问显存
    内存

    这是一张1MB的内存条,物理地址0xF0000-0xFFFFF是属于ROM-BIOS的区域,0xB8000-0xBFFFF是输入显存的区域,也就是说,我们只需往这个地址里写内容,就可以将其显示在屏幕上了

    • 字符属性:在显存中,一个字符是要占用两个字节的,第一个字节存储字符的ASCII码,第二个字节存储字符的显示属性(也就是字符的颜色等等)

    字符

    K位是闪烁位(1-闪烁,0-不闪烁),I位是亮度位(1-高亮,0-正常),前景色就是字符的颜色,背景色就是字符的背景色

    • 显示字符
    ; es指向显存
    mov ax, 0xb800
    mov es, ax
    
    ; 打印字符
    mov byte [es:0x00], 'L'     ; 可以直接用字符,但要注意引号
    mov byte [es:0x01], 0x07    ; 字符的显示属性 00000111,黑底白字
    

    上面的byte用来修饰目的操作数,指定操作的字节数,这里不赘述了

显示标号的汇编地址

  • 汇编地址
    汇编地址是在源程序编译期间,编译器为每条指令确定的汇编地址指示该指令相对于程序或者段起始处的距离,以字节计,当编译后的程序装入物理内存后,它又是该指令在内存段内的偏移地址

    总结起来就是指令相对于程序起始地址的偏移量

  • 标号
    简单来说标号就相当于存储汇编地址的变量,这样可以不用特意去记地址,更人性化
    例如start: mov ax, 0xb800(这里冒号可写可不写),这里标号start就存储着指令mov ax, 0xb800的汇编地址,这样写的好处就方便跳转

显示十进制数字

需要注意的是数字是没法直接显示在屏幕上的,我们需要将其转化成字符写入显存中才可以显示。

例如我们想要显示整数123,需要先将其转化为'1','2','3'并写入显存,其实这就是该整数的个位、十位、百位

  • 在程序中声明并初始化数据
    我们需要再内存中留出一些空间来保存这些数位
    在这里介绍下声明数据所用的伪指令(伪指令没有对应的机器指令,由编译器处理)

    • DB(declare byte): 声明字节数据
    • DW(declare word): 声明数据
    • DD(declare double word): 声明双字数据
    • DQ(declare quad word): 声明四字数据

    例如number db 0, 0, 0,我们就声明了3个字节数据,并将其初始化为0,number代表了这些数据的起始汇编地址,我们就可以将分解的数位保存在这里啦

  • 分解数的各个数位
    其实就是不断地用它的进制数去除得到的余数就是各个数位了。例如十进制数123,禁止数为10,那就用10除3次,依次是3、2、1

程序:

; ------- 分解数位
mov ax, 123
mov bx, 10 ; 存储进制数

mov cx, cs
mov ds, cx ; 因为现在数据和代码都在同一个段内,所以ds和cs相同

mov dx, 0
div bx
mov [0x7c00 + number + 0x00], dl ; ds = 0x0000,number表示的汇编地址是相对于程序加载处0x7c00的,0x00表示第一个数位

xor dx, dx ; 将dx清0
div bx
mov [0x7c00 + number + 0x01], dl
...
...
number db 0, 0, 0

下面这张图就解释了为什么是[0x7c00 + number]而不是[number]

number

div指令的用法大家就自行查阅了哈

  • 显示分解出来的各个数位
    唯一需要注意的就是将内存中的数字转化为字符,0的ASCII码是0x30,所以数字加上0x30就能转化成ASCII码了
 mov al,[0x7c00+number+0x00]   ; 取出数字
 add al,0x30                   ; 转化为ASCII码
 mov [es:0x22],al              ; 将字符写入显存,这个写入地址大家看着改哈
 mov byte [es:0x23],0x04       ; 设置字符显示属性

使程序进入无限循环状态

可以用jmp $表示悬停在此行,或者用infi: jmp near infi就一直循环在这里

  • 直接绝对转移: jmp后是一个绝对地址
    例如jmp 0x5000:0xfc0,这会直接设置cs和ip寄存器

  • 相对转移: jmp后是一个标号,是以相对量进行转移
    例如infi: jmp near infi,这里的near关键字是用于指示相对量是16位的
    具体就是用标号(目标位置)处的汇编地址减去当前指令的汇编地址,在减去当前指令的长度,就得到转移的操作数---相对量

    在举个例子好了,以下的指令都是假设的,只是为了方便理解

    汇编地址     标号    汇编指令的机器码
       0        one         0 0 0    ; 3字节
       3        two         1 1 1    ; 3字节,假设这一行是相对的跳转指令
       6        three       2 2 2    ; 3字节
       9        four        3 3 3    ; 3字节
    
    1. 假设标号为two的那行指令是要跳转到标号为four,首先目标汇编地址是9,当前指令的汇编地址是3,当前指令的长度为3字节,相对量=9-3-3=3,也就是说向前移动3个字节就能成功跳转到标号four
    2. 假设标号为two的那行指令是要跳转到标号为one,首先目标汇编地址是0,当前指令的汇编地址是3,当前指令的长度为3字节,相对量=0-3-3=-6,也就是说向后移动6个字节就能成功跳转到标号one

理解了以上后,我们就明白,两个汇编地址A-B相减得到的是包含的字节数(有点类似于[B开头,A开头),数学上的区间),在减去当前指令的长度就能得到汇编地址相差多少字节(相对量,类似于(B结尾,A开头) )

完整源程序

mov ax, 0xb800 			; es指向文本模式的显存缓冲区
mov es, ax

mov byte [es:0x00], 'L'
mov byte [es:0x01], 0x07 ; 黑底白字
mov byte [es:0x02], 'a'
mov byte [es:0x03], 0x07 ; 黑底白字
mov byte [es:0x04], 'b'
mov byte [es:0x05], 0x07 ; 黑底白字
mov byte [es:0x06], 'e'
mov byte [es:0x07], 0x07 ; 黑底白字
mov byte [es:0x08], 'l'
mov byte [es:0x09], 0x07 ; 黑底白字
mov byte [es:0x0a], ' '
mov byte [es:0x0b], 0x07 ; 黑底白字
mov byte [es:0x0c], 'o'
mov byte [es:0x0d], 0x07 ; 黑底白字
mov byte [es:0x0e], 'f'
mov byte [es:0x0f], 0x07 ; 黑底白字
mov byte [es:0x10], 'f'
mov byte [es:0x11], 0x07 ; 黑底白字
mov byte [es:0x12], 's'
mov byte [es:0x13], 0x07 ; 黑底白字
mov byte [es:0x14], 'e'
mov byte [es:0x15], 0x07 ; 黑底白字
mov byte [es:0x16], 't'
mov byte [es:0x17], 0x07 ; 黑底白字
mov byte [es:0x18], ':'
mov byte [es:0x19], 0x07 ; 黑底白字

; ------- 分解数位
mov ax, 12345
mov bx, 10 

mov cx, cs
mov ds, cx ; 因为现在数据和代码都在同一个段内,所以ds和cs相同

mov dx, 0
div bx
mov [0x7c00 + number + 0x00], dl ; ds = 0x0000,number表示的汇编地址是相对于程序加载处0x7c00的,0x00表示第一个数位

xor dx, dx
div bx
mov [0x7c00 + number + 0x01], dl

xor dx, dx
div bx
mov [0x7c00 + number + 0x02], dl

xor dx, dx
div bx
mov [0x7c00 + number + 0x03], dl

xor dx, dx
div bx
mov [0x7c00 + number + 0x04], dl
; ----- 分解数位结束

; ------- 显示数字
 mov al,[0x7c00+number+0x04]
 add al,0x30
 mov [es:0x1a],al
 mov byte [es:0x1b],0x04
 
 mov al,[0x7c00+number+0x03]
 add al,0x30
 mov [es:0x1c],al
 mov byte [es:0x1d],0x04
 
 mov al,[0x7c00+number+0x02]
 add al,0x30
 mov [es:0x1e],al
 mov byte [es:0x1f],0x04

 mov al,[0x7c00+number+0x01]
 add al,0x30
 mov [es:0x20],al
 mov byte [es:0x21],0x04

 mov al,[0x7c00+number+0x00]
 add al,0x30
 mov [es:0x22],al
 mov byte [es:0x23],0x04
 
 mov byte [es:0x24],'D'
 mov byte [es:0x25],0x07
  
infi: jmp near infi
; ------- 显示数字结束

; 数据
number db 0, 0, 0, 0, 0 ; 5字节

times 203 db 0 ; 零填充至510字节
dw 0xaa55 ; 结束标志

标签:number,字节,chapter5,al,扇区,mov,------,byte,es
From: https://www.cnblogs.com/winter-z/p/18337687

相关文章

  • 没有显示屏也能远程控制?ToDesk的虚拟屏做到了!
    如果你习惯多屏办公,但远程控制时受控电脑却只有一个屏幕,或者连屏幕都没有怎么办?如果你想远控家里电脑打游戏,但不想打开显示屏被发现,或是需要远程打开模拟器和visualstudio等软件,但苦于没有显示器怕远控不成功?小社长今天给你安利ToDesk远程控制的虚拟屏功能!只要开启就能让你摆脱......
  • Markdown的使用方法
    Markdown的使用非常简单。以下是一些基本的Markdown语法,可以帮助你开始使用它来格式化文本。标题在文字前面加上#来创建标题。#的数量代表标题的级别。markdown复制#一级标题##二级标题###三级标题####四级标题#####五级标题######六级标题段落与换......
  • ToDesk标注功能和白板有什么区别?手机可以使用吗?
    经常需要远程会议或者远程上课的小伙伴对于白板一定不陌生,它可以提供文档在线演示、编辑、批注等辅助性功能,方便小伙伴在远程会议或上课中进行讲解、展示和教学等。最近小社长发现ToDesk远程控制软件新出了个标注功能,比单独下个白板软件更方便,而且免费版本就能享受,手机电脑都可以......
  • EF Core性能优化技巧
    代码层面的优化1.使用实例池EFCore2.0为DbContext引入新的注册方式:透明地注册了DbContext实例池,使用这种方式可以避免始终创建新的实例,EFCore将重置其状态并将其存储在内部池中;当下次请求新的实例时,将返回该共用实例,而不是设置新的实例使用示例:services.AddDbContext<Han......
  • NewStarCTF WEEK4|WEB PharOne
    首先进入后查看源码进入class.php看见unlike很明显是一个phar反序列化的利用我们有两种选择一一句话木马<?phpclassFlag{public$cmd;}$a=newFlag();$a->cmd="echo\"<?=@eval(\\\$_POST['a']);\">/var/www/html/1.php";$phar=newPhar("......
  • 洛谷-P3869 [TJOI2009] 宝藏
    Abstract传送门本题是状态压缩+记忆化BFS的典型例子。Idea要求从出发点到终点的最短步数,BFS自然是首选的方法,那么,如何构造搜索的每一个节点呢?考虑到机关的数量比较小,最多10种,我们可以考虑用状态压缩去描述机关当前的状态,然后再记录当前的横纵坐标,以及行走的步数即可。值得......
  • js 并发
    functionconcurRequest(maxnum){returnnewPromise((resolve,reject)=>{letindex=0letcount=0constresults=[]asyncfunctionrequest(){consti=indexconsturl=urls[index]......
  • 使用chrome浏览器驱动自动打开浏览器
    查看自己google浏览器的版本下载与之对应的google浏览器驱动将驱动配置到系统的环境变量开始自动化调用importtimefromseleniumimportwebdriver#创建Chrome浏览器驱动driver=webdriver.Chrome()#打开网页url='https://www.zhihu.com/search?type=content......
  • R : 折线图
    #清空工作环境,删除所有对象rm(list=ls())setwd("C:\\Users\\Administrator\\Desktop\\New_microtable\\Co-occurrenceNetwork")#设置工作目录#加载必要的包library(ggplot2)library(reshape2)#创建数据框data<-data.frame(Time=c("DAS28","......
  • 记录一次CentOS/Linux下安装vsftp服务器的过程
    1安装ftp软件yuminstallvsftpd*-y2配置服务启动#启用firewalld服务systemctlstartvsftpd.service#开启vsftpd服务这条命令设置firewalld服务在系统启动时自动启动。systemctlenable命令用于管理系统服务的启动和停止配置。启用服务后,它会在每次系统启动时......