小弟在网上看到一篇老罗的文章,名叫“为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