我正在尝试完成这个仅用程序集制作的PE文件,它应该在控制台中显示一条消息。我想以这种方式组织它,我可以稍后添加更多的东西(知道在哪里添加代码,数据,导入的函数)。
我创建4个部分现在,为代码,数据,外行数据和导入的元素。我在这个阶段的主要问题是:为程序集中的PE文件创建和使用部分(NASM)
- 节头有些值使可执行文件无效(没有有效的win32)
- 指针从数据部分元素是错误的
- 一些涉及计算的首选的绝对地址,部分对齐和文件对齐可能是错误的
首先,我将显示所有我的代码在下面。有些事情,真的并不重要不会为了节省时间,并使其更容易阅读 这是NASM代码被添加
; Constants (use '$' as prefix)
$SECTION_ALIGNMENT equ 4096 ; Each section is aligned to 4096 in memory
$FILE_ALIGNMENT equ 512 ; Each section is aligned to 512 on disk
$PREFERRED_ADDRESS equ 4194304 ; Preffered address for EXE is 4 MB
$TOTAL_PE_SECTIONS equ 4 ; Code, Data, Bss and IData
; Image size = headers aligned to section alignment + sections size aligned
; to next multiple of section alignment, everything aligned, too
$IMAGE_SIZE equ $SECTION_ALIGNMENT + (HEADERS_SIZE/$SECTION_ALIGNMENT) + \
$TOTAL_PE_SECTIONS * $SECTION_ALIGNMENT
; Will help us align some of the values to the next specified multiple
%define Round(Number, Multiple) Multiple+(Number/Multiple)
section .header progbits vstart=0
; This is the MZ header
DOS_HEADER:
db "MZ" ; MZ signature
; ...
; Here we have all the members of the DOS header, in 4 paragraphs
; ...
db PE_HEADER ; The last one is pointing to the PE header
DOS_STUB:
; ...
; A small DOS program to display a simple message in DOS (64 bytes)
; ...
; This is the PE header
PE_HEADER:
db "PE", 0, 0 ; PE signature
dw 0x014C ; Platform Intel I386
dw $TOTAL_PE_SECTIONS
dd 1371668450 ; Creation timestamp
dd 0 ; No symbols table
dd 0 ; No symbols
dw SECTIONS_TABLE - OPT_HEADER ; Optional header size
dw 0x0002|0x0004|0x0008|0x0100|0x0200 ; Characteristics
; Optional header
OPT_HEADER:
dw 0x010B ; Signature
db 0 ; Linker version
db 0 ; Minor linker version
dd CODE_SIZE
dd DATA_SIZE ; Initialized data size
dd BSS_SIZE ; Uninitiated data size
dd CODE ; Entry point
dd CODE ; Code RVA
dd DATA ; Data RVA
dd $PREFERRED_ADDRESS ; Preferred address in memory
dd $SECTION_ALIGNMENT
dd $FILE_ALIGNMENT
dw 4 ; OS version
dw 0 ; Minor OS version
dw 0 ; Image version
dw 0 ; Minor image version
dw 3 ; Subsystem version
dw 10 ; Minor subsystem version
dd 0 ; WIN32 version
dd $IMAGE_SIZE ; Image size calculated above
dd Round(HEADERS_SIZE, $SECTION_ALIGNMENT) ; Headers size
dd 0 ; Checksum
dw 3 ; System interface CUI
dw 0 ; DLL characteristics
dd 4096 ; Reserved stack
dd 4096 ; Still not ??
dd 65536 ; sure about ??
dd 0 ; these ??
dd 0
dd 2 ; Data directory entries
dd 0 ; Export table pointer
dd 0 ; Export table size
dd I_TABLE ; Import table pointer
dd I_TABLE_S ; Size of import table
dq 0 ; Reserved
SECTIONS_TABLE:
CODE_SECTION_HEADER:
db ".code", 0, 0, 0
dd Round(CODE_SIZE, $SECTION_ALIGNMENT) ; Size in memory
dd CODE
dd Round(CODE_SIZE, $FILE_ALIGNMENT) ; Size on disk
dd Round(0, $FILE_ALIGNMENT) ; Real start address
dd 0
dd 0
dw 0
dw 0
dd 0x00000020|0x20000000|0x40000000|0x80000000
DATA_SECTION_HEADER:
db ".data", 0, 0, 0
dd Round(DATA_SIZE, $SECTION_ALIGNMENT) ; Size in memory
dd $SECTION_ALIGNMENT * 2
dd Round(DATA_SIZE, $FILE_ALIGNMENT) ; Size on disk
dd Round(0, $FILE_ALIGNMENT) ; Real start address
dd 0
dd 0
dw 0
dw 0
dd 0x00000040|0x40000000|0x80000000
BSS_SECTION_HEADER:
db ".bss", 0, 0, 0, 0
dd Round(BSS_SIZE, $SECTION_ALIGNMENT) ; Size in memory
dd $SECTION_ALIGNMENT * 3
dd 0
dd 0
dd 0
dd 0
dw 0
dw 0
dd 0x00000080|0x40000000|0x80000000
IDATA_SECTION_HEADER:
db ".idata", 0, 0
dd Round(IDATA_SIZE, $SECTION_ALIGNMENT) ; Size in memory
dd $SECTION_ALIGNMENT * 4
dd 0
dd Round(0, $FILE_ALIGNMENT) ; Real start address
dd 0
dd 0
dw 0
dw 0
dd 0x00000040|0x40000000|0x80000000
HEADERS_SIZE equ $$ - DOS_HEADER
align 512 ; Align to 512 bytes in memory
section .scode vstart=$SECTION_ALIGNMENT align=16
use32
CODE:
push -11
call dword [$PREFERRED_ADDRESS + F_GetStdHandle]
push 0
push 0x402000
push 6
push $PREFERRED_ADDRESS + hello
push eax
call dword [$PREFERRED_ADDRESS + F_WriteConsole]
push -1
call dword [$PREFERRED_ADDRESS + F_Sleep]
ret
CODE_SIZE equ $$ - CODE
section .sdata vstart=$SECTION_ALIGNMENT*2 progbits align=4
DATA:
hello: db 'Hello!'
DATA_SIZE equ $$ - DATA
section .sbss vstart=$SECTION_ALIGNMENT*3 align=4
BSS:
dd 5
BSS_SIZE equ $$ - BSS
section .sidata vstart=$SECTION_ALIGNMENT*4 align=4
IDATA:
F_Sleep: dd I_Sleep
F_WriteConsole: dd I_WriteConsole
F_GetStdHandle: dd I_GetStdHandle
dd 0
I_TABLE:
.originalfthk dd 0
.timedate dd 0
.forwarder dd 0
.name dd kernel32
.firstthunk dd IDATA
I_TABLE_S equ $$ - I_TABLE
times 20 db 0
kernel32: db 'kernel32.dll', 0
I_Sleep:
dw 0
db 'Sleep', 0
align 2
I_WriteConsole:
dw 0
db 'WriteConsoleA', 0
align 2
I_GetStdHandle:
dw 0
db 'GetStdHandle', 0
IDATA_SIZE equ $$ - IDATA
这里的主要问题是,可执行崩溃,因为从指针代码段是错误的。我正在讨论指向.sdata
的hello消息的指针以及来自.sidata
部分的指向导入函数的指针。如果我将的hello变量和整个内容都复制到.scode
(下面的ret
)中,但它可以工作,但只要我将所有东西都复制到适当的部分,exe就会中断。
所以,看起来地址是错误的计算。从这里开始,在部分标题或其他地方可能有错误的值。你怎么看?
更新:
执行下面的更改后,我现在有一个问题。只要.data
节小于512字节,一切正常。一旦超过了,我会得到'奇怪的无效win32应用程序'错误。
所以,在这里我有2个HTML文件导出PEInfo。这第一个包含工作文件(其中.data
截面小于512个字节)的信息: Working EXE PEInfo
第二个包含腐败EXE,当.data
部分包含多于512个字节的信息:Corrupt EXE PEInfo
也许有人可以发现坠机的不同和原因。
如何将您的文件加载到PE Explorer或其他类似的工具?这应该给你一个关于标题中哪些字段可能不正确的提示。 – Michael
我很久没有做Windows了!有一件事我看到......在你的dos头文件末尾:'db PE_HEADER'。当然这应该是'dd',不是吗?我怀疑这是否是您的问题(?),我同意部分地址可能无法正确计算。我认为迈克尔有一个好主意! (FWIW,使用链接器更容易!) –