从自定义 PE 文件中的 dll 导入时,无法找到过程入口点 MessageBoxA

问题描述

我一直在尝试掌握 PE 文件格式(只是为了自学一些新东西)并尝试创建一个简单的 .exe,它显示一个消息框然后退出,我使用了 { {3}} 作为基础,然后使用格式中 tinyPE 中的内容构建在其之上。

问题是,当我尝试运行它时,我得到一个 The procedure entry point MessageBoxA Could not be located in the dynamic link library D:\path\to\my\test.exe 弹出窗口(听起来 Windows 试图从 exe 本身导入该函数,但我不明白为什么会这样做)

我尝试重新排列内容并使用标题,但没有任何帮助。我还使用 PE Explorer 检查了导入,但它似乎正确读取了导入并说它应该按预期从 kernel32.dll 导入

这是我的代码

bits 32

align 1,db 0

mz_header:
    dw "MZ"                       ; e_magic
    dw 0                          ; e_cblp
    dw 0                          ; e_cp
    dw 0                          ; e_crlc
    dw 0                          ; e_cparhdr
    dw 0                          ; e_minalloc
    dw 0                          ; e_maxalloc
    dw 0                          ; e_ss
    dw 0                          ; e_sp
    dw 0                          ; e_csum
    dw 0                          ; e_ip
    dw 0                          ; e_cs
    dw 0                          ; e_lsarlc
    dw 0                          ; e_ovno
    times 4 dw 0                  ; e_res
    dw 0                          ; e_oemid
    dw 0                          ; e_oeminfo
    times 10 dw 0                 ; e_res2
    dd pe_header                  ; e_lfanew

pe_header:
    dd "PE"
    dw 0x014C                     ; Machine (Intel 386)
    dw 2                          ; NumberOfSections
    dd 0x4545BE5D                 ; TimeDateStamp
    dd 0                          ; PointerToSymbolTable
    dd 0                          ; NumberOfSymbols
    dw pe_optional_header_size    ; SizeOfOptionalHeader
    dw 0x103                      ; characteristics (no relocations,executable,32 bit)

pe_optional_header:
    dw 0x10B                      ; Magic (PE32)
    db 8                          ; MajorLinkerVersion
    db 0                          ; MinorLinkerVersion
    dd text_size                  ; SizeOfCode
    dd 0                          ; SizeOfInitializedData
    dd 0                          ; SizeOfUninitializedData
    dd _main                      ; AddressOfEntryPoint
    dd text_begin                 ; BaSEOfCode
    dd filesize                   ; BaSEOfData
    dd 0x400000                   ; ImageBase
    dd 1                          ; SectionAlignment
    dd 1                          ; FileAlignment
    dw 4                          ; MajorOperatingSystemVersion
    dw 0                          ; MinorOperatingSystemVersion
    dw 0                          ; MajorImageVersion
    dw 0                          ; MinorImageVersion
    dw 4                          ; MajorSubsystemVersion
    dw 0                          ; MinorSubsystemVersion
    dd 0                          ; Win32VersionValue
    dd filesize                   ; SizeOfImage
    dd header_total_size          ; SizeOfheaders
    dd 0                          ; CheckSum
    dw 2                          ; Subsystem (Win32 GUI)
    dw 0x400                      ; Dllcharacteristics
    dd 0x100000                   ; SizeOfStackReserve
    dd 0x1000                     ; SizeOfStackCommit
    dd 0x100000                   ; SizeOfheapReserve
    dd 0x1000                     ; SizeOfheapCommit
    dd 0                          ; LoaderFlags
    dd 4                          ; NumberOfRvaAndSizes

rva:
    dd 0
    dd 0
    dd import_dir_table
    dd import_dir_table_size
    times 12 dd 0,0              ; This is necessary for a valid executable,probably as padding

pe_optional_header_size equ $ - pe_optional_header

; Section table
text_section:
    db ".text",0           ; Section name
    dd text_size                  ; Size when loaded
    dd header_total_size          ; Adress when loaded
    dd text_size                  ; Size
    dd text_begin                 ; Points to section beginning
    dd 0,0                       ; Pointer to relocations and line numbers
    dw 0,0                       ; Count of relocations and line numbers
    dd 0x60000020                 ; characteristics
rdata_section:
    db ".rdata",0             ; Section name
    dd rdata_size                 ; Size when loaded
    dd rdata_begin                ; Adress when loaded
    dd rdata_size                 ; Size
    dd rdata_begin                ; Points to section beginning
    dd 0,0                       ; Count of relocations and line numbers
    dd 0x40000040                 ; characteristics
    
header_total_size equ $ - $$

; .text section
text_begin:
; Entry function
_main:
    ; try to call the imported function
    push dword 0
    push dword mBox_message + 0x400000 
    push dword 0
    push dword 1
    call [import_adress_table + 0x400000]
    
    mov eax,42
    ret

text_size equ $ - text_begin

; .rdata section
rdata_begin equ $ - $$

import_dir_table:
    dd import_lookup_table                    ; Import lookup table
    dd 0,0                                   ; Timestamp and forwarder chain,unused
    dd kernel32                               ; Name of dll
    dd import_adress_table                    ; Import adress table

    ; Empty entry to signify end of import dir table
    dd 0,0

import_dir_table_size equ $ - import_dir_table

; Like the lookup table,but entries are replaced
; with real adresses of imported functions
import_adress_table:
    dd namehint_table
    dd 0

; Stores DWORD pointers to Name/Hint tables
import_lookup_table:
    dd namehint_table
    dd 0

; Stores a hint (?) and a function name to import
namehint_table:
    db 0,0
    db "MessageBoxA",0   ; Function name
    
; String used to import the kernel32.dll
kernel32:
    db "kernel32.dll",0
    
; Other .rdata stuff

mBox_message:
    db "Hello,World!",0

rdata_size equ $ - rdata_begin
    
filesize equ $ - $$

我使用 NASM 2.15.5 组装它:nasm -f bin -o test.exe test.asm

那么我哪里出错了?提前致谢

解决方法

原来的问题被评论里的RbMm解决了,我错误地导入了kernel32.dll而不是user32.dll(尝试调用ExitProcess时遗留的)

导入正确的库解决了错误,但要使其工作并出现消息框,我必须导入 MessageBoxA 调用的所有函数,要找到这些函数,只需创建一个调用 MessageBoxA 的测试程序,然后查看 MSVC 生成的导入:

#include <winuser.h>
int main()
{
    return MessageBoxA(NULL,"Test",NULL,0);
}