MBR笔记

Wesley13
• 阅读 713

bochs:1 00000000000e[WGUI ] Sim client size(0, 0) != stretched size(640, 480)!

bochs:2 b 0x7c00
bochs:3 c
00000003740i[BIOS ] $Revision: 1.166 $ $Date: 2006/08/11 17:34:12 $
00000319045i[KBD  ] reset-disable command received
00000321693i[PIDE ] new BM-DMA address: 0xc000
00000327577i[P2I  ] PCI IRQ routing: PIRQA# set to 0x0b
00000327593i[P2I  ] write: ELCR2 = 0x08
00000327613i[ACPI ] new irq line = 11
00000446187i[VBIOS] VGABios $Id: vgabios.c,v 1.66 2006/07/10 07:47:51 vruppert Exp $
00000446258i[BXVGA] VBE known Display Interface b0c0
00000446290i[BXVGA] VBE known Display Interface b0c4
00000449215i[VBIOS] VBE Bios $Id: vbe.c,v 1.58 2006/08/19 09:39:43 vruppert Exp $
00000759983i[BIOS ] ata0-0: PCHS=512/4/16 translation=none LCHS=512/4/16
00000800002i[WGUI ] dimension update x=720 y=400 fontheight=16 fontwidth=9 bpp=8
(0) Breakpoint 1, 0x0000000000007c00 in ?? ()
Next at t=957062

;中断与0x7c00   开始MBR程序
;关中断
(0) [0x0000000000007c00] 0000:7c00 (unk. ctxt): cli                       ; fa
bochs:4 n
Next at t=957063
(0) [0x0000000000007c01] 0000:7c01 (unk. ctxt): xor ax, ax                ; 31c0
bochs:5 n
Next at t=957064
;设置段寄存器
(0) [0x0000000000007c03] 0000:7c03 (unk. ctxt): mov ss, ax                ; 8ed0
bochs:6 n
Next at t=957065
;设置栈顶
(0) [0x0000000000007c05] 0000:7c05 (unk. ctxt): mov sp, 0x7c00            ; bc007c
bochs:7 n
Next at t=957066
;开中断
(0) [0x0000000000007c08] 0000:7c08 (unk. ctxt): sti                       ; fb
bochs:8 n
Next at t=957067
;设置数据段寄存器   就是把0x7c0 赋值给数据段寄存器  这里估计是源代码写重复了已经赋值了结果下面还用ax赋值给ds
;源代码中作者果然写重复了
;这里写重复了push和pop以及下面的都是已经把07c0h赋值给ds数据段寄存器了
 push 07c0h
 pop ds
 mov  ax, 07c0h       
 mov  ds, ax
;//////////////////////////////////////////////////分割线////////////////////////////////////

(0) [0x0000000000007c09] 0000:7c09 (unk. ctxt): push 0x07c0               ; 68c007
bochs:9 n
Next at t=957068
(0) [0x0000000000007c0c] 0000:7c0c (unk. ctxt): pop ds                    ; 1f
bochs:10
Next at t=957069
(0) [0x0000000000007c0d] 0000:7c0d (unk. ctxt): mov ax, 0x07c0            ; b8c007
bochs:11 n
Next at t=957070
(0) [0x0000000000007c10] 0000:7c10 (unk. ctxt): mov ds, ax                ; 8ed8
bochs:12 n
Next at t=957071
;加载ntldr 
;count - ntldr扇区总数   80000h/512-8=0x3f8
(0) [0x0000000000007c12] 0000:7c12 (unk. ctxt): push 0x000003f8           ; 6668f8030000
bochs:13 n
Next at t=957072
;src开始读取的扇区号
(0) [0x0000000000007c18] 0000:7c18 (unk. ctxt): push 0x00000008           ; 666808000000
bochs:14 n
Next at t=957073
;des - 存放数据的目的地址(物理内存地址)
(0) [0x0000000000007c1e] 0000:7c1e (unk. ctxt): push 0x00020000           ; 666800000200
bochs:15 n
Next at t=957074
;这里是call  LoadSector(int des,int src,int count);
;用c语言描述:

 void LoadSector(int des,int src,int count)
{
     int run = count / 64; //计算扇区的循环次数 为了提高效率不安扇区127的倍数取,取2的6次方64
     int mod = count % 64; //计算剩余扇区
     for(int i=0,i<run,i++)
     {
          ReadWriteSector(0x80,src,0,64,des,0x42); //每次读取64扇区
          src = src +64; //重写计算扇区
          des = des + 64*512; //重新计算目的地址
     }
     if(mod) //如果纯在剩余扇区,读取一次就ok了
     {
      ReadWriteSector(0x80,src,0,64,des,0x42);
     }
}

(0) [0x0000000000007c24] 0000:7c24 (unk. ctxt): call .+7 (0x00007c2e)     ; e80700
bochs:16 n
Next at t=1171020
;采用fastboot跳转至  0x2000:0003 如果是NTFS boot则跳转至0x2000:0000刚好执行 jmp RealStart 而fatboot则会忽略3B这条指令
(0) [0x0000000000007c27] 0000:7c27 (unk. ctxt): push 0x2000               ; 680020
bochs:17 n
Next at t=1171021
(0) [0x0000000000007c2a] 0000:7c2a (unk. ctxt): push 0x0000               ; 680000
bochs:18 n
Next at t=1171022
(0) [0x0000000000007c2d] 0000:7c2d (unk. ctxt): retf                      ; cb
bochs:19 n
Next at t=1171023
(0) [0x0000000000020000] 2000:0000 (unk. ctxt): jmp .+509 (0x00020200)    ; e9fd01
bochs:20

LoadSector实现:

 void LoadSector(int des,int src,int count)
{
     int run = count / 64; //计算扇区的循环次数 为了提高效率不安扇区127的倍数取,取2的6次方64
     int mod = count % 64; //计算剩余扇区
     for(int i=0,i<run,i++)
     {
          ReadWriteSector(0x80,src,0,64,des,0x42); //每次读取64扇区
          src = src +64; //重写计算扇区
          des = des + 64*512; //重新计算目的地址
     }
     if(mod) //如果纯在剩余扇区,读取一次就ok了
     {
          ReadWriteSector(0x80,src,0,64,des,0x42);
     }
}

LoadSector的nasm源代码:

 void LoadSector(
; int des, 
; int src, 
; int count);
LoadSector:
;{
 push  ebp  
 mov  ebp, esp  ;保存栈框架  这里是0x7c00-4-4-4-2=0x7bf2  进入LoadSector的三次push call LoadSector占2B
 
 sub  esp, 0E4h  ;开辟栈空间0e4h=228
 push  ebx  
 push  esi  
 push  edi  
 
 ;int run = count / 64;
 mov  eax,dword [ebp+0Eh]  ;ebp+0eh为进入函数后的esp+14及最开始的push count
 cdq                 ;扩展edx为eax的高位
 and  edx, 3Fh 
 add  eax, edx 
 sar  eax, 6     ;右移6位及除以64
 mov  dword [ebp-8], eax  ;保存循环次数ebp-8
 
 ;int mod = count % 64;
 mov  eax, dword [ebp+0Eh]  ;读取扇区数 这里就是将参数count的值传入给eax  就是最开始的ebp+14
 and  eax, 8000003Fh   ;实现摸64操作
 jns  .set_mod
 dec  eax  
 or  eax,0FFFFFFC0h 
 inc  eax  
 
.set_mod: 
 mov  dword [ebp-14h], eax  ;将64的余数放到ebp -  14h中  最开始开辟了228B的空间
 ;for(int i=0; i<run; i++)
 mov  dword [ebp-20h], 0  ;i的空间地址设置成为0
 jmp  _read
 
_loop:
 mov  eax,dword [ebp-20h] 
 add  eax,1 
 mov  dword [ebp-20h],eax 
_read:   
    mov  eax,dword [ebp-20h]  ;将i的值给eax和次数比较
 cmp  eax,dword [ebp-8]   ;eax和ebp-8及最开始的count比较
 jge  _left     ;大于等于则跳转 退出循环
 ;{
 ;ReadWriteSector(0x80, src, 0, 64, des, 0x42);
 push  dword 42h
 mov  eax, dword [ebp+6] 
 push  eax  
 push  dword 40h  
 push  dword 0    
 mov  ecx, dword [ebp+0Ah] 
 push  ecx  
 push  dword 80h  
 call  ReadWriteSector
 add  esp, 24
 ;src = src + 64;
 mov  eax, dword [ebp+0Ah] 
 add  eax, 40h 
 mov  dword [ebp+0Ah], eax 
 ;des = des + 64*512;
 mov  eax, dword [ebp+6] 
 add  eax, 8000h 
 mov  dword [ebp+6], eax 
 ;}
 jmp  _loop
 ;if(mod)
_left:
 cmp  dword [ebp-14h],0           
    je  .return
 ;{
  ;ReadWriteSector(0x80, src, 0, mod, des, 0x42);
 push  dword 42h 
 mov  eax, dword [ebp+6] 
 push  eax  
 mov  ecx, dword [ebp-14h] 
 push  ecx  
 push  dword 0    
 mov  edx, dword [ebp+0Ah] 
 push  edx  
 push  dword 80h  
 call  ReadWriteSector
 add  esp, 24
 ;}
;}
.return:   
    pop  edi  
 pop  esi  
 pop  ebx  
 add  esp, 0E4h 
 mov  esp, ebp 
 pop  ebp  
 ret 12

 ReadWriteSector汇编代码
相关的数据结构
;Disk Address Packet
struc DAP                        
 .PacketSize     resb  1     ;数据包的大小,固定为10h
 .Reserved       resb  1     ;预留空间固定为1字节
 .BlockCount     resw  1   ;0~127 要传输的扇区数目
 .BufferOffset   resw  1     ;传输缓冲的偏移地址
 .BufferSegment  resw  1    ;传输缓冲的地址段
 .LBNLow         resd  1   ;0
 .LBNHigh        resd  1  ;
endstruc  
 
struc SectorFrame      
 .DriveNum        resd  1 ;表示读取数据所在的磁盘
 .LBNLow          resd  1 ;要读取数据所在的骑士扇区号
 .LBNHigh         resd  1 ;
 .BlockCount      resd  1 ;一次读取的扇区数
 .Buffer          resd  1    ;所读取数据存放的物理地址
 .ReadWrite       resd  1 ;表示进行什么操作  读还是写
endstruc

 
;NTSTATUS 
;(_cdecl* ReadWriteSector)(
; ULONG DriveNum, 
; ULONG LBNLow, 
; ULONG LBNHigh, 
; ULONG BlockCount, 
; PVOID Buffer, 
; ULONG ReadWrite); // Read=0x42,Write=0x43
 
ReadWriteSector:
    push  bp
    mov  bp, sp
    add  bp, 4
    push  ds
    push  si
    push  bx
 
    push  0
    pop  ds
     
 sub  sp, 16
 mov  si, sp
 mov  byte [si+DAP.PacketSize], 10h        
 mov  byte [si+DAP.Reserved], 0          
 mov  al,byte [bp+SectorFrame.BlockCount]
 mov  byte[si+DAP.BlockCount], al           
 mov  byte[si+DAP.BlockCount+1], 0         
 mov  eax, dword[bp+SectorFrame.Buffer]
    mov  bx, ax
    and  bx, 0fh     
    mov  word[si+DAP.BufferOffset], bx        
    shr  eax, 4
    mov  word[si+DAP.BufferSegment], ax        
    mov  eax, dword[bp+SectorFrame.LBNLow]
    mov  dword[si+DAP.LBNLow], eax            
    mov  eax, dword[bp+SectorFrame.LBNHigh]
    mov  dword[si+DAP.LBNHigh], eax           
    mov  ah, byte [bp+SectorFrame.ReadWrite]                                          
    mov  dl, byte [bp+SectorFrame.DriveNum]          
    int  13h
    jc   .error
    xor  eax, eax
.error:
    and  eax, 0000ffffh
            
 add  sp, 16
 pop  bx
 pop  si
 pop  ds
 
 pop  bp
 retn
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java爬虫之JSoup使用教程
title:Java爬虫之JSoup使用教程date:201812248:00:000800update:201812248:00:000800author:mecover:https://imgblog.csdnimg.cn/20181224144920712(https://www.oschin
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这