Я пытаюсь закончить этот файл 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
и указатели на импортированные функции, из раздела .sidata
. Если я скопирую как переменную hello, так и весь контент .sidata
в .scode
(ниже ret
), он работает, но как только я копирую каждую вещь в том, что должно быть ее соответствующим разделом, exe ломается.
Итак, похоже, что адрес просчитан. Начиная с этого места, в заголовках разделов или в другом месте могут быть неправильные значения. Как вы думаете?
UPDATE:
Там проблема у меня сейчас, после реализации изменений ниже. Все работает нормально, пока раздел .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, проще использовать компоновщик!) –