问题描述
我一直在尝试掌握 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);
}