主题:请教高手代码错误在哪?
小弟在网上看到一篇老罗的文章,名叫“为PE文件添加新节显示启动信息”
代码ml,link都通过了,只是被修改的pe文件不但没有预期的效果,反而不好使了
研究了好几天也不知代码错在哪,请高手们指教!
我装的是xp系统,弹出错误发送报告!
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\comdlg32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\comdlg32.lib
WndProc proto :DWORD, :DWORD, :DWORD, :DWORD
AddNewSection proto :DWORD
CTEXT MACRO y:VARARG
LOCAL sym
CONST segment
ifidni <y>,<>
sym db 0
else
sym db y,0
endif
CONST ends
exitm <offset sym>
ENDM
.const
IDI_LC equ 1
IDC_BUTTON_OPEN equ 3000
MAXSIZE equ 260
Head_Len equ sizeof IMAGE_NT_HEADERS + sizeof IMAGE_SECTION_HEADER
.data
szDlgName db "lc_dialog", 0
szCaption db "Section Add demo by LC", 0
ofn OPENFILENAME <>
szFileName db MAXSIZE dup(0)
szFilterString db "PE 可执行文件", 0, "*.exe", 0, 0
szMyTitle db "请打开一个PE可执行文件…", 0
PE_Header IMAGE_NT_HEADERS <0>
My_Section IMAGE_SECTION_HEADER <>
szDllName db "User32", 0
szMessageBoxA db "MessageBoxA", 0
.data?
hInstance HINSTANCE ?
.code
main:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam, eax, offset szDlgName, 0, WndProc, 0
invoke ExitProcess, eax
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.if uMsg == WM_CLOSE
invoke EndDialog, hWnd, 0
.elseif uMsg == WM_INITDIALOG
;设置我的图标:
invoke LoadIcon, hInstance, IDI_LC
invoke SendMessage, hWnd, WM_SETICON, ICON_SMALL, eax
.elseif uMsg == WM_COMMAND
mov eax, wParam
mov edx, eax
shr edx, 16
movzx eax, ax
.if edx == BN_CLICKED
.if eax == IDCANCEL
invoke EndDialog, hWnd, NULL
.elseif eax == IDC_BUTTON_OPEN || eax == IDOK
;调用子程序,添加节:
invoke AddNewSection, hWnd
.endif
.endif
.else
mov eax, FALSE
ret
.endif
mov eax, TRUE
ret
WndProc endp
AddNewSection proc uses ecx hWnd:HWND
LOCAL hFile: HANDLE
LOCAL dwPE_Header_OffSet: DWORD
LOCAL dwFileReadWritten: DWORD
LOCAL dwMySectionOffSet: DWORD
LOCAL dwLastSection_SizeOfRawData: DWORD
LOCAL dwLastSection_PointerToRawData: DWORD
mov ofn.lStructSize, sizeof ofn
push hWnd
pop ofn.hwndOwner
push hInstance
pop ofn.hInstance
mov ofn.lpstrFilter, offset szFilterString
mov ofn.lpstrFile, offset szFileName
mov ofn.nMaxFile, MAXSIZE
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER
mov ofn.lpstrTitle, offset szMyTitle
invoke GetOpenFileName, addr ofn
.if eax == 0
jmp Err_CreateFile_Exit
.endif
invoke CreateFile, addr szFileName, GENERIC_READ or GENERIC_WRITE,\
FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox, hWnd, CTEXT("打开文件失败!"), addr szCaption, MB_OK or MB_ICONHAND
jmp Err_CreateFile_Exit
.endif
mov hFile, eax
invoke SetFilePointer, hFile, 3ch, 0, FILE_BEGIN
invoke ReadFile, hFile, addr dwPE_Header_OffSet, 4, addr dwFileReadWritten, NULL
invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, FILE_BEGIN
invoke ReadFile, hFile, addr PE_Header, Head_Len, addr dwFileReadWritten, NULL
;****************************************
;判断是否有效的PE文件,是的话才继续:
;****************************************
.if [PE_Header.Signature] != IMAGE_NT_SIGNATURE
;如果不是有效的PE文件,就给出提示:
invoke MessageBox, hWnd, CTEXT("这不是一个有效的Win32 PE文件!"), addr szCaption, MB_OK or MB_ICONHAND
jmp Exit
.endif
;****************************************
;判断是否有足够空间存储新节:
;****************************************
movzx eax, [PE_Header.FileHeader.NumberOfSections] ;得到添加新节前有多少个节:
mov ecx, 28h ;28h = sizeof IMAGE_SECTION_HEADER
mul ecx ;eax = NumberOfSections * sizeof IMAGE_SECTION_HEADER
add eax, dwPE_Header_OffSet ;eax = eax + PE文件头偏移
add eax, 18h ;18h = sizeof IMAGE_FILE_HEADER
movzx ecx, [PE_Header.FileHeader.SizeOfOptionalHeader]
add eax, ecx ;eax = eax + sizeof IMAGE_OPTIONAL_HEADER
add eax, 28h ;添加一个新节的大小
.if eax > [PE_Header.OptionalHeader.SizeOfHeaders]
;不够的话给出提示:
invoke MessageBox, NULL, CTEXT("没有足够的空间来加入一个新节!"), addr szCaption, MB_OK or MB_ICONHAND
jmp Exit
.endif
;****************************************
;保存原入口,后面要用到:
;****************************************
mov eax, [PE_Header.OptionalHeader.AddressOfEntryPoint]
mov Old_AddressOfEntryPoint, eax
mov eax, [PE_Header.OptionalHeader.ImageBase]
mov Old_ImageBase, eax
;**************************************************
;计算新节的偏移地址:
;(其实跟上面的“判断是否有足够空间存储新节”基本上一样)
;**************************************************
movzx eax, [PE_Header.FileHeader.NumberOfSections]
mov ecx, 28h
mul ecx ;eax = NumberOfSections * sizeof IMAGE_SECTION_HEADER
add eax, 4h ;4h = sizeof "PE\0\0"
add eax, dwPE_Header_OffSet
add eax, sizeof IMAGE_FILE_HEADER
add eax, sizeof IMAGE_OPTIONAL_HEADER
mov dwMySectionOffSet, eax ;现在得到了我们的新节的偏移地址
;****************************************
;填充我们自己的节的信息:
;(这部分请查看PE格式,很容易明白,不多说了)
;****************************************
mov dword ptr [My_Section.Name1], "CL." ;名字就叫做“.LC”吧,呵呵……
mov [My_Section.Misc.VirtualSize], offset vEnd - offset vStart
push [PE_Header.OptionalHeader.SizeOfImage]
pop [My_Section.VirtualAddress]
mov eax, [My_Section.Misc.VirtualSize]
mov ecx, [PE_Header.OptionalHeader.FileAlignment]
cdq
div ecx
inc eax
mul ecx
mov [My_Section.SizeOfRawData], eax ;SizeOfRawData在EXE文件中是对齐到FileAlignMent的整数倍的值
mov eax, dwMySectionOffSet
sub eax, 18h ;这个偏移是定位到最后一节的“SizeOfRawData”
invoke SetFilePointer, hFile, eax, 0, FILE_BEGIN
invoke ReadFile, hFile, addr dwLastSection_SizeOfRawData, 4, addr dwFileReadWritten, NULL
invoke ReadFile, hFile, addr dwLastSection_PointerToRawData, 4, addr dwFileReadWritten, NULL
;每个节的 PointerToRawData 等于它的上一节的 SizeOfRawData + PointerToRawData:
mov eax, dwLastSection_SizeOfRawData
add eax, dwLastSection_PointerToRawData
mov [My_Section.PointerToRawData], eax
mov [My_Section.PointerToRelocations], 0h
mov [My_Section.PointerToLinenumbers], 0h
mov [My_Section.NumberOfRelocations], 0h
mov [My_Section.NumberOfLinenumbers], 0h
mov [My_Section.Characteristics], 0E0000020h ;可读可写可执行
;**************************************************
;重新写入IMAGE_SECTION_HEADER:(包含了新节的信息)
;**************************************************
invoke SetFilePointer, hFile, dwMySectionOffSet, 0, FILE_BEGIN
invoke WriteFile, hFile, addr My_Section, sizeof IMAGE_SECTION_HEADER, addr dwFileReadWritten, NULL
;****************************************
;得到 MessageBoxA 的线性地址:
;****************************************
invoke GetModuleHandle, addr szDllName
invoke LoadLibrary, addr szDllName
invoke GetProcAddress, eax, addr szMessageBoxA
mov MessageBoxA_Addr, eax
;****************************************
;在文件的最后写入我们的新节:
;****************************************
invoke SetFilePointer, hFile, 0, 0, FILE_END
push 0
lea eax, dwFileReadWritten
push eax
push [My_Section.SizeOfRawData]
lea eax, vStart
push eax
push hFile
call WriteFile
;**************************************************
;改写IMAGE_NT_HEADERS,使新节可以首先执行:
;(需要改写 SizeOfImage 和 AddressOfEntryPoint)
;**************************************************
inc [PE_Header.FileHeader.NumberOfSections]
mov eax, [My_Section.Misc.VirtualSize]
mov ecx, [PE_Header.OptionalHeader.SectionAlignment]
cdq
div ecx
inc eax
mul ecx
add eax, [PE_Header.OptionalHeader.SizeOfImage]
mov [PE_Header.OptionalHeader.SizeOfImage], eax ;SizeOfImage是一个对齐到SectionAlignment的整数倍的值
mov eax, [My_Section.VirtualAddress]
mov [PE_Header.OptionalHeader.AddressOfEntryPoint], eax ;现在的 AddressOfEntryPoint 是指向新节的第一条指令
invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, FILE_BEGIN
invoke WriteFile, hFile, addr PE_Header, sizeof IMAGE_NT_HEADERS, addr dwFileReadWritten, NULL
;****************************************
;完成!显示成功信息:
;****************************************
invoke MessageBox, hWnd, CTEXT("添加新节成功!"), addr szCaption, MB_OK or MB_ICONINFORMATION
Exit:
;关闭文件:
invoke CloseHandle, hFile
Err_CreateFile_Exit:
ret
AddNewSection endp
;****************************************
;呵呵,我们自己的东东:
;****************************************
vStart:
call nStart
nStart:
pop ebp
sub ebp, offset nStart ;得到新节在文件中的实际偏移地址
;显示对话框:
push MB_OK or MB_ICONINFORMATION
lea eax, szMyCaption[ebp]
push eax
lea eax, szMyMsg[ebp]
push eax
push 0
call MessageBoxA_Addr[ebp]
;恢复原入口地址。当这个节执行完毕后,就回到了原来的文件入口处继续执行:
mov eax, Old_ImageBase[ebp]
add eax, Old_AddressOfEntryPoint[ebp]
push eax
ret
;变量定义:
MessageBoxA_Addr dd 0
szMyMsg db "为PE文件添加新节显示启动信息", 0
szMyCaption db "LC", 0
Old_ImageBase dd 0
Old_AddressOfEntryPoint dd 0
vEnd:
end main
代码ml,link都通过了,只是被修改的pe文件不但没有预期的效果,反而不好使了
研究了好几天也不知代码错在哪,请高手们指教!
我装的是xp系统,弹出错误发送报告!
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\comdlg32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\comdlg32.lib
WndProc proto :DWORD, :DWORD, :DWORD, :DWORD
AddNewSection proto :DWORD
CTEXT MACRO y:VARARG
LOCAL sym
CONST segment
ifidni <y>,<>
sym db 0
else
sym db y,0
endif
CONST ends
exitm <offset sym>
ENDM
.const
IDI_LC equ 1
IDC_BUTTON_OPEN equ 3000
MAXSIZE equ 260
Head_Len equ sizeof IMAGE_NT_HEADERS + sizeof IMAGE_SECTION_HEADER
.data
szDlgName db "lc_dialog", 0
szCaption db "Section Add demo by LC", 0
ofn OPENFILENAME <>
szFileName db MAXSIZE dup(0)
szFilterString db "PE 可执行文件", 0, "*.exe", 0, 0
szMyTitle db "请打开一个PE可执行文件…", 0
PE_Header IMAGE_NT_HEADERS <0>
My_Section IMAGE_SECTION_HEADER <>
szDllName db "User32", 0
szMessageBoxA db "MessageBoxA", 0
.data?
hInstance HINSTANCE ?
.code
main:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam, eax, offset szDlgName, 0, WndProc, 0
invoke ExitProcess, eax
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.if uMsg == WM_CLOSE
invoke EndDialog, hWnd, 0
.elseif uMsg == WM_INITDIALOG
;设置我的图标:
invoke LoadIcon, hInstance, IDI_LC
invoke SendMessage, hWnd, WM_SETICON, ICON_SMALL, eax
.elseif uMsg == WM_COMMAND
mov eax, wParam
mov edx, eax
shr edx, 16
movzx eax, ax
.if edx == BN_CLICKED
.if eax == IDCANCEL
invoke EndDialog, hWnd, NULL
.elseif eax == IDC_BUTTON_OPEN || eax == IDOK
;调用子程序,添加节:
invoke AddNewSection, hWnd
.endif
.endif
.else
mov eax, FALSE
ret
.endif
mov eax, TRUE
ret
WndProc endp
AddNewSection proc uses ecx hWnd:HWND
LOCAL hFile: HANDLE
LOCAL dwPE_Header_OffSet: DWORD
LOCAL dwFileReadWritten: DWORD
LOCAL dwMySectionOffSet: DWORD
LOCAL dwLastSection_SizeOfRawData: DWORD
LOCAL dwLastSection_PointerToRawData: DWORD
mov ofn.lStructSize, sizeof ofn
push hWnd
pop ofn.hwndOwner
push hInstance
pop ofn.hInstance
mov ofn.lpstrFilter, offset szFilterString
mov ofn.lpstrFile, offset szFileName
mov ofn.nMaxFile, MAXSIZE
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER
mov ofn.lpstrTitle, offset szMyTitle
invoke GetOpenFileName, addr ofn
.if eax == 0
jmp Err_CreateFile_Exit
.endif
invoke CreateFile, addr szFileName, GENERIC_READ or GENERIC_WRITE,\
FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox, hWnd, CTEXT("打开文件失败!"), addr szCaption, MB_OK or MB_ICONHAND
jmp Err_CreateFile_Exit
.endif
mov hFile, eax
invoke SetFilePointer, hFile, 3ch, 0, FILE_BEGIN
invoke ReadFile, hFile, addr dwPE_Header_OffSet, 4, addr dwFileReadWritten, NULL
invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, FILE_BEGIN
invoke ReadFile, hFile, addr PE_Header, Head_Len, addr dwFileReadWritten, NULL
;****************************************
;判断是否有效的PE文件,是的话才继续:
;****************************************
.if [PE_Header.Signature] != IMAGE_NT_SIGNATURE
;如果不是有效的PE文件,就给出提示:
invoke MessageBox, hWnd, CTEXT("这不是一个有效的Win32 PE文件!"), addr szCaption, MB_OK or MB_ICONHAND
jmp Exit
.endif
;****************************************
;判断是否有足够空间存储新节:
;****************************************
movzx eax, [PE_Header.FileHeader.NumberOfSections] ;得到添加新节前有多少个节:
mov ecx, 28h ;28h = sizeof IMAGE_SECTION_HEADER
mul ecx ;eax = NumberOfSections * sizeof IMAGE_SECTION_HEADER
add eax, dwPE_Header_OffSet ;eax = eax + PE文件头偏移
add eax, 18h ;18h = sizeof IMAGE_FILE_HEADER
movzx ecx, [PE_Header.FileHeader.SizeOfOptionalHeader]
add eax, ecx ;eax = eax + sizeof IMAGE_OPTIONAL_HEADER
add eax, 28h ;添加一个新节的大小
.if eax > [PE_Header.OptionalHeader.SizeOfHeaders]
;不够的话给出提示:
invoke MessageBox, NULL, CTEXT("没有足够的空间来加入一个新节!"), addr szCaption, MB_OK or MB_ICONHAND
jmp Exit
.endif
;****************************************
;保存原入口,后面要用到:
;****************************************
mov eax, [PE_Header.OptionalHeader.AddressOfEntryPoint]
mov Old_AddressOfEntryPoint, eax
mov eax, [PE_Header.OptionalHeader.ImageBase]
mov Old_ImageBase, eax
;**************************************************
;计算新节的偏移地址:
;(其实跟上面的“判断是否有足够空间存储新节”基本上一样)
;**************************************************
movzx eax, [PE_Header.FileHeader.NumberOfSections]
mov ecx, 28h
mul ecx ;eax = NumberOfSections * sizeof IMAGE_SECTION_HEADER
add eax, 4h ;4h = sizeof "PE\0\0"
add eax, dwPE_Header_OffSet
add eax, sizeof IMAGE_FILE_HEADER
add eax, sizeof IMAGE_OPTIONAL_HEADER
mov dwMySectionOffSet, eax ;现在得到了我们的新节的偏移地址
;****************************************
;填充我们自己的节的信息:
;(这部分请查看PE格式,很容易明白,不多说了)
;****************************************
mov dword ptr [My_Section.Name1], "CL." ;名字就叫做“.LC”吧,呵呵……
mov [My_Section.Misc.VirtualSize], offset vEnd - offset vStart
push [PE_Header.OptionalHeader.SizeOfImage]
pop [My_Section.VirtualAddress]
mov eax, [My_Section.Misc.VirtualSize]
mov ecx, [PE_Header.OptionalHeader.FileAlignment]
cdq
div ecx
inc eax
mul ecx
mov [My_Section.SizeOfRawData], eax ;SizeOfRawData在EXE文件中是对齐到FileAlignMent的整数倍的值
mov eax, dwMySectionOffSet
sub eax, 18h ;这个偏移是定位到最后一节的“SizeOfRawData”
invoke SetFilePointer, hFile, eax, 0, FILE_BEGIN
invoke ReadFile, hFile, addr dwLastSection_SizeOfRawData, 4, addr dwFileReadWritten, NULL
invoke ReadFile, hFile, addr dwLastSection_PointerToRawData, 4, addr dwFileReadWritten, NULL
;每个节的 PointerToRawData 等于它的上一节的 SizeOfRawData + PointerToRawData:
mov eax, dwLastSection_SizeOfRawData
add eax, dwLastSection_PointerToRawData
mov [My_Section.PointerToRawData], eax
mov [My_Section.PointerToRelocations], 0h
mov [My_Section.PointerToLinenumbers], 0h
mov [My_Section.NumberOfRelocations], 0h
mov [My_Section.NumberOfLinenumbers], 0h
mov [My_Section.Characteristics], 0E0000020h ;可读可写可执行
;**************************************************
;重新写入IMAGE_SECTION_HEADER:(包含了新节的信息)
;**************************************************
invoke SetFilePointer, hFile, dwMySectionOffSet, 0, FILE_BEGIN
invoke WriteFile, hFile, addr My_Section, sizeof IMAGE_SECTION_HEADER, addr dwFileReadWritten, NULL
;****************************************
;得到 MessageBoxA 的线性地址:
;****************************************
invoke GetModuleHandle, addr szDllName
invoke LoadLibrary, addr szDllName
invoke GetProcAddress, eax, addr szMessageBoxA
mov MessageBoxA_Addr, eax
;****************************************
;在文件的最后写入我们的新节:
;****************************************
invoke SetFilePointer, hFile, 0, 0, FILE_END
push 0
lea eax, dwFileReadWritten
push eax
push [My_Section.SizeOfRawData]
lea eax, vStart
push eax
push hFile
call WriteFile
;**************************************************
;改写IMAGE_NT_HEADERS,使新节可以首先执行:
;(需要改写 SizeOfImage 和 AddressOfEntryPoint)
;**************************************************
inc [PE_Header.FileHeader.NumberOfSections]
mov eax, [My_Section.Misc.VirtualSize]
mov ecx, [PE_Header.OptionalHeader.SectionAlignment]
cdq
div ecx
inc eax
mul ecx
add eax, [PE_Header.OptionalHeader.SizeOfImage]
mov [PE_Header.OptionalHeader.SizeOfImage], eax ;SizeOfImage是一个对齐到SectionAlignment的整数倍的值
mov eax, [My_Section.VirtualAddress]
mov [PE_Header.OptionalHeader.AddressOfEntryPoint], eax ;现在的 AddressOfEntryPoint 是指向新节的第一条指令
invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, FILE_BEGIN
invoke WriteFile, hFile, addr PE_Header, sizeof IMAGE_NT_HEADERS, addr dwFileReadWritten, NULL
;****************************************
;完成!显示成功信息:
;****************************************
invoke MessageBox, hWnd, CTEXT("添加新节成功!"), addr szCaption, MB_OK or MB_ICONINFORMATION
Exit:
;关闭文件:
invoke CloseHandle, hFile
Err_CreateFile_Exit:
ret
AddNewSection endp
;****************************************
;呵呵,我们自己的东东:
;****************************************
vStart:
call nStart
nStart:
pop ebp
sub ebp, offset nStart ;得到新节在文件中的实际偏移地址
;显示对话框:
push MB_OK or MB_ICONINFORMATION
lea eax, szMyCaption[ebp]
push eax
lea eax, szMyMsg[ebp]
push eax
push 0
call MessageBoxA_Addr[ebp]
;恢复原入口地址。当这个节执行完毕后,就回到了原来的文件入口处继续执行:
mov eax, Old_ImageBase[ebp]
add eax, Old_AddressOfEntryPoint[ebp]
push eax
ret
;变量定义:
MessageBoxA_Addr dd 0
szMyMsg db "为PE文件添加新节显示启动信息", 0
szMyCaption db "LC", 0
Old_ImageBase dd 0
Old_AddressOfEntryPoint dd 0
vEnd:
end main