OK so investingating Mikl's code in my earlier thread, I made this first code to just pop up some values:
include \masm32\include\masm32rt.inc
image_base=400000h
.data
buffer dd 'ZM','EP';Signantures
dw 14Ch ;Machine
dw 1 ;count of section
szInfoText db "API Addresses:",13,10
db "LoadLibraryA: 0x%08lX",13,10
db "MessageBoxA: 0x%08lX",0
Result db "Result:", 0
cBuff db 70 DUP (0)
_MessageBox dd 0
_LoadLibrary dd 0
.code
start:
xor ebx,ebx
mov eax, MessageBoxA
push eax
sub eax,_MessageBox-buffer+image_base+4
mov _MessageBox,eax
mov eax, LoadLibraryA
push eax
sub eax, _LoadLibrary-buffer+image_base+4
mov _LoadLibrary,eax
push offset szInfoText
push offset cBuff
call wsprintfA
push 0
push offset Result
push offset cBuff
push 0
call MessageBoxA
push _MessageBox
push _LoadLibrary
push offset szInfoText
push offset cBuff
call wsprintfA
push 0
push offset Result
push offset cBuff
push 0
call MessageBoxA
call ExitProcess
end start
the repetetive nature of this made me wish for my first function:
include \masm32\include\masm32rt.inc
image_base=400000h
.data
buffer dd 'ZM','EP';Signantures
dw 14Ch ;Machine
dw 1 ;count of section
szInfoText db "API Addresses:",13,10
db "LoadLibraryA: 0x%08lX",13,10
db "MessageBoxA: 0x%08lX",0
Result db "Result:", 0
cBuff db 70 DUP (0)
_MessageBox dd 0
_LoadLibrary dd 0
.code
start:
xor ebx,ebx
mov eax, MessageBoxA
push eax
sub eax,_MessageBox-buffer+image_base+4
mov _MessageBox,eax
mov eax, LoadLibraryA
push eax
sub eax, _LoadLibrary-buffer+image_base+4
mov _LoadLibrary,eax
call ShowMyMessage
add esp, 8
push _MessageBox
push _LoadLibrary
call ShowMyMessage
add esp, 8
call ExitProcess
PUBLIC ShowMyMessage
ShowMyMessage PROC
; Subroutine Prologue
push ebp ; Save the old base pointer value.
mov ebp, esp ; Set the new base pointer value.
sub esp, 70 ; Make room for my 70 byte buffer.
push edi ; Save the values of registers that the function
push esi ; will modify. This function uses EDI and ESI.
; (no need to save EBX, EBP, or ESP)
; Subroutine Body
mov eax, [ebp+8] ; Move value of parameter 1 into EAX
mov esi, [ebp+12] ; Move value of parameter 2 into ESI
;mov edi, [ebp+16] ; Move value of parameter 3 into EDI
push esi
push eax
push offset szInfoText
push [ebp-70] ;our 70 byte buffer
call wsprintfA
push 0
push offset Result
push [ebp-70]
push 0
call MessageBoxA
; Subroutine Epilogue
pop esi ; Recover register values
pop edi
mov esp, ebp ; Deallocate local variables
pop ebp ; Restore the caller's base pointer value
ret
ShowMyMessage ENDP
end start
this fails silently. It seems to fail inside wsprintfA.
I am trying to declare a local buffer within my function and then send that buffer to wsprintfA. I am suspecting that is done wrong.
Any pointer to how to correct this?
I figured it out. so I need to send a pointer to my local variable.
the call to wsprinfA becomes:
lea edi, [ebp-70]
push esi
push eax
push offset szInfoText
push edi
call wsprintfA
it works
2 points....
1) normally, you can use INVOKE to push variables (INVOKE is an internal masm macro)
INVOKE MessageBox,hWnd,offset szMessageText,offset szTitleText,MB_OK
the last argument listed is the first to be pushed
sometimes, i use PUSH rather than INVOKE, if i want to call a function in between pushes
constants, like MB_OK, MB_YESNO, etc, are defined in windows.inc
2) the windows ABI is a set of rules that should be followed when writing win32 functions
even though the rules are not always required,
if you write a function that follows them, you can re-use that function in places where they are required
the rules include all kinds of things but here, we are mainly concerned with these:
a) EAX may be destroyed across the call, and is used to return a status or return value
b) ECX and EDX may be destroyed across the call
in assembly language, we can also use them to return values
but, it's clumsy to get them if the function is called from a compiled language
c) EBX, EBP, ESI, and EDI must be preserved across the call
d) if you set the direction flag inside a function, you should clear it before returning
there is a different ABI for 64-bit programs
windows API functions follow the same rules
so, you know that EAX, ECX, EDX are volatile across a call and the others are preserved
here is an example of a win32 function
create a prototype in the project include file, or otherwise near the beginning of the program
SomeFunc PROTO :HWND,:DWORD
this allows the use of INVOKE with the function
SomeFunc PROC USES EBX ESI EDI hWnd:HWND,dwArg2:DWORD
;---------------------------
LOCAL dwLocal1 :DWORD
LOCAL rcLocal2 :RECT
LOCAL abLocal3[24] :BYTE
;---------------------------
;some code here
INVOKE GetClientRect,hWnd,addr rcLocal2
;some more code here
lea edx,abLocal3
;some more code here
mov eax,dwArg2
imul eax,5
mov dwLocal1,eax
;some more code here
ret
SomeFunc ENDP
i might call it like this...
INVOKE SomeFunc,hWnd,70
thank you dave.
I had missed using lea on the local.
Hi StarsInTheSky,
You must balance the stack manually if you are calling C functions without using the invoke macro :
include \masm32\include\masm32rt.inc
.data
format db 'testing wsprintf : %s',0
string db 'This is a demo.'
.data?
buffer db 64 dup(?)
.code
start:
push OFFSET string
push OFFSET format
push OFFSET buffer
call wsprintf
add esp,3*4
invoke StdOut,ADDR buffer
invoke ExitProcess,0
END start
Hi Vortex,
Oh thank you. I was only doing that for my own function, but not when calling wsprintfA.
From now on I will check the function to see whether they are cdecl :t
https://msdn.microsoft.com/en-us/library/windows/desktop/ms647550(v=vs.85).aspx
I read somewhere else that MessageBoxA is a stdcall and will clean up by itself. But reading on msdn, there is no mentioning of it.
It just says winapi ?
https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx
win api functions are StdCall
you can look at the prototypes
MessageBox is in winuser.inc i think
msvcrt.inc for wsprintf
the default convention for PROTO is StdCall
thank you for the helpful answers :) :t
wsprintf is part of the Windows API, in User32, but note that it does use the C calling convention.
"Well Microsoft, here's another nice mess you've gotten us into."
I'm pretty sure that Ralph said to Alice, "Well Alice, here's another fine mess that you've gotten us into."
Quote from: dedndave on May 10, 2015, 08:53:12 PM
2 points....
1) normally, you can use INVOKE to push variables (INVOKE is an internal masm macro)
INVOKE MessageBox,hWnd,offset szMessageText,offset szTitleText,MB_OK
I thought that you couldn't use "OFFSET" in an INVOKE statement. You had to use "ADDR". What's the story?
Oliver,
ADDR does a bit more than OFFSET but if the address IS an OFFSET in the .DATA or .DATA? sections, it works fine. MASM actually maintains the distinction between an OFFSET versus a LOCAL where the ADDR operator simplifies it for INVOKE usage.
Quote from: hutch-- on December 01, 2015, 07:32:39 AM
Oliver,
ADDR does a bit more than OFFSET but if the address IS an OFFSET in the .DATA or .DATA? sections, it works fine. MASM actually maintains the distinction between an OFFSET versus a LOCAL where the ADDR operator simplifies it for INVOKE usage.
That makes sense. Thanks Hutch.