;TinyPE header builder
;How to use:
;	include 'tiny'			;need include for macros
;	import KERNEL32,ExitProcess...	;State imports here before we can build header
;	import USER32,MessageBoxA...
;	FormatPE			;Build small PE header, default console, use FormatPE GUI to build GUI
;	;--------------- user code start here ---------------
;	Start:		;Program Entry point
;	;--------------- user code ends here ----------------
;	EndPE				;Setup filesize etc for PE header
;Problems
;	VirusTotal will give some warnings

macro align alignment*,char {
    if $ mod alignment > 0
	db alignment - ($ mod alignment) dup (char)
    end if	
}
macro	ddround n,r {	dd (n+r-1) and -r }

dll_tables equ
dll_imports equ dd 0,0,0,0,0
dll_strings equ

filealign = 4
sectalign = 4   ; must be 4 because of e_lfanew
adjust = sectalign - filealign
image_base = 0x400000
dll_count = 0

macro	import dll,[func] {
    common
	macro dll_tables \{
	    dll_tables
	    if dll_count > 0
		dd 0
	    end if
	    dll_count = dll_count + 1
	    dll#_table: 
	        forward
		    func = $ + image_base + adjust
			dd _#func+adjust-2
		common
	\}
	macro dll_imports \{
	    dd	0,0,0,dll#_name+adjust, dll#_table+adjust
	    dll_imports
	\}
	macro dll_strings \{
	    dll_strings
	    dll#_name	db `dll,0
		forward
		    _#func	db `func,0
		common
	\}
}

macro	FormatPE subsys {
format binary as 'exe'
use32

; MZ header
; The only two fields that matter are e_magic and e_lfanew
    dw "MZ"       ; e_magic
    dw 0          ; e_cblp UNUSED

    dd "PE"       ; e_cp, e_crlc UNUSED       ; PE signature

; PE header
    dw 0x014C     ; e_cparhdr UNUSED          ; Machine (Intel 386)
    dw 1          ; e_minalloc UNUSED         ; NumberOfSections

pe_entry:
    jmp near Start-image_base
    db 0,0,0
;   dd 0          ; e_maxalloc, e_ss UNUSED   ; TimeDateStamp UNUSED
;   dd 0          ; e_sp, e_csum UNUSED       ; PointerToSymbolTable UNUSED
    dd 0          ; e_ip, e_cs UNUSED         ; NumberOfSymbols UNUSED
    dw sections-opthdr ; e_lsarlc UNUSED      ; SizeOfOptionalHeader
    dw 0x103      ; e_ovno UNUSED             ; Characteristics

; PE optional header

opthdr:
    dw 0x010B     ; e_res UNUSED              ; Magic (PE32)
    db 8                                      ; MajorLinkerVersion UNUSED
    db 0                                      ; MinorLinkerVersion UNUSED

sections:
    ddround codesize, filealign               ; SizeOfCode UNUSED		; Name UNUSED
    dd 0          ; e_oemid, e_oeminfo UNUSED ; SizeOfInitializedData UNUSED
    dd codesize	  ; e_res2 UNUSED             ; SizeOfUninitializedData UNUSED	; VirtualSize
    dd pe_entry                               ; AddressOfEntryPoint		; VirtualAddress
    dd codesize				      ; BaseOfCode UNUSED		; SizeOfRawData
    dd pe_entry				      ; BaseOfData UNUSED		; PointerToRawData
    dd 0x400000                               ; ImageBase			; PointerToRelocations UNUSED
    dd sectalign  ; e_lfanew                  ; SectionAlignment		; PointerToLinenumbers UNUSED
    dd filealign                              ; FileAlignment			; NumberOfRelocations UNUSED
										; NumberOfLinenumbers UNUSED
    dw 4                                      ; MajorOSVersion UNUSED		; Characteristics UNUSED 
    dw 0                                      ; MinorOSVersion UNUSED
    dw 0                                      ; MajorImageVersion UNUSED
    dw 0                                      ; MinorImageVersion UNUSED
    dw 4                                      ; MajorSubsystemVersion
    dw 0                                      ; MinorSubsystemVersion UNUSED
    dd 0                                      ; Win32VersionValue UNUSED
    dd ((hdrsize + sectalign-1) and -sectalign) + ((codesize + sectalign-1) and -sectalign)
				              ; SizeOfImage

    ddround hdrsize, filealign                ; SizeOfHeaders
    dd 0                                      ; CheckSum UNUSED
    subsystem = 3
match =GUI any,subsys \{ subsystem = 2 \}
    dw subsystem			      ; Subsystem (Win32 CONSOLE)	;GUI = 2, CONSOLE = 3
    dw 0x400                                  ; DllCharacteristics UNUSED
    dd 0x100000                               ; SizeOfStackReserve
    dd 0x1000                                 ; SizeOfStackCommit
    dd 0x100000                               ; SizeOfHeapReserve
    dd 0x1000                                 ; SizeOfHeapCommit UNUSED
    dd 0                                      ; LoaderFlags UNUSED
    dd 2                                      ; NumberOfRvaAndSizes UNUSED

; Data directories
; The debug directory size at offset 0x34 from here must be 0
    dq 0		;export
    dd idata+adjust 	;import section rva
    dd idata.size	;import section size

opthdrsize = $ - opthdr
hdrsize = $ - $$

	dll_tables
	idata:	dll_imports
	.size = $-idata
	dll_strings
	org	$ + image_base
	purge	align
}

macro	pushd [args] {
	reverse
	match any, args \{
		local ..continue
		if args eqtype ''
		    CALL ..continue
		    db args,0
		    ..continue:
		else
		    pushd args
		end if \}
}

macro	call proc,[args] {
	common
	    pushd args
	    call dword proc }

macro	EndPE {
	codesize = $ - pe_entry
	filesize = $ - $$ }

;Basic WIN32 includes
struc TCHAR [val] { common match any, val \{ . db val \}
                           match , val \{ . db ? \} }
include 'include/macro/struct.inc'
include 'include/equates/kernel32.inc'
include 'include/equates/user32.inc'
include 'include/equates/gdi32.inc'
include 'include/equates/comctl32.inc'
include 'include/equates/comdlg32.inc'
include 'include/equates/shell32.inc'
include 'include/equates/wsock32.inc'
