assemblynasmportable-executable

Wrong library loads wrong function in manually-generated PE 64-bit executable


I have 64 bit manually-generated PE executable. I need to load two libraries kernel32.dll and user.dll. It gives the first error.

enter image description here

If I have only one library (this would be kernel32.dll) I get the second error. Is there any way to get another error.

enter image description here

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:

Solution

  • 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