本文最后更新于 406 天前,其中的信息可能已经有所发展或是发生改变。
内容目录
0x01 Memcpy
1.1 code
Memcpy函数完成并测试
org 0x7c00 jmp short start nop define: BaseOfStack equ 0x7c00 BaseOfLoader equ 0x9000 RootEntryOffset equ 19 RootEntryLength equ 14 EntryItemLength equ 32 FatEntryOffset equ 1 FatEntryLength equ 9 header: BS_OEMName db "D.T.Soft" BPB_BytsPerSec dw 512 BPB_SecPerClus db 1 BPB_RsvdSecCnt dw 1 BPB_NumFATs db 2 BPB_RootEntCnt dw 224 BPB_TotSec16 dw 2880 BPB_Media db 0xF0 BPB_FATSz16 dw 9 BPB_SecPerTrk dw 18 BPB_NumHeads dw 2 BPB_HiddSec dd 0 BPB_TotSec32 dd 0 BS_DrvNum db 0 BS_Reserved1 db 0 BS_BootSig db 0x29 BS_VolID dd 0 BS_VolLab db "D.T.OS-0.01" BS_FileSysType db "FAT12 " start: mov ax, cs mov ss, ax mov ds, ax mov es, ax mov sp, BaseOfStack mov ax, RootEntryOffset mov cx, RootEntryLength mov bx, Buf call ReadSector mov si, Target mov cx, TarLen mov dx, 0 call FindEntry cmp dx, 0 jz output ;test MemCpy 内存没有重叠 ;mov si, Target ;mov di, Buf ;mov cx, TarLen ;call MemCpy ;test MemCpy 内存重叠 si < di 把源内存的内容向后移动两个字节,打印顺序etob ;mov si, Target ;mov di, si ;add di, 2 ;mov cx, TarLen ;call MemCpy ;test MemCpy 内存重叠 si > di,打印顺序btoe mov si, Target mov di, si sub di, 2 mov cx, TarLen call MemCpy output: ;mov bp, Buf ;打印内存没有重叠 ;mov cx, TarLen ;mov bp, Target ;打印内存重叠si < di ;add bp, 2 ;改进:Target向后偏移两个字节的地方开始打印,去掉开头部分的打印 ;mov cx, TarLen mov bp, MsgStr ;打印内存重叠si > di mov cx, MsgLen ; "LOADER "拷贝到"No LOADER ..."时,由于sub di, 2操作,拷贝的目标地址是从"No LOADER ..."最后两个".."开始的 call Print last: hlt jmp last ; ds:si --> source ; es:di --> destination ; cx --> length MemCpy: push si push di push cx push ax cmp si, di ;比较源内存和目标内存的大小关系 ja btoe add si, cx add di, cx dec si dec di jmp etob btoe: cmp cx, 0 jz done mov al, [si] mov byte [di], al inc si inc di dec cx jmp btoe etob: cmp cx, 0 jz done mov al, [si] mov byte [di], al dec si dec di dec cx jmp etob done: pop ax pop cx pop di pop si ret ; es:bx --> root entry offset address ; ds:si --> target string ; cx --> target length ; ; return: ; (dx !=0 ) ? exist : noexist ; exist --> bx is the target entry FindEntry: push di push bp push cx mov dx, [BPB_RootEntCnt] mov bp, sp find: cmp dx, 0 jz noexist mov di, bx mov cx, [bp] call MemCmp cmp cx, 0 jz exist add bx, 32 dec dx jmp find exist: noexist: pop cx pop bp pop di ret ; ds:si --> source ; es:di --> destination ; cx --> length ; ; return: ; (cx == 0) ? equal : noequal MemCmp: push si push di push ax compare: cmp cx, 0 jz equal mov al, [si] cmp al, byte [di] jz goon jmp noequal goon: inc si inc di dec cx jmp compare equal: noequal: pop ax pop di pop si ret ; es:bp --> string address ; cx --> string length Print: mov dx, 0 ;把字符串打印都按屏幕的左上角 ////////////////////////////// mov ax, 0x1301 mov bx, 0x0007 int 0x10 ret ; no parameter ResetFloppy: push ax push dx mov ah, 0x00 mov dl, [BS_DrvNum] int 0x13 pop dx pop ax ret ; ax --> logic sector number ; cx --> number of sector ; es:bx --> target address ReadSector: push bx push cx push dx push ax call ResetFloppy push bx push cx mov bl, [BPB_SecPerTrk] div bl mov cl, ah add cl, 1 mov ch, al shr ch, 1 mov dh, al and dh, 1 mov dl, [BS_DrvNum] pop ax pop bx mov ah, 0x02 read: int 0x13 jc read pop ax pop dx pop cx pop bx ret MsgStr db "No LOADER ..." MsgLen equ ($-MsgStr) Target db "LOADER " TarLen equ ($-Target) EntryItem times EntryItemLength db 0x00 Buf: times 510-($-$$) db 0x00 db 0x55, 0xaa
1.2 验证结果
;test MemCpy 内存没有重叠 正常情况
测试2:
纠正:红色框中注释部分修改为 si < di
纠正:红色框中注释部分修改为 si < di
测试3:
因为是从后向前拷贝,最前面两个肯定是被拷贝到相邻的空间里去了,打印一下相邻的空间看下
0x02 FatVec
备注: 这个验证和验证结果不太理解,有待补充
2.1 code
org 0x7c00 jmp short start nop define: BaseOfStack equ 0x7c00 BaseOfLoader equ 0x9000 ;最后要把目标程序加载到这个地址处,fat表加载到这个地址的前面 RootEntryOffset equ 19 RootEntryLength equ 14 EntryItemLength equ 32 FatEntryOffset equ 1 FatEntryLength equ 9 header: BS_OEMName db "D.T.Soft" BPB_BytsPerSec dw 512 BPB_SecPerClus db 1 BPB_RsvdSecCnt dw 1 BPB_NumFATs db 2 BPB_RootEntCnt dw 224 BPB_TotSec16 dw 2880 BPB_Media db 0xF0 BPB_FATSz16 dw 9 BPB_SecPerTrk dw 18 BPB_NumHeads dw 2 BPB_HiddSec dd 0 BPB_TotSec32 dd 0 BS_DrvNum db 0 BS_Reserved1 db 0 BS_BootSig db 0x29 BS_VolID dd 0 BS_VolLab db "D.T.OS-0.01" BS_FileSysType db "FAT12 " start: mov ax, cs mov ss, ax mov ds, ax mov es, ax mov sp, BaseOfStack mov ax, RootEntryOffset mov cx, RootEntryLength mov bx, Buf call ReadSector mov si, Target mov cx, TarLen mov dx, 0 call FindEntry cmp dx, 0 jz output ;---------------------------------------------------- ;########备份第一个目录项######## mov si, bx ;对应目录项的起始地址 mov di, EntryItem ;在拷贝之后,EntryItem是目录项入口地址 mov cx, EntryItemLength call MemCpy ;########加载fat表,计算fat表占用的内存######## mov ax, FatEntryLength ;扇区长度 mov cx, [BPB_BytsPerSec];每个扇区的大小 mul cx ;ax中就保存了fat表占用的内存 mov bx, BaseOfLoader ;0x9000 -> fat表加载到0x9000地址的前面 sub bx, ax ;减去fat表在内存中占的字节数,bx中存放的是fat表起始位置 mov ax, FatEntryOffset mov cx, FatEntryLength ; ax --> logic sector number ; cx --> number of sector ; es:bx --> target address call ReadSector ;fat表就在内存当中了 ;########查表 cx对应的表项######## mov cx, [EntryItem + 0x1A] ;cx表示起始簇的值,0x1A是 DIR_FstClus目标项的偏移位置 ; cx --> index ; bx --> fat table address 在内存当中的起始位置(基址) call FatVec ;---------------------------------------------------- jmp last output: mov bp, MsgStr mov cx, MsgLen call Print last: hlt jmp last ; cx --> index ; bx --> fat table address 在内存当中的起始位置(基址) ; ; return: ; dx --> fat[index] fat表项的值 FatVec: mov ax, cx mov cl, 2 div cl ; 判断是奇数还是偶数,进入不同的关系式处理流程,商al 余数ah push ax ;商合余数入栈 ; i = j / 2 * 3 mov ah, 0 ;index/2之后取正数,把这个余数置为0 mov cx, 3 mul cx mov cx, ax ;cx保存对应的表项在内存中的起始位置:i = index/2*3 pop ax cmp ah, 0 jz even jmp odd even: ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i]; mov dx, cx ;Fat[i]中i add dx, 1 ;Fat[i+1]中的i+1 add dx, bx ;计算真正的 Fat[i+1] 的地址,为什么真正的地址这么计算? mov bp, dx mov dl, byte [bp] ;拿到Fat[i+1]的值 and dl, 0x0F shl dx, 8 add cx, bx ; cx是表项在内存当中的起始字节数,加上bx就是内存地址 mov bp, cx ; or dl, byte [bp] ;结果存在dl中,也就是dx的低八位 jmp return odd: ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F ); mov dx, cx add dx, 2 add dx, bx mov bp, dx mov dl, byte [bp] mov dh, 0 ; 高8位清空,右移位可以保存值 shl dx, 4 add cx, 1 add cx, bx mov bp, cx mov cl, byte [bp] shr cl, 4 and cl, 0x0F mov ch, 0 ; 高8位清空,右移位可以保存值 or dx, cx return: ret ; ds:si --> source ; es:di --> destination ; cx --> length MemCpy: push si push di push cx push ax cmp si, di ja btoe add si, cx add di, cx dec si dec di jmp etob btoe: cmp cx, 0 jz done mov al, [si] mov byte [di], al inc si inc di dec cx jmp btoe etob: cmp cx, 0 jz done mov al, [si] mov byte [di], al dec si dec di dec cx jmp etob done: pop ax pop cx pop di pop si ret ; es:bx --> root entry offset address ; ds:si --> target string ; cx --> target length ; ; return: ; (dx !=0 ) ? exist : noexist ; exist --> bx is the target entry FindEntry: push di push bp push cx mov dx, [BPB_RootEntCnt] mov bp, sp find: cmp dx, 0 jz noexist mov di, bx mov cx, [bp] call MemCmp cmp cx, 0 jz exist add bx, 32 dec dx jmp find exist: noexist: pop cx pop bp pop di ret ; ds:si --> source ; es:di --> destination ; cx --> length ; ; return: ; (cx == 0) ? equal : noequal MemCmp: push si push di push ax compare: cmp cx, 0 jz equal mov al, [si] cmp al, byte [di] jz goon jmp noequal goon: inc si inc di dec cx jmp compare equal: noequal: pop ax pop di pop si ret ; es:bp --> string address ; cx --> string length Print: mov dx, 0 mov ax, 0x1301 mov bx, 0x0007 int 0x10 ret ; no parameter ResetFloppy: push ax push dx mov ah, 0x00 mov dl, [BS_DrvNum] int 0x13 pop dx pop ax ret ; ax --> logic sector number ; cx --> number of sector ; es:bx --> target address ReadSector: push bx push cx push dx push ax call ResetFloppy push bx push cx mov bl, [BPB_SecPerTrk] div bl mov cl, ah add cl, 1 mov ch, al shr ch, 1 mov dh, al and dh, 1 mov dl, [BS_DrvNum] pop ax pop bx mov ah, 0x02 read: int 0x13 jc read pop ax pop dx pop cx pop bx ret MsgStr db "No LOADER ..." MsgLen equ ($-MsgStr) Target db "LOADER " TarLen equ ($-Target) EntryItem times EntryItemLength db 0x00 Buf: times 510-($-$$) db 0x00 db 0x55, 0xaa
2.2 验证结果
读取一下img文件,加载LOADER文件文件
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QString img = "/home/delphi/OS/Fat12Test/data.img"; Fat12Header f12; qDebug() << "Read Header:"; PrintHeader(f12, img); qDebug() << endl; qDebug() << "Print Root Entry:"; PrintRootEntry(f12, img); qDebug() << endl; qDebug() << "Print File Content:"; QString content = QString(ReadFileContent(f12, img, "LOADER")); qDebug() << content; return a.exec(); }
读取到的j为4,表示起始簇号为4,并且只使用一个扇区来保存文件的内容,
for(int i=0, j=re.DIR_FstClus; j<0xFF7; i+=512, j=vec[j])
vec[j]获取表项值的时候,得到了一个非法的值,和j<0xFF7不符 ???
打断点 看寄存器的值
调用FatVec函数前后值的变化