NASM - The Netwide Assembler
NASM Forum => Summer of Code Ideas => Topic started by: nalsakas on May 24, 2015, 02:45:34 PM
-
I named these macro sets as Nasm PE macros, and their include file is "pe.inc". I have already made too much afford to make these set of macros happen. These macros uses bin file format output. It is flat binary. Macros fills in necessary headers.
Sample usage:
PE32
SECTION DATA
SECTION CODE
START
instructions
END
But in order to go one step forward I need a few features from nasm which aren't develop yet (as far as I know).
Request 1:
First is I need to test if a label is defined before or after the current test location. I need a preprocessor directive, something like %iflabel / %endif.
Example 1:
label1:
instructions....
%iflabel label2
do something
%endif
label2:
instructions....
%$label3:
instructions....
Request 2:
I need to test if a single line macro defined after current line? %ifdef doesn't work in these situations.
Example 2:
%ifdef %$sometihng
.... This isn't working
%endif
%assign %$something otherthings
Request 3:
I could get the last value of a single line macro (a %define statement). In order for me to fill in section table of pe file I need to know in advance how many sections are defined in pe file. I need to get last declared value of section number counter, each section increments the value by one.
Example 3:
; PE Section Header
; How to get last value of %$SECTION_COUNT???
; It is not even defined yet
%assign %$SECTION_COUNT 0
%$SECTION_1
%assign %$SECTION_COUNT %$SECTION_COUNT + 1
%$SECTION_2
%assign %$SECTION_COUNT %$SECTION_COUNT + 1
-
I have nearly completed PE macro sets. As I mentioned earlier there are a few limitations of nasm. Because of that I can't produce more than one section in PE header. But that is not a big problem for me. I still can produce one section PE file. Resulting executable will have only one section. And will be smaller.
Because of that explicitly defining a SECTION isn't needed. So I will remove SECTION macro from future versions.
IMPORT and EXPORT macros are included and are ready. I am still working on RESOURCE macros.
There is example source codes you can find below. This is how source code of asm will look if you use PE macros.
In order to produce output, use -f bin assembler switch.
Since labels in asm source code are offset based I had to invent VA() macro in order to turn offset based labels into virtual addresses. It is usualy linkers job but since we don't use linker in this project we have to manually turn offsets into VA's.
Example PE32 file:
%include "pe.inc"
; For 32-bit executable use PE32
; For 32-bit dll use DLL32
; 64-bit PE and DLL's are not ready yet
PE32
; Data declarations
Title db 'Title of MessageBox',0
; enty point of executable
START
; machine intructions
...
push VA(Title)
push 0
call [VA(MessageBoxA)]
LocalFunction:
...
ret
; Setup import directory if you need to
IMPORT
; write down imported dll's
LIB user32.dll
; write down imported functions
FUNC MessageBoxA
ENDIMPORT
LIB kernel32.dll
FUNC ExitProcess
...
ENDLIB
ENDIMPORT
; Setup Export Directory if you need to
EXPORT
; write down local functions to export
FUNC LocalFunction
...
ENDEXPORT
; Setup Resource Directory if you need to
RESOURCE
; I am working on details
ENDRESOURCE
END
; End of executable
-
Although my work on RESOURCE directory macros continues, I have published pe macros on github. Anyone wants to give it a try link is here.
https://github.com/nalsakas/pe.git
With these macro sets one can produce PE32, DLL32 files with IMPORT and EXPORT directory support. RESOURCE directory currently supports only raw resources, user defined resources and MENU resources. MENU support recently added.
Example use of menus:
MENU menuname
MENUITEM 'File', 101h
POPUP 'Edit'
MENUITEM 'Copy' ,200h
MENUITEM 'Paste', 201h
ENDPOPUP
MENUITEM 'Help', 300h
ENDMENU
-
#VERSION 0.2, 11/06/2015
- README file updated
- Sample applications added.
- EXPORT macro now needs a module name.
- Bugs cleared from EXPORT macro.
There was a bug in EXPORT macro. It is corrected.
EXPORT macro now needs export module name which is mandatory by pe format. User has to type filename here. I was try to get file name from __FILE__ macro but it returns path too. So I removed default implementation.
3 sample code examples added to the project. One is simple MessageBox, other is simple window with menu, and last one is a simple DLL exports a function.
My work on DIALOG resource continues...
Get latest work here:
https://github.com/nalsakas/pe.git
-
Wow, very interesting, I will use it certainly in future for a better of executable's system understanding and for more customizing x)
I'm a little noob in eng, so can you shortly describe what is VA/RVA ?
-
They are short for VA = Virtual Address and RVA = Relative Virtual Address. You can find these definitions in official/unofficial pe file format specifications.
-
#VERSION 0.3, 16/06/2015
- README file updated
- Sample applications added.
- DIALOG resource added.
- STRINGTABLE resource added.
- Many control types added for DIALOG resource
With this version we can add DIALOG resource type to our executables. Sample usage is given below.
1) First we need to add DIALOG to the RESOURCE tree
RESOURCE
TYPE RT_DIALOG
ID ID_DIALOG
LANG
LEAF RVA(dialog), SIZEOF(dialog)
ENDLANG
ENDID
ENDTYPE
ENDRESOURCE
2) Next we define our DIALOG resource
; dialogs name/label is same as the one mentioned on LEAF node.
; x,y coordinates
; cx, cy are width and heights
DIALOG dialog, x, y, cx, cy
; Dialogs can have optional FONT, CAPTION, MENU, STYLE and EXSTYLE macros
FONT size, 'font face'
STYLE bitflags
EXSTYLE bitflags
MENU resource_id
CAPTION 'text'
; Child controls
CONTROL 'text', id, class_id, x, y, cx, cy, optional style, optional exstyle
; Predefined child controls doesn't have class_id
PUSHBUTTON 'text', id, x, y, cx, cy, optional style, optional exstyle
...
ENDDIALOG
How to use STRINGTABLES?
1) Add stringtable to the resource tree as above.
2) Add stringtable as below
STRINGTABLE label
STRING 'First String'
STRING "Second String"
ENDSTRINGTABLE
3) Access strings from assembly code by using SID() macro. Short for string id.
LoadString, hInst, SID(String Table Resource ID, Index of string in the table)
SID(x,y) takes two parameter. First is ID of table defined in resource tree and other is string's index in table.
New sample applications are added to the project and old ones are updated.
-
ACCELERATOR resource support added. Example application is added to the project.
USAGE: First include accelerator into resorce tree than add following definitions.
ACCELERATORTABLE accelerator
; %1 = ascii key or virtual key
; %2 = ID of key
; %3 = flags
ACCELERATOR 'A', ID_ACTION_SHIFT_A, FSHIFT
ACCELERATOR VK_F5, ID_ACTION_CONTROL_F5, FCONTROL | FVIRTKEY
ACCELERATOR VK_RETURN, ID_ACTION_ALT_ENTER, FALT | FVIRTKEY
; default flag is shift key if not entered.
ACCELERATOR 'H', IDM_FILE_HELP
ENDACCELERATORTABLE
-
BITMAP resource support added.
With BITMAP macro you can include bitmaps into your resources. Then you can use them inside asm code with LoadBitmap API. To start with bitmaps first include an resource of type RT_BITMAP into resource tree. Than add file with BITMAP macro. Sample application is given in samples directory.
; %1 = label
; %2 = Bitmap file in string form
BITMAP bitmap1, 'bitmap.bmp'
Get the latest work is here:
https://github.com/nalsakas/pe
-
64-bit support added.
Now you can use PE64 and DLL64. Sample applications are added. Project is 99% completed. I will work on ICON resources next.
Get the latest work from here: https://github.com/nalsakas/pe
Is there anyone using NASM PE MACROS out there?
-
Because of the nature of icon file format and limitations of macros I may not add a support for icons. It can be made by hand though. But I couldn't find a proper way of handling icon file format.
Icon file format is a container for multiple images, such as bitmaps and pngs. Although icon file looks a single resource in rc scripts, all internal images gets expanded and take a different resource id in executable. Resource compiler makes that behind the scenes.
Maybe I will find a way someday but not today.
It can be done manually by hand with the help of nasm's incbin directive. But it is tedious.
I wish nasm has had preprocessor version of incbin directive something like %incbin. Incbin runs at assemble time not at preprocessor time.
If I had preprocessor %incbin I could probably made ICON macros.
As of now I can say that development of NASM PE MACROS is finished.
Apart from bug fixes I don't plan to add any other feature.
Have a nice day
-
FLAT MODEL
PE32, PE64, DLL32 and DLL64 macros now optionally excepts FLAT parameter. When it is used it removes the necessity of using VA() macro at labels. PE32 has optional third argument which is both section alignment and file alignment constant. If you don't supply anything it is 1000h.
After FLAT model your code looks simpler because all VA() references are removed. Downside is that in default 1000h file and section alignment your executable's size increases.
%include "../pe.inc"
PE32 FLAT
BYTE Title, "NASM PE MACROS",0
BYTE Text, "Flat memory works!",0
START
push 0
push Title
push Text
push 0
call [MessageBoxA]
ret
IMPORT
LIB user32.dll
FUNC MessageBoxA
ENDLIB
ENDIMPORT
END
-
64-bit support added.
Is there anyone using NASM PE MACROS out there?
Hi nalsakas, great work and interesting idea.
I'm testing 64-bit support.
64_dialogbox.asm:
I inserted new lines of code at the end of START procedure,
basically it should display a new message box when main window closes, BUT
instead of showing the new message box - the program terminates.
New lines of code, well this code is based on yours, only message box content is message box title.
Added an attachment of source files.
-
Hi encryptor256,
Problem is not related to NASM PE MACROS but related to stack balancing. I am myself also new to 64-bit calling convention. I coudn't fully grasp the entire register based win64 calling convention. Although I found the cause and solution of the problem I don't know how to explain it. I've just added add esp, 40 at the beginning of MessageBoxA call.
Maybe someone here on forums can help us understand how win64 calling convention works :-)
START
push rbp
mov rbp, rsp
; shadow stack area
sub rsp, 40
; Get module handle
mov rcx, 0
call [VA(GetModuleHandleA)]
mov [VA(hIns)], rax
; DialogBox
mov r9, VA(DlgProc)
mov r8, 0
mov rdx, ID_DIALOG
mov rcx, [VA(hIns)]
call [VA(DialogBoxParamA)]
add rsp, 40 ;---> Addition
mov r9, 0
mov r8, VA(title)
mov rdx, VA(title)
mov rcx, 0
call [VA(MessageBoxA)]
.return:
mov rsp, rbp
pop rbp
ret
-
Problem is not related to NASM PE MACROS but related to stack balancing.
Confirm! I already knew where the problem lies, I just wanted for you to struggle a bit. :-X ::)
Problem is here - incorrectly aligned stack according to your prolog setup.
So, according to your prolog setup routine should be (fixed):
; For START procedure and DlgProc too.
; ...
; shadow stack area
; sub rsp, 40 (NO)
sub rsp, 32 ; YES
; ...
Added attachment named: "64_dialogbox_new_new.asm".
I changed everywhere "sub rsp, 40" to "sub rsp, 32" and it works, now.
+ For later: If you call a procedure with more than four arguments, then stack shadow space should be increased appropriately too.
-
Hmm, thank you for your contribution. I will update 64-bit sample applications in the project directory according to your corrections.
Can you write a brief tutorial on win64 calling convention if you don't mind? About registers, shadow space, must preserved registers etc.
Did you experiment with FLAT mode?
-
X:
+ There is anoter problem: DialogBoxParam (https://msdn.microsoft.com/en-us/library/windows/desktop/ms645465%28v=vs.85%29.aspx) requires five arguments.
So, last one of them should be initialized and stored in stack space.
Changed START procedure:
; ...
; shadow stack area
sub rsp, 48
; ...
; ...
; DialogBox
xor rax,rax
mov [rsp+32],rax ; dwInitParam
mov r9, VA(DlgProc) ; lpDialogFunc
xor r8, r8 ; hWndParent
mov rdx, ID_DIALOG ; lpTemplateName
mov rcx, [VA(hIns)] ; hInstance
call [VA(DialogBoxParamA)]
; ...
I would recommend to change source code to this, 64_dialogbox_new_new.asm:
%include '../pe.inc'
%include '../windows.inc'
; Resource IDs
%define ID_DIALOG 10
%define ID_BUTTON 11
%define ID_EDIT 20
PE64
; Data declerations
BYTE title, "NASM PE MACROS",0
QWORD hIns
BYTE buffer[256]
START
push rbp
mov rbp, rsp
; shadow stack area
sub rsp, 48
; Get module handle
mov rcx, 0
call [VA(GetModuleHandleA)]
mov [VA(hIns)], rax
; DialogBox
xor rax,rax
mov [rsp+32],rax ; dwInitParam
mov r9, VA(DlgProc) ; lpDialogFunc
xor r8, r8 ; hWndParent
mov rdx, ID_DIALOG ; lpTemplateName
mov rcx, [VA(hIns)] ; hInstance
call [VA(DialogBoxParamA)]
; // Begin: ###################
; // {
mov r9, 0
mov r8, VA(title)
mov rdx, VA(title)
mov rcx, 0
call [VA(MessageBoxA)]
; // };
.return:
mov rsp, rbp
pop rbp
ret
; Dialog Procedure
; [r9] = lParam
; [r8] = wParam
; [rdx] = uMsg
; [rcx] = hDlg
DlgProc:
; save parameters on shadow
mov qword [rsp + 8], rcx
mov qword [rsp + 16], rdx
mov qword [rsp + 24], r8
mov qword [rsp + 32], r9
push rbp
mov rbp, rsp
; shadow stack area
sub rsp, 32
; switch msg
cmp qword [rbp + 24], WM_CLOSE
je .close
cmp qword [rbp + 24], WM_COMMAND
je .command
cmp qword [rbp + 24], WM_INITDIALOG
je .initdialog
.default:
xor rax, rax
.return:
mov rsp, rbp
pop rbp
ret
.initdialog:
mov eax, 1
jmp .return
.close:
mov rdx, 1
mov rcx, [rbp + 16]
call [VA(EndDialog)]
mov rax, 1
jmp .return
.command:
mov rax, [rbp + 32]
cmp ax, ID_BUTTON
je .command_button
jmp .default
.command_button:
; GetDlgItemText
mov r9, 255
mov r8, VA(buffer)
mov rdx, ID_EDIT
mov rcx, [rbp + 16]
call [VA(GetDlgItemTextA)]
; MessageBox
mov r9, 0
mov r8, VA(title)
mov rdx, VA(buffer)
mov rcx, 0
call [VA(MessageBoxA)]
mov rax, 1
jmp .return
; Data Directories
IMPORT
LIB user32.dll
FUNC MessageBoxA
FUNC DialogBoxParamA
FUNC EndDialog
FUNC SendMessageA
FUNC GetDlgItemTextA
ENDLIB
LIB kernel32.dll
FUNC GetModuleHandleA
FUNC LoadLibraryA
FUNC FreeLibrary
ENDLIB
ENDIMPORT
RESOURCE
TYPE RT_DIALOG
ID ID_DIALOG
LANG
LEAF RVA(dialog), SIZEOF(dialog)
ENDLANG
ENDID
ENDTYPE
ENDRESOURCE
DIALOG dialog, 0, 0, 210, 142
STYLE DS_CENTER
CAPTION "NASM PE MACROS"
DEFPUSHBUTTON "OK", ID_BUTTON, 2, 122, 208, 18
EDITTEXT ID_EDIT, 2, 2, 208, 120, ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL
ENDDIALOG
END
; Assemble
; nasm -f bin -o 64_dialogbox_new_new.exe 64_dialogbox_new_new.asm
Y:
Can you write a brief tutorial on win64 calling convention if you don't mind? About registers, shadow space, must preserved registers etc.
It can be easily found on google, like x64 calling convention or x64 stack alignment.
Did you experiment with FLAT mode?
No.
Z:
Suggestion:
If you want to clear-zero out-initialize a register use, like examples here:
xor rax,rax
xor r8,r8
-
What is the reason behind allocating 48 bytes for shadow stack space? DialogBoxParamA needs 5 parameters x 8 bytes = 40 bytes in total for shadow stack space.
-
DialogBoxParamA needs 5 parameters x 8 bytes = 40 bytes in total for shadow stack space.
Yes.
What is the reason behind allocating 48 bytes for shadow stack space?
+8 is for alignment.
-
So you are saying subtracting extra 8 bytes for alignment shouldn't hurt.
sub rsp, 48 --> OK, works
But why subtracting 8 bytes more crashes application?
sub rsp, 56 ---> NOT OK, crashes
Moreover putting extra alignment in Dlgproc also craches application.
DlgProc:
sub rsp, 32 ---> OK
sub rsp, 40 --> NOT OK
-
But why subtracting 8 bytes more crashes application?
sub rsp, 56 ---> NOT OK, crashes
Stack is not aligned and crashes.
Hey check this out: Stack alignment in x64 assembly (http://stackoverflow.com/questions/19128291/stack-alignment-in-x64-assembly)
There is one: "vandale" individual who complains and one: "lurker" who explains.
EDIT:
Moreover putting extra alignment in Dlgproc also craches application.
DlgProc:
sub rsp, 32 ---> OK
sub rsp, 40 --> NOT OK
Yes! According to your prolog routine and later function calls, the number 32 is appropriate and stack will be aligned correctly, BUT 32+8 = 40 would ruin proper alignment.
-
There are way too many things going on in this thread for me to go over every post, so I thought I would focus on the primary topic.
Request 1:
First is I need to test if a label is defined before or after the current test location. I need a preprocessor directive, something like %iflabel / %endif.
That one already exists. %ifid will tell you if an identifier is already defined.
Request 2:
I need to test if a single line macro defined after current line? %ifdef doesn't work in these situations.
This also, already exists. %ifmacro will tell you if a macro is currently defined.
Request 3:
I could get the last value of a single line macro (a %define statement). In order for me to fill in section table of pe file I need to know in advance how many sections are defined in pe file. I need to get last declared value of section number counter, each section increments the value by one.
To my knowledge, this one hasn't be implemented. But if you need to know how many sections are going to be used, why not ask the user. Add an operand to your PE macro that asks for the section count.
PE [type], [bits], [sections]
Usage:
PE EXE, 64, 5
PE DLL, 32, 2
HtH,
Bryant
-
Hi Bryant,
Actually Request 2 isn't supported by nasm.
Below code block produces "something is defined". Because macro is defined before test.
%define something 1
%ifdef something
%warning "something is defined"
%else
%warning "something isn't defined"
%endif
Whereas following code block produces "something isn't defined". Because macro isn't defined before test.
%ifdef something
%warning "something is defined"
%else
%warning "something isn't defined"
%endif
%define something 1
Actually right now I don't need anything new from nasm. I made it work without future requests. PE macros works with current nasm and successfully produces PE32, PE64, DLL32 and DLL64 files using only nasm.
When I start to build PE macros I thought It would be fine to support multiple sections. But later I changed my mind. One section is enough for an executable. That way they become smaller.
regards