PE Golf(4)

前回のPE Golfはコンソール版のHello worldで、プロゴルファーがアリアリ97bytesを提示したところで終わっていた。
のだが物好きな人は結構いるみたいで、GUI版トラックバックが来たのでちょっと見てみた。

しかし一年経つと全く覚えていない。とりあえず189bytesは勝てそうにないので、97bytes版と同じインチキをしてみることにしたところ112bytes版が完成。たぶんXP SP2でしか動きません。

BITS 32
ORG  0

ImageBase       equ 0x00400000
user32dll       equ 0x7c84f004  ; !!
LoadLibraryA    equ 0x7c801d77  ; !!
MessageBoxA     equ 0x77d3058a  ; !!

filealign equ 4
sectalign equ 4   ; must be 4 because of e_lfanew

%define round(n, r) (((n+(r-1))/r)*r)

        dw "MZ"
        dw 0
pe_hdr  dd "PE"                 ; Signature
        dw 0x014C               ; CPU: i386
        dw 1                    ; Number of Sections

code1:
        push dword user32dll
        call LoadLibraryA - ImageBase
        jmp short code2

        dw 4                    ; offset between sections and opthdr
        dw 0x0103               ; Characteristics: RELOCS_STRIPPED|EXECUTABLE|32BI
opthdr:
        dw 0x010B               ; Magic
code2:
        push dword 0x10040      ; MB_ICONASTERISK | MB_SETFOREGROUND
        xor eax, eax
        jmp short code3
        nop

        dd codesize
        dd code1                ; 
        dd codesize
        dd code1                ; EntryPoint
        dd ImageBase            ; ImageBase Address
sectbl: dd 4                    ; PE hdr / Section Alignment
        dd 4                    ; File Alignment

code3:
        mov edx, hello + ImageBase
        push edx
        push edx
        push eax

        dw 4                    ; Subsys Major Ver
code4:
        call MessageBoxA - ImageBase
        ret

        dd round(hdrsize, sectalign)+round(codesize,sectalign) ; SizeOfImage
        dd round(hdrsize, filealign)              ; SizeOfHeaders

        nop
        nop
        nop
        nop

        db 2                    ; IMAGE_SUBSYSTEM_WINDOWS_GUI
        db 0
hello   db 'Hello, world!',0

codesize equ $ - code1

hdrsize equ $ - $$

filesize equ $ - $$
  • kernel32.dllは常に読み込まれているのでロードしない。
  • 自分の環境ならAPIのアドレスは既知なので直接埋め込む。(インポートセクションやGetProcAddressを使用していない)
  • インポートセクションを使わないので、user32.dllをLoadLibrary()で読み込む必要がある。
  • user32.dllという文字列がkernel32.dllに存在するのでありがたく利用する。

ということでインポートセクションがありません。
メッセージを埋め込む余裕がなかったので末尾についているという無様なことになってます。この部分はかなり怪しげで、コードを埋め込むと実行できなくなったりします。

ところでkernel32.dllは読み込まれているというよりは、単にメモリにマップされているだけぽい。(なのでローダー処理なしで利用できる…ということだと思う)