| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3722 人关注过本帖
标题:[转帖]win2k下NTFS分区用ntldr加载进dos源代码
只看楼主 加入收藏
zhulei1978
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:53
帖 子:1351
专家分:1200
注 册:2006-12-17
结帖率:100%
收藏
 问题点数:0 回复次数:4 
[转帖]win2k下NTFS分区用ntldr加载进dos源代码
QQ:179641795
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
搜索更多相关主题的帖子: 源代码 
2016-08-06 09:34
zhulei1978
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:53
帖 子:1351
专家分:1200
注 册:2006-12-17
收藏
得分:0 
程序代码:
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

其实我就是改变社会风气,提高少女素质,刺激电影市道,提高年轻人内涵,玉树临风,风度翩翩的整蛊专家,我名叫古晶,英文名叫JingKoo!
2016-08-06 09:35
zhulei1978
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:53
帖 子:1351
专家分:1200
注 册:2006-12-17
收藏
得分:0 
程序代码:
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


其实我就是改变社会风气,提高少女素质,刺激电影市道,提高年轻人内涵,玉树临风,风度翩翩的整蛊专家,我名叫古晶,英文名叫JingKoo!
2016-08-06 09:35
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
约略看了一下,第1扇区的功能是虚拟一个driveA,再读入(若有)ghost.img,并把控制权交到ghost.img的boot区
似乎并未发现读入ntldr的代码,不过把ghost.img改为ntldr,修改一些程序,也是通用的...
另外,程式只针对NTFS,若是普通的fat32(比如usb的一般格式),程式反而会退出,其实就是重启..
2016-08-07 07:40
zhulei1978
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:53
帖 子:1351
专家分:1200
注 册:2006-12-17
收藏
得分:0 
好象没有读入ntldr的代码

其实我就是改变社会风气,提高少女素质,刺激电影市道,提高年轻人内涵,玉树临风,风度翩翩的整蛊专家,我名叫古晶,英文名叫JingKoo!
2016-08-07 10:57
快速回复:[转帖]win2k下NTFS分区用ntldr加载进dos源代码
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.055756 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved