コンソールにメッセージが表示されるはずのアセンブリのみで作成されたこの PE ファイルを完成させようとしています。後で簡単に追加できるように整理したいと思います(コード、データ、インポートされた関数を追加する場所を知っています)。
今のところ、code、data、uninitiated data、およびimport elementsの 4 つのセクションを作成しました。この段階での私の主な問題は次のとおりです。
- セクション ヘッダーの一部の値により、実行可能ファイルが無効になります (有効な 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
ここでの主な問題は、コード セクションからのポインタが間違っているために実行可能ファイルがクラッシュすることです。からの hello メッセージへのポインタと、セクション.sdata
からのインポートされた関数へのポインタについて話しているのです。.sidata
hello 変数とコンテンツ全体の両方.sidata
を.scode
(ベローret
) にコピーすると機能しますが、それぞれを適切なセクションにコピーするとすぐに、exe が壊れます。
そのため、住所の計算が間違っているようです。ここから始めて、セクションヘッダーまたは他の場所に間違った値がある可能性があります。どう思いますか?
更新:
以下の変更を実装した後、現在問題があります。.data
セクションが 512 バイト未満である限り、すべて正常に機能します。それを超えると、「奇妙な無効なwin32アプリケーション」エラーが発生します。
したがって、ここではPEInfoによってエクスポートされた 2 つの HTML ファイルがあります。この最初のものには、作業ファイルの情報が含まれています (.data
セクションが 512 バイト未満の場合):
Working EXE PEInfoセクションに 512 バイト以上が含まれている
場合、2 番目のファイルには破損した EXE の情報が含まれます: Corrupt EXE PEInfo.data
誰かがクラッシュの違いと理由を見つけることができるかもしれません。