NTFS是Windows NT以及之后的Windows 2000、Windows XP、Windows Server 2003、Windows Server 2008、Windows Vista和Windows 7的标准文件系统。NTFS取代了文件分配表(FAT)文件系统,为Microsoft的Windows系列操作系统提供文件系统。NTFS对FAT和HPFS(高性能文件系统)作了若干改进,例如,支持元数据,并且使用了高级数据结构,以便于改善性能、可靠性和磁盘空间利用率,并提供了若干附加扩展功能,如访问控制列表(ACL)和文件系统日志。该文件系统的详细定义属于商业秘密 ,但 Microsoft 已经将其注册为 知识产权产品。
NTFS 提供长文件名、数据保护和恢复,并通过目录和文件许可实现安全性。NTFS 支持大硬盘和在多个硬盘上存储文件(称为卷)。例如,一个大公司的数据库可能大得必须跨越不同的硬盘。NTFS 提供内置安全性特征,它控制文件的隶属关系和访问。从DOS或其他操作系统上不能直接访问 NTFS 分区上的文件。如果要在DOS下读写NTFS分区文件的话可以借助第三方软件;现如今,Linux系统上已可以使用 NTFS-3G进行对 NTFS 分区的完美读写,不必担心数据丢失。
Win 2000采用了更新版本的NTFS文件系统NTFS 5.0,它的推出使得用户不但可以像Win 9X那样方便快捷地操作和管理计算机,同时也可享受到NTFS所带来的系统安全性。 NTFS 允许文件名的长度可达 256 个字符。虽然 DOS 用户不能访问 NTFS 分区,但是 NTFS 文件可以拷贝到 DOS 分区。每个 NTFS 文件包含一个可被 DOS 文件名格式认可的 DOS 可读文件名。这个文件名是 NTFS 从长文件名的开始字符中产生的。
我们来实现在VC++下面实现读取MBR。 C++内联汇编 在C++代码中插入__asm {}即可
我们亲自来分析实现NTFS文件恢复。
[cpp] view plaincopy
- ;******************************************************
- .386
- .model flat, stdcall
- option casemap :none
- ;******************************************************
- ; Include 文件定义
- ;******************************************************
- include \masm32\include\windows.inc
- include \masm32\include\user32.inc
- includelib \masm32\lib\user32.lib
- include \masm32\include\kernel32.inc
- includelib \masm32\lib\kernel32.lib
- ;*******************************************************
- ; Equ 等值定义
- ;*******************************************************
- ICO_MAIN equ 1000h ;图标ID
- DLG_MAIN equ 1 ;对话框ID
- IDC_PARTITION equ 101h ;盘符名输入框ID
- IDC_FILENAME equ 102h ;文件名ID
- ;*******************************************************
- ; 数据段
- ;*******************************************************
- .data
- hFile_Disk dd 0 ;磁盘文件号
- hFile dd 0 ;文件号
- FileName db '\\.\' ;打开文件名为\\.\X:形式的文件则打开了X分区
- PARTITION db 3 dup (0) ;请注意FileName和等待用户输入的PARTITION共
- ;同组成了要打开的文件名(分区)
- FILENAMEA db 25 dup (0) ;等待用户输入的字符缓存
- FILENAMEU db 50 dup (0) ;转换成Unicode字符串的缓存
- ErrCap db '失败',00 ;错误对话框的Caption
- ErrorInfo1 db '可能的原因是:',0dh
- db '1.该程序不能在除NT以外的系统中执行;',0dh
- db '2.您输入的盘符无效!',00h
- ErrorInfo2 db '读盘错误!',00
- ErrorInfo3 db '该程序只能恢复NTFS文件系统中的数据!',0dh
- db '您打开的磁盘不是NTFS文件系统!',00h
- ErrorInfo4 db '移动文件指针错误!',00h
- Info1 db '请在当前文件夹下查看已恢复的文件!如果文件扩展名不对,请自行',0dh
- db '修改扩展名,如果没有文件,则说明您输入的文件没有找到!',00h
- Recoveried dd 30h ;用来存放已经恢复的文件个数0~z
- _0 db 00 ;字符串结束
- Readed dd 0
- System_Id db 'NTFS' ;DBR中NTFS卷的标志
- MFT_Flag db 'FILE' ;MFT的标志
- StateFindFile dd 0 ;该数据是FindFile过程的返回值
- StringLength dd 0 ;该地址用于存放用户输入的文件名的输入长度
- MFTTime dd 1024
- Temp db 'Text',00
- EdiOffset dd 0 ;
- IndicEdi dd 0 ;用来在比较字符串中存放Edi所指向的字符串的指针
- FileNameOffset dd 0 ;用来存放文件名偏移
- FileSize dd 0 ;用来存放常驻80H属性的文件大小
- FileSize1 dq 0 ;用来存放系统分配给非常驻80H属性的大小
- FileSize2 dq 0 ;用来存放非常驻80H属性的文件真实大小
- Edi80 dd 0 ;用来保存非常驻80H属性的运行列表偏移
- CInfo1 db 0 ;用来保存运行列表的第一个字节的低4位
- CInfo2 db 0 ;用来保存运行列表的第一个字节的高4位
- ResidentFlag dd 0ffh ;80H属性常驻与非常驻标志,为0表示常驻,为1表示非常驻
- ByeofOneC dd 0 ;每簇字节数
- RunC dd 0 ;运行相对起始簇号
- RunC2 dd 0 ;运行绝对起始簇号
- RunByte dd 0 ;运行字节数
- RunCN dd 0 ;运行起始簇号
- RunFirstAddr dq 0 ;运行起始偏移字节
- ;__________________________________________________________________
- .data?
- hInstance dd ?
- DBR db 512 dup (?) ;512字节作为DBR的缓冲
- MFTFirstSector dd ? ;MFT首扇区存放的缓冲
- MFTFirstOffset dd 2 dup (?)
- Filling db 8 dup (?) ;这个是没有用的数据,只是为了让后面的MFT在
- ;程序执行时起始偏移在XXXXXXX0上,方便调试
- MFT db 1024*1024 dup (?);1M作为MFT的缓冲
- DataBuffer db 1024*1024 dup (?);1M字节做为文件数据缓冲
- FileNameLong dd ?
- FileNameBuffer dw 260 dup (?)
- ;*******************************************************
- ; 代码段
- ;*******************************************************
- .code
- ;*******************************************************
- _ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam
- mov eax,wMsg
- .if eax == WM_CLOSE ;如果消息为WM_CLOSE,当按下右上角的关闭按钮
- invoke EndDialog,hWnd,NULL ;hWnd为对话框窗口句柄,结束对话框
- ret
- .elseif eax == WM_INITDIALOG ;初始化代码
- invoke GetDlgItem,hWnd,IDOK ;取IDOK句柄
- invoke EnableWindow,eax,FALSE ;IDOK显示为灰色(确定按钮)
- invoke LoadIcon,hInstance,ICO_MAIN ;设置标题栏图标
- invoke SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
- .elseif eax == WM_COMMAND
- mov eax,wParam
- ;_____________________________________________________________________
- .if ax == IDCANCEL ;如果用户点击“取消”按钮
- invoke EndDialog,hWnd,NULL ;关闭对话框
- mov eax,TRUE
- ret
- .elseif ax== IDOK ;如果用户点击“确定”按钮
- invoke CreateFileA,offset FileName,\ ;打开用户输入的盘符
- GENERIC_READ OR GENERIC_WRITE,\
- FILE_SHARE_READ OR FILE_SHARE_WRITE,\
- NULL,OPEN_EXISTING,NULL,NULL
- mov [hFile_Disk],eax ;保存该分区的文件号
- cmp eax,INVALID_HANDLE_VALUE ;判断其是否成功(为-1失败)
- jz _98CODE ;失败则转
- invoke ReadFile,[hFile_Disk],\
- offset DBR,512,\
- offset Readed,NULL
- cmp eax,0
- jz ReadFail
- mov edx,dword ptr [DBR+3] ;将该分区的分区标志送edx
- mov ebx,dword ptr System_Id
- cmp edx,ebx ;是NTFS分区吗?
- jnz P_Err ;不是则转
- CALL FirstMFTOffset ;定位MFT的起始偏移
- invoke SetFilePointer,[hFile_Disk],\
- dword ptr [MFTFirstOffset],\ ;移动文件指针的低32位
- offset MFTFirstOffset+4,\ ;移动文件指针的高32位
- FILE_BEGIN ;从文件(分区)开始处计算
- cmp eax,-1
- jz MoveFail
- ReadMFT:
- mov dword ptr [MFTTime],1024 ;用于计算指针是否指到了内存中的MFT尾
- invoke ReadFile,[hFile_Disk],\ ;读1兆MFT
- offset MFT,1024*1024,\
- offset Readed,NULL
- add dword ptr [MFTFirstOffset],1024*1024 ;保存当前磁盘指针
- adc dword ptr [MFTFirstOffset+4],0
- cmp eax,0
- jz ReadFail
-
- mov edi,offset MFT
- CallFindFile:
- call FindFile ;查找符合用户输入的已经删除的文件
- ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
- .if [StateFindFile]==0 ;FindFile过程返回状态数据[StateFindFile]为0
- ;表示所有的MFT都找完了
- invoke MessageBoxA,NULL,offset Info1,offset Temp,MB_OK
- ret
- ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
-
- .elseif [StateFindFile]==1 ;FindFile过程返回状态数据[StateFindFile]为1
- ;表示该文件未被删除或这不是用户要恢复的文件
- ReadToo:
- dec dword ptr [MFTTime]
- cmp dword ptr [MFTTime],0
- jz ReadMFT ;结果为0则表示要读下1兆MFT了
- add edi,1024 ;edi向后1K,指向下一个MFT
- jmp CallFindFile ;继续查找符合用户输入的已经删除的文件
- ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
- .elseif [StateFindFile]==2 ;FindFile过程返回状态数据[StateFindFile]为2
- ;表示这是一个用户要恢复的文件(文件名包含用户输入)
- call ReadData ;这个过程将要恢复文件的数据读入内存中
- ;创建要恢复的文件,文件名为原来的文件名
- ;______________________________________________________
- .if dword ptr [ResidentFlag]==0 ;如果为常驻属性
- invoke CreateFileW,offset FileNameBuffer,\ ;创建要恢复的文件
- GENERIC_READ OR GENERIC_WRITE,\ ;为读和写打开
- 0,NULL,\ ;不允许文件再被打开
- CREATE_NEW,\ ;创建新文件,如果文件已经存在则返回失败代码
- NULL,NULL
-
-
- mov [hFile],eax ;保存文件号
- invoke WriteFile,[hFile],\ ;写文件
- offset DataBuffer,[FileSize],\
- offset Readed,NULL
- invoke CloseHandle,[hFile] ;关闭文件
- jmp ReadToo ;继续找是否还有包含用户输入的文件
- ;_____________________________________________________
- .elseif dword ptr [ResidentFlag]==1 ;如果为非常驻属性
- mov dword ptr [RunC2],0 ;绝对起始簇号清零
- jmp ReadToo
- ;invoke MessageBoxA,NULL,offset ErrorInfo1,offset Temp,MB_OK
- .endif
- ;_______________________________________________________
- ret
- .endif
- ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
-
-
-
-
- _98CODE:
- invoke MessageBoxA,NULL,offset ErrorInfo1,offset ErrCap,MB_OK
- mov eax,TRUE
- ret
- ReadFail:
- invoke CloseHandle,[hFile_Disk] ;关闭文件(关闭分区)
- invoke MessageBoxA,NULL,offset ErrorInfo2,offset ErrCap,MB_OK
- mov eax,TRUE
- ret
- P_Err:
- invoke CloseHandle,[hFile_Disk] ;关闭文件(关闭分区)
- invoke MessageBoxA,NULL,offset ErrorInfo3,offset ErrCap,MB_OK
- mov eax,TRUE
- ret
- MoveFail:
- invoke CloseHandle,[hFile_Disk] ;关闭文件(关闭分区)
- invoke MessageBoxA,NULL,offset ErrorInfo4,offset ErrCap,MB_OK
- mov eax,TRUE
- ret
- ;_____________________________________________________________________
- .elseif ax == IDC_PARTITION ;如果用户在盘符文本框中输入
- invoke SendDlgItemMessage,hWnd,\ ;限制文本输入为2个字符
- IDC_PARTITION,EM_LIMITTEXT,2,NULL
- invoke GetDlgItemText,hWnd,IDC_PARTITION,\
- addr PARTITION,sizeof PARTITION ;取用户输入文本到PARTITION处
- invoke GetDlgItem,hWnd,IDOK ;取IDOK句柄(确定按钮)
- invoke EnableWindow,eax,TRUE ;置确定按钮为可用
- mov eax,TRUE
- ret
- ;_____________________________________________________________________
- .elseif ax == IDC_FILENAME ;如果用在文件名文本框中输入
- invoke SendDlgItemMessage,hWnd,\ ;限制文本输入为24个字符
- IDC_FILENAME,EM_LIMITTEXT,24,NULL
- invoke GetDlgItemText,hWnd,IDC_FILENAME,\ ;取用户输入到FILENAMEA处
- addr FILENAMEA,sizeof FILENAMEA
- call CompString ;计算用户输入的字符的长度,并保存在StringLength处
- ;将ANSI字符串转换为Unicode字符串
- invoke MultiByteToWideChar,1,0,addr FILENAMEA,\ ;AUSI地址FILENAMEA首地址
- -1,addr FILENAMEU,\ ;-1为自动大小(为0结束)
- sizeof FILENAMEU ;转换到FILENAMEU,大小为FILENAMEU的大小
- mov edi,offset FILENAMEU
- call ToCaps ;将FILENAMEU中的Unicode字符串中的小写字母转换为大写
- mov eax,TRUE
- ret
- .endif
- ;_____________________________________________________________________
- .else
- mov eax,FALSE
- ret
- .endif
- mov eax,TRUE
- ret
- _ProcDlgMain endp
- ;*******************************************************
- ;该过程用于计算用户输入的文件名的长度(Unicode的长度),并保存在StringLength处
- CompString proc
- mov eax,00h
- mov edi,offset FILENAMEU
- CmpString:
- cmp byte ptr [edi],00 ;字符串是否结束
- jz ExitProc
- inc eax
- inc edi
- inc edi
- jmp CmpString
- ExitProc:
- mov [StringLength],eax
- ret
- CompString endp
- ;*******************************************************
- ;小写的Unicode字母转大写
- ToCaps proc
- Char:
- mov bx,word ptr [edi] ;将字符串中的一个字送BX
- .while bx>=61h && bx<=7ah ;这个字是UNICODE小写字母么,是则执行循环体
- sub bx,20h ;将其转变为大小的Unicode字符
- mov word ptr [edi],bx ;再将这个转变后的字符送回字符串中
- inc edi ;指针加2
- inc edi
- mov bx,word ptr [edi] ;继续将下一个字符串中的一个字送BX
- .break .if bx==00h ;如果是00则表示已经到了字符串尾,则退出循环
- .endw
- cmp bx,00 ;bx为0表示已经到了字符串的尾部
- jz Okchar ;到了字符串的尾部转返回处
- inc edi ;指针加2(因为是Unicode字符)
- inc edi
- jnz Char ;不是小写Unicode字母则跳过这个字符继续做下一个字符的判断
- Okchar:
- ret
- ToCaps endp
- ;*******************************************************
- ;计算$MFT起始偏移,并存放在MFTFirstOffset
- FirstMFTOffset proc
- mov edi,offset DBR
- mov eax,dword ptr [edi+30h] ;MFT起始簇号送eax
- mov cl,[edi+0dh]
- movzx ebx,cl ;每簇扇区数送ebx
- mul ebx ;MFT起始簇号*每簇扇区数=MFT起始扇区号,高位保存在edx中
- ;低位保存在eax中
- mov edi,offset MFTFirstSector
- mov [edi],eax ;将MFT起始扇区号保存
- mov ebx,512 ;每扇区字节数送ebx
- mul ebx ;每扇区字节数*MFT起始扇区号=MFT起始偏移
- mov edi,offset MFTFirstOffset ;放MFT起始偏移的地址送edi
- mov [edi],eax ;保存MFT起始偏移(低位)
- mov [edi+4],edx ;保存MFT起始偏移(高位)
- ;经过以上算法后,MFTFirstOffset保存的就是MFT起始偏移了
- ret
- FirstMFTOffset endp
- ;*******************************************************
- ;判断当前MFT是否是用户要恢复的文件
- FindFile proc
- push edi
- NextFindFile:
- ;_____________________________________________________
- .if dword ptr [edi] != 454c4946h ;如果这不是一个合法的MFT,则表明已经读完了卷中所有的MFT
- cmp dword ptr [edi],44414142h ;在windows 2K中,有可能出现标志为“BAAD”的空MFT
- jnz NoMft
- mov [StateFindFile],1 ;[StateFindFile]赋1后退出,跳过这个MFT
- jmp ExitProc
- NoMft:
- mov [StateFindFile],0 ;[StateFindFile]赋0后退出
- jmp ExitProc
- ;_____________________________________________________
- .elseif word ptr [edi+16h] != 0 ;如果这个文件是未被删除的
- mov [StateFindFile],1 ;[StateFindFile]赋1后退出
- jmp ExitProc
- ;_____________________________________________________
- .else
- add di,word ptr [edi+14h]
- mov dword ptr [EdiOffset],edi ;保存属性头开始偏移
- ;((((((((((((((((((((((((((((((((((((((((((((((((((((((
- FindAttribute:
- .if dword ptr [edi]==30h ;是30h属性的话
- CmpFileNameLeng: ;比较文件名长度
- push edx
- pop edx
- add di,word ptr [edi+14h] ;将30H属性头后的属性偏移送edi
- ;(属性头14H处为该属性开始的相对偏移)
- mov edx,dword ptr [edi+30h] ;保存文件大小,为后面恢复文件做准备
- mov dword ptr [FileSize2],edx ;30H属性偏移30H后的8个字节是文件的实际大小
- mov edx,dword ptr [edi+34h]
- mov dword ptr [FileSize2+4],edx
- movzx eax,byte ptr [edi+40h] ;edi+40中存放的是30H属性的文件名Unicode长度
- mov dword ptr [FileNameLong],eax ;保存文件名长度
- cmp eax,dword ptr [StringLength] ;该长度和用户输入的文件名长度进行比较
- jc Next ;如果CF=1(有借位)则转,有借位则表示用户输
- ;入的字符串的长度大于该文件的文件名长度,
- ;这肯定不是用户要恢复的文件了
- jmp CmpFileName
- Next:
- mov edi,dword ptr [EdiOffset] ;将属性头开始偏移送回edi
- add edi,dword ptr [edi+4h] ;edi为下一个属性的偏移(属性头04~07为该属性的长度)
- mov dword ptr [EdiOffset],edi ;保存下一个属性头开始偏移
- jmp FindAttribute ;继续找下一个属性
- CmpFileName:
- movzx eax,byte ptr [edi+40h] ;该文件30H属性的文件名长度送eax
- add edi,42h ;30H属性开始的偏移+42后为该文件文件名的开始偏移送edi(源串地址)
- mov dword ptr [IndicEdi],edi ;保存文件名的开始偏移
- mov dword ptr [FileNameOffset],edi ;保存文件名开始偏移!!!!!!!!!!!
- sub eax,dword ptr [StringLength] ;eax=文件名长度-用户输入的串长度
- inc eax ;eax加1,结果为串比较时移动源串指针的次数
- push edi
- call ToCaps ;将小写的Unicode码转为大写,为比较串做准备
- pop edi
- mov ecx,dword ptr [StringLength] ;计数器=用户输入的串的长度
- mov ebx,ecx ;保存用户输入串长度到ebx
- mov esi,offset [FILENAMEU] ;目的串地址
- Compare:
- repz cmpsw ;比较源串和目的串
- jz Alike ;一样则说明这就是用户要恢复的文件,一样则转
- dec eax
- cmp eax,0 ;为0表示比较完毕都没有发现文件名中包含了用户输入的字符串
- jz Next ;继续找下一个属性
- mov esi,offset [FILENAMEU] ;重新指向用户输入串的首地址目的串地址
- add dword ptr [IndicEdi],2 ;文件名字符串向后移动两个单位,指向下一个字符
- mov edi,dword ptr [IndicEdi]
- mov ecx,ebx ;比较的次数=用户输入的串的长度
- jmp Compare ;转比较处
- Alike:
- xor eax,eax
- mov edi,offset FileNameBuffer
- mov ecx,128 ;循环128次,将文件名缓冲区清零
- ClearBuffer:
- mov dword ptr [edi],eax
- add edi,4
- loop ClearBuffer ;清除文件名缓冲区
- mov esi,dword ptr [FileNameOffset] ;源地址为30H属性中文件名的开始
- mov edi,offset FileNameBuffer ;目标地址为FileNameBuffer
- mov ecx,dword ptr [FileNameLong] ;传送次数为文件名长度
- rep movsw ;拷贝文件名到FileNameBuffer中
- mov [StateFindFile],2 ;这就是用户要恢复的文件[StateFindFile]赋值2后退出
- jmp ExitProc
- ;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
- .elseif dword ptr [edi]==0ffffffffh ;是属性结束的话,说明这个文件不是用户要恢复的
- mov [StateFindFile],1 ;[StateFindFile]赋1后退出
- jmp ExitProc
- ;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
- .else ;是其他属性的话直接将指针加上属性长度得到后面的属性开始,重新判断
- jmp Next
-
- .endif
- ;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
- .endif
- ExitProc:
- pop edi ;将该MFT的起始偏移写回edi
- ret
- FindFile endp
- ;*******************************************************
- ReadData proc
- push edi ;保存要恢复文件的MFT的开始地址
- add di,word ptr [edi+14h]
- FindNext:
- mov dword ptr [EdiOffset],edi ;保存属性头开始偏移
- .if dword ptr [edi]==80h ;是80h属性的话
- cmp byte ptr [edi+9h],0 ;该80H属性是否有属性名[edi+09H]为0表示没有属性名
- jnz Next ;有属性名的80H属性不是用户数据属性,跳过这个属性,比较下一个
- .if byte ptr [edi+08]==0 ;[edi+08]==0(一个字节) 表示该属性为常驻属性
- movzx eax,word ptr [edi+14h] ;属性开始的偏移(属性头的长度)送eax
- mov ebx,dword ptr [edi+4h] ;包括属性头长度在内的属性长度
- sub ebx,eax ;ebsx=包括属性头长度在内的属性长度 - 属性头的长度=用户数据的长度(文件大小)
- mov dword ptr [FileSize],ebx ;文件大小
- mov ecx,ebx ;循环次数为文件大小
- mov esi,edi ;把80H属性头开始的偏移送esi
- add si,word ptr [edi+14h] ;把80H属性开始的偏移送esi(源地址)
- mov edi,offset DataBuffer ;把数据缓存区的地址送edi(目的地址)
- rep movsb ;将要恢复的用户数据传到DataBuffer中
- inc dword ptr [Recoveried] ;每恢复一个文件将[Recoveried]加1
- mov dword ptr [ResidentFlag],0 ;给常驻与非常驻标志置0,表示常驻
- jmp ExitProc
- .elseif byte ptr [edi+08]==1 ;[edi+08]==1(一个字节)表示该属性为非常驻属性
- ;获取文件的大小
- mov edx,dword ptr [edi+30h] ;保存文件大小,为后面恢复文件做准备
- mov dword ptr [FileSize1],edx ;80H属性头偏移30H后的8个字节是文件的真实大小
- mov edx,dword ptr [edi+34h]
- mov dword ptr [FileSize1+4],edx
- invoke CreateFileW,offset FileNameBuffer,\ ;创建要恢复的文件
- GENERIC_READ OR GENERIC_WRITE,\ ;为读和写打开
- 0,NULL,\ ;不允许文件再被打开
- CREATE_NEW,\ ;创建新文件,如果文件已经存在则返回失败代码
- NULL,NULL
- mov [hFile],eax ;保存文件号
-
- push edi ;保存edi
- push eax ;保存eax
- mov edi,offset DBR
- mov cl,byte ptr [edi+0dh]
- movzx ebx,cl ;每簇扇区数送ebx
- mov eax,512
- mul ebx ;每簇扇区数乘以每扇区字节数=每簇字节数
- mov dword ptr [ByeofOneC],eax ;每簇字节数保存到ByeofOneC
- pop eax
- pop edi
- xor ebx,ebx
- mov bx,word ptr [edi+20h]
- add edi,ebx ;把80H属性运行列表开始的偏移送edi
-
- Recover:
- call RunInfo ;获取运行起始字节偏移(在RunFirstAddr处),和该运行占有的字节数(在RunByte处)
- invoke SetFilePointer,[hFile_Disk],\ ;移动文件指针到运行数据开始处
- dword ptr [RunFirstAddr],\ ;移动文件指针的低32位
- offset RunFirstAddr+4,\ ;移动文件指针的高32位
- FILE_BEGIN ;从文件(分区)开始处计算
-
- ReadWrite:
- .if dword ptr [RunByte]>100000H ;如果运行大小大于1M字节
- invoke ReadFile,[hFile_Disk],\ ;读1兆字节的运行数据
- offset DataBuffer,1024*1024,\
- offset Readed,NULL
- invoke WriteFile,[hFile],\ ;写1M数据到文件
- offset DataBuffer,1024*1024,\
- offset Readed,NULL
- sub dword ptr [RunByte],1024*1024 ;RunByte减1M字节
- sub dword ptr [FileSize1],1024*1024 ;文件大小减1M字节
- jmp ReadWrite ;继续读数据写进文件
- .elseif dword ptr [RunByte]<=100000H ;如果运行大小小于或等于1M字节
- invoke ReadFile,[hFile_Disk],\ ;读运行大小字节的运行数据
- offset DataBuffer,[RunByte],\
- offset Readed,NULL
- invoke WriteFile,[hFile],\ ;写运行最后剩下的实际文件大小字节数据到文件
- offset DataBuffer,dword ptr [FileSize1],\; [FileSize1]总是小于[RunByte]的
- offset Readed,NULL
- mov al,byte ptr [CInfo1]
- movzx ecx,al
- add edi,ecx
- mov al,byte ptr [CInfo2]
- movzx ecx,al
- add edi,ecx
- inc edi ;这样edi就指向了下一个运行列表的开始
- cmp byte ptr [edi],0 ;有下一个运行列表吗?
- jnz Recover ;不是0表示还有下一个运行,继续处理下一个运行
- invoke CloseHandle,[hFile] ;没有下一个运行则关闭文件
- invoke SetFilePointer,[hFile_Disk],\ ;还原磁盘指针
- dword ptr [MFTFirstOffset],\ ;移动文件指针的低32位
- offset MFTFirstOffset+4,\ ;移动文件指针的高32位
- FILE_BEGIN ;从文件(分区)开始处计算
-
- .endif
- ExitReadWrite:
- mov dword ptr [ResidentFlag],1 ;给常驻与非常驻标志置1,表示非常驻
- jmp ExitProc
- .endif
- .elseif dword ptr [edi]==0ffffffffh ;是属性结束的话,就退出
- jmp ExitProc
- .else ;是其他属性的话
- Next:
- mov edi,dword ptr [EdiOffset] ;将属性头开始偏移送回edi
- add edi,dword ptr [edi+4h] ;edi为下一个属性的偏移(属性头04~07为该属性的长度)
- jmp FindNext ;继续找下一个属性
- .endif
- ExitProc:
- pop edi ;将该MFT的起始偏移写回edi
- ret
- ReadData endp
- ;*******************************************************
- RunInfo proc
- ;获取文件起始字节偏移,和该运行占有的字节数
- mov dword ptr [Edi80],edi ;将属性运行列表偏移保存到Edi80
- mov al,byte ptr [edi] ;把运行列表的第一个字节送al,其高
- ;4位表示多少运行列表中多少个字节为起始簇
- ;低4位表示多少个字节表示簇大小
- push eax
- mov cl,4
- shr al,cl ;将al逻辑右移4位,结果al为该运行起始的簇号所占字节数
- mov byte ptr [CInfo1],al
- pop eax
- and al,0fh ;清al高4位后al为该运行的簇数占有的字节
- mov byte ptr [CInfo2],al
- ;计算运行的总共的字节数
- push edi
- mov esi,edi
- inc esi ;源地址为运行所占簇数偏移
- mov edi,offset RunCN ;目标地址
- xor ecx,ecx
- mov cl,byte ptr [CInfo2]
- rep movsb ;将运行簇数保存到RunCN处
- mov eax,dword ptr [RunCN] ;将运行簇数送eax
- mov ebx,dword ptr [ByeofOneC] ;将每簇字节数送ebx
- mul ebx
- mov dword ptr [RunByte],eax ;该运行所占字节数偏移送RunByte处
- pop edi
- ;计算运行的起始偏移字节
- push edi
- mov esi,edi
- inc esi
- xor ecx,ecx
- mov cl,byte ptr [CInfo2]
- add esi,ecx ;esi指向运行起始簇偏移(源地址)
- mov edi,offset RunC ;目标地址
- mov cl,byte ptr [CInfo1] ;循环次数为运行列表中起始簇所占字节数
- rep movsb ;将运行的起始簇号保存到RunC处
- mov eax,dword ptr [RunC] ;将相对运行起始簇号送eax
- add dword ptr [RunC2],eax ;计算绝对起始簇号
- mov eax, dword ptr [RunC2] ;绝对起始簇号送eax
- mov ebx,dword ptr [ByeofOneC] ;将每簇字节数送ebx
- mul ebx
- mov dword ptr [RunFirstAddr],eax
- mov dword ptr [RunFirstAddr+4],edx ;保存运行起始偏移到RunFirstAddr处
- pop edi
-
- ret
-
- RunInfo endp
- ;*******************************************************
- start:
- invoke GetModuleHandle,NULL ;得到模块句柄(NULL为本模块)
- mov hInstance,eax ;保存模块句柄
- invoke DialogBoxParam,hInstance,\ ;创建模块对话框,从hInstance指定模块装入
- DLG_MAIN,NULL,\ ;装入DLG_MAIN参数指定的对话框,父对话框为NULL
- offset _ProcDlgMain,NULL ;过程地址为_ProcDlgMain的首地址,
- ;当作WM_INITDIALOG消息的lParam传给过程对话框定义为NULL(未定义)
- invoke ExitProcess,NULL ;退出程序
- end start
|