I have 64 bit manually-generated PE executable. I need to load two libraries kernel32.dll
and user.dll
. It gives the first error.
If I have only one library (this would be kernel32.dll
) I get the second error. Is there any way to get another error.
Is there any way to get all libraries correct? Bear in mind that code is ported from 32bit executable. You can see the code below.
bits 64
BASE equ 400000h
ALIGNMENT equ 512
%define SECTALIGN 4096
STD_OUTPUT_HANDLE equ -11
NULL equ 0
%define ROUND(v, a) (((v + a - 1) / a) * a)
%define ALIGNED(v) (ROUND(v, ALIGNMENT))
%define RVA(obj) (obj - BASE)
section header progbits start=0 vstart=BASE
mz_hdr:
dw "MZ" ; DOS magic
times 0x3a db 0 ; [UNUSED] DOS header
dd RVA(pe_hdr) ; address of PE header
pe_hdr:
dw "PE",0 ; PE magic + 2 padding bytes
dw 0x8664 ; i386 architecture
dw 2 ; two sections
dd __POSIX_TIME__ ; [UNUSED] timestamp
dd 0 ; [UNUSED] symbol table pointer
dd 0 ; [UNUSED] symbol count
dw OPT_HDR_SIZE ; optional header size
dw 0x0002 ; characteristics: 32-bit, executable
opt_hdr:
dw 0x020b ; optional header magic
db 13,37 ; [UNUSED] linker version
dd ALIGNED(S_TEXT_SIZE) ; [UNUSED] code size
dd ALIGNED(S_IDATA_SIZE) ; [UNUSED] size of initialized data
dd 0 ; [UNUSED] size of uninitialized data
dd RVA(section..text.vstart) ; entry point address
dd RVA(section..text.vstart) ; [UNUSED] base of code
dd RVA(section..idata.vstart) ; [UNUSED] base of data
dq BASE ; image base
dd SECTALIGN ; section alignment
dd ALIGNMENT ; file alignment
dw 4,0 ; [UNUSED] OS version
dw 0,0 ; [UNUSED] image version
dw 4,0 ; subsystem version
dd 0 ; [UNUSED] Win32 version
dd RVA(the_end) ; size of image
dd ALIGNED(ALL_HDR_SIZE) ; size of headers
dd 0 ; [UNUSED] checksum
dw 3 ; subsystem = console
dw 0 ; [UNUSED] DLL characteristics
dq 0x0010000000000000 ; [UNUSED] maximum stack size
dq 0x0000100000000000 ; initial stack size
dq 0x0010000000000000 ; maximum heap size
dq 0x0000100000000000 ; [UNUSED] initial heap size
dd 0 ; [UNUSED] loader flags
dd 16 ; number of data directory entries
dd 0,0 ; no export table
dd RVA(import_table) ; import table address
dd IMPORT_TABLE_SIZE ; import table size
times 14 dd 0,0 ; no other entries in the data directories
OPT_HDR_SIZE equ $ - opt_hdr
sect_hdr_text:
db ".text",0,0,0 ; section name
dd ALIGNED(S_TEXT_SIZE) ; virtual size
dd RVA(section..text.vstart) ; virtual address
dd ALIGNED(S_TEXT_SIZE) ; file size
dd section..text.start ; file position
dd 0,0 ; no relocations or debug info
dw 0,0 ; no relocations or debug info
dd 0x60000020 ; flags: code, readable, executable
sect_hdr_idata:
db ".idata",0,0 ; section name
dd ALIGNED(S_IDATA_SIZE) ; virtual size
dd RVA(section..idata.vstart) ; virtual address
dd ALIGNED(S_IDATA_SIZE) ; file size
dd section..idata.start ; file position
dd 0,0 ; no relocations or debug info
dw 0,0 ; no relocations or debug info
dd 0xC0000040 ; flags: data, readable, writeable
ALL_HDR_SIZE equ $ - $$
;;;;;;;;;;;;;;;;;;;; .text ;;;;;;;;;;;;;;;;;
section .text progbits follows=header align=ALIGNMENT vstart=BASE+SECTALIGN*1
s_text:
; set up stack frame for *lpBytesWritten
; push STD_OUTPUT_HANDLE
; call [GetStdHandle]
; push NULL
; push buffer
; push message_size
; push message
; push eax
; call [WriteConsoleA]
push rbp
mov rbp, rsp
sub rsp, 40
push 0
call [ExitProcess]
mov rsp, rbp
pop rbp
ret
S_TEXT_SIZE equ $ - s_text
;;;;;;;;;;;;;;;;;;;; .idata ;;;;;;;;;;;;;;;;;
section .idata progbits follows=.text align=ALIGNMENT vstart=BASE+SECTALIGN*2
s_idata:
; message db "Hello World!",0
; message_size equ $ - message
; buffer resd 4
; buffer2 resb 64
import_table:
; import of kernel32.dll
dd 0 ; [UNUSED] read-only IAT
dd 0 ; [UNUSED] timestamp
dd 0 ; [UNUSED] forwarder chain
dd RVA(N_kernel32) ; library name
dd RVA(IAT_kernel32) ; IAT pointer
; import of user32.dll
dd 0 ; [UNUSED] read-only IAT
dd 0 ; [UNUSED] timestamp
dd 0 ; [UNUSED] forwarder chain
dd RVA(N_user32) ; library name
dd RVA(IAT_user32) ; IAT pointer
; terminator (empty item)
times 5 dd 0
IMPORT_TABLE_SIZE: equ $ - import_table
IAT_kernel32:
ExitProcess: dd RVA(H_ExitProcess)
GetStdHandle: dd RVA(H_GetStdHandle)
WriteConsoleA: dd RVA(H_WriteConsoleA)
dd 0
IAT_user32:
MessageBoxA: dd RVA(H_MessageBoxA)
dd 0
align 4, db 0
N_kernel32: db "kernel32.dll",0
align 4, db 0
N_user32: db "user32.dll",0
align 2, db 0
H_MessageBoxA: db 0,0,"MessageBoxA",0
align 2, db 0
H_GetStdHandle: db 0,0,"GetStdHandle",0
align 2, db 0
H_WriteConsoleA: db 0,0,"WriteConsoleA",0
align 2, db 0
H_ExitProcess: db 0,0,"ExitProcess",0
S_IDATA_SIZE equ $ - s_idata
align ALIGNMENT, db 0
the_end:
Adjustment needed in function assignment part. Instead of double words quad words should be used.
IAT_kernel32:
ExitProcess: dq RVA(H_ExitProcess)
GetStdHandle: dq RVA(H_GetStdHandle)
WriteConsoleA: dq RVA(H_WriteConsoleA)
dq 0
IAT_user32:
MessageBoxA: dq RVA(H_MessageBoxA)
dq 0
Alignments should be corrected according to this example
align 16, db 0
N_kernel32: db "kernel32.dll",0
align 16, db 0
N_user32: db "user32.dll",0
align 8, db 0
H_ExitProcess: db 0,0,"ExitProcess",0
align 8, db 0
H_GetStdHandle: db 0,0,"GetStdHandle",0
align 8, db 0
H_WriteConsoleA: db 0,0,"WriteConsoleA",0
align 8, db 0
H_MessageBoxA: db 0,0,"MessageBoxA",0