flat assembler
Message board for the users of flat assembler.

Index > Windows > Manual Win32 Programming

Author
Thread Post new topic Reply to topic
Tukang Paip



Joined: 09 Jun 2004
Posts: 11
Location: Malaysia
Tukang Paip
I just recently experimenting building Win32 application manually (without using fasm
"format PE" directive). Here's the result. As you can see in the include file, some of the
macros are not optimized and perhaps wrong. I'm not fully understand the macro facility yet.
Also the constants and structs are a bit messy because I'm trying to make an include file
that can ease ANSI/UNICODE programming.
Currently I have no idea how to implement the resource directory builder macro set because
I cannot find the actual individual resource format in PE file. Also, the base relocation
directory is almost impossible to be automate by macros. I can live without base reloc info
in my dll (this will be a problem for a dll intended to be loaded in every process).

The include file is not perfect; I just include
what actually needed to compile the code template below. I recommend you to use an editor with
a syntax highlighting feature that can be customized to read the source. It really helps!

Because I'm in internet cafe right now, i cannot provide more examples,
in the future I will give them and also post small tuto about how fasm preprocessor really works.. (Please note, I only test all samples in Win xp and using FASM 1.52, release 03-04-2004). ENJOY!!!!

Code:
;modify this according to your needs
include "%finc%\mpe.inc"

;Use the PE.* macros below to change some the important fields of PE headers.
;The macros just change an already defined numerical constant (except PE.ENTRY)
;so you can only use these macros at the beginning of source file (before the header)
;and after the include.
;The value in the commented macro invocation is the default.
;PE.BASE 0x400000
;PE.ENTRY Main
;PE.FLAG EXE NORELOC NODEBUG NOLINENUMBERINFO NOLOCALSYMSINFO BYTESHIGH BYTESLOW
PE.FLAG EXE NORELOC NODEBUG
;PE.ALIGN 0x200,0x1000
;PE.STACK 0x10000, 0x1000
PE.STACK 0,0
;PE.HEAP 0x10000,0
PE.HEAP 0,0
;PE.OSVER 4,1
PE.OSVER 5,1
;PE.SUBSYSTEM GUI
;PE.SUBSYSTEMVER 4,1

;dos header and some of nt headers (before data dir array)
DOS_HEADER:
dw "MZ"
rb 0x3A
dd NT_HEADERS
NT_HEADERS:
dw "PE", 0
FILE_HEADER:
dw 0x014c, SectionCount
dd %t, 0, 0
dw 224, Characteristics
OPTIONAL_HEADER:
dw 0x10b
db MajorLinkerVer, MinorLinkerVer
dd 0, 0, 0, EntryPoint, 0, 0, ImageBase, SectionAlignment, FileAlignment
dw MajorOSVer, MinorOSVer, 0, 0, MajorSubsystemVer, MinorSubsystemVer
dd 0, SizeOfImage, HeaderSize, 0
dw Subsystem, 0
dd StackReserved, StackCommitted, HeapReserved, HeapCommitted, 0, 16

;data dir arrays. DIR.ENTRY is a macro (just to make it look nice). Basically
;the actual contents of each dir must be wrapped between
;<Name>_DIR_START and <Name>_DIR_END labels where <Name> is specified as argument
;below. For example, if you create your own import dir, wrap it between
;IMPORT_DIR_START and IMPORT_DIR_END labels. Currently I only have 3 data dir
;creation macros - import, export and tls.
DIR.ENTRY EXPORT        ;;;;;
DIR.ENTRY IMPORT        ;;;;;
DIR.ENTRY RESOURCE      ;;;;;
DIR.ENTRY EXCEPTION
DIR.ENTRY SECURITY
DIR.ENTRY BASERELOC     ;;
DIR.ENTRY DEBUG
DIR.ENTRY COPYRIGHT
DIR.ENTRY GLOBALPTR
DIR.ENTRY TLS           ;;;
DIR.ENTRY LOADCONFIG
DIR.ENTRY BOUNDIMPORT
DIR.ENTRY IAT
DIR.ENTRY DELAYLOAD
DIR.ENTRY COM
DIR.ENTRY RESERVED

;the section headers area. SECTION.HEADER macro is nothing. It's just there
;to make this look nice Smile. SECTION.ENTRY works with SECTION macro (described
;below) and it must receive a number (e.g 1,2,3,4..). It create the individual
;section header (the number is the important part in this macro as well as in
;SECTION macro). In its definition, you will see usage of label such as
;Section#Number#Name and etc.. All these labels are declared using SECTION macro
;below.
;SECTION.ENDHEADER declare the constant SectionCount (see PE headers above)
SECTION.HEADER
    SECTION.ENTRY <1>
    SECTION.ENTRY <2>
SECTION.ENDHEADER

;After SECTION.ENDHEADER, you can actually enlarge the size of header
;by using any method (e.g rb directive) but I think the header size cannot
;exceed the first section's rva.

;Here you should use SECTION macro to define individual section's contents.
;I cannot describe more about the SECTION, ENDSECTIOn and ENDPROGRAM macros
;because I'm not sure if they're always correct in any circumstances.
;Basically SECTION macro receives 3 types of args, A number (section number
;for generating the label to be used in SECTION.ENTRY above, section name
;(must be quoted string and can be of any length.. only 8 chars are taken)
;and the characteristics of the section. Please note there are 2 types of
;characteristic constant you can use : the one that is not preceeded with dot
;(e.g Code, Executable etc) and the one with dot in front of its name (e.g
;.IDATA, .RSRC). The dot name is given without comma, e.g
;.CODE .DATA (and not .CODE, .DATA). You can check the SECTION macro for
;more info on this.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Section 1 - code only                                                     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                         SECTION <1>, "<Achik>", .CODE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;CONSTANT, IDATA and UDATA is a data declaration macros. CONSTANT and IDATA
;are the same, it's just to hint you that you should put a constant data in
;a read only section. I make 2 version of it because maybe later I want to change their
;implementation. These macros didn't declare anything at the current offset!
;You must use DECLARE.CONSTANT, DECLARE.IDATA and DECLARE.UDATA to declare them.
;So any vars declared using these macros are group together at wherever you use
;the DECLARE.* macros. Note that the DECLARE.* macros can work multiple time,
;each time it will declare the previously define CONSTANT, IDATA (except UDATA).
;UDATA works differently and you should use it only once (per section or per program).
;If DECLARE.UDATA is used, it must be at the end of section (just before the ENDSECTION).

CONSTANT MsgTitle TEXT "Template Test"
CONSTANT MsgByOrd TEXT "This is a call By Ordinal"
UDATA hInstance dd  ?

;FUNCTION, ENTER, EXIT and ENDF works together to define a function. The first argument
;is a function name and second is function calling convention. This is only useful if it's
;called using CALL macro (not the "call"). 2 types of calling convention naming
;as argument can be used. __cdecl and CDECL. When using __cdecl no comma is needed after the
;function name (example below) but is needed when using CDECL. Supported calling conventions
;are CDECL (__cdecl), WINAPI/CALLBACK/STDCALL(__winapi, __callback, __stdcall) and PASCAL (__pascal).
;PROC and ENDP is just alias to FUNCTION and ENDF. Although it's not a requirement, you should
;call any labels defined with FUNCTION macro with CALL macro because it will take care of
;parameter pushed direction and stack cleanup for you.

;The PUSH macro can push normal pushable operand, runtime affective address, e.g
;value of ebp+8 (edx is trashed), string (single/multi-bytes), float and double constant,
;and int64 constant (see definition of PUSH macro) for more info on how to correctly
;push all these.

;Only the APICALL and IMPDATA works with IMPORT macros set. See description of import dir
;creation below. Unless you already accessed labels created in IMPORT macro using either
;of these macros, you cannot use any other instructions/methods to access them.
FUNCTION Main __cdecl
    ENTER
    xor     ebx, ebx
    APICALL KERNEL32.GetModuleHandleA, ebx
    mov     [hInstance], eax
    IMPDATA eax, USER32.MessageBoxA
    PUSH    ebx, MsgTitle, "This is a call By Name", ebx
    call    eax
    CALL    Foo, MsgByOrd, MsgTitle
    push    MsgTitle MsgByOrd
    push    @f
    jmp     Foo
    @@:
    APICALL USER32.MessageBoxW, ebx, MsgByNameW, L "Template Test (Unicode)", ebx
.Return:
    EXIT
ENDF

PROC Foo, <WINAPI>, .Msg, .Title
    ENTER
    xor     eax, eax
    push    eax [.Title] [.Msg] eax
    APICALL USER32.@477
    push    eax [.Title] [.Msg] eax
    call    [USER32.@477] ;USER32.@477 already used in APICALL above, this instruction will compile.
    EXIT
ENDP

;The vars defined with CONSTANT (above) will end up declared here. Please note :
;use CONSTANT macro first, then declare it with DECLARE.CONSTANT below them.
DECLARE.CONSTANT

;ENDSECTION is a requirement. Although this macro can receives a number, it
;is not a requirement.
                                  ENDSECTION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Section 2 - data r/w                                                      ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                          SECTION <2>, "<Achik>", .DATA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;DIR.IMPORT, DIR.ENDIMPORT, NODEFAULTIMPORT, LIBRARY and IMPORT macros must be used
;after all APICALL and IMPDATA usage because they use conditional preprocessing.
;The import creation macro set is complex and I think they still need to be improved.
;They just end up like that because of this reason :
;-I want to implement an import macro that can include default Win32 system API such
; as from KERNEL32,USER32,GDI32 and ADVAPI32 and I want the compilation to be fast.
; Without conditional processing, the code template took over 20 seconds to compile
; while with conditional processing, it takes less than 5 seconds.
; I also want the default import can be overridden (using NODEFAULTIMPORT) completely.
; I also want a perfect import dir that have the original first thunk and first thunk,
; and I want to be able to call a function by ordinal. Then I want to be able to add
; more function to an already imported library (such as the default library) and so
; on....
;To make this simple :- To create the import dir, you need to
;-wrap it in DIR.IMPORT and DIR.ENDIMPORT
;-between them, you can override the default import using NODEFAULTIMPORT macro
; (as demonstrated below).
;-use LIBRARY to import new dll function
;-use IMPORT to import new function in dll defined with LIBRARY (any LIBRARY
; usage must lead its IMPORT equivalent). You can use IMPORT many times over
; the same dll name (as shown below) but you cannot import the same function
; name more than once.
;-use NODEFAULTIMPORT only to removes default functions list included in the include file.
DIR.IMPORT
    NODEFAULTIMPORT GDI32,ADVAPI32,SHELL32,SHLWAPI,COMCTL32,COMDLG32
    IMPORT  USER32,\
            477
DIR.ENDIMPORT

;you can safely use the DECLARE.* macros even if no corresponding * macro
;was used, e.g IDATA macro never used in this source, DECLARE.IDATA will
;do nothing.
DECLARE.IDATA
DECLARE.UDATA

                                  ENDSECTION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                                  ENDPROGRAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;    


Description: the include file
Download
Filename: mpe.rar
Filesize: 133.82 KB
Downloaded: 277 Time(s)

Post 09 Jun 2004, 05:45
View user's profile Send private message Visit poster's website MSN Messenger Reply with quote
Vortex



Joined: 17 Jun 2003
Posts: 318
Vortex
What's the use of all this stuff? Creating PEs from scratch had beed discussed before:

http://board.flatassembler.net/topic.php?t=1309

_________________
Code it... That's all...
Post 09 Jun 2004, 10:01
View user's profile Send private message Visit poster's website Reply with quote
comrade



Joined: 16 Jun 2003
Posts: 1137
Location: Russian Federation
comrade
Tukang Paip wrote:
Currently I have no idea how to implement the resource directory builder macro set because
I cannot find the actual individual resource format in PE file.


Resources are implemented as macros in standard FASM package too. See INCLUDE/MACRO/RESOURCE.INC

_________________
comrade (comrade64@live.com; http://comrade.ownz.com/)
Post 09 Jun 2004, 12:00
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
Tukang Paip



Joined: 09 Jun 2004
Posts: 11
Location: Malaysia
Tukang Paip
Quote:
What's the use of all this stuff? Creating PEs from scratch had beed discussed before:


I know.. its just to show you the power of fasm's macroinstruction facilities.

resource macros in std fasm include is good... but i'm still trying to make a better macros. Currently i still use them with some modification.

and here is the include files I used in my manual programming (edited version).
(to do) :
-base reloc dir creation.
-complete resource dir creation.
-easy production of ANSI/UNICODE version of program.
-data structures and constants related to win32 versioning.
-a better way to manipulate imported data and the creation of import dir (current
implementation make compilaion really slow).
-better UDATA macro.
http://www26.brinkster.com/paipx/inc.html

and also more examples :

http://www26.brinkster.com/paipx/ex.html

My first attempt to explain about fasm preprocessor (please forgive my bad english).
This is far from complete. I will post a new doc (it should be a complete doc) next week.

http://www26.brinkster.com/paipx/pphowto.txt
Post 12 Jun 2004, 03:08
View user's profile Send private message Visit poster's website MSN Messenger Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.