找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 3699|回复: 0

[原]VisualC++信息安全编程(2)内联汇编实现NTFS文件恢复

[复制链接]
发表于 2012-3-7 00:07:22 | 显示全部楼层 |阅读模式


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文件恢复。
  1. ;******************************************************
  2. .386
  3. .model flat, stdcall
  4. option casemap :none
  5. ;******************************************************
  6. ; Include 文件定义
  7. ;******************************************************
  8. include                \masm32\include\windows.inc
  9. include                \masm32\include\user32.inc
  10. includelib      \masm32\lib\user32.lib
  11. include         \masm32\include\kernel32.inc
  12. includelib      \masm32\lib\kernel32.lib
  13. ;*******************************************************
  14. ; Equ 等值定义
  15. ;*******************************************************
  16. ICO_MAIN        equ                1000h  ;图标ID
  17. DLG_MAIN        equ                1      ;对话框ID
  18. IDC_PARTITION   equ             101h    ;盘符名输入框ID
  19. IDC_FILENAME    equ             102h   ;文件名ID
  20. ;*******************************************************
  21. ; 数据段
  22. ;*******************************************************
  23. .data
  24. hFile_Disk     dd   0               ;磁盘文件号
  25. hFile          dd   0               ;文件号
  26. FileName       db   '\\.\'          ;打开文件名为\\.\X:形式的文件则打开了X分区
  27. PARTITION      db   3  dup (0)      ;请注意FileName和等待用户输入的PARTITION共
  28.                                     ;同组成了要打开的文件名(分区)
  29. FILENAMEA      db   25 dup (0)      ;等待用户输入的字符缓存
  30. FILENAMEU      db   50 dup (0)      ;转换成Unicode字符串的缓存
  31. ErrCap         db   '失败',00       ;错误对话框的Caption
  32. ErrorInfo1     db   '可能的原因是:',0dh
  33.                db   '1.该程序不能在除NT以外的系统中执行;',0dh
  34.                db   '2.您输入的盘符无效!',00h
  35. ErrorInfo2     db   '读盘错误!',00
  36. ErrorInfo3     db   '该程序只能恢复NTFS文件系统中的数据!',0dh
  37.                db   '您打开的磁盘不是NTFS文件系统!',00h
  38. ErrorInfo4     db   '移动文件指针错误!',00h
  39. Info1          db   '请在当前文件夹下查看已恢复的文件!如果文件扩展名不对,请自行',0dh
  40.                db   '修改扩展名,如果没有文件,则说明您输入的文件没有找到!',00h
  41. Recoveried     dd   30h               ;用来存放已经恢复的文件个数0~z
  42. _0             db   00               ;字符串结束
  43. Readed         dd   0
  44. System_Id      db   'NTFS'           ;DBR中NTFS卷的标志
  45. MFT_Flag       db   'FILE'           ;MFT的标志
  46. StateFindFile  dd   0                ;该数据是FindFile过程的返回值
  47. StringLength   dd   0                ;该地址用于存放用户输入的文件名的输入长度
  48. MFTTime        dd   1024
  49. Temp           db   'Text',00
  50. EdiOffset      dd   0                ;
  51. IndicEdi       dd   0                ;用来在比较字符串中存放Edi所指向的字符串的指针
  52. FileNameOffset dd   0                ;用来存放文件名偏移
  53. FileSize       dd   0                ;用来存放常驻80H属性的文件大小
  54. FileSize1      dq   0                ;用来存放系统分配给非常驻80H属性的大小
  55. FileSize2      dq   0                ;用来存放非常驻80H属性的文件真实大小
  56. Edi80          dd   0                ;用来保存非常驻80H属性的运行列表偏移
  57. CInfo1         db   0                ;用来保存运行列表的第一个字节的低4位
  58. CInfo2         db   0                ;用来保存运行列表的第一个字节的高4位
  59. ResidentFlag   dd   0ffh             ;80H属性常驻与非常驻标志,为0表示常驻,为1表示非常驻
  60. ByeofOneC      dd   0                ;每簇字节数
  61. RunC           dd   0                ;运行相对起始簇号
  62. RunC2          dd   0                ;运行绝对起始簇号
  63. RunByte        dd   0                ;运行字节数
  64. RunCN          dd   0                ;运行起始簇号
  65. RunFirstAddr   dq   0                ;运行起始偏移字节
  66. ;__________________________________________________________________
  67. .data?
  68. hInstance      dd   ?
  69. DBR            db   512 dup (?)      ;512字节作为DBR的缓冲
  70. MFTFirstSector dd   ?                ;MFT首扇区存放的缓冲
  71. MFTFirstOffset dd   2 dup (?)
  72. Filling        db   8 dup (?)        ;这个是没有用的数据,只是为了让后面的MFT在
  73.                                      ;程序执行时起始偏移在XXXXXXX0上,方便调试
  74. MFT            db   1024*1024 dup (?);1M作为MFT的缓冲
  75. DataBuffer     db   1024*1024 dup (?);1M字节做为文件数据缓冲
  76. FileNameLong   dd   ?
  77. FileNameBuffer dw   260 dup (?)
  78. ;*******************************************************
  79. ; 代码段
  80. ;*******************************************************
  81. .code
  82. ;*******************************************************
  83. _ProcDlgMain        proc        uses ebx edi esi hWnd,wMsg,wParam,lParam
  84.     mov      eax,wMsg
  85. .if        eax == WM_CLOSE         ;如果消息为WM_CLOSE,当按下右上角的关闭按钮
  86.     invoke    EndDialog,hWnd,NULL        ;hWnd为对话框窗口句柄,结束对话框
  87.     ret
  88. .elseif  eax == WM_INITDIALOG             ;初始化代码
  89.     invoke    GetDlgItem,hWnd,IDOK         ;取IDOK句柄
  90.     invoke    EnableWindow,eax,FALSE      ;IDOK显示为灰色(确定按钮)
  91.     invoke    LoadIcon,hInstance,ICO_MAIN     ;设置标题栏图标
  92.     invoke    SendMessage,hWnd,WM_SETICON,ICON_BIG,eax   
  93. .elseif  eax == WM_COMMAND
  94.     mov       eax,wParam
  95.      ;_____________________________________________________________________
  96.       .if  ax == IDCANCEL                         ;如果用户点击“取消”按钮
  97.           invoke    EndDialog,hWnd,NULL           ;关闭对话框
  98.           mov       eax,TRUE
  99.           ret
  100.       .elseif  ax== IDOK                           ;如果用户点击“确定”按钮
  101.           invoke    CreateFileA,offset FileName,\  ;打开用户输入的盘符
  102.                     GENERIC_READ OR GENERIC_WRITE,\
  103.                     FILE_SHARE_READ OR FILE_SHARE_WRITE,\
  104.                     NULL,OPEN_EXISTING,NULL,NULL
  105.           mov       [hFile_Disk],eax               ;保存该分区的文件号
  106.           cmp       eax,INVALID_HANDLE_VALUE       ;判断其是否成功(为-1失败)
  107.           jz        _98CODE                        ;失败则转
  108.           invoke    ReadFile,[hFile_Disk],\
  109.                     offset DBR,512,\
  110.                     offset Readed,NULL
  111.           cmp       eax,0
  112.           jz        ReadFail
  113.           mov       edx,dword ptr [DBR+3]          ;将该分区的分区标志送edx
  114.           mov       ebx,dword ptr System_Id      
  115.           cmp       edx,ebx                        ;是NTFS分区吗?
  116.           jnz       P_Err                          ;不是则转
  117.           CALL      FirstMFTOffset                 ;定位MFT的起始偏移
  118.           invoke    SetFilePointer,[hFile_Disk],\
  119.                     dword ptr [MFTFirstOffset],\   ;移动文件指针的低32位
  120.                     offset MFTFirstOffset+4,\      ;移动文件指针的高32位
  121.                     FILE_BEGIN                     ;从文件(分区)开始处计算
  122.           cmp       eax,-1
  123.           jz        MoveFail
  124.        ReadMFT:
  125.           mov       dword ptr [MFTTime],1024       ;用于计算指针是否指到了内存中的MFT尾
  126.           invoke    ReadFile,[hFile_Disk],\        ;读1兆MFT
  127.                     offset MFT,1024*1024,\
  128.                     offset Readed,NULL
  129.           add       dword ptr [MFTFirstOffset],1024*1024  ;保存当前磁盘指针
  130.           adc       dword ptr [MFTFirstOffset+4],0
  131.           cmp       eax,0
  132.           jz        ReadFail
  133.          
  134.           mov       edi,offset MFT
  135.        CallFindFile:                       
  136.           call      FindFile             ;查找符合用户输入的已经删除的文件
  137.               ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
  138.               .if     [StateFindFile]==0 ;FindFile过程返回状态数据[StateFindFile]为0
  139.                                          ;表示所有的MFT都找完了
  140.                    invoke    MessageBoxA,NULL,offset Info1,offset Temp,MB_OK
  141.                    ret
  142.               ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((        
  143.               .elseif [StateFindFile]==1 ;FindFile过程返回状态数据[StateFindFile]为1
  144.                                          ;表示该文件未被删除或这不是用户要恢复的文件
  145.                 ReadToo:
  146.                   dec dword ptr [MFTTime]
  147.                   cmp dword ptr [MFTTime],0
  148.                   jz  ReadMFT           ;结果为0则表示要读下1兆MFT了
  149.                   add edi,1024          ;edi向后1K,指向下一个MFT
  150.                   jmp CallFindFile      ;继续查找符合用户输入的已经删除的文件
  151.               ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((                                       
  152.               .elseif [StateFindFile]==2 ;FindFile过程返回状态数据[StateFindFile]为2
  153.                                          ;表示这是一个用户要恢复的文件(文件名包含用户输入)
  154.                   call ReadData           ;这个过程将要恢复文件的数据读入内存中
  155.                   ;创建要恢复的文件,文件名为原来的文件名
  156.                  ;______________________________________________________
  157.                      .if   dword ptr [ResidentFlag]==0       ;如果为常驻属性
  158.                         invoke    CreateFileW,offset FileNameBuffer,\  ;创建要恢复的文件
  159.                             GENERIC_READ OR GENERIC_WRITE,\ ;为读和写打开
  160.                             0,NULL,\                        ;不允许文件再被打开
  161.                             CREATE_NEW,\                 ;创建新文件,如果文件已经存在则返回失败代码
  162.                             NULL,NULL
  163.                         mov       [hFile],eax                  ;保存文件号
  164.                         invoke    WriteFile,[hFile],\          ;写文件
  165.                                   offset DataBuffer,[FileSize],\      
  166.                                   offset Readed,NULL
  167.                         invoke    CloseHandle,[hFile]           ;关闭文件
  168.                         jmp       ReadToo                       ;继续找是否还有包含用户输入的文件
  169.                   ;_____________________________________________________
  170.                       .elseif  dword ptr [ResidentFlag]==1    ;如果为非常驻属性
  171.                         mov       dword ptr [RunC2],0    ;绝对起始簇号清零
  172.                         jmp       ReadToo                  
  173.                        ;invoke    MessageBoxA,NULL,offset ErrorInfo1,offset Temp,MB_OK
  174.                       .endif
  175.                   ;_______________________________________________________
  176.                   ret
  177.               .endif
  178.               ;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((         
  179.         _98CODE:         
  180.           invoke    MessageBoxA,NULL,offset ErrorInfo1,offset ErrCap,MB_OK
  181.           mov            eax,TRUE
  182.           ret
  183.         ReadFail:
  184.           invoke    CloseHandle,[hFile_Disk]        ;关闭文件(关闭分区)
  185.           invoke    MessageBoxA,NULL,offset ErrorInfo2,offset ErrCap,MB_OK
  186.           mov            eax,TRUE
  187.           ret
  188.         P_Err:
  189.           invoke    CloseHandle,[hFile_Disk]        ;关闭文件(关闭分区)
  190.           invoke    MessageBoxA,NULL,offset ErrorInfo3,offset ErrCap,MB_OK
  191.           mov            eax,TRUE
  192.           ret
  193.         MoveFail:
  194.           invoke    CloseHandle,[hFile_Disk]        ;关闭文件(关闭分区)
  195.           invoke    MessageBoxA,NULL,offset ErrorInfo4,offset ErrCap,MB_OK
  196.           mov            eax,TRUE
  197.           ret      
  198.       ;_____________________________________________________________________
  199.       .elseif  ax == IDC_PARTITION                     ;如果用户在盘符文本框中输入
  200.           invoke    SendDlgItemMessage,hWnd,\          ;限制文本输入为2个字符
  201.                     IDC_PARTITION,EM_LIMITTEXT,2,NULL   
  202.           invoke    GetDlgItemText,hWnd,IDC_PARTITION,\
  203.                     addr PARTITION,sizeof PARTITION    ;取用户输入文本到PARTITION处
  204.           invoke    GetDlgItem,hWnd,IDOK               ;取IDOK句柄(确定按钮)
  205.           invoke    EnableWindow,eax,TRUE              ;置确定按钮为可用
  206.           mov       eax,TRUE
  207.           ret
  208.       ;_____________________________________________________________________
  209.       .elseif  ax == IDC_FILENAME                   ;如果用在文件名文本框中输入
  210.           invoke    SendDlgItemMessage,hWnd,\       ;限制文本输入为24个字符
  211.                     IDC_FILENAME,EM_LIMITTEXT,24,NULL
  212.           invoke    GetDlgItemText,hWnd,IDC_FILENAME,\  ;取用户输入到FILENAMEA处
  213.                     addr FILENAMEA,sizeof FILENAMEA
  214.           call      CompString                     ;计算用户输入的字符的长度,并保存在StringLength处
  215.           ;将ANSI字符串转换为Unicode字符串
  216.           invoke    MultiByteToWideChar,1,0,addr FILENAMEA,\ ;AUSI地址FILENAMEA首地址
  217.                     -1,addr FILENAMEU,\          ;-1为自动大小(为0结束)
  218.                     sizeof FILENAMEU             ;转换到FILENAMEU,大小为FILENAMEU的大小
  219.           mov       edi,offset  FILENAMEU
  220.           call      ToCaps          ;将FILENAMEU中的Unicode字符串中的小写字母转换为大写
  221.           mov       eax,TRUE
  222.           ret
  223.       .endif
  224.       ;_____________________________________________________________________
  225. .else
  226.     mov      eax,FALSE
  227.     ret
  228. .endif
  229.     mov      eax,TRUE
  230.     ret
  231. _ProcDlgMain        endp
  232. ;*******************************************************
  233. ;该过程用于计算用户输入的文件名的长度(Unicode的长度),并保存在StringLength处
  234. CompString    proc
  235.     mov  eax,00h
  236.     mov  edi,offset FILENAMEU
  237.   CmpString:
  238.     cmp  byte ptr [edi],00      ;字符串是否结束
  239.     jz   ExitProc
  240.     inc  eax
  241.     inc  edi
  242.     inc  edi
  243.     jmp  CmpString
  244.   ExitProc:
  245.     mov  [StringLength],eax
  246.     ret
  247. CompString    endp
  248. ;*******************************************************
  249. ;小写的Unicode字母转大写
  250. ToCaps        proc
  251.   Char:
  252.     mov  bx,word ptr [edi]       ;将字符串中的一个字送BX
  253. .while   bx>=61h && bx<=7ah       ;这个字是UNICODE小写字母么,是则执行循环体
  254.     sub  bx,20h                  ;将其转变为大小的Unicode字符
  255.     mov  word ptr [edi],bx       ;再将这个转变后的字符送回字符串中
  256.     inc  edi                     ;指针加2
  257.     inc  edi                     
  258.     mov  bx,word ptr [edi]       ;继续将下一个字符串中的一个字送BX
  259. .break .if bx==00h                ;如果是00则表示已经到了字符串尾,则退出循环
  260. .endw
  261.     cmp  bx,00                   ;bx为0表示已经到了字符串的尾部
  262.     jz   Okchar                  ;到了字符串的尾部转返回处
  263.     inc  edi                     ;指针加2(因为是Unicode字符)
  264.     inc  edi                              
  265.     jnz  Char                    ;不是小写Unicode字母则跳过这个字符继续做下一个字符的判断   
  266.   Okchar:
  267.     ret
  268. ToCaps    endp
  269. ;*******************************************************
  270. ;计算$MFT起始偏移,并存放在MFTFirstOffset
  271. FirstMFTOffset  proc
  272.     mov  edi,offset DBR
  273.     mov  eax,dword ptr [edi+30h]  ;MFT起始簇号送eax
  274.     mov  cl,[edi+0dh]
  275.     movzx ebx,cl       ;每簇扇区数送ebx
  276.     mul  ebx           ;MFT起始簇号*每簇扇区数=MFT起始扇区号,高位保存在edx中
  277.                        ;低位保存在eax中
  278.     mov  edi,offset MFTFirstSector
  279.     mov  [edi],eax     ;将MFT起始扇区号保存
  280.     mov  ebx,512       ;每扇区字节数送ebx
  281.     mul  ebx           ;每扇区字节数*MFT起始扇区号=MFT起始偏移
  282.     mov  edi,offset MFTFirstOffset ;放MFT起始偏移的地址送edi
  283.     mov  [edi],eax     ;保存MFT起始偏移(低位)
  284.     mov  [edi+4],edx     ;保存MFT起始偏移(高位)
  285.     ;经过以上算法后,MFTFirstOffset保存的就是MFT起始偏移了
  286.     ret
  287. FirstMFTOffset  endp
  288. ;*******************************************************
  289. ;判断当前MFT是否是用户要恢复的文件
  290. FindFile  proc
  291.     push  edi
  292. NextFindFile:
  293.   ;_____________________________________________________
  294.   .if     dword ptr [edi] != 454c4946h ;如果这不是一个合法的MFT,则表明已经读完了卷中所有的MFT
  295.     cmp   dword ptr [edi],44414142h    ;在windows 2K中,有可能出现标志为“BAAD”的空MFT
  296.     jnz   NoMft
  297.     mov   [StateFindFile],1            ;[StateFindFile]赋1后退出,跳过这个MFT
  298.     jmp   ExitProc  
  299.   NoMft:
  300.     mov   [StateFindFile],0       ;[StateFindFile]赋0后退出
  301.     jmp   ExitProc
  302.   ;_____________________________________________________
  303.   .elseif word ptr [edi+16h] != 0                        ;如果这个文件是未被删除的
  304.     mov   [StateFindFile],1                                ;[StateFindFile]赋1后退出
  305.     jmp   ExitProc
  306.   ;_____________________________________________________
  307.   .else
  308.     add   di,word ptr [edi+14h]
  309.     mov   dword ptr [EdiOffset],edi                            ;保存属性头开始偏移
  310.       ;((((((((((((((((((((((((((((((((((((((((((((((((((((((
  311.         FindAttribute:
  312.       .if     dword ptr [edi]==30h             ;是30h属性的话
  313.         CmpFileNameLeng:                       ;比较文件名长度
  314.             push  edx
  315.             pop   edx
  316.             add   di,word ptr [edi+14h]        ;将30H属性头后的属性偏移送edi
  317.                                                ;(属性头14H处为该属性开始的相对偏移)
  318.             mov   edx,dword ptr [edi+30h]      ;保存文件大小,为后面恢复文件做准备                                               
  319.             mov   dword ptr [FileSize2],edx    ;30H属性偏移30H后的8个字节是文件的实际大小
  320.             mov   edx,dword ptr [edi+34h]      
  321.             mov   dword ptr [FileSize2+4],edx
  322.             movzx eax,byte ptr [edi+40h]       ;edi+40中存放的是30H属性的文件名Unicode长度
  323.             mov   dword ptr [FileNameLong],eax ;保存文件名长度
  324.             cmp   eax,dword ptr [StringLength] ;该长度和用户输入的文件名长度进行比较
  325.             jc    Next                         ;如果CF=1(有借位)则转,有借位则表示用户输
  326.                                                ;入的字符串的长度大于该文件的文件名长度,
  327.                                                ;这肯定不是用户要恢复的文件了
  328.             jmp   CmpFileName
  329.         Next:
  330.             mov   edi,dword ptr [EdiOffset]    ;将属性头开始偏移送回edi
  331.             add   edi,dword ptr [edi+4h]       ;edi为下一个属性的偏移(属性头04~07为该属性的长度)
  332.             mov   dword ptr [EdiOffset],edi    ;保存下一个属性头开始偏移     
  333.             jmp   FindAttribute                ;继续找下一个属性
  334.         CmpFileName:
  335.             movzx eax,byte ptr [edi+40h]       ;该文件30H属性的文件名长度送eax
  336.             add   edi,42h                      ;30H属性开始的偏移+42后为该文件文件名的开始偏移送edi(源串地址)
  337.             mov   dword ptr [IndicEdi],edi     ;保存文件名的开始偏移
  338.             mov   dword ptr [FileNameOffset],edi ;保存文件名开始偏移!!!!!!!!!!!
  339.             sub   eax,dword ptr [StringLength] ;eax=文件名长度-用户输入的串长度
  340.             inc   eax                          ;eax加1,结果为串比较时移动源串指针的次数
  341.             push  edi
  342.             call  ToCaps                       ;将小写的Unicode码转为大写,为比较串做准备
  343.             pop   edi
  344.             mov   ecx,dword ptr [StringLength] ;计数器=用户输入的串的长度
  345.             mov   ebx,ecx                      ;保存用户输入串长度到ebx   
  346.             mov   esi,offset [FILENAMEU]       ;目的串地址
  347.         Compare:
  348.             repz cmpsw                        ;比较源串和目的串
  349.             jz    Alike                        ;一样则说明这就是用户要恢复的文件,一样则转
  350.             dec   eax
  351.             cmp   eax,0                        ;为0表示比较完毕都没有发现文件名中包含了用户输入的字符串                       
  352.             jz    Next                         ;继续找下一个属性
  353.             mov   esi,offset [FILENAMEU]       ;重新指向用户输入串的首地址目的串地址
  354.             add   dword ptr [IndicEdi],2       ;文件名字符串向后移动两个单位,指向下一个字符
  355.             mov   edi,dword ptr [IndicEdi]
  356.             mov   ecx,ebx                      ;比较的次数=用户输入的串的长度
  357.             jmp   Compare                      ;转比较处                       
  358.         Alike:
  359.             xor   eax,eax
  360.             mov   edi,offset FileNameBuffer
  361.             mov   ecx,128                      ;循环128次,将文件名缓冲区清零
  362.         ClearBuffer:
  363.             mov   dword ptr [edi],eax  
  364.             add   edi,4                          
  365.             loop  ClearBuffer                    ;清除文件名缓冲区
  366.             mov   esi,dword ptr [FileNameOffset] ;源地址为30H属性中文件名的开始
  367.             mov   edi,offset FileNameBuffer      ;目标地址为FileNameBuffer
  368.             mov   ecx,dword ptr [FileNameLong]   ;传送次数为文件名长度
  369.             rep   movsw                          ;拷贝文件名到FileNameBuffer中
  370.             mov   [StateFindFile],2            ;这就是用户要恢复的文件[StateFindFile]赋值2后退出
  371.             jmp   ExitProc   
  372.       ;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((      
  373.       .elseif dword ptr [edi]==0ffffffffh      ;是属性结束的话,说明这个文件不是用户要恢复的
  374.             mov   [StateFindFile],1            ;[StateFindFile]赋1后退出
  375.             jmp   ExitProc
  376.       ;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
  377.       .else                                     ;是其他属性的话直接将指针加上属性长度得到后面的属性开始,重新判断
  378.             jmp   Next
  379.            
  380.       .endif
  381.       ;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
  382.   .endif
  383.   ExitProc:
  384.     pop  edi                        ;将该MFT的起始偏移写回edi
  385.     ret      
  386. FindFile  endp
  387. ;*******************************************************
  388. ReadData  proc
  389.     push  edi                       ;保存要恢复文件的MFT的开始地址
  390.     add   di,word ptr [edi+14h]
  391.   FindNext:
  392.     mov   dword ptr [EdiOffset],edi   ;保存属性头开始偏移
  393. .if      dword ptr [edi]==80h        ;是80h属性的话
  394.     cmp   byte  ptr [edi+9h],0        ;该80H属性是否有属性名[edi+09H]为0表示没有属性名
  395.     jnz   Next                        ;有属性名的80H属性不是用户数据属性,跳过这个属性,比较下一个
  396.         .if   byte ptr [edi+08]==0        ;[edi+08]==0(一个字节) 表示该属性为常驻属性
  397.             movzx  eax,word ptr [edi+14h]   ;属性开始的偏移(属性头的长度)送eax
  398.             mov    ebx,dword ptr [edi+4h]   ;包括属性头长度在内的属性长度
  399.             sub    ebx,eax                  ;ebsx=包括属性头长度在内的属性长度 - 属性头的长度=用户数据的长度(文件大小)
  400.             mov    dword ptr [FileSize],ebx ;文件大小
  401.             mov    ecx,ebx                  ;循环次数为文件大小
  402.             mov    esi,edi                  ;把80H属性头开始的偏移送esi
  403.             add    si,word ptr [edi+14h]    ;把80H属性开始的偏移送esi(源地址)
  404.             mov    edi,offset DataBuffer    ;把数据缓存区的地址送edi(目的地址)
  405.             rep    movsb                    ;将要恢复的用户数据传到DataBuffer中
  406.             inc    dword ptr [Recoveried]   ;每恢复一个文件将[Recoveried]加1
  407.             mov    dword ptr [ResidentFlag],0 ;给常驻与非常驻标志置0,表示常驻
  408.             jmp    ExitProc     
  409.         .elseif byte ptr [edi+08]==1      ;[edi+08]==1(一个字节)表示该属性为非常驻属性
  410.             ;获取文件的大小
  411.             mov    edx,dword ptr [edi+30h]      ;保存文件大小,为后面恢复文件做准备                                               
  412.             mov    dword ptr [FileSize1],edx    ;80H属性头偏移30H后的8个字节是文件的真实大小
  413.             mov    edx,dword ptr [edi+34h]      
  414.             mov    dword ptr [FileSize1+4],edx
  415.             invoke    CreateFileW,offset FileNameBuffer,\  ;创建要恢复的文件
  416.                       GENERIC_READ OR GENERIC_WRITE,\ ;为读和写打开
  417.                       0,NULL,\                        ;不允许文件再被打开
  418.                       CREATE_NEW,\                 ;创建新文件,如果文件已经存在则返回失败代码
  419.                       NULL,NULL
  420.             mov       [hFile],eax                  ;保存文件号
  421.             
  422.             push   edi                          ;保存edi
  423.             push   eax                          ;保存eax            
  424.             mov    edi,offset DBR
  425.             mov    cl,byte ptr [edi+0dh]
  426.             movzx  ebx,cl       ;每簇扇区数送ebx
  427.             mov    eax,512
  428.             mul    ebx           ;每簇扇区数乘以每扇区字节数=每簇字节数
  429.             mov    dword ptr [ByeofOneC],eax ;每簇字节数保存到ByeofOneC
  430.             pop    eax
  431.             pop    edi
  432.             xor    ebx,ebx
  433.             mov    bx,word ptr [edi+20h]
  434.             add    edi,ebx    ;把80H属性运行列表开始的偏移送edi
  435.          Recover:
  436.             call   RunInfo   ;获取运行起始字节偏移(在RunFirstAddr处),和该运行占有的字节数(在RunByte处)
  437.             invoke    SetFilePointer,[hFile_Disk],\ ;移动文件指针到运行数据开始处
  438.                       dword ptr [RunFirstAddr],\   ;移动文件指针的低32位
  439.                       offset RunFirstAddr+4,\      ;移动文件指针的高32位
  440.                       FILE_BEGIN                     ;从文件(分区)开始处计算                 
  441.          ReadWrite:
  442.             .if     dword ptr [RunByte]>100000H ;如果运行大小大于1M字节
  443.                  invoke    ReadFile,[hFile_Disk],\        ;读1兆字节的运行数据
  444.                            offset DataBuffer,1024*1024,\
  445.                            offset Readed,NULL                 
  446.                  invoke    WriteFile,[hFile],\          ;写1M数据到文件
  447.                            offset DataBuffer,1024*1024,\      
  448.                            offset Readed,NULL
  449.                  sub    dword ptr [RunByte],1024*1024  ;RunByte减1M字节
  450.                  sub    dword ptr [FileSize1],1024*1024 ;文件大小减1M字节
  451.                  jmp    ReadWrite                      ;继续读数据写进文件
  452.             .elseif dword ptr [RunByte]<=100000H ;如果运行大小小于或等于1M字节
  453.                  invoke    ReadFile,[hFile_Disk],\        ;读运行大小字节的运行数据
  454.                            offset DataBuffer,[RunByte],\
  455.                            offset Readed,NULL                 
  456.                  invoke    WriteFile,[hFile],\          ;写运行最后剩下的实际文件大小字节数据到文件
  457.                            offset DataBuffer,dword ptr [FileSize1],\; [FileSize1]总是小于[RunByte]的  
  458.                            offset Readed,NULL
  459.                  mov       al,byte ptr [CInfo1]
  460.                  movzx     ecx,al
  461.                  add       edi,ecx
  462.                  mov       al,byte ptr [CInfo2]
  463.                  movzx     ecx,al
  464.                  add       edi,ecx
  465.                  inc       edi               ;这样edi就指向了下一个运行列表的开始
  466.                  cmp       byte ptr [edi],0 ;有下一个运行列表吗?
  467.                  jnz       Recover    ;不是0表示还有下一个运行,继续处理下一个运行
  468.                  invoke    CloseHandle,[hFile] ;没有下一个运行则关闭文件
  469.                  invoke    SetFilePointer,[hFile_Disk],\  ;还原磁盘指针
  470.                            dword ptr [MFTFirstOffset],\   ;移动文件指针的低32位
  471.                            offset MFTFirstOffset+4,\      ;移动文件指针的高32位
  472.                            FILE_BEGIN                     ;从文件(分区)开始处计算
  473.                   
  474.             .endif
  475.           ExitReadWrite:
  476.             mov    dword ptr [ResidentFlag],1 ;给常驻与非常驻标志置1,表示非常驻
  477.             jmp    ExitProc   
  478.         .endif
  479. .elseif  dword ptr [edi]==0ffffffffh ;是属性结束的话,就退出
  480.     jmp   ExitProc
  481. .else                                ;是其他属性的话
  482.   Next:
  483.     mov   edi,dword ptr [EdiOffset]   ;将属性头开始偏移送回edi
  484.     add   edi,dword ptr [edi+4h]      ;edi为下一个属性的偏移(属性头04~07为该属性的长度)
  485.     jmp   FindNext                    ;继续找下一个属性
  486. .endif
  487.   ExitProc:
  488.     pop  edi                          ;将该MFT的起始偏移写回edi
  489.     ret
  490. ReadData  endp
  491. ;*******************************************************
  492. RunInfo   proc   
  493.     ;获取文件起始字节偏移,和该运行占有的字节数
  494.     mov    dword ptr [Edi80],edi    ;将属性运行列表偏移保存到Edi80
  495.     mov    al,byte ptr [edi]        ;把运行列表的第一个字节送al,其高
  496.                                             ;4位表示多少运行列表中多少个字节为起始簇
  497.                                             ;低4位表示多少个字节表示簇大小
  498.     push   eax
  499.     mov    cl,4
  500.     shr    al,cl                    ;将al逻辑右移4位,结果al为该运行起始的簇号所占字节数
  501.     mov    byte ptr [CInfo1],al
  502.     pop    eax
  503.     and    al,0fh                   ;清al高4位后al为该运行的簇数占有的字节
  504.     mov    byte ptr [CInfo2],al
  505.     ;计算运行的总共的字节数
  506.     push   edi
  507.     mov    esi,edi
  508.     inc    esi                      ;源地址为运行所占簇数偏移
  509.     mov    edi,offset RunCN         ;目标地址
  510.     xor    ecx,ecx
  511.     mov    cl,byte ptr [CInfo2]
  512.     rep    movsb                    ;将运行簇数保存到RunCN处
  513.     mov    eax,dword ptr [RunCN]     ;将运行簇数送eax        
  514.     mov    ebx,dword ptr [ByeofOneC] ;将每簇字节数送ebx
  515.     mul    ebx                     
  516.     mov    dword ptr [RunByte],eax  ;该运行所占字节数偏移送RunByte处
  517.     pop    edi
  518.     ;计算运行的起始偏移字节
  519.     push   edi
  520.     mov    esi,edi
  521.     inc    esi
  522.     xor    ecx,ecx
  523.     mov    cl,byte ptr [CInfo2]
  524.     add    esi,ecx                 ;esi指向运行起始簇偏移(源地址)
  525.     mov    edi,offset RunC         ;目标地址
  526.     mov    cl,byte ptr [CInfo1]    ;循环次数为运行列表中起始簇所占字节数
  527.     rep    movsb                   ;将运行的起始簇号保存到RunC处
  528.     mov    eax,dword ptr [RunC]     ;将相对运行起始簇号送eax
  529.     add    dword ptr [RunC2],eax    ;计算绝对起始簇号
  530.     mov    eax, dword ptr [RunC2]    ;绝对起始簇号送eax   
  531.     mov    ebx,dword ptr [ByeofOneC] ;将每簇字节数送ebx
  532.     mul    ebx                     
  533.     mov    dword ptr [RunFirstAddr],eax
  534.     mov    dword ptr [RunFirstAddr+4],edx ;保存运行起始偏移到RunFirstAddr处
  535.     pop    edi
  536.     ret
  537. RunInfo   endp
  538. ;*******************************************************
  539. start:
  540.     invoke    GetModuleHandle,NULL    ;得到模块句柄(NULL为本模块)
  541.     mov       hInstance,eax           ;保存模块句柄
  542.     invoke    DialogBoxParam,hInstance,\ ;创建模块对话框,从hInstance指定模块装入
  543.               DLG_MAIN,NULL,\            ;装入DLG_MAIN参数指定的对话框,父对话框为NULL
  544.               offset _ProcDlgMain,NULL  ;过程地址为_ProcDlgMain的首地址,
  545.                                         ;当作WM_INITDIALOG消息的lParam传给过程对话框定义为NULL(未定义)
  546.     invoke    ExitProcess,NULL          ;退出程序
  547. end    start
复制代码

作者:yincheng01 发表于2012-1-6 6:39:49 原文链接


您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-5-1 01:05 , Processed in 0.014880 second(s), 5 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表