【问题标题】:Windows 10 won't recognize hand-made PE executables that work in WINEWindows 10 无法识别在 WINE 中工作的手工制作的 PE 可执行文件
【发布时间】:2020-12-22 08:41:52
【问题描述】:

我已经(在汇编程序中,没有链接器)制作了一个适用于 x86-64 的 EXE,它在 Linux 下的 Wine 中运行得非常好。这是一个调用 MessageBoxA 和 ExitProcess 的基本 HelloWorld。

Windows 10 无法识别它,提示“此程序无法在您的计算机上执行,请与您的供应商联系以获取适合您计算机的版本”。

我使用 PE 格式阅读器(PE 工具和 CFF Explorer)来分析我的 PE EXE。 PE Optional 标头中的所有数字都与其他工作 EXE(如操作系统版本、子系统版本)中的相同。只有特定于我的文件和部分的那些是不同的。而且 Windows 不会将该文件识别为我的计算机上的可执行文件。

我什至从哪里开始查看 WINdows 错误消息之外的内容?是否有任何工具可以通过比“Bad exe”更具体的错误消息来检查 EXE 的有效性? (这是 xdbg 报告的内容。

在 Wine 上,我能够做到 WINEDEBUG=+all wine my.exe 这给了我关于哪里出了问题的提示,我能够修复它并让它工作。 Windows 中有这样的工具吗?

BITS 64

    falign  equ 1000h   ; section file position modulo
    imageBase   equ 400000h

; MZ header
DOSHDR:
        db  0x4D, 0x5A, 0x90, 0,
        dd  3, 4, 0xFFFF, 0xB8, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0
        dd  PEHDR
        db  0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

    ALIGN   falign, db 33h

    doshdrSize  equ $ - DOSHDR
    
MetaM:              ; MetaBlk for module M
    msg db  "Hello, Ann!", 0
    title   db  "Hello, Anna!", 0
    titlew  dw  42Fh, 44Ah, 0
    msgw    dw  416h, 42Bh, 0
    title2w dw  44Ah, 42Fh, 0

    ALIGN   8, db 0FEh
    MessageBoxA     dq  0
    MessageBoxW     dq  0
    ExitProcess     dq  0

    MessageBoxW0        dq  0   ; a duplicate entry for User32.MessageBoxW
    ALIGN   falign, db 11h

    metamSize       equ $ - MetaM

CodeM:
BEGIN:
    ENTRY:  
        sub rsp, 28h  
        mov rcx, 0       ; hWnd = HWND_DESKTOP
        lea rdx, [imageBase + msg]    ; LPCSTR lpText
        lea r8, [imageBase + title]   ; LPCSTR lpCaption
        mov r9d, 0   ; uType = MB_OK
        mov rax, [imageBase + MessageBoxA]
        call    rax

        mov rcx, 0       ; hWnd = HWND_DESKTOP
        lea rdx, [imageBase + msgw]    ; LPCSTR lpText
        lea r8, [imageBase + titlew]   ; LPCSTR lpCaption
        mov r9d, 0   ; uType = MB_OK
        call    [imageBase + MessageBoxW]

        mov rcx, 0       ; hWnd = HWND_DESKTOP
        lea rdx, [imageBase + msgw]    ; LPCSTR lpText
        lea r8, [imageBase + title2w]   ; LPCSTR lpCaption
        mov r9d, 0   ; uType = MB_OK
        call    [imageBase + MessageBoxW0]

        mov ecx, eax
        call    [imageBase + ExitProcess]
END:

    ALIGN   falign, db 0AAh

    codemSize   equ $ - CodeM

IMPORTS:
    ; DLL names - iterate modules
    user32dll       db  "USER32.DLL", 0
    kernel32dll     db  "KERNEL32.DLL", 0
    
    ; Hint/Name entry - iterate externals
    MessageBoxA_:
        dq  MessageBoxA__
        dq  0
    MessageBoxA__       db  0, 0, "MessageBoxA", 0,
    ExitProcess_    dq  ExitProcess__
        dq  0
    ExitProcess__       db  0, 0, "ExitProcess", 0, 1
    MessageBoxW_:
        dq  MessageBoxW__
        dq  0
    MessageBoxW__       db  0, 0, "MessageBoxW", 0

    ImportsDir:
    ; So this is the Directory, with one entry NOT for every imported DLL,
    ; but rather one entry for every use of an external name by a CP module
    ; that is, if a name is used in N modules, it will have N entries in the directory
        dd  MessageBoxA_, 0, 0, user32dll, MessageBoxA
        dd  ExitProcess_, 0, 0, kernel32dll, ExitProcess
        dd  MessageBoxW_, 0, 0, user32dll, MessageBoxW0
        dd  MessageBoxW_, 0, 0, user32dll, MessageBoxW
        dd  0, 0, 0, 0, 0
    directorySize   equ $ - ImportsDir
    
    importsSize equ $ - IMPORTS
    
PEHDR:
        db  "PE", 0, 0  ; signature
        dw  8664h   ; machine
        dw  3   ; # of sections
        dd  0   ; timedatestamp
        dd  0   ; pointer to symtab - deprecated
        dd  0   ; # symtab entries
        dw  opthdrSize  ; size of optional header
        dw  203h    ; flags - characteristics
        
OPTHDR:
        dw  20Bh    ; magic
        db  0   ; maj linker ver
        db  1   ; minor linker ver
        dd  codemSize   ; total code size
        dd  metamSize   ; total init data size
        dd  0   ; total uninit data size
        dd  ENTRY   ; entrypoint RVA    
        dd  ENTRY   ; base of code
        
        dq  imageBase   ; image base
        
        dd  1000h   ; section address alignment
        dd  falign  ; section pos alignment
        dw  5   ; major OS version
        dw  2   ; minor OS version
        dw  0   ; major image ver
        dw  1   ; minor image ver
        dw  5   ; major subsystem ver
        dw  2   ; minor subsystem ver
        dd  0   ; win32 version value = 0
        dd  fileSize    ; size of image - that is, in memory!
        dd  ((doshdrSize + pehdrSize) + falign - 1) / falign * falign
                ; size of headers
        dd  0   ; checksum
        dw  2   ; subsystem: GUI = 2, CUI =3, NATIVE = 1
        dw  0   ; dll characteristics
        dq  1000000h    ; max stack
        dq  1000h   ; min stack
        dq  1000000h    ; max heap
        dq  1000h   ; min heap
        dd  0   ; loader flag = 0
    ; Directories
        dd  2   ; number of directories
        ; export table hdr
        dd  0, 0
        ; import table hdr
        dd  ImportsDir  ; addr of import table
        dd  directorySize   ; size of import table
    ;times 14   dq  0   ; end of directories
    opthdrSize  equ $ - OPTHDR
    pehdrSize   equ $ - PEHDR

    Sections:
        ; MetaM
        db  "F", 0, 0, 0, 0 ; null name
        dd  metamSize   ; size
        dd  MetaM   ; addr RVA
        dd  metamSize   ; length
        dd  MetaM   ; pos
        dd  0   ; no relocations
        dd  0   ; no linenum
        dw  0
        dw  0
        dd  0C0000040h  ; flags: datasection writeable readable
        ; CodeM
        db  "W", 0  ; null name
        dd  codemSize   ; size
        dd  CodeM   ; addr RVA
        dd  codemSize   ; length
        dd  CodeM   ; pos
        dd  0   ; no relocations
        dd  0   ; no linenum
        dw  0
        dw  0
        dd  0E0000020h  ; flags: codesection writeable readable executable
        ; IMPORTS
        db  ".idata", 0, 0
        dd  importsSize ; size
        dd  IMPORTS ; addr RVA
        dd  importsSize ; length
        dd  IMPORTS ; pos
        dd  0   ; no relocations
        dd  0   ; no linenum
        dw  0
        dw  0
        dd  0E0000020h  ; flags: codesection writeable readable executable
    
    fileSize    equ $
;END:

【问题讨论】:

  • 我不知道这是否适用,但last 时我看到 Windows 无法加载 exe,它需要一个 RDATA 部分(即使它没有使用)。跨度>
  • 嗯.. 我只是能够制作另一个没有重定位的 .exe(使用 nasm + golink)=> 没有 RDATA,并且在 Windows 10 和 Wine 下都运行得很好。我也重新拥有 16 个目录,而不仅仅是我需要的 2 个。无济于事。
  • 您在 Optional 标头中仅声明了两个数据目录,但 PE 通常有 16 个(尽管其中大多数是零)。我怀疑 Windows 加载程序在尝试将 MessageBoxA 和 ExitProcess 的 VA 绑定到 ImportAddress 表时失败,并且它发现 IAT 根本不存在于您的 PE 中..
  • 在上一条评论中,我提到我已经回到了其中的 16 个目录中,但这并没有帮助。我还将 PE 标头移回文件中,并将其放在 DOS 存根之后 - 就像大多数 exe 一样,并重新排列导入部分以仅引用每个模块一次。现在 Windows 不会给出该消息。相反,应用程序会静默失败。在 x64dbg 中,我发现 Windows 加载了我的 exe,但没有链接它。一直以来,Wine 都执行了我尝试过的每一个符号 PE 布局,并成功链接并运行了我的 exe。

标签: assembly windows-10 portable-executable wine


【解决方案1】:

这里有很多问题。您说这段代码在 wine 上运行的事实表明 wine非常 宽容。视窗?没那么多。

首先,这是我正在使用的构建命令(基于上面 OP 的原始代码):nasm.exe org.asm -o org.exe

对 org.exe 使用 dumpbin(来自 VS2019)给我们:

File Type: EXECUTABLE IMAGE
org.exe : fatal error LNK1107: invalid or corrupt file: cannot read at 0x31DE

不是一个充满希望的开始。我做的第一件事(有所作为)是在Sections:中更改此代码

; MetaM
db  "F", 0, 0, 0, 0 ; null name

...

; CodeM
db  "W", 0  ; null name

按照规范,它们应该是 8 个字节长,而不仅仅是以空字符结尾的字符串。更改了这些,现在 dumpbin 给了我:

File Type: EXECUTABLE IMAGE

  Summary

        1000 .idata
        1000 CodeM
        1000 MetaM

更好。我的下一步是dumpbin /headers a.exe,它给了我:

LINK : fatal error LNK1000: Internal error during ReadOptionalHeader

通过取消注释目录下的行来解决此问题:times 14 dq 0

我不会发布整个 dumpbin 输出,但我只想说它现在显示了所有部分的标题。

接下来是查看dumpbin /imports a.exe。不是对每个 dll 的所有导入进行分组,而是在此处为每个导入提供了自己的部分。这不可能。所以我修复了 iData 部分。我也修复了对齐问题。可能还有很多其他问题需要修复,但至少现在它可以运行了:

BITS 64

    falign  equ 200h   ; section file position modulo
    imageBase   equ 400000h

; MZ header
DOSHDR:
        db  0x4D, 0x5A, 0x90, 0,
        dd  3, 4, 0xFFFF, 0xB8, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0
        dd  PEHDR
        db  0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

    ALIGN   falign, db 33h

    doshdrSize  equ $ - DOSHDR
    
MetaM:              ; MetaBlk for module M
    msg db  "Hello, Ann!", 0
    title   db  "Hello, Anna!", 0
    titlew  dw  42Fh, 44Ah, 0
    msgw    dw  416h, 42Bh, 0
    title2w dw  44Ah, 42Fh, 0

    ALIGN   8, db 0FEh

    ALIGN   falign, db 11h

    metamSize       equ $ - MetaM

CodeM:
BEGIN:
    ENTRY:  
        sub rsp, 28h  
        mov rcx, 0       ; hWnd = HWND_DESKTOP
        lea rdx, [imageBase + msg]    ; LPCSTR lpText
        lea r8, [imageBase + title]   ; LPCSTR lpCaption
        mov r9d, 0   ; uType = MB_OK
        mov rax, [imageBase + MessageBoxA]
        call    rax

        mov ecx, eax
        call    [imageBase + ExitProcess]
END:

    ALIGN   falign, db 0AAh

    codemSize   equ $ - CodeM

;========
IMPORTS:
    ; Import Address Table
    ExitProcess    dq ExitProcess__
    MessageBoxA    dq MessageBoxA__
    MessageBoxW    dq MessageBoxW__
    dq 0

    ImportsDir:
        dd  ExitProcess_, 0, 0, kernel32dll, ExitProcess
        dd  MessageBoxA_, 0, 0, user32dll, MessageBoxA
        dd  0, 0, 0, 0, 0
    directorySize   equ $ - ImportsDir

    ; Import Lookup Table
    ExitProcess_ dq ExitProcess__
    dq 0

    ; Hint/Name entry - iterate externals
    ExitProcess__       db  64h, 1, "ExitProcess", 0
    dq 0

    MessageBoxA_ dq MessageBoxA__
    MessageBoxW_ dq MessageBoxW__
    dq 0

    MessageBoxA__  db 0, 0, "MessageBoxA", 0
    MessageBoxW__  db 0, 0, "MessageBoxW", 0
    dq 0

    kernel32dll   db  "KERNEL32.dll", 0
    user32dll     db  "USER32.dll", 0
    
    importsSize equ $ - IMPORTS
;========
   ALIGN 16 
PEHDR:
        db  "PE", 0, 0  ; signature
        dw  8664h   ; machine
        dw  3   ; # of sections
        dd  0   ; timedatestamp
        dd  0   ; pointer to symtab - deprecated
        dd  0   ; # symtab entries
        dw  opthdrSize  ; size of optional header
        dw  203h    ; flags - characteristics
        
OPTHDR:
        dw  20Bh    ; magic
        db  0   ; maj linker ver
        db  1   ; minor linker ver
        dd  codemSize   ; total code size
        dd  metamSize   ; total init data size
        dd  0   ; total uninit data size
        dd  ENTRY   ; entrypoint RVA    
        dd  ENTRY   ; base of code
        
        dq  imageBase   ; image base
        
        dd  falign   ; section address alignment
        dd  falign  ; section pos alignment
        dw  5   ; major OS version
        dw  2   ; minor OS version
        dw  0   ; major image ver
        dw  1   ; minor image ver
        dw  5   ; major subsystem ver
        dw  2   ; minor subsystem ver
        dd  0   ; win32 version value = 0
        dd  fileSize    ; size of image - that is, in memory!
        dd  ((doshdrSize + pehdrSize) + falign - 1) / falign * falign
                ; size of headers
        dd  0   ; checksum
        dw  2   ; subsystem: GUI = 2, CUI =3, NATIVE = 1
        dw  0   ; dll characteristics
        dq  1000000h    ; max stack
        dq  1000h   ; min stack
        dq  1000000h    ; max heap
        dq  1000h   ; min heap
        dd  0   ; loader flag = 0
    ; Directories
        dd  16   ; number of directories
        ; export table hdr
        dd  0, 0
        ; import table hdr
        dd  ImportsDir  ; addr of import table
        dd  directorySize   ; size of import table
    dd 0, 0
    dd 0, 0
    dd 0, 0
    dd 0, 0
    dd 0, 0
    dd 0, 0
    dd 0, 0
    dd 0, 0
    dd 0, 0
    dd 0, 0
        dd ExitProcess, 8 * 3
    dd 0, 0
    dd 0, 0
    dd 0, 0
    opthdrSize  equ $ - OPTHDR
    pehdrSize   equ $ - PEHDR

    Sections:
        ; MetaM
        db  "MetaM", 0, 0, 0 ; null name
        dd  metamSize   ; size
        dd  MetaM   ; addr RVA
        dd  metamSize   ; length
        dd  MetaM   ; pos
        dd  0   ; no relocations
        dd  0   ; no linenum
        dw  0
        dw  0
        dd  0C0000040h  ; flags: datasection writeable readable
        ; CodeM
        db  "CodeM", 0, 0, 0  ; null name
        dd  codemSize   ; size
        dd  CodeM   ; addr RVA
        dd  codemSize   ; length
        dd  CodeM   ; pos
        dd  0   ; no relocations
        dd  0   ; no linenum
        dw  0
        dw  0
        dd  0E0000020h  ; flags: codesection writeable readable executable
        ; IMPORTS
        db  ".idata", 0, 0
        dd  importsSize ; size
        dd  IMPORTS ; addr RVA
        dd  importsSize ; length
        dd  IMPORTS ; pos
        dd  0   ; no relocations
        dd  0   ; no linenum
        dw  0
        dw  0
        dd  0E0000020h  ; flags: codesection writeable readable executable
    
    fileSize    equ $
;END:

现在它正在工作,我会把清理工作留给你。告诉安我打过招呼......


更新:

所以我做了一些清理工作。

  • 更多文档
  • 更少的硬编码值(尽可能计算)
  • 在文件中使用 512 字节对齐(较小的图像大小),同时仍使用 4k 页面(以允许页面保护)。因此,不同的字段使用不同的偏移量。

FWIW

; Check for NASM version at least 2.15.05
%if __?NASM_VERSION_ID?__ < 0x0020F0500
%error "Newer version of nasm required"
%endif

%define RoundTo(a, b) ((((a) + ((b) - 1)) / (b)) * (b))
%define Stringify(&val) val

%macro NameEntry 2
%1__  dw %2
db Stringify(%1), 0
%endmacro

salign    equ 1000h   ; Page size in memory
falign    equ 200h    ; Page size in file
imageBase equ 400000h ; Requested load address

BITS 16

section headers start=0
startoffile:

    ; MZ header https://wiki.osdev.org/MZ
    dw  "MZ"                        ; Signature
    dw (dosBlkSize - mzStructSize) % 512  ; Bytes on last page
    dw RoundTo(dosBlkSize, 512) / 512     ; # of 512 byte pages
    dw 0                            ; Relocation items
    dw RoundTo(mzStructSize, 16) / 16 ; Header size in paragraphs
    dw 0                            ; Minimum allocation
    dw 0xffff                       ; Maximum allocation in paragraphs (1M).
    dw 0                            ; Initial SS
    dw 0xb8                         ; Initial SP
    dw 0                            ; Checksum
    dw 0                            ; Initial IP
    dw 0                            ; Initial CS
    dw 0                            ; Relocation table
    dw 0                            ; Overlay
    dq 0                            ; Reserved
    dw 0                            ; OEM identifier
    dw 0                            ; OEM info
    times 20 db 0                   ; Reserved
    dd PEHDR                        ; PE header start

mzStructSize  equ $ - $$ ; aka 64

dosstartcode:   ; Print the error and exit
    push cs
    pop  ds
    mov  dx, dosmsg - dosstartcode
    mov  ah, 0x9
    int  0x21       ; Show string up to '$'
    mov  ax, 4c01h
    int  0x21       ; Exit process with error code 1

    dosmsg db `This program cannot be run in DOS mode.\r\r\n$`

dosBlkSize  equ $ - $$

ALIGN 16

; From https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
PEHDR:
    dd  "PE"            ; signature
    dw  8664h           ; machine x64
    dw  SectionsCount   ; # of sections
    dd  __POSIX_TIME__  ; timedatestamp
    dd  0               ; pointer to symtab - deprecated
    dd  0               ; # symtab entries
    dw  opthdrSize      ; size of optional header
    dw  2h              ; flags: Executable
       
OPTHDR:
    dw  20Bh            ; magic
    db  0               ; maj linker ver
    db  0               ; minor linker ver
    dd  codeSizeS       ; total memory code size
    dd  rdataSizeS      ; total memory init data size
    dd  0               ; total uninit data size
    dd  ENTRY           ; entrypoint RVA   
    dd  section..text.start ; base of code in file
    dq  imageBase       ; image base
    dd  salign          ; section address alignment
    dd  falign          ; section pos alignment
    dw  10              ; major OS version
    dw  0               ; minor OS version
    dw  0               ; major image ver
    dw  1               ; minor image ver
    dw  6               ; major subsystem ver
    dw  2               ; minor subsystem ver
    dd  0               ; win32 version value = 0
    dd  fileSize        ; size of image in memory
    dd  headersSizeF    ; size of DOS stub + PE header + sections
    dd  0               ; checksum
    dw  2               ; subsystem: GUI
    dw  8160h           ; dll characteristics: HighEntropy, Relocatable, NX, TS aware
    dq  100h            ; max stack
    dq  100h            ; min stack
    dq  100h            ; max heap
    dq  100h            ; min heap
    dd  0               ; loader flag

HeaderDirectories:
    dd  HeaderDirectoryCount   ; number of directories
       
    ; Address, Size
    dd  0, 0                        ; Export
    dd ImportsDir, ImportsDirSize   ; Import
    dd 0, 0                         ; Resource
    dd 0, 0                         ; Exception
    dd 0, 0                         ; Certificates
    dd 0, 0                         ; Base Relocation
    dd 0, 0                         ; Debug
    dd 0, 0                         ; Architecture
    dd 0, 0                         ; Global Pointer
    dd 0, 0                         ; Thread Storage
    dd 0, 0                         ; Load Configuration
    dd 0, 0                         ; Bound Import
    dd IATStart, IATSize            ; Import Address Table
    dd 0, 0                         ; Delay Import
    dd 0, 0                         ; COM Descriptor
    dd 0, 0                         ; Reserved

HeaderDirectorySize equ $ - HeaderDirectories
HeaderDirectoryCount equ HeaderDirectorySize / 8

opthdrSize  equ $ - OPTHDR

startOfSections:

    dq  ".text"
    dd  codeSizeS           ; size in memory pages
    dd  ENTRY               ; addr RVA (memory offset)
    dd  codeSize            ; length
    dd  section..text.start ; pos (file offset)
    dd  0           ; relocations addr
    dd  0           ; linenum addr
    dw  0           ; relocations count
    dw  0           ; linenum count
    dd  030000020h  ; flags: Code, Shared, Execute Only

    dq  ".rdata"
    dd  rdataSizeS              ; size in memory pages
    dd  RDATA                   ; addr RVA (memory offset)
    dd  rdataSize               ; length
    dd  section.rdata.start     ; pos (file offset)
    dd  0           ; relocations addr
    dd  0           ; linenum addr
    dw  0           ; relocations count
    dw  0           ; linenum count

    ; Take advantage of the fact that the loader cheats and 
    ; writes imports to readonly pages @ startup
    dd  040000040h  ; flags: Initialized Data, Read Only

SectionsSize equ $ - startOfSections
SectionsCount equ SectionsSize / 40
   
ALIGN 16
headersSizeF equ RoundTo($ - $$, falign)
headersSizeS equ RoundTo($ - $$, salign)

BITS 64

DEFAULT REL ; so we don't have to keep adding imageBase

SECTION .text vstart=headersSizeS align=falign follows=headers

    ENTRY: 
        sub rsp, 28h 
        xor ecx, ecx      ; hWnd = HWND_DESKTOP
        lea rdx, [msg]    ; LPCSTR lpText
        lea r8, [title]   ; LPCSTR lpCaption
        xor r9d, r9d      ; uType = MB_OK
        call [MessageBoxA]

        ; The return value from MessageBoxA may not be what you think
        mov ecx, eax
        call [ExitProcess]

codeSize   equ $ - $$
codeSizeS  equ RoundTo(codeSize, salign)

SECTION rdata vstart=headersSizeS+codeSizeS align=falign

RDATA:

IATStart:

; Import Address Table
Kernel32TableA:
    ExitProcess    dq ExitProcess__

User32TableA:
    MessageBoxA    dq MessageBoxA__
    MessageBoxW    dq MessageBoxW__

IATSize equ $ - IATStart

ImportsDir:
    dd  Kernel32TableL, 0, 0, kernel32dll, Kernel32TableA
    dd  User32TableL, 0, 0, user32dll, User32TableA

ImportsDirSize   equ $ - ImportsDir

; Kernel32 Import Lookup Table
Kernel32TableL:
    dq ExitProcess__
    dq 0 ; end of table marker

; Name, Hint
NameEntry ExitProcess, 164h

; User32 Import Lookup Table
User32TableL:
    dq MessageBoxA__
    dq MessageBoxW__
    dq 0 ; end of table marker

; Name, Hint
NameEntry MessageBoxA, 28fh
NameEntry MessageBoxW, 28ch

kernel32dll   db  "KERNEL32.dll", 0
user32dll     db  "USER32.dll", 0

; Constant data
msg     db  "Hello, Ann!", 0
title   db  "Hello, Anna!", 0

ALIGN 16
rdataSize equ $ - RDATA
rdataSizeS equ RoundTo(rdataSize, salign)

fileSize equ RDATA + rdataSizeS

【讨论】:

  • 应该是 8 字节长的字段可以使用 dq "CodeM" 或任何使 NASM 用零填充最多 8 个字节的倍数。 (NASM 使字符串/多字符文字按照您通常希望的方式工作,这与 MASM 或 GAS 非常不同。)
  • 大卫,感谢您的工作!我会告诉安...现在,部分名称 - 我有 8 个字节长,但取出一些字节用于发布)。感谢您对 dumpbin 的引用 - 虽然它是一个巨大的软件包的一部分,但如果我将来需要它,我会看看。我发现关键问题是我自己的遗漏 - 字段 imageSize 应该是页面对齐的,但事实并非如此。一旦我弄清楚并解决了这个问题,一切就开始工作了。
  • 另外,你是对的:我的导入不是按 DLL 列出的,而是按符号列出的——每个符号都有自己的部分。这适用于 Wine 和 Windows。这样做的原因是我不需要集中式 IAT,而是在一个 PE 中需要多个 IAT,并且这些符号不是按 DLL 排序的。 IAT 唯一未记录的要求是它的第一个条目必须是非零。如果第一个 IAT 条目为零,则它不链接,即使第一个 ILT 条目不为零。
  • 我现在确实使用了 16 个目录;但是 MS 规范不需要 16。但事实上,如果我有 2,它将不会运行 exe。我在某处读到 .NET 可执行文件将有 2 个目录。在 Linux 上,file 将我的 2 目录 exe 识别为 .NET 文件。
  • 还有其他用于检查 PE 图像的实用程序,但 DumpBin 是 MS 的官方工具。由于您的问题是加载(与执行),因此我们需要查看文件/节标题。我将您的程序与可比较的 exe 进行了比较,在它起作用之前进行了更改。不需要 16 个目录,但似乎您至少需要 7 个(调试目录),我认为至少需要 13 个(IAT)。不确定您打算如何说服加载程序填充多个 iats?
【解决方案2】:

我想发布可在 Wine 和 Windows 10 中运行的最终版本。简而言之,这就是问题所在:

  1. 图像大小字段未对齐。必须是页面对齐的 (1000h)。我的错。
  2. 错误计算的标头大小。规范差。这帮助我弄清楚了,而不是规范:PE format walkthru
  3. 拥有 2 个目录不起作用,认为这与规范不矛盾。我没有尝试除 16 以外的数字。规格不佳。顺便说一下,目录中的 IAT 是无关紧要的;事实上,如果你导入 2 个 DLL,每个都会得到和 IAT;应该在目录中引用哪一个?答:装载机不在乎。
  4. IAT 的第一个条目必须为非零,否则此 IAT 将被忽略且不填写。这是非常无证的。规格不佳。

积极的一面,

  1. 我能够将 PE 标头和节列表放在文件末尾,这与通常将其放置在 DOS 存根之后和节之前不同。
  2. 我能够以一种有点奇怪的方式组织导入,每个导入的符号一个 IAT,而不是每个 DLL 一个 IAT。 在这两个问题中,我和加载程序都遵循规范的字母,这是一件好事。
BITS 64
; nasm -f bin -o pe.exe pe.asm && chmod +x pe.exe && ./pe.exe

    salign  equ 1000h   ; section file position modulo
    falign  equ 1000h   ; section file position modulo
    imageBase   equ 400000h

; MZ header
DOSHDR:
        db  0x4D, 0x5A, 0x90, 0,
        dd  3, 4, 0xFFFF, 0xB8, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0
        dd  PEHDR
        db  0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

    ALIGN   8, db 0FFh
    doshdrSize  equ $ - DOSHDR

    ALIGN   falign, db 55h
MetaM:              ; MetaBlk for module M
    msg db  "Hello, Ann!", 0
    title   db  "Hello, Anna!", 0
    titlew  dw  42Fh, 44Ah, 0
    msgw    dw  416h, 42Bh, 0
    title2w dw  44Ah, 42Fh, 0

    ALIGN   8, db 0FEh
    MessageBoxA     dq  01
    MessageBoxW     dq  01
    ExitProcess     dq  01

    MessageBoxW0        dq  01  ; a duplicate entry for User32.MessageBoxW

    ALIGN   falign, db 11h
    metamSize       equ $ - MetaM

CodeM:
BEGIN:
    ENTRY:  
    ; for PROXIES instead of IAT
        sub rsp, 28h  
        mov rcx, 0       ; hWnd = HWND_DESKTOP
        lea rdx, [imageBase + msg]    ; LPCSTR lpText
        lea r8, [imageBase + title]   ; LPCSTR lpCaption
        mov r9d, 0   ; uType = MB_OK
        mov rax, [imageBase + MessageBoxA]
        call    rax

        mov rcx, 0       ; hWnd = HWND_DESKTOP
        lea rdx, [imageBase + msgw]    ; LPCSTR lpText
        lea r8, [imageBase + titlew]   ; LPCSTR lpCaption
        mov r9d, 0   ; uType = MB_OK
        call    [imageBase + MessageBoxW]

        mov rcx, 0       ; hWnd = HWND_DESKTOP
        lea rdx, [imageBase + msgw]    ; LPCSTR lpText
        lea r8, [imageBase + title2w]   ; LPCSTR lpCaption
        mov r9d, 0   ; uType = MB_OK
        call    [imageBase + MessageBoxW]

        mov ecx, eax
        call    [imageBase + ExitProcess]
END:

    ALIGN   falign, db 0AAh
    codemSize   equ $ - CodeM

IMPORTS:
    
    ImportsDir:
    ; So this is the Directory, with one entry NOT for every imported DLL,
    ; but rather one entry for every use of an external name by a CP module
    ; that is, if a name is used in N modules, it will have N entries in the directory
        dd  MessageBoxA_, 0, 0, user32dll, MessageBoxA
        dd  ExitProcess_, 0, 0, kernel32dll, ExitProcess
        dd  MessageBoxW_, 0, 0, user32dll, MessageBoxW0
        dd  MessageBoxW_, 0, 0, user32dll, MessageBoxW
        dd  0, 0, 0, 0, 0
    directorySize   equ $ - ImportsDir
    
    ; DLL names - iterate modules
    user32dll       db  "USER32.DLL", 0
    kernel32dll     db  "KERNEL32.DLL", 0
    
    ; Hint/Name entry - iterate externals
    MessageBoxA_:
        dq  MessageBoxA__
        dq  0
    MessageBoxA__       db  0, 0, "MessageBoxA", 0
    ExitProcess_    dq  ExitProcess__
        dq  0
    ExitProcess__       db  0, 0, "ExitProcess", 0
    MessageBoxW_:
        dq  MessageBoxW__
        dq  0
    MessageBoxW__       db  0, 0, "MessageBoxW", 0
    
    
    importsSize equ $ - IMPORTS
    
            ALIGN   8, db 99h
    
PEHDR:
        db  "PE", 0, 0  ; signature
        dw  8664h   ; machine
        dw  3   ; # of sections
        dd  0   ; timedatestamp
        dd  0   ; pointer to symtab - deprecated
        dd  0   ; # symtab entries
        dw  opthdrSize  ; size of optional header
        dw  203h    ; flags - characteristics
        
OPTHDR:
        dw  20Bh    ; magic
        db  0   ; maj linker ver
        db  1   ; minor linker ver
        dd  codemSize   ; total code size
        dd  metamSize   ; total init data size
        dd  0   ; total uninit data size
        dd  ENTRY   ; entrypoint RVA    
        dd  ENTRY   ; base of code
        
        dq  imageBase   ; image base
        
        dd  1000h   ; section address alignment
        dd  falign  ; section pos alignment
        dw  5   ; major OS version
        dw  1   ; minor OS version
        dw  0   ; major image ver
        dw  1   ; minor image ver
        dw  5   ; major subsystem ver
        dw  0   ; minor subsystem ver
        dd  0   ; win32 version value = 0
        dd  4000h       ;(*(fileSize + salign - 1) / salign * salign*)
                ; imageSize - that is, in memory!
        dd  salign
                ; size of headers
        dd  0   ; checksum
        dw  2   ; subsystem: GUI = 2, CUI =3, NATIVE = 1
        dw  0   ; dll characteristics
        dq  1000000h    ; max stack
        dq  1000h   ; min stack
        dq  1000000h    ; max heap
        dq  1000h   ; min heap
        dd  0   ; loader flag = 0
    ; Directories
        dd  16  ; number of directories
        ; export table hdr
        dd  0, 0
        ; import table hdr
        dd  ImportsDir  ; addr of import table
        dd  directorySize   ; size of import table
    times 14    dd  0, 0    ; empty directories
    ;   dd  kernel32IAT ; IATs
    ;   dd  5 * 8
    ;times 3    dd  0, 0    ; empty directories
    opthdrSize  equ $ - OPTHDR
    pehdrSize   equ $ - PEHDR

    Sections:
        ; MetaM
        db  "F***", 0, 0, 0, 0  ; null name
        dd  metamSize   ; size
        dd  MetaM   ; addr RVA
        dd  metamSize   ; length
        dd  MetaM   ; pos
        dd  0   ; no relocations
        dd  0   ; no linenum
        dw  0
        dw  0
        dd  0C0000040h  ; flags: datasection writeable readable
        ; CodeM
        db  "Windows", 0    ; null name
        dd  codemSize   ; size
        dd  CodeM   ; addr RVA
        dd  codemSize   ; length
        dd  CodeM   ; pos
        dd  0   ; no relocations
        dd  0   ; no linenum
        dw  0
        dw  0
        dd  0E0000020h  ; flags: codesection writeable readable executable
        ; IMPORTS
        db  ".idata", 0, 0
        dd  importsSize ; size
        dd  IMPORTS ; addr RVA
        dd  importsSize ; length
        dd  IMPORTS ; pos
        dd  0   ; no relocations
        dd  0   ; no linenum
        dw  0
        dw  0
        dd  0E0000020h  ; flags: codesection writeable readable executable

    
    fileSize    equ $

;END.

附:我觉得很奇怪,编程中的一个事实标准是使用颜色来突出显示语法,而不是使用颜色来突出显示含义。甚至没有黑体/斜体。所以,我希望我可以对源代码中的关键部分进行着色或加粗——唉,这是不可能的。在我的编程环境 - BlackBox Component Builder - 我可以随意使用我想要的颜色和粗体/斜体:

【讨论】:

  • 很高兴您找到了适合您的解决方案。我相信我在此处发布的(更新的)代码有一些好处:更小的可执行文件,需要更少的内存页面,更清楚所有值的含义(因为它们是计算的,而不仅仅是硬编码)等等。但是你比我更了解你的需求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-16
  • 2015-10-24
  • 2015-01-27
  • 1970-01-01
  • 1970-01-01
  • 2018-09-06
相关资源
最近更新 更多