[原]VisualC++信息安全编程(2)内联汇编实现NTFS文件恢复
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文件恢复。
;******************************************************
.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 3dup (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的标志
StateFindFiledd 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
.elseifeax == 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
.elseifeax == WM_COMMAND
mov eax,wParam
;_____________________________________________________________________
.ifax == IDCANCEL ;如果用户点击“取消”按钮
invoke EndDialog,hWnd,NULL ;关闭对话框
mov eax,TRUE
ret
.elseifax== IDOK ;如果用户点击“确定”按钮
invoke CreateFileA,offset FileName,\;打开用户输入的盘符
GENERIC_READ OR GENERIC_WRITE,\
FILE_SHARE_READ OR FILE_SHARE_WRITE,\
NULL,OPEN_EXISTING,NULL,NULL
mov ,eax ;保存该分区的文件号
cmp eax,INVALID_HANDLE_VALUE ;判断其是否成功(为-1失败)
jz _98CODE ;失败则转
invoke ReadFile,,\
offset DBR,512,\
offset Readed,NULL
cmp eax,0
jz ReadFail
mov edx,dword ptr ;将该分区的分区标志送edx
mov ebx,dword ptr System_Id
cmp edx,ebx ;是NTFS分区吗?
jnz P_Err ;不是则转
CALL FirstMFTOffset ;定位MFT的起始偏移
invoke SetFilePointer,,\
dword ptr ,\ ;移动文件指针的低32位
offset MFTFirstOffset+4,\ ;移动文件指针的高32位
FILE_BEGIN ;从文件(分区)开始处计算
cmp eax,-1
jz MoveFail
ReadMFT:
mov dword ptr ,1024 ;用于计算指针是否指到了内存中的MFT尾
invoke ReadFile,,\ ;读1兆MFT
offset MFT,1024*1024,\
offset Readed,NULL
add dword ptr ,1024*1024;保存当前磁盘指针
adc dword ptr ,0
cmp eax,0
jz ReadFail
mov edi,offset MFT
CallFindFile:
call FindFile ;查找符合用户输入的已经删除的文件
;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
.if ==0 ;FindFile过程返回状态数据为0
;表示所有的MFT都找完了
invoke MessageBoxA,NULL,offset Info1,offset Temp,MB_OK
ret
;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
.elseif ==1 ;FindFile过程返回状态数据为1
;表示该文件未被删除或这不是用户要恢复的文件
ReadToo:
dec dword ptr
cmp dword ptr ,0
jzReadMFT ;结果为0则表示要读下1兆MFT了
add edi,1024 ;edi向后1K,指向下一个MFT
jmp CallFindFile ;继续查找符合用户输入的已经删除的文件
;((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
.elseif ==2 ;FindFile过程返回状态数据为2
;表示这是一个用户要恢复的文件(文件名包含用户输入)
call ReadData ;这个过程将要恢复文件的数据读入内存中
;创建要恢复的文件,文件名为原来的文件名
;______________________________________________________
.if dword ptr ==0 ;如果为常驻属性
invoke CreateFileW,offset FileNameBuffer,\;创建要恢复的文件
GENERIC_READ OR GENERIC_WRITE,\ ;为读和写打开
0,NULL,\ ;不允许文件再被打开
CREATE_NEW,\ ;创建新文件,如果文件已经存在则返回失败代码
NULL,NULL
mov ,eax ;保存文件号
invoke WriteFile,,\ ;写文件
offset DataBuffer,,\
offset Readed,NULL
invoke CloseHandle, ;关闭文件
jmp ReadToo ;继续找是否还有包含用户输入的文件
;_____________________________________________________
.elseifdword ptr ==1 ;如果为非常驻属性
mov dword ptr ,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, ;关闭文件(关闭分区)
invoke MessageBoxA,NULL,offset ErrorInfo2,offset ErrCap,MB_OK
mov eax,TRUE
ret
P_Err:
invoke CloseHandle, ;关闭文件(关闭分区)
invoke MessageBoxA,NULL,offset ErrorInfo3,offset ErrCap,MB_OK
mov eax,TRUE
ret
MoveFail:
invoke CloseHandle, ;关闭文件(关闭分区)
invoke MessageBoxA,NULL,offset ErrorInfo4,offset ErrCap,MB_OK
mov eax,TRUE
ret
;_____________________________________________________________________
.elseifax == 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
;_____________________________________________________________________
.elseifax == 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,offsetFILENAMEU
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
moveax,00h
movedi,offset FILENAMEU
CmpString:
cmpbyte ptr ,00 ;字符串是否结束
jz ExitProc
inceax
incedi
incedi
jmpCmpString
ExitProc:
mov,eax
ret
CompString endp
;*******************************************************
;小写的Unicode字母转大写
ToCaps proc
Char:
movbx,word ptr ;将字符串中的一个字送BX
.while bx>=61h && bx<=7ah ;这个字是UNICODE小写字母么,是则执行循环体
subbx,20h ;将其转变为大小的Unicode字符
movword ptr ,bx ;再将这个转变后的字符送回字符串中
incedi ;指针加2
incedi
movbx,word ptr ;继续将下一个字符串中的一个字送BX
.break .if bx==00h ;如果是00则表示已经到了字符串尾,则退出循环
.endw
cmpbx,00 ;bx为0表示已经到了字符串的尾部
jz Okchar ;到了字符串的尾部转返回处
incedi ;指针加2(因为是Unicode字符)
incedi
jnzChar ;不是小写Unicode字母则跳过这个字符继续做下一个字符的判断
Okchar:
ret
ToCaps endp
;*******************************************************
;计算$MFT起始偏移,并存放在MFTFirstOffset
FirstMFTOffsetproc
movedi,offset DBR
moveax,dword ptr ;MFT起始簇号送eax
movcl,
movzx ebx,cl ;每簇扇区数送ebx
mulebx ;MFT起始簇号*每簇扇区数=MFT起始扇区号,高位保存在edx中
;低位保存在eax中
movedi,offset MFTFirstSector
mov,eax ;将MFT起始扇区号保存
movebx,512 ;每扇区字节数送ebx
mulebx ;每扇区字节数*MFT起始扇区号=MFT起始偏移
movedi,offset MFTFirstOffset ;放MFT起始偏移的地址送edi
mov,eax ;保存MFT起始偏移(低位)
mov,edx ;保存MFT起始偏移(高位)
;经过以上算法后,MFTFirstOffset保存的就是MFT起始偏移了
ret
FirstMFTOffsetendp
;*******************************************************
;判断当前MFT是否是用户要恢复的文件
FindFileproc
pushedi
NextFindFile:
;_____________________________________________________
.if dword ptr != 454c4946h ;如果这不是一个合法的MFT,则表明已经读完了卷中所有的MFT
cmp dword ptr ,44414142h ;在windows 2K中,有可能出现标志为“BAAD”的空MFT
jnz NoMft
mov ,1 ;赋1后退出,跳过这个MFT
jmp ExitProc
NoMft:
mov ,0 ;赋0后退出
jmp ExitProc
;_____________________________________________________
.elseif word ptr != 0 ;如果这个文件是未被删除的
mov ,1 ;赋1后退出
jmp ExitProc
;_____________________________________________________
.else
add di,word ptr
mov dword ptr ,edi ;保存属性头开始偏移
;((((((((((((((((((((((((((((((((((((((((((((((((((((((
FindAttribute:
.if dword ptr ==30h ;是30h属性的话
CmpFileNameLeng: ;比较文件名长度
pushedx
pop edx
add di,word ptr ;将30H属性头后的属性偏移送edi
;(属性头14H处为该属性开始的相对偏移)
mov edx,dword ptr ;保存文件大小,为后面恢复文件做准备
mov dword ptr ,edx ;30H属性偏移30H后的8个字节是文件的实际大小
mov edx,dword ptr
mov dword ptr ,edx
movzx eax,byte ptr ;edi+40中存放的是30H属性的文件名Unicode长度
mov dword ptr ,eax ;保存文件名长度
cmp eax,dword ptr ;该长度和用户输入的文件名长度进行比较
jc Next ;如果CF=1(有借位)则转,有借位则表示用户输
;入的字符串的长度大于该文件的文件名长度,
;这肯定不是用户要恢复的文件了
jmp CmpFileName
Next:
mov edi,dword ptr ;将属性头开始偏移送回edi
add edi,dword ptr ;edi为下一个属性的偏移(属性头04~07为该属性的长度)
mov dword ptr ,edi ;保存下一个属性头开始偏移
jmp FindAttribute ;继续找下一个属性
CmpFileName:
movzx eax,byte ptr ;该文件30H属性的文件名长度送eax
add edi,42h ;30H属性开始的偏移+42后为该文件文件名的开始偏移送edi(源串地址)
mov dword ptr ,edi ;保存文件名的开始偏移
mov dword ptr ,edi ;保存文件名开始偏移!!!!!!!!!!!
sub eax,dword ptr ;eax=文件名长度-用户输入的串长度
inc eax ;eax加1,结果为串比较时移动源串指针的次数
pushedi
callToCaps ;将小写的Unicode码转为大写,为比较串做准备
pop edi
mov ecx,dword ptr ;计数器=用户输入的串的长度
mov ebx,ecx ;保存用户输入串长度到ebx
mov esi,offset ;目的串地址
Compare:
repz cmpsw ;比较源串和目的串
jz Alike ;一样则说明这就是用户要恢复的文件,一样则转
dec eax
cmp eax,0 ;为0表示比较完毕都没有发现文件名中包含了用户输入的字符串
jz Next ;继续找下一个属性
mov esi,offset ;重新指向用户输入串的首地址目的串地址
add dword ptr ,2 ;文件名字符串向后移动两个单位,指向下一个字符
mov edi,dword ptr
mov ecx,ebx ;比较的次数=用户输入的串的长度
jmp Compare ;转比较处
Alike:
xor eax,eax
mov edi,offset FileNameBuffer
mov ecx,128 ;循环128次,将文件名缓冲区清零
ClearBuffer:
mov dword ptr ,eax
add edi,4
loopClearBuffer ;清除文件名缓冲区
mov esi,dword ptr ;源地址为30H属性中文件名的开始
mov edi,offset FileNameBuffer ;目标地址为FileNameBuffer
mov ecx,dword ptr ;传送次数为文件名长度
rep movsw ;拷贝文件名到FileNameBuffer中
mov ,2 ;这就是用户要恢复的文件赋值2后退出
jmp ExitProc
;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
.elseif dword ptr ==0ffffffffh ;是属性结束的话,说明这个文件不是用户要恢复的
mov ,1 ;赋1后退出
jmp ExitProc
;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
.else ;是其他属性的话直接将指针加上属性长度得到后面的属性开始,重新判断
jmp Next
.endif
;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
.endif
ExitProc:
popedi ;将该MFT的起始偏移写回edi
ret
FindFileendp
;*******************************************************
ReadDataproc
pushedi ;保存要恢复文件的MFT的开始地址
add di,word ptr
FindNext:
mov dword ptr ,edi ;保存属性头开始偏移
.if dword ptr ==80h ;是80h属性的话
cmp byteptr ,0 ;该80H属性是否有属性名为0表示没有属性名
jnz Next ;有属性名的80H属性不是用户数据属性,跳过这个属性,比较下一个
.if byte ptr ==0 ;==0(一个字节) 表示该属性为常驻属性
movzxeax,word ptr ;属性开始的偏移(属性头的长度)送eax
mov ebx,dword ptr ;包括属性头长度在内的属性长度
sub ebx,eax ;ebsx=包括属性头长度在内的属性长度 - 属性头的长度=用户数据的长度(文件大小)
mov dword ptr ,ebx ;文件大小
mov ecx,ebx ;循环次数为文件大小
mov esi,edi ;把80H属性头开始的偏移送esi
add si,word ptr ;把80H属性开始的偏移送esi(源地址)
mov edi,offset DataBuffer ;把数据缓存区的地址送edi(目的地址)
rep movsb ;将要恢复的用户数据传到DataBuffer中
inc dword ptr ;每恢复一个文件将加1
mov dword ptr ,0 ;给常驻与非常驻标志置0,表示常驻
jmp ExitProc
.elseif byte ptr ==1 ;==1(一个字节)表示该属性为非常驻属性
;获取文件的大小
mov edx,dword ptr ;保存文件大小,为后面恢复文件做准备
mov dword ptr ,edx ;80H属性头偏移30H后的8个字节是文件的真实大小
mov edx,dword ptr
mov dword ptr ,edx
invoke CreateFileW,offset FileNameBuffer,\;创建要恢复的文件
GENERIC_READ OR GENERIC_WRITE,\ ;为读和写打开
0,NULL,\ ;不允许文件再被打开
CREATE_NEW,\ ;创建新文件,如果文件已经存在则返回失败代码
NULL,NULL
mov ,eax ;保存文件号
push edi ;保存edi
push eax ;保存eax
mov edi,offset DBR
mov cl,byte ptr
movzxebx,cl ;每簇扇区数送ebx
mov eax,512
mul ebx ;每簇扇区数乘以每扇区字节数=每簇字节数
mov dword ptr ,eax ;每簇字节数保存到ByeofOneC
pop eax
pop edi
xor ebx,ebx
mov bx,word ptr
add edi,ebx ;把80H属性运行列表开始的偏移送edi
Recover:
call RunInfo ;获取运行起始字节偏移(在RunFirstAddr处),和该运行占有的字节数(在RunByte处)
invoke SetFilePointer,,\ ;移动文件指针到运行数据开始处
dword ptr ,\ ;移动文件指针的低32位
offset RunFirstAddr+4,\ ;移动文件指针的高32位
FILE_BEGIN ;从文件(分区)开始处计算
ReadWrite:
.if dword ptr >100000H ;如果运行大小大于1M字节
invoke ReadFile,,\ ;读1兆字节的运行数据
offset DataBuffer,1024*1024,\
offset Readed,NULL
invoke WriteFile,,\ ;写1M数据到文件
offset DataBuffer,1024*1024,\
offset Readed,NULL
sub dword ptr ,1024*1024;RunByte减1M字节
sub dword ptr ,1024*1024 ;文件大小减1M字节
jmp ReadWrite ;继续读数据写进文件
.elseif dword ptr <=100000H ;如果运行大小小于或等于1M字节
invoke ReadFile,,\ ;读运行大小字节的运行数据
offset DataBuffer,,\
offset Readed,NULL
invoke WriteFile,,\ ;写运行最后剩下的实际文件大小字节数据到文件
offset DataBuffer,dword ptr ,\; 总是小于的
offset Readed,NULL
mov al,byte ptr
movzx ecx,al
add edi,ecx
mov al,byte ptr
movzx ecx,al
add edi,ecx
inc edi ;这样edi就指向了下一个运行列表的开始
cmp byte ptr ,0 ;有下一个运行列表吗?
jnz Recover ;不是0表示还有下一个运行,继续处理下一个运行
invoke CloseHandle, ;没有下一个运行则关闭文件
invoke SetFilePointer,,\;还原磁盘指针
dword ptr ,\ ;移动文件指针的低32位
offset MFTFirstOffset+4,\ ;移动文件指针的高32位
FILE_BEGIN ;从文件(分区)开始处计算
.endif
ExitReadWrite:
mov dword ptr ,1 ;给常驻与非常驻标志置1,表示非常驻
jmp ExitProc
.endif
.elseifdword ptr ==0ffffffffh ;是属性结束的话,就退出
jmp ExitProc
.else ;是其他属性的话
Next:
mov edi,dword ptr ;将属性头开始偏移送回edi
add edi,dword ptr ;edi为下一个属性的偏移(属性头04~07为该属性的长度)
jmp FindNext ;继续找下一个属性
.endif
ExitProc:
popedi ;将该MFT的起始偏移写回edi
ret
ReadDataendp
;*******************************************************
RunInfo proc
;获取文件起始字节偏移,和该运行占有的字节数
mov dword ptr ,edi ;将属性运行列表偏移保存到Edi80
mov al,byte ptr ;把运行列表的第一个字节送al,其高
;4位表示多少运行列表中多少个字节为起始簇
;低4位表示多少个字节表示簇大小
push eax
mov cl,4
shr al,cl ;将al逻辑右移4位,结果al为该运行起始的簇号所占字节数
mov byte ptr ,al
pop eax
and al,0fh ;清al高4位后al为该运行的簇数占有的字节
mov byte ptr ,al
;计算运行的总共的字节数
push edi
mov esi,edi
inc esi ;源地址为运行所占簇数偏移
mov edi,offset RunCN ;目标地址
xor ecx,ecx
mov cl,byte ptr
rep movsb ;将运行簇数保存到RunCN处
mov eax,dword ptr ;将运行簇数送eax
mov ebx,dword ptr ;将每簇字节数送ebx
mul ebx
mov dword ptr ,eax;该运行所占字节数偏移送RunByte处
pop edi
;计算运行的起始偏移字节
push edi
mov esi,edi
inc esi
xor ecx,ecx
mov cl,byte ptr
add esi,ecx ;esi指向运行起始簇偏移(源地址)
mov edi,offset RunC ;目标地址
mov cl,byte ptr ;循环次数为运行列表中起始簇所占字节数
rep movsb ;将运行的起始簇号保存到RunC处
mov eax,dword ptr ;将相对运行起始簇号送eax
add dword ptr ,eax ;计算绝对起始簇号
mov eax, dword ptr ;绝对起始簇号送eax
mov ebx,dword ptr ;将每簇字节数送ebx
mul ebx
mov dword ptr ,eax
mov dword ptr ,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
作者:yincheng01 发表于2012-1-6 6:39:49 原文链接
页:
[1]