📄 用ntldr加载进dos.txt
字号:
; 找到我们的LCN,清除堆栈返回.
pop ebx
pop ebx
pop ebx
ret
MftLcn20:
; 在这个文件记录里不能找到VCN,在下一个....
pop ecx ;ecx=剩余文件记录号....当前...
pop eax ;eax->当前FRS
pop edx ;edx=VCN
add eax,BytesPerFrs ;eax->下一个文件记录
loop MftLcn10
; 没找到
xor eax, eax
ret
ComputeMftLcn endp
;*********************************************************
;ReadNonresidentAttribute:读来自非常驻属性的簇
;入口: eax=要读的开始VCN
; ebx=属性
; ecx=要读的簇数
; es:edi=缓冲
ReadNonresidentAttribute proc
push es
push ds
pushad
cmp byte ptr [ebx+08h], 01h
je ReadNR10 ;是非常驻属性
jmp ErrorExit
ReadNR10:
cmp ecx, 00000000
jne ReadNR20
; 没有要读的簇号.返回.
popad
pop ds
pop es
ret
ReadNR20:
push ebx
push eax ;当前VCN
push ecx
push edi
push es
call ComputeLcn ;eax=要读的LCN,ecx=运行长度
mov edx, ecx ;edx=剩余的长度
pop es
pop edi
pop ecx
cmp ecx, edx
jnl ReadNR30
mov edx, ecx ;运行长度高于剩余的.只读剩余的
ReadNR30:
call ReadClusters
sub ecx, edx ;减去剩余的簇
mov ebx, edx
mov eax, edx ;eax=剩余的簇
movzx edx, SectorsPerCluster
mul edx
movzx edx, BytesPerSector
mul edx ;eax=要读的字节
add edi, eax ;修改缓冲以备读下一个
pop eax
add eax, ebx ;修改要的VCN
pop ebx ;ebx=属性
jmp ReadNR10
ReadNonresidentAttribute endp
;************************************************************
;ReadWholeAttribute: 读一个属性列表
;入口: ebx->属性 es:edi=缓冲
ReadWholeAttribute proc
cmp byte ptr [ebx+08h], 00 ;常驻属性
jne rwa10
push es
push ds
pushad
lea edx, dword ptr [ebx+10h] ;edx->常驻属性信息
mov ecx, dword ptr [edx] ;ecx = bytes in value
mov esi, ebx ;esi->属性
add si, word ptr [edx+04h] ;esi->属性值
repz movsb
popad
pop ds
pop es
ret
rwa10:
; 这是个非常驻属性调用ReadNonresidentAttribute VCN0
lea edx, dword ptr [ebx+10h];edx->非常驻属性信息
mov ecx, dword ptr [edx+08h];ecx = HighestVcn
inc ecx ;ecx=在属性的簇
sub eax, eax ;eax=开始VCN
call ReadNonresidentAttribute
ret
ReadWholeAttribute endp
;*********************************************************
;SearchAttrList: 搜索FRS属性链表,........
;入口: ecx=类型代码 eax=FRS头
;出口: eax=FRN文件记录号(0为失败)
SearchAttrList proc
push ecx
mov ebx, 00000020h ;$ATTRIBUTE_LIST
mov ecx, 00000000 ;属性名长度
mov edx, 00000000 ;属性名
call LocateAttributeRecord
or eax, eax
je SearchAttrList$NotFoundIndex1
; 读属性链表.eax->属性链表属性
mov ebx, eax
push ds
pop es
mov edi, AttrList ;ds:edi->属性链表缓冲
call ReadWholeAttribute
push ds
pop es
mov ebx, AttrList ;es:ebx->开始属性链表入口
pop ecx
SearchAttrList$LookingForIndex:
cmp es:[bx], ecx ;.ATTRLIST_TypeCode
je SearchAttrList$FoundIndex
cmp dword ptr es:[bx], 0FFFFFFFFh
je SearchAttrList$NotFoundIndex2
cmp word ptr es:[bx+04h], 0000
je SearchAttrList$NotFoundIndex2
movzx eax, word ptr es:[bx+04h]
add bx, ax
mov ax, bx
and ax, 8000h
je SearchAttrList$LookingForIndex
; 下一个32k段.....
mov ax, es
add ax, 0800h
mov es, ax
and bx, 7FFFh
jmp SearchAttrList$LookingForIndex
SearchAttrList$FoundIndex:
; 找到索引,返回FRN
mov eax, es:[bx+10h]
ret
SearchAttrList$NotFoundIndex1:
pop ecx
SearchAttrList$NotFoundIndex2:
xor eax, eax
ret
SearchAttrList endp
;*****************************************************
;UpcaseName: 转换所有名字为大写
;入口: esi->名字 ecx->名字长度
UpcaseName proc
or ecx, ecx
jne UN5
ret
UN5:
push ecx
push esi
UN10:
cmp word ptr [esi], 0061h;如果它小于'a'
jl UN20
cmp word ptr [esi], 007Ah;如果高于'z'
jg UN20
sub word ptr [esi], 0020h;转换小写字符
UN20:
add esi, 00000002h ;移到下一个unicode字符
loop UN10
pop esi
pop ecx
ret
UpcaseName endp
;**********************************************************
;VcnFromMappingPair:
;入口: ebx->映射字节
;出口: ecx->VCN来自映射
VcnFromMappingPair proc
sub ecx, ecx
mov cl, byte ptr [ebx] ;ecx=字节数
and cl, 0Fh ;ecx=v
cmp ecx, 00000000
jne VFMP5
sub ecx, ecx
ret
VFMP5:
push ebx
push edx
add ebx, ecx ;ebx->压缩的vcn前个字节
movsx edx, byte ptr [ebx]
dec ecx
dec ebx
VFMP10:
cmp ecx, 00000000
je VFMP20
shl edx, 08h
mov dl, byte ptr [ebx]
dec ebx
dec ecx
jmp VFMP10
VFMP20:
mov ecx, edx
pop edx
pop ebx
ret
VcnFromMappingPair endp
;****************************************************************
;SetupMft: 读MFT文件记录段(MFT FRS)到内存
SetupMft proc
push es
push ds
pushad
mov eax, 00000001
mov SegmentsInMft,eax
mov eax, MftFrs
add eax, BytesPerFrs
mov NextBuffer,eax
; 读FRS 0 到第一个MFT FRS缓冲,请务必解决更新序列列阵
mov eax, MftStartLcn
movzx ebx, SectorsPerCluster
mul ebx ;eax= MFT开始扇区
mov SectorBase,eax
mov eax, SectorsPerFrs
mov SectorCount,ax
mov ebx, MftFrs
push ds
pop es
call DoRead
movzx edi, bx ;es:edi = 缓冲
call MultiSectorFixup
; 确定是否MFT有一个属性链表属性
mov eax, MftFrs
mov ebx, 00000020h ;$ATTRIBUTE_LIST
mov ecx, 00000000
mov edx, 00000000
call LocateAttributeRecord
or eax, eax
je SetupMft99 ;没有属性链表,完成安装
; 读属性链表,eax->属性链表属性
mov ebx, eax
push ds
pop es
mov edi, AttrList ;ds:edi->属性链表缓冲
call ReadWholeAttribute
mov ebx, AttrList ;第一个属性链入口
; 现在搜索属性链$DATA属性.ebx->属性链表入口.
SetupMft10:
cmp dword ptr [bx], 00000080h ;.ATTRLIST_TypeCode, $DATA
je SetupMft20
add bx, [bx+04h] ;.ATTRLIST_Length
jmp SetupMft10
SetupMft20:
;......................
cmp dword ptr [bx], 00000080h
je SetupMft99
push ebx
mov eax, [ebx+10h] ;***.ATTRLIST_SegmentReference.REF_LowPart
mov edi, NextBuffer
push ds
pop es
call ReadFrs
pop ebx
; 调整NextBuffer and SegmentsInMft以备下一个属性.....
mov eax, BytesPerFrs
add NextBuffer, eax
inc SegmentsInMft
; 到下一个属性链表入口
add bx, [ebx+04h] ;***.ATTRLIST_Length
jmp SetupMft20
SetupMft99:
popad
pop ds
pop es
ret
SetupMft endp
;*******************************************************************************
;DoRead: 从SectorBase开始的LBA扇区,读SectorCount个扇区到ES:EBX处.使用扩展
; int13h操作一次最多读(1000h-BytesPerSector)/BytesPerSector个扇区.
; 物理地址=段地址*16+偏移,段地址=物理地址/16,偏移=物理地址 MOD 16
; 注意:要求设置的缓冲区地址低4位为零.以下只用了段地址=物理地址/16.
DoRead proc
push ds
pushad
push cs
pop ds
mov si,offset DAP ;ds:si=缓冲区首址
mov eax,SectorBase
add eax,HiddenSectors
mov [si+8],eax ;设置操作开始LBA
xor eax,eax
mov ax,es ;eax=段地址
shl eax,4 ;eax=eax*10h
add eax,ebx ;eax=缓冲区物理地址
mov bx,SectorCount
DR10:
push eax ;保存当前物理地址
shr eax,4 ;eax=段地址
mov word ptr [si+4],0 ;设置缓冲区偏移
mov [si+6],ax ;设置缓冲区段址
mov eax,10000h ;eax=64KB,edx(0~10000h)
movzx ecx,BytesPerSector ;一个扇区字节.
sub eax,ecx ;防止操作到段边界处.
mov edi,eax ;edi=该段分块
xor edx,edx
div ecx ;64KB段:一次最多扇区数.
cmp ax,bx ;实际操作扇区数按64K段分.
jg DR20
mov [si+2],ax
mov ah,42h
mov dl,DriveNumber
int 13h
; 处理到下一个读缓冲区,把SectorCount*BytesPerSector.
; 按64kb-BytesPerSector进行分块读.防止int13边界出错.
pop eax ;eax=当前物理地址
add eax,edi ;eax=下一个64k分块
sub bx,[si+2] ;bx=剩余扇区数
movzx ecx,word ptr [si+2]
add [si+8],ecx ;下一个64kB分块开始LBA
jmp DR10
DR20:
pop eax
mov [si+2],bx
mov ah,42h
mov dl,DriveNumber
int 13h
; 读完成退出.
popad
pop ds
ret
dap db 10h,00,14 dup(0) ;定义扩展读要用的参数.
DoRead endp
;****************************************************************************
;********************************************************************
;HardDiskImageVirtualFloppy: 将硬盘的软盘镜像文件.虚拟成A盘.
;入口: ebp=软盘镜像文件在硬盘的开始LBA
HardDiskImageVirtualFloppy proc
jmp Install ;跳到安装程序
;BiosInt13h服务程序....
INT13Handler:
cmp dl,0 ;不是读软盘?
jz FloppyR
jmp dword ptr cs:[200h]
FloppyR:
pushad
push ds
cmp ah,42h ;是LBA方式读
jz LBARead
cmp ah,02 ;是CHS方式读
jnz Exit
push cs
pop ds
mov si,210h ;ds:si->磁盘数据包
mov [si+2],al ;要读的扇区数
mov [si+4],bx ;缓冲区偏移值
mov [si+6],es ;缓冲区段地址
mov [si+8],cl
and dword ptr [si+8],3fh ;要读的扇区号
dec byte ptr [si+8] ;S-1
mov ax,cs:[18h] ;PS每磁道扇区数
mul dh ;dh要读的磁头号
add [si+8],ax ;+H*PS
xchg ch,cl
shr ch,6 ;cx要读的磁道号
mov ax,cs:[18h] ;PS每磁道扇区数
mul cx ;C*PS
mov bx,cs:[1ah] ;磁头数
mul bx ;PH每柱面磁道数
add [si+8],ax ;+C*PH*PS
LBARead:
mov eax,cs:[204h] ;镜像文件开始扇区编号
add [si+8],eax ;得到读软盘在硬盘LBA
mov ah,42h ;用扩展int13读硬盘
mov dl,80h ;读硬盘(C)镜像文件
Exit:
pushf
call dword ptr cs:[200h]
pop ds
popad
iret
;*****************************************************
;安装硬盘的软盘镜像文件,虚拟成A盘的int13h服务程序
Install:
push es
push ds
pushad
cli ;有些操作要求关中断.
; 分配高端内存以便我们的int13h服务程序驻留..
xor ax,ax
mov ds,ax
mov ax,ds:[413h]
dec ax
mov ds:[413h],ax ;ax=可用内存(单位KB)
shl eax,0ah ;eax=eax*1024
shr eax,4 ;eax=eax/16
;*************************************************
; 将我们的int13h服务将程序复制到分配的内存
mov es,ax ;es:0->分配高端内存
push cs
pop ds
mov di,230h ;es:di->我们的int13h程序
mov si,offset INT13Handler
mov cx,offset Install-offset INT13Handler
cld
repz movsb
; 读取软盘镜像第一个扇区到此,以取得BPB
mov si,offset HDIVFdap
mov [si+6],es ;es:0
mov [si+8],ebp ;镜像文件开始LBA
mov ah,42h
mov dl,DriveNumber
int 13h
; 设置参数int13服务程序要的参数及..
xor ax,ax
mov ds,ax
mov eax,ds:[4ch] ;保存旧的int13h服务程序
mov es:[200h],eax ;es:200h旧的int13h服务程序
mov es:[204h],ebp ;es:200h镜像文件开始LBA
mov word ptr es:[210h],10h ;es:210h->扩展int13h参数包
mov ds:[4ch],230h
mov ds:[4eh],es ;设置int13h为我们的程序
;*******************************************************
sti ;最后开中断
popad
pop ds
pop es
ret
HDIVFdap db 10h,00,01,00,00,00,10 dup(0)
HardDiskImageVirtualFloppy endp
;***************************************************************************
NTFSDOSAPI endp
;********************************************************************************
;********************************************************************************
org 2000h ;所有的代码结束最小长度2000h
;********************************************************************************
CodeEnd:
Start ENDP
CSEG ENDS
END Start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -