#2
zhulei19782016-08-06 09:35
程序代码: LFMP5: add ebx, edx ;ebx->压缩的VCN前个字节 add ebx, ecx ;ebx->LCN最字节 movsx edx, byte ptr [ebx] dec ecx dec ebx LFMP10: cmp ecx, 00000000 je LFMP20 shl edx, 08h mov dl, byte ptr [ebx] dec ebx dec ecx jmp LFMP10 LFMP20: mov ecx, edx pop edx pop ebx ret LcnFromMappingPair endp ;******************************************************** ;LoadIndexFrs: 根据索引类型代码定位并装入相应的FRS ;入口: eax=索引类型代码 ecx->要装入的FRS缓冲 ;出口: eax->在FRS缓冲的偏移(为0失败) LoadIndexFrs proc push ecx push eax mov eax, 00000005h ;设置为根目录索引代码 push ds pop es mov edi, ecx ;es:edi装入的缓冲 call ReadFrs mov eax, ecx ;搜索到FRS pop ebx push ebx movzx ecx, index_name_length ;属性名长度 mov dx, offset index_name ;mov edx,offset index_name call LocateAttributeRecord pop ebx pop ecx or eax, eax jne LoadIndexFrs$Exit ;如果在目录找到,返回. ; 如果在当前FRS没有找到,则搜索属性列表. mov eax, ecx mov ecx, ebx push eax push ebx call SearchAttrList pop ebx pop edi or eax, eax je LoadIndexFrs$Exit push ds pop es call ReadFrs mov eax, edi movzx ecx, index_name_length mov dx, offset index_name ;mov edx,offset index_name call LocateAttributeRecord LoadIndexFrs$Exit: ret LoadIndexFrs endp ;******************************************************************************** ;LocateAttributeRecord: 查找一个属性在记录在一个FRS ;入口: eax->FRS ebx=属性代码 ; ecx=属性名长度 edx->属性名 ;出口: eax->属性记录(0表示未找到) LocateAttributeRecord proc add ax, word ptr [eax+14h] ;eax->下一个属性记录 lar10: cmp dword ptr [eax], 0FFFFFFFFh ;属性记录结束 je lar99 cmp dword ptr [eax], ebx jne lar80 ;比较属性代码 or ecx, ecx ;属性名长度不为0时 jne lar20 cmp byte ptr [eax+09h], 00 ;比较属性名长度 jne lar80 ret lar20: cmp cl, byte ptr [eax+09h] jne lar80 mov esi, eax add si, word ptr [eax+0Ah] ;esi->属性名保存缓冲 call UpcaseName push ecx push ds pop es mov edi, edx repz cmpsw ;比较属性名 pop ecx jne lar80 ret lar80: ; 到下一个属性记录 cmp dword ptr [eax+04h], 00000000 je lar99 ;属性记录为0退出 add eax, dword ptr [eax+04h] ;eax->下一个属性记录 jmp lar10 ;继续查找 lar99: ; 未找到,失败返回 sub eax, eax ret LocateAttributeRecord endp ;******************************************************************** ;LocateIndexEntry: 在一个文件名索引查找一个索引入口 ;入口: eax->索引头 ebx->要查找文件名 ecx=文件名长度 ;出口: eax->索引入口(为0失败) LocateIndexEntry proc mov esi, ebx call UpcaseName add eax, dword ptr [eax] ;eax->第一个索引入口 lie10: test word ptr [eax+0Ch], 0002h ;索引入口结束 jne lie99 lea edx, dword ptr [eax+10h] ;edx -> FILE_NAME属性值 cmp cl, byte ptr [edx+40h] ;比较文件名长度 jne lie80 lea esi, dword ptr [edx+42h] ;esi->文件名缓冲 call UpcaseName push ecx push ds pop es mov edi, ebx repz cmpsw ;比较文件名 pop ecx jne lie80 ret lie80: cmp word ptr [eax+08h], 0000 ;入口长度为0退出 je lie99 add ax, word ptr [eax+08h] ;eax->下一个入口 jmp lie10 ;继续查找 lie99: ; 没找到失败返回 xor eax, eax ret LocateIndexEntry endp ;************************************************* ;MultiSectorFixup: 修正读磁盘结构..... ;入口: es:edi=缓冲 MultiSectorFixup proc push es push ds pushad movzx ebx, word ptr es:[edi+04h];ebx=更新偏移 movzx ecx, word ptr es:[edi+06h];ecx=更新偏移 or ecx, ecx je ErrorExit add ebx, edi add ebx, 00000002h add edi, 000001feh ;SEQUENCE_NUMBER_STRIDE - 2 dec ecx MSF10: or ecx, ecx je MSF30 mov ax, word ptr es:[ebx] mov word ptr es:[edi], ax add ebx, 00000002h add edi, 00000200h ;SEQUENCE_NUMBER_STRIDE dec ecx jmp MSF10 MSF30: popad pop ds pop es ret MultiSectorFixup endp ;************************************************************* ;ReadClusters: 在磁盘读一个运行簇 ;入口: eax=要读的LCN edx=要读的簇 es:edi->缓冲 ;注意: 真正要读的开始扇区LBA)=SectorBase+HiddenSectors ReadClusters proc push es push ds pushad mov ebx, edx movzx ecx, SectorsPerCluster mul ecx ;转换LCN到扇区编号 mov SectorBase, eax ;保存扇区编号(LBA) mov eax, ebx mul ecx mov SectorCount,ax ;要读的扇区数 ; 将es:edi参数转换成调用int13h时的es:ebx mov ebx,edi call DoRead ;调用磁盘读 popad pop ds pop es ret ReadClusters endp ;************************************************** ;ReadFrs: 读一个FRS ;入口: eax=FRS号 es:edi=缓冲 ReadFrs proc push es push ds pushad mul SectorsPerFrs ;eax=在MFT数据属性的扇区号 mov ecx, SectorsPerFrs call ReadMftSectors call MultiSectorFixup popad pop ds pop es ret ReadFrs endp ;******************************************************************* ;ReadIndexBlock: 在根目录读一个索引块 ;入口: eax=块号 ReadIndexBlock proc push es push ds pushad mul SectorsPerIndexBlock ;eax=要读的第一个VBN mov ebx, IndexAllocation ;ebx->$INDEX_ALLOCATION属性 mov ecx, SectorsPerIndexBlock ;ecx=要读的扇区 push ds pop es mov edi, IndexBlockBuffer ;es:edi->索引块缓冲 call ReadIndexBlockSectors call MultiSectorFixup popad pop ds pop es ret ReadIndexBlock endp ;********************************************************************** ;ReadIndexBlockSectors: 读扇区来自一个索引分配属性 ;入口: eax=要读的开始VBN ; ebx->属性 ; ecx=要读的扇区数 ; es:edi=缓冲 ;注意: 真正要读的开始扇区LBA)=SectorBase+HiddenSectors ReadIndexBlockSectors proc push es push ds pushad cmp byte ptr [ebx+08h], 01h ;.ATTR_FormCode, NONRESIDENT_FORM je ReadIBS_10 ; 这是个常驻属性 jmp ErrorExit ReadIBS_10: cmp ecx, 00000000 jne ReadIBS_20 ; 没有要读的,返回. popad pop ds pop es ret ReadIBS_20: push ebx push eax ;当前VBN push ecx push edi push es ; VBN转换到VCN:用VBN除以每簇扇区数 余数X ; VCN转换到LCN:通过属性里面的映射 ; LCN转换到LBN:用LCN乘以每簇扇区数 加上X ; VBN除以每簇扇区数,余数表示其余扇区在簇里 push ecx ;保存剩余扇区数 xor edx, edx movzx ecx, SectorsPerCluster;ecx=每簇扇区数 div ecx ;eax=VCN push edx ;保存余数 call ComputeLcn ;获取VCN的LCN.返回eax=LCN ecx=剩余簇 movzx ebx, SectorsPerCluster mul ebx ;eax=LBN簇 pop edx add eax, edx push eax ;保存我们的LBN movzx eax, SectorsPerCluster mul ecx ;eax=在扇区的剩余运行长度 mov edx, eax ;剩余运行长度 pop eax ;eax=LBN pop ecx ;要读的剩余扇区 pop es pop edi pop ecx cmp ecx, edx jnl ReadIBS_30 ; 运行长度高于剩余的.只读剩余 mov edx, ecx ReadIBS_30: mov SectorBase,eax mov SectorCount,dx ; 将es:edi参数转换成调用int13h时的es:ebx push ebx mov ebx,edi call DoRead pop ebx sub ecx, edx ;修正要读的剩余扇区 mov ebx, edx mov eax, edx movzx edx, BytesPerSector mul edx add edi, eax ;修正缓冲以备下一个读的扇区 pop eax add eax, ebx ;修正要读的VBN pop ebx jmp ReadIBS_10 ReadIndexBlockSectors endp ;*********************************************** ;ReadMftSectors: 读扇区来自MFT ;入口: eax=开始VBN ecx=要读的扇区数 ; es:edi=缓冲区 ReadMftSectors proc push es push ds pushad RMS$Again: push eax ;保存开始VBN push ecx xor edx, edx ; VBN除以SectorsPerCluster得到VCN movzx ebx, SectorsPerCluster div ebx ;eax=VCN push edx ;保存剩余的 push edi call ComputeMftLcn ;eax=LCN pop edi or eax, eax ;LCN=0 je ErrorExit movzx ebx, SectorsPerCluster mul ebx ;eax=开始LBN簇 pop edx ;edx=剩余扇区 add eax, edx ;eax=LBN mov SectorBase,eax pop ecx ;要读的扇区数 movzx ebx, SectorsPerCluster cmp ecx, ebx jle RMS10 mov SectorCount,bx ;这时读一个簇 sub ecx, ebx ;ecx=要读的剩余扇区数 pop eax ;eax=VBN add eax, ebx ;VBN+=要读的扇区数 push eax ;保存下一个VBN push ecx ;剩余扇区数 jmp RMS20 RMS10: pop eax ;eax=VBN add eax, ecx ;VBN += sectors this read push eax mov SectorCount,cx mov ecx, 00000000 push ecx ;保存剩余的 RMS20: ; 将es:edi参数转换成调用int13h时的es:ebx mov ebx,edi call DoRead add edi, BytesPerCluster pop ecx pop eax cmp ecx, 00000000 jg RMS$Again popad pop ds pop es ret ReadMftSectors endp ;**************************************************************** ;ComputeMftLcn: 算出MFT一个簇的LCN ;入口: eax=VCN ;出口: eax=LCN(0,失败)注意:与调试的win2k版本代码不同 ComputeMftLcn proc mov edx, eax mov ecx, SegmentsInMft ;ecx=要搜索的文件记录号(FRS) mov eax, MftFrs ;eax->要搜索的第一个FRS MftLcn10: push edx push eax push ecx push edx mov ebx, 00000080h ;$DATA mov ecx, 00000000 mov edx, ecx call LocateAttributeRecord ; eax->$DATA属性 or eax, eax je ErrorExit ;这个文件记录里没有$DATA属性 mov ebx, eax ;ebx->属性 pop eax ;eax=VCN call ComputeLcn or eax, eax je MftLcn20 ; 找到我们的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 |
EMAIL:cheng_5104@
作者:成松林
程序代码:
.386p
CSEG SEGMENT USE16
ASSUME CS:CSEG,DS:CSEG,ES:CSEG
START PROC
CodeStart:
;************************************************************************
;主引导程序第一个扇区:
;完成将代码拷贝到2000:0处,接着转到该处继续执行.......
BOOTCodeSector1 proc
org 0 ;第一个扇区开始于0
cli
xor ax,ax
mov ss,ax ;设置新堆栈0:2000h
mov sp,2000h
sti
push cs
pop ds ;ds=cs
mov ax,2000h
mov es,ax ;es=2000h
mov si,offset CodeStart ;ds:si->CodeStart
xor di,di ;es:di->新缓冲区
; 注意:拷贝代码长度2000h=16*512,这是因为Ntldr加载多扇区启动时.
; 要求的最小度为16个扇区长度,小于16个扇区时只加载1个扇区..
mov cx,2000h ;不用计算代码长度..
cld ;我们代码没这么长...
repz movsb ;把代码拷贝到2000:0处
push es
push offset BOOTCode10 - offset CodeStart
retf ;转到BOOTStart处执行
;***************************************************************************
;完成在NTFS卷下查找文件ghost.img(这是个可启动的软盘镜像文件)找到加载启动它..
BOOTCode10:
jmp BOOTCode20
file_name_length dw 9
file_name dw 'G', 'H', 'O', 'S', 'T','.','I','M','G'
filenamebuffer db 256 dup (0)
BOOTCode20:
push cs
pop ds
call NTFSMain ;安装NTFS参数等
movzx ecx, file_name_length
mov ax, offset file_name
call FindFile ;查找文件
or eax, eax
je BOOTCode99 ;没找到文件退出
mov ebp,0 ;获取开始LBA
call GetFileDATAorLBA ;eax=开始LBA
or eax, eax
je BOOTCode99 ;失败退出
mov ebp,eax ;ebp=开始LBA
call HardDiskImageVirtualFloppy
xor ax,ax
mov es,ax
mov bx,7c00h
mov ax,0201h
mov cx,1
mov dx,0
int 13h
push es
push 7c00h
retf ;启动可启动软盘镜像
BOOTCode99:
int 18h ;出错退出
org 1ffh ;第一个扇区结束于1ffh
BOOTCodeSector1 endp
;***************************************************************
;引导程序第二个扇区:无条件转到第一个扇区开始处执行.....
;注意:Ntldr加载长于一个扇区时:要求1:全长代码不小于2000h(也就是
; 16个扇区长),要求2:必须定义第二个扇区,而且第二个扇区的开始处
; 代码要无条件转到第一个扇区开始处执行.分析得来!没具体资料...
BOOTCodeSector2 proc
org 200h ;第二个扇区开始于200h
jmp BOOTCodeSector1
org 3ffh ;第二个扇区结束于3ffh
BOOTCodeSector2 endp
;****************************************************************
;注意:其他代码从这里开始,Ntldr要求所有代度长度最低要占用16个扇区.
; 我们这里不足尾部填0.达到Ntldr要求长度....
org 400h
;******************************************************************************
;******************************************************************************
;******************************************************************************
;NTFSDOSAPI: NTFS文件操作DOS系统调用接口!
;入口: eax=要调用的API号 以及相应API参数
;出口: eax=零严重错误返回 以及相应API返回
NTFSDOSAPI proc
;push cs
;pop ds
;jmp FoundNTFSAPI
;*******************************************************************
;可以把NTFS封装成公共接口.安装成中断调用也可以..定义子函数入口偏移
NTFSAPIStart:
dw offset NTFSMain
dw offset FindFile
dw offset ReadFrs
;*********************************************************************
;杂乱的定义.注意:默认操作的是C盘.....
index_name dw '$', 'I', '3', '0'
index_name_length dw 4
DriveNumber db 80h ;默认操作的是C盘
SectorBase dd ? ;操作扇区开始LBA
SectorCount dw ? ;操作的扇区数
NtfsSP dw ? ;保存堆栈
NtfsRET dw ? ;保存返回偏移
NtfsCS dw ? ;保存返回段值
NTFSFlags dw ? ;保存标志寄存器
;*******************************************************
;NTFS分区BPB这里需要的参数,以及计算机出来的参数...
BytesPerSector dw ? ;每扇区字节数
SectorsPerCluster db ? ;每簇扇区数
HiddenSectors dd ? ;隐藏扇区数
MftStartLcn dd ? ;MFT开始LCN
ClustersPerFrs dd ? ;每文件记录簇数
BytesPerCluster dd ? ;每簇字节数
BytesPerFrs dd ? ;每文件记录段字节数
SectorsPerFrs dd ? ;每文件记录段扇区数
BytesPerIndexBlock dd ? ;在根索引每索引块字节数
ClustersPerIndexBlock dd ? ;在根索引每索引块簇数
SectorsPerIndexBlock dd ? ;在根索引每索引块扇区数
;********************************************************
;NTFS初始化要用的文件记录文件等缓冲及地址
AttrList dd 0e000h;属性链表缓冲首址
MftFrs dd 03000h;第一个MFT文件记录首址
SegmentsInMft dd ? ;文件记录号在MFT数据属性记录
RootIndexFrs dd ? ;根索引文件记录地址
AllocationIndexFrs dd ? ;分配索引文件记录地址
BitmapIndexFrs dd ? ;位图索引文件记录地址
IndexRoot dd ? ;根索引$INDEX_ROOT属性地址
IndexAllocation dd ? ;根索引$INDEX_ALLOCATION属性地址
IndexBitmap dd ? ;根索引$BITMAP属性地址
FileFrs dd ? ;要查找的文件的文件记录地址
IndexBlockBuffer dd ? ;当前索引缓冲区地址
IndexBitmapBuffer dd ? ;索引位图缓冲区地址
NextBuffer dd ? ;在缓冲区的下一个空闲缓冲区
;数据定义结束.
;***************************************************************
;***************************************************************
;Main: 获取设置NTFS常用的参数,安装NTFS要用到的文件记录...
; 如:每簇扇区数,每文件记录扇区数,,如:根目录索引记录.
NTFSMain proc
push ds
pushad
push cs
pop ds
mov ax,0201h
mov ebx,MftFrs
mov cx,1
mov dh,01
mov dl,DriveNumber
int 13h ;读NTFS引导记录(LBA:3fh)
cmp dword ptr [bx+3],5346544eh ;是NTFS?
jnz ErrorExit
; 获取NTFS资料.......
mov ax,[bx+0bh]
mov BytesPerSector,ax
mov al,[bx+0dh]
mov SectorsPerCluster,al
mov eax,[bx+1ch]
mov HiddenSectors,eax
mov eax,[bx+30h]
mov MftStartLcn,eax
mov eax,[bx+40h]
mov ClustersPerFrs,eax
movzx eax, BytesPerSector ;eax=每扇区字节数
movzx ebx, SectorsPerCluster ;ebx=每簇扇区数
mul ebx
mov BytesPerCluster,eax ;eax=每簇字节数
mov ecx, ClustersPerFrs
cmp cl, 00
jg NTFSMain1
neg cl
mov eax, 00000001
shl eax, cl ;eax=每FRS字节数
jmp NTFSMain2
NTFSMain1:
mov eax, BytesPerCluster
mul ecx ;eax=每FRS字节数
NTFSMain2:
mov BytesPerFrs,eax
movzx ebx,BytesPerSector
xor edx, edx
div ebx
mov SectorsPerFrs,eax
call SetupMft
; 下面是加载各个属性
mov ecx, NextBuffer
mov RootIndexFrs, ecx
add ecx, BytesPerFrs
mov AllocationIndexFrs,ecx
add ecx, BytesPerFrs
mov BitmapIndexFrs,ecx
add ecx, BytesPerFrs
mov FileFrs, ecx
add ecx,BytesPerFrs
mov IndexBlockBuffer,ecx
mov eax, 00000090h ;$INDEX_ROOT
mov ecx, AllocationIndexFrs
call LoadIndexFrs
or eax, eax
je ErrorExit
mov IndexRoot,eax
mov eax, 000000A0h ;$INDEX_ALLOCATION
mov ecx, AllocationIndexFrs
call LoadIndexFrs
mov IndexAllocation, eax
mov eax, 000000B0h ;$BITMAP
mov ecx, BitmapIndexFrs
call LoadIndexFrs
mov IndexBitmap,eax
mov eax,IndexRoot
or eax, eax
je ErrorExit
cmp byte ptr [eax+08h], 00
jne ErrorExit
; eax -> $INDEX_ROOT 属性记录
lea edx, dword ptr [eax+10h] ;edx->常驻信息
add ax, word ptr [edx+04h] ;eax -> value of $INDEX_ROOT
movzx ecx, byte ptr [eax+0Ch]
mov ClustersPerIndexBlock,ecx
mov ecx, dword ptr [eax+08h]
mov BytesPerIndexBlock,ecx
mov eax, BytesPerIndexBlock
movzx ecx, BytesPerSector
xor edx, edx
div ecx
mov SectorsPerIndexBlock,eax
mov eax, IndexBlockBuffer
add eax, BytesPerIndexBlock
mov IndexBitmapBuffer,eax
cmp IndexAllocation,00000000
je NTFSMain30
cmp IndexBitmap,00000000
je ErrorExit
mov ebx, IndexBitmap
push ds
pop es
mov edi, IndexBitmapBuffer
call ReadWholeAttribute
NTFSMain30:
popad
pop ds
ret
;********************************************
; 所有NTFS严重错误都无条件转到这里处理.
ErrorExit:
int 18h
NTFSMain endp
;******************************************************************************
;GetFileDATAorLBA :根据文件记录索引入口获取在硬盘的位置(LBA)及数据
;入口: eax=文件记录索引入口ebp=0获取位置非0获取数据es:edi=缓冲区
;出口: eax=文件开始LBA(0表示失败) es:edi=文件数据
GetFileDATAorLBA proc
pushad
push es
push edi
; 读文件记录的DATA属性
; eax -> 文件记录索引入口
mov eax, dword ptr [eax] ;.IE_FileReference.REF_LowPart
push cs
pop es
mov edi, FileFrs ;es:edi=缓冲
call ReadFrs
mov eax, FileFrs
mov ebx, 00000080h ;$DATA
mov ecx, 00000000 ;属性名长度
mov edx, 00000000 ;属性名
call LocateAttributeRecord
; eax -> $DATA 文件属性
or eax, eax
jz GetFileDATAorLBA99
movzx ebx, word ptr [eax+0Ch];.ATTR_Flags
and ebx, 000000FFh ;是不是压缩了的
jnz GetFileDATAorLBA99
mov ebx, eax
; 获取开始
cmp ebp,0 ;是获取位置还是获取数据
jnz GetFileDATA
; 获取文件开始LBA
cmp byte ptr [ebx+08h], 00 ;常驻属性
jne GetFileLBA
jmp GetFileDATAorLBA99 ;文件在文件记录里可以返回在内存位置
GetFileLBA:
lea edx, dword ptr [ebx+10h] ;edx->非常驻属性信息
mov ecx, dword ptr [edx+08h] ;ecx = HighestVcn
inc ecx ;ecx=在属性的簇
sub eax, eax ;eax=开始VCN
call ComputeLcn ;eax=开始LCN
movzx ecx, SectorsPerCluster
mul ecx ;转换LCN到扇区编号
mov SectorBase, eax ;保存扇区编号(LBA)
mov SectorCount,1
pop edi
pop es
popad
mov eax,SectorBase
add eax,HiddenSectors ;文件开始LBA
ret
; 获取文件数据
GetFileDATA:
mov ebx, eax
pop edi
pop es
call ReadWholeAttribute ;读数据到es:edi
popad
ret
GetFileDATAorLBA99:
pop edi
pop es
popad
xor eax,eax
ret
GetFileDATAorLBA endp
;*****************************************************************************
;ComputeLcn: 转换VCN到LCN
;入口: eax->VCN ebx->属性
;出口: eax->LCN(为0没找到) ecx->剩余运行长度
ComputeLcn proc
cmp byte ptr [ebx+08h], 01 ;比较属性值,要是非常驻属性
je clcn10
sub eax, eax ;这是个常驻属性
ret
clcn10:
lea esi, dword ptr [ebx+10h] ;esi->非常驻属性信息
mov edx, dword ptr [esi+08h] ;edx = HighestVcn
cmp eax, edx
ja clcn15 ;VCN是HighestVcn
mov edx, dword ptr [esi] ;edx = LowestVcn
cmp eax, edx
jnb clcn20
clcn15:
sub eax, eax ;VCN 不在属性里
ret
clcn20:
add bx, word ptr [esi+10h] ;ebx -> 映射
sub esi, esi
clcn30:
; ebx -> Current mapping pair count byte
; edx == Current VCN
; esi == Current LCN
cmp byte ptr [ebx], 00
je clcn99
call LcnFromMappingPair
add esi, ecx ;esi = 当前映射LCN
call VcnFromMappingPair
add ecx, edx ;ecx=下一个VCN
cmp eax, ecx ;如果小于下一个VCN...
jl clcn80 ;... 我们找到正确的映射.
mov edx, ecx ;当前VCN = 下一个VCN
push eax
movzx ecx, byte ptr [ebx] ;ecx = 字节数
mov eax, ecx
and eax, 0000000Fh ;eax = VCN字节数
shr ecx, 04h
add ebx, ecx ;ecx = LCN字节数
add ebx, eax
inc ebx ;ebx -> 下一个字节数
pop eax
jmp clcn30
clcn80:
; 找到我们要映射的值
sub ecx, eax ;ecx=剩余运行长度
sub eax, edx
add eax, esi ;eax=LCN
ret
clcn99:
; VCN没有在这个属性里
sub eax, eax ;没找到
ret
ComputeLcn endp
;************************************************************************************
;Findfile: 在根目录;下查找一个文件的索引入口
;入口: eax->要查找的文件名称 ecx=文件名长度
;出口: eax->文件索引入口 NULL表示查找失败
FindFile proc
push eax
push ecx
; 开始, 搜索根目录
mov edx, eax
mov eax, IndexRoot ;eax ->INDEX_ROOT属性
lea ebx, dword ptr [eax+10h] ;ebx -> 常驻属性
add ax, word ptr [ebx+04h] ;eax -> Index Root value
lea eax, dword ptr [eax+10h] ;eax -> Index Header
mov ebx, edx
call LocateIndexEntry
or eax, eax
je FindFile20 ;没找到
; 在根目录找到,结果保存在eax,清除堆栈返回
pop ecx
pop ecx
ret
FindFile20:
; 在根目录没找到,接着在索引分配的缓冲区里查找.
mov eax, IndexAllocation
or eax, eax
jne FindFile30
; 若没有索引分配属性,清除堆并失败返回.
pop ecx
pop ecx
xor eax, eax
ret
FindFile30:
; 搜索索引分配块,搜索这个B+树.........注意:算法.
mov edx, IndexAllocation ;edx->分配索引属性
lea edx, dword ptr [edx+10h] ;edx->非常属性
mov eax, dword ptr [edx+08h] ;eax = HighestVcn
inc eax ;eax = 簇在属性
mov ebx, BytesPerCluster
mul ebx ;字节在属性
xor edx, edx
div BytesPerIndexBlock ;转换为索引块
push eax
FindFile40:
; 搜索剩余的索引块
pop eax ;剩余索引块
or eax, eax
je FindFile90
dec eax ;下一个索引块
push eax
call IsBlockInUse
jb FindFile40
call ReadIndexBlock
pop edx ;搜索剩余缓冲
pop ecx ;edx=文件名长度
pop ebx ;ebx->文件名
push ebx
push ecx
push edx
; 索引缓冲搜索是在索引分配缓冲块
mov eax, IndexBlockBuffer ;eax->索引分配块
lea eax, dword ptr [eax+18h] ;eax->索引头
call LocateIndexEntry ;eax->找到入口
or eax, eax
je FindFile40
; 找到清除堆栈,返回.
pop ecx
pop ecx
pop ecx
ret
FindFile90:
; 文件没找到,失败回.
pop ecx
pop ecx
xor eax,eax
ret
FindFile endp
;******************************************************************************************
;IsBlockInUse: 索引分配块用来检查索引位图.
;入口: eax=块号
IsBlockInUse proc
push eax
push ebx
push ecx
mov ebx, IndexBitmapBuffer
mov ecx, eax
shr eax, 03h ;eax=字节号
and ecx, 00000007h ;ecx=在字节的位号
add ebx, eax ;ebx -> byte to test
mov eax, 00000001h
shl eax, cl ;eax=mask
test byte ptr [ebx], al
je IBU10
clc ;Block is not in use.
jmp IBU20
IBU10:
stc ; Block is in use.
IBU20:
pop ecx
pop ebx
pop eax
ret
IsBlockInUse endp
;*********************************************************************
;LcnFromMappingPair:
;入口: ebx->映射字节数
;出口: ecx->LCN来自映射
LcnFromMappingPair proc
push ebx
push edx
sub edx, edx
mov dl, byte ptr [ebx] ;edx = count byte
and edx, 0000000Fh ;edi = v
sub ecx, ecx
mov cl, byte ptr [ebx]
shr cl, 04h ;ecx = l
cmp ecx, 00000000
jne LFMP5
sub ecx, ecx
pop edx
pop ebx
ret