Any Way To Make This Snippet More Efficient? - performance

I just started playing around with MASM styled assembly and after playing around long enough managed to make a sort of loop. This is just from tinkering so I was wondering if anybody could give me any insight and explanation on if this code is inefficient or how it can be improved.
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
.data
MsgBxTitle db "Loop Step", NULL
.data?
Buff dd ?
MsgBxBody dd ?
.code
start:
XOR eax,eax
MOV Buff, eax
lp:
invoke dw2hex, Buff, addr MsgBxBody
invoke MessageBox, NULL, addr MsgBxBody, addr MsgBxTitle, MB_OKCANCEL
.IF eax==IDCANCEL
RET
.ENDIF
INC Buff
CMP Buff,10
JL lp
RET
end lp
invoke ExitProcess, NULL
end start

You can shave 16 bytes off the code this way. Zero a register and push that for zero. Use a register for you dword buffer. Using registers Assemble to smaller opcodes and are "faster" than memory (labels).
I personally don't like/use the high level stuff.
start:
xor edi, edi
xor esi, esi
mov ebx, 10
lp:
push offset MsgBxBody
push edi
call dw2hex
push MB_OKCANCEL
push offset MsgBxTitle
push offset MsgBxBody
push esi
call MessageBox
test eax, IDCANCEL
jnz Done
inc edi
dec ebx
jns lp
Done:
push esi
call ExitProcess
end start

When displaying your results with MessageBox, I don't see that efficiency or performance is relevant. I have questions about your control flow. Where is "RET" intended to return to? When, if ever, is ExitProcess invoked? I don't know what "end lp" does, so perhaps I'm missing something...
Best,
Frank

Related

How to find out the age of a file in ASM?

Greetings to all the geniuses of the digital age
Yesterday's task is still on the agenda: "Use the GetOpenFileName function to select a file. Check if the file is less than 3 days old, execute it. Otherwise, display a dialog asking to delete the file. If the user needs it, wipe." (Note: If a task is told to use a structure, it must be placed in dynamically allocated memory)"
I figured out how to open the file and now everything works like a Swiss watch. But another trouble arose.
How to determine the age of a file?
In general, I first thought to use GetFileTime to extract all data about the file time, then use FileTimeToLocalFileTime to convert it to local time, and using FileTimeToSystemTime - to system time. Then subtract one from the other using sub, and so on as per the task.
Here, the FileTimeToLocalFileTime function requires a FILETIME structure with the following parameters:
DWORD dwLowDateTime;
DWORD dwHighDateTime;
And the FileTimeToSystemTime function requires a SYSTEMTIME structure with the following parameters:
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
And how to be then? How to find the age of a file? Is there any alternative way? And if my method works, then what exactly and from what should I take it?
File.inc
include WINDOWS.inc
include user32.inc
include kernel32.inc
include comdlg32.inc
includelib user32.lib
includelib kernel32.lib
includelib comdlg32.lib
.data
Time_title db ' Lab_3',0
format db 'More than 3 days. Delete file?', 0
buf db 255 dup(0)
hFile dd 0
readed dd 0
hmem dd 0
File.asm
.386
.model flat,STDCALL
option casemap :none ;case sensitive
include Third.inc
include RADbg.inc
Mem_Alloc PROC Buf_Size:DWORD
add Buf_Size,4
invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,Buf_Size
push eax
invoke GlobalLock,eax
pop [eax]
add eax,4
Mem_Alloc endp
Mem_Free PROC DATA:DWORD
mov eax,DATA
sub eax,4
mov eax,[eax]
push eax
push eax
call GlobalUnlock
call GlobalFree
Mem_Free endp
.code
Begin:
call main
invoke ExitProcess,NULL
main proc
LOCAL ftCreate, ftLocale: FILETIME;
LOCAL stUTC, stLocal: SYSTEMTIME;
invoke Mem_Alloc, 1000h
mov hmem, eax
invoke Mem_Alloc, sizeof OPENFILENAME
mov edi, eax
assume edi: ptr OPENFILENAME
xor eax, eax
mov [edi].lStructSize, sizeof OPENFILENAME
mov [edi].lpstrFile, offset buf
mov [edi].nMaxFile, 255
invoke GetOpenFileName, edi
invoke CreateFile, [edi].lpstrFile, GENERIC_READ,\
FILE_SHARE_READ, NULL, OPEN_EXISTING,\
FILE_ATTRIBUTE_NORMAL, NULL
mov hFile,eax ;
invoke GetFileTime, hFile, addr ftCreate, NULL, NULL
invoke FileTimeToLocalFileTime, addr ftCreate, addr ftLocale
invoke FileTimeToSystemTime, addr ftCreate, addr stUTC
cmp eax, 1
jz l1
invoke ReadFile, hFile, hmem, 1000h, addr readed, 0
invoke MessageBox, 0, hmem, addr Time_title, MB_OKCANCEL
jmp l2
l1:
invoke MessageBox, 0, addr format, addr Time_title, MB_OKCANCEL
cmp eax, IDOK
jne l2
invoke DeleteFile, addr [edi].lpstrFile
l2:
assume edi: dword
invoke CloseHandle, hFile
invoke Mem_Free, hmem
invoke Mem_Free, edi
ret
main endp
end Begin
As FILETIME and RtlTimeToSecondsSince1970 said, You should copy the low- and high-order parts of the file time to a ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart member.
So, subtract the 64-bit value in the ULARGE_INTEGER structure initialized with the file time from the 64-bit value of the ULARGE_INTEGER structure initialized with the current system time.

FASM write Hello World to console with NO includes or dependencies at all

I've seen
How to write hello world in assembler under Windows?
and
Writing hello,world to console in Fasm with DOS
How to write to the console in fasm?
I've tried / seen code like this MASM example from this answer
;---ASM Hello World Win64 MessageBox
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
.data
title db 'Win64', 0
msg db 'Hello World!', 0
.code
main proc
sub rsp, 28h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, msg ; LPCSTR lpText
lea r8, title ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
add rsp, 28h
mov ecx, eax ; uExitCode = MessageBox(...)
call ExitProcess
main endp
End
(to which I get an error "Illegal instruction" on windows 64 bit extrn MessageBoxA:PROC because FASM doesn't understand that MASM directive.)
also this FASM example from this question
; Example of 64-bit PE program
format PE64 GUI
entry start
section '.text' code readable executable
start:
sub rsp,8*5 ; reserve stack for API use and make stack dqword aligned
mov r9d,0
lea r8,[_caption]
lea rdx,[_message]
mov rcx,0
call [MessageBoxA]
mov ecx,eax
call [ExitProcess]
section '.data' data readable writeable
_caption db 'Win64 assembly program',0
_message db 'Hello World!',0
section '.idata' import data readable writeable
dd 0,0,0,RVA kernel_name,RVA kernel_table
dd 0,0,0,RVA user_name,RVA user_table
dd 0,0,0,0,0
kernel_table:
ExitProcess dq RVA _ExitProcess
dq 0
user_table:
MessageBoxA dq RVA _MessageBoxA
dq 0
kernel_name db 'KERNEL32.DLL',0
user_name db 'USER32.DLL',0
_ExitProcess dw 0
db 'ExitProcess',0
_MessageBoxA dw 0
db 'MessageBoxA',0
but it displays a message box and also has external dependencies "kernel32.dll" and "user32.dll"
also tried this example from the FASM forum
format pe console
include 'win32ax.inc'
entry main
section '.data!!!' data readable writeable
strHello db 'Hello World !',13,10,0
strPause db 'pause',0
section '.txt' code executable readable
main:
; you can use crt functions or windows API.
cinvoke printf,strHello
cinvoke system,strPause; or import getc()
; or
; invoke printf,srtHello
; add esp, 4
; or use WriteFile and GetStdHandle APIs
push 0
call [ExitProcess]
section '.blah' import data readable
library kernel32,'kernel32.dll',\
msvcrt,'msvcrt.dll' ;; C-Run time from MS. This is always on every windows machine
import kernel32,\
ExitProcess,'ExitProcess'
import msvcrt,\
printf,'printf',\
system,'system'
but it depends on win32ax.inc and other imports
also
format PE console
include 'win32ax.inc'
.code
start:
invoke WriteConsole,<invoke GetStdHandle,STD_OUTPUT_HANDLE>,"Hello World !",13,0
invoke Sleep,-1
.end start
but requires "win32ax.inc" import
closest I could find without the win32ax from the FASM forum:
format pe64 console
entry start
STD_OUTPUT_HANDLE = -11
section '.text' code readable executable
start:
sub rsp,8*7 ; reserve stack for API use and make stack dqword aligned
mov rcx,STD_OUTPUT_HANDLE
call [GetStdHandle]
mov rcx,rax
lea rdx,[message]
mov r8d,message_length
lea r9,[rsp+4*8]
mov qword[rsp+4*8],0
call [WriteFile]
mov ecx,eax
call [ExitProcess]
section '.data' data readable writeable
message db 'Hello World!',0
message_length = $ - message
section '.idata' import data readable writeable
dd 0,0,0,RVA kernel_name,RVA kernel_table
dd 0,0,0,0,0
kernel_table:
ExitProcess dq RVA _ExitProcess
GetStdHandle dq RVA _GetStdHandle
WriteFile dq RVA _WriteFile
dq 0
kernel_name db 'KERNEL32.DLL',0
user_name db 'USER32.DLL',0
_ExitProcess db 0,0,'ExitProcess',0
_GetStdHandle db 0,0,'GetStdHandle',0
_WriteFile db 0,0,'WriteFile',0
but still requires the kernel32.dll and user32.dll
Any way to do this without any external DLLs at all? I know just the program fasm itself does it, and prints to the console, doesn't it?
Any way to do this without any external DLLs at all?
Under Windows: Definitely no!
Windows uses some methods (probably syscall) to enter the operating system, however, there are no official entry points.
This means that it is (unlikely but) possible that exactly the same program that shows the "Hello world" message box in the current Windows version will do something completely different after the next Windows update!
Because Microsoft is assuming that every Windows program is only calling the OS by using the .dll files that match the kernel version, they can do this.
I don't know about Windows 10, but an older Windows version (I don't remember if it was XP, Vista or 7) even simply assumed that an .exe file returns at once if it does not use any .dll file: The program was not even started in this case!
I know just the program fasm itself does it, and prints to the console
That is not the case, fasm is also using the kernel32 APIs.
FWIW kernel32 is loaded into the memory space of every process in Windows, so there is no penalty or overhead in using the kernel32 APIs.
You may like this Windows example in €ASM, which doesn't explicitly mention any DLL and doesn't require other external libraries.
Just save the source as "bluej.asm", assemble and link with euroasm bluej.asm and run as bluej.exe.
Nevertheless, you won't get away without using API functions imported from the default Windows system library "kernel32.dll".
bluej PROGRAM Format=PE, Entry=Start:
IMPORT GetStdHandle,WriteFile,ExitProcess
Start: PUSH -11 ; Param 1: standard output handle identificator.
CALL GetStdHandle; Return StdOutput handle in EAX.
PUSH 0 ; Param 5: no overlap.
PUSH Written ; Param 4: Address of a variable to store number of written bytes.
PUSH MsgSize ; Param 3: Number of bytes to write.
PUSH Msg ; Param 2: Address of text.
PUSH EAX ; Param 1: Output file handle.
CALL WriteFile ; System call.
PUSH 0 ; Errorlevel.
CALL ExitProcess ; System call.
Written DD 0
Msg DB "Hello, world!"
MsgSize EQU $ - Msg
ENDPROGRAM
What constitures as "dependency" to you? If you want to avoid even operating system DLL's, then you're probably out of luck. You can't rely on syscall numbers alone.
"no dependencies" can also mean "just using existing OS DLL's", such as ntdll, kernel32, etc., but without using 3rd party DLL's that may not be present, such as a specific version of the C runtime.
One method I would like to show is retrieving function pointers from the PEB. This is code that I've written and that I personally use, if I want to have shellcode that has no import section.
PebGetProcAddress works similarly to GetProcAddress, except that the DLL name and function name must be a hash, and the DLL must be loaded by using LoadLibrary.
This may not answer your question exactly, but I hope it gets you somewhat closer to your goal or help others who read it.
PebApi.asm
proc PebGetProcAddress ModuleHash:DWORD, FunctionHash:DWORD
local FirstEntry:DWORD
local CurrentEntry:DWORD
local ModuleBase:DWORD
local ExportDirectory:DWORD
local NameDirectory:DWORD
local NameOrdinalDirectory:DWORD
local FunctionCounter:DWORD
; Get InMemoryOrderModuleList from PEB
mov eax, 3
shl eax, 4
mov eax, [fs:eax] ; fs:0x30
mov eax, [eax + PEB.Ldr]
mov eax, [eax + PEB_LDR_DATA.InMemoryOrderModuleList.Flink]
mov [FirstEntry], eax
mov [CurrentEntry], eax
; Find module by hash
.L_module:
; Compute hash of case insensitive module name
xor edx, edx
mov eax, [CurrentEntry]
movzx ecx, word[eax + LDR_DATA_TABLE_ENTRY.BaseDllName.Length]
test ecx, ecx
jz .C_module
mov esi, [eax + LDR_DATA_TABLE_ENTRY.BaseDllName.Buffer]
xor eax, eax
cld
.L_module_hash:
lodsb
ror edx, 13
add edx, eax
cmp al, 'a'
jl #f
sub edx, 0x20 ; Convert lower case letters to upper case
##: dec ecx
test ecx, ecx
jnz .L_module_hash
; Check, if module is found by hash
cmp edx, [ModuleHash]
jne .C_module
; Get module base
mov eax, [CurrentEntry]
mov eax, [eax + LDR_DATA_TABLE_ENTRY.DllBase]
mov [ModuleBase], eax
; Get export directory
mov eax, [ModuleBase]
add eax, [eax + IMAGE_DOS_HEADER.e_lfanew]
mov eax, [eax + IMAGE_NT_HEADERS32.OptionalHeader.DataDirectoryExport.VirtualAddress]
add eax, [ModuleBase]
mov [ExportDirectory], eax
; Get name table
mov eax, [ExportDirectory]
mov eax, [eax + IMAGE_EXPORT_DIRECTORY.AddressOfNames]
add eax, [ModuleBase]
mov [NameDirectory], eax
; Get name ordinal table
mov eax, [ExportDirectory]
mov eax, [eax + IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals]
add eax, [ModuleBase]
mov [NameOrdinalDirectory], eax
; Find function in export directory by hash
mov [FunctionCounter], 0
.L_functions:
mov eax, [ExportDirectory]
mov eax, [eax + IMAGE_EXPORT_DIRECTORY.NumberOfNames]
cmp eax, [FunctionCounter]
je .E_functions
; Compute hash of function name
xor edx, edx
mov esi, [NameDirectory]
mov esi, [esi]
add esi, [ModuleBase]
xor eax, eax
cld
.L_function_hash:
lodsb
test al, al
jz .E_function_hash
ror edx, 13
add edx, eax
jmp .L_function_hash
.E_function_hash:
; Check, if function is found by hash
cmp edx, [FunctionHash]
jne .C_functions
; Return function address
mov eax, [ExportDirectory]
mov eax, [eax + IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
add eax, [ModuleBase]
mov ebx, [NameOrdinalDirectory]
movzx ebx, word[ebx]
lea eax, [eax + ebx * 4]
mov eax, [eax]
add eax, [ModuleBase]
ret
.C_functions:
add [NameDirectory], 4
add [NameOrdinalDirectory], 2
inc [FunctionCounter]
jmp .L_functions
.E_functions:
; Function not found in module's export table
xor eax, eax
ret
.C_module:
; Move to next module, exit loop if CurrentEntry == FirstEntry
mov eax, [CurrentEntry]
mov eax, [eax + LIST_ENTRY.Flink]
mov [CurrentEntry], eax
cmp eax, [FirstEntry]
jne .L_module
; Module not found
xor eax, eax
ret
endp
PebApi.inc
macro pebcall modulehash, functionhash, [arg]
{
common
if ~ arg eq
reverse
pushd arg
common
end if
stdcall PebGetProcAddress, modulehash, functionhash
call eax
}
Example
PEB_User32Dll = 0x63c84283
PEB_MessageBoxW = 0xbc4da2be
; pebcall translates to a call to PebGetProcAddress and the call to the returned function pointer
pebcall PEB_User32Dll, PEB_MessageBoxW, NULL, 'Hello, World!', NULL, MB_OK
How to generate hashes for module names and function names
#define ROTR(value, bits) ((DWORD)(value) >> (bits) | (DWORD)(value) << (32 - (bits)))
DWORD ComputeFunctionHash(LPCSTR str)
{
DWORD hash = 0;
while (*str)
{
hash = ROTR(hash, 13) + *str++;
}
return hash;
}
DWORD ComputeModuleNameHash(LPCSTR str, USHORT length)
{
DWORD hash = 0;
for (USHORT i = 0; i < length; i++)
{
hash = ROTR(hash, 13) + (str[i] >= 'a' ? str[i] - 0x20 : str[i]);
}
return hash;
}

Can anyone explain me how does this Flat Assembler code works?

I am trying to learn me making GUI programs in assembly. I downloaded Flat Assembler and started to read the example programs. There I found this code.
This is 64 bit code in assembly (fasm) for Windows. It makes empty window. But there was very few comments in It, so It's hard for me to understand what's going on. I commented here which parts I don't understand.
format PE64 GUI 5.0
entry start
include 'win64a.inc'
section '.idata' import data readable writeable
library kernel32,'KERNEL32.DLL',\
user32,'USER32.DLL'
include 'api\kernel32.inc'
include 'api\user32.inc'
section '.data' data readable writeable
_title TCHAR 'Win64 program template',0
_class TCHAR 'FASMWIN64',0
_error TCHAR 'Startup failed.',0
wc WNDCLASSEX sizeof.WNDCLASSEX,0,WindowProc,0,0,NULL,NULL,NULL,COLOR_BTNFACE+1,NULL,_class,NULL
msg MSG
section '.text' code readable executable
start:
sub rsp,8 ; Make stack dqword aligned
invoke GetModuleHandle,0 ;GetModuleHandle,0?
mov [wc.hInstance],rax ;wc.hInstance?
invoke LoadIcon,0,IDI_APPLICATION ;LoadIcon,0,IDI_APPLICATION?
mov [wc.hIcon],rax ;wc.hIcon?
mov [wc.hIconSm],rax ;ec.hIconSm?
invoke LoadCursor,0,IDC_ARROW ;LoadCursor,0,IDC_ARROW?
mov [wc.hCursor],rax ;wc.hCursor?
invoke RegisterClassEx,wc ;RegisterClassEx,wc?
test rax,rax ;test?
jz error
invoke CreateWindowEx,0,_class,_title,WS_VISIBLE+WS_DLGFRAME+WS_SYSMENU,128,128,256,192,NULL,NULL,[wc.hInstance],NULL
test rax,rax
jz error
msg_loop: ;What does this function?
invoke GetMessage,msg,NULL,0,0
cmp eax,1
jb end_loop
jne msg_loop
invoke TranslateMessage,msg
invoke DispatchMessage,msg
jmp msg_loop
error:
invoke MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK
end_loop:
invoke ExitProcess,[msg.wParam]
proc WindowProc uses rbx rsi rdi, hwnd,wmsg,wparam,lparam ;?
; Note that first four parameters are passed in registers,
; while names given in the declaration of procedure refer to the stack
; space reserved for them - you may store them there to be later accessible
; if the contents of registers gets destroyed. This may look like:
; mov [hwnd],rcx
; mov [wmsg],edx
; mov [wparam],r8
; mov [lparam],r9
cmp edx,WM_DESTROY
je .wmdestroy
.defwndproc: ;What does this?
invoke DefWindowProc,rcx,rdx,r8,r9
jmp .finish
.wmdestroy:
invoke PostQuitMessage,0
xor eax,eax
.finish:
ret
endp

Strange behaviour with a simple MASM32 program

I want to write a MASM program similar to the following C++ program :
#include <Windows.h>
#include <iostream>
typedef UINT (_stdcall *FuncPtr)(LPCSTR lpCmdLine, UINT uCmdShow);
int main(void)
{
HMODULE hDll = LoadLibrary(TEXT("Kernel32.dll"));
FuncPtr func_addr = reinterpret_cast<FuncPtr>(GetProcAddress(hDll, "WinExec"));
(*func_addr)("C:\\WINDOWS\\system32\\calc.exe", SW_SHOWDEFAULT);
FreeLibrary(hDll);
return (0);
}
As you can see, this code execute the microsoft calculator. I just want to do the same thing using MASM but the execution fails.
Here's the MASM source code :
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\msvcrt.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\msvcrt.lib
.data
LpFileName db "kernel32.dll", 0
procName db "WinExec", 0
display db "addr_func = 0x%x", 0
.data?
hModule HMODULE ?
procAddr FARPROC ?
.code
start:
invoke LoadLibrary, offset LpFileName
mov hModule, eax
invoke GetProcAddress, hModule, ADDR procName
mov procAddr, eax
INVOKE crt_printf, ADDR display, procAddr
mov esi, procAddr
call esi
db "C:\WINDOWS\system32\calc.exe"
invoke FreeLibrary, hModule
invoke ExitProcess, NULL
end start
The crt_printf output is correct. The same address is printed like withe the C++ program. So the address passed to call is the same one. However the execution fails.
Here's a MASM32 code which works but this time the address of the function WinExec is hardcoded like this :
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
.code
start:
jmp _Debut
_Final:
TCHAR 233
dword 42424242h
_Suite:
mov esi, 779e304eh
call esi
jmp _Final
_Debut:
xor eax, eax
push eax
call _Suite
db "C:\WINDOWS\system32\calc.exe"
end start
See the line mov esi, 779e304eh. But dynamically, there is a problem. If I disassemble the code just above we can see that the order of bytes is reversed.
8EEH047E379
Maybe it's not the case dynamically and maybe I need a keyword in the following line (between the comma and procAddr):
mov esi, procAddr
I cannot find the solution. I'm lost. Can anyone help me?
Thanks a lot in advance for your help.
The execution fails because you are not passing it's parameters.
Here you just call the function without any arguments or rather with invalid arguments (because whatever is currently on the stack will be taken and the stack is corrupted in the process).
mov esi, procAddr
call esi
You should do
push SW_SHOWDEFAULT
push offset YourPathToCalc
mov esi, procAddr
call esi
In your samplecode this is what is done here implicitly
xor eax, eax
push eax ; uCmdShow
call _Suite ; Returnadress is the address of the commandline so this is bascially the "push path"
Another thing you are missing is, that when WinExec returns, it will start executing the path in your case so you need a jmp somewhere after the call.
And as Gunner pointed out, the path must be 0 terminated.
To add to the correct answer Devolus posted, your path to calc is not NULL terminated.
This
"C:\WINDOWS\system32\calc.exe" is not correct!
Instead it should be:
"C:\WINDOWS\system32\calc.exe", 0
Also, if you are going to put strings in the code section to use, you need to give them a label in order to use them and you need to jump over them otherwise the CPU will try to execute the bytes.
INVOKE crt_printf, ADDR display, procAddr
mov esi, procAddr
push SW_SHOWDEFAULT
push offset Calc
call esi
jmp #F
Calc db "C:\WINDOWS\system32\calc.exe", 0
##:
invoke FreeLibrary, hModule
invoke ExitProcess, NULL
* EDIT *
To convert that code to Assembly using MASM, all that is needed is this:
.data
LpFileName db "kernel32", 0
procName db "WinExec", 0
Calc db "calc", 0
.code
start:
invoke LoadLibrary, offset LpFileName
push eax
invoke GetProcAddress, eax, ADDR procName
push SW_SHOWDEFAULT
push offset Calc
call eax
call FreeLibrary
invoke ExitProcess, NULL
end start

Push an argument into stack?

I know that the first four arguments are in the register (RCX, RDX, R8, R9), and that additional arguments are pushed on the stack.
Question:
How to push an argument onto the stack? I tried with (push 0) but it does not work?
Code (MASM64)
extrn ExitProcess: PROC
extrn MessageBoxExA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
sub rsp, 38h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, message ; LPCSTR lpText
lea r8, caption ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
push 0 ; wLanguageId
call MessageBoxExA
mov ecx, eax
add rsp, 38h
call ExitProcess
Start ENDP
End
I'm know that MessageBox and MessageBoxEx work the same way, but im trying to use MessageBoxEx because its need one parameter to be passed (for learning purpose).
I know I've asked similar question, but it is more related to vb.net while this is not.
My assembly is a little rusty, but I was under the impression that all arguments went onto the stack (in reverse order) - I'd have thought you want to be pushing r8 and rdx in as well as the other arguments. Frankly though you might as well just keep doing lea rax, param and push rax for each of the arguments that are pointers.
The order in which the arguments are passed and whether they are passed in registers or on the stack (along with whether caller or callee is responsible for cleanup) is defined by the 'Calling Convention'.
What you are probably thinking of is STDCALL or CDECL, both are calling conventions used in 32-bit Windows that pass arguments on the stack in reverse order (right to left). x64 has moved to a FastCall calling convention where the arguments are passed in forward order (from left to right) and the first 4 arguments are passed in the registers RCX, RDX, R8 & R9. Any arguments beyond 4 are passed on the stack in the same left-to-right order. The original poster had the correct calling convention setup for x64 assembly with MASM. Also, the above responder who said the shadowspace valued subtracted from RSP should be 20h (32d) is correct. The shadow space is allowing space on the stack for the 4 arguments that are passed in by the registers in FastCall.
Changing the code above to:
extrn ExitProcess: PROC
extrn MessageBoxExA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
sub rsp, 20h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, message ; LPCSTR lpText
lea r8, caption ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
push 0 ; wLanguageId
call MessageBoxExA
mov ecx, eax
add rsp, 20h
call ExitProcess
Start ENDP
End
Works just fine in Visual Studio on a 64-bit machine

Resources