Hi all!
I have made some small update in import, stdcall, invoke, ccall and cinvoke macroses for next reasons:
1. In case when some of application functions should be placed in separate DLL and still used in that application all "stdcall"s with such functions must be replaced with "invoke"s - not so easy, IMHO. With this macro update direct/indirect calls are detected automatically and are based on if function is actually imported or not.
2. Some of DLLs have exported functions with same names. For example ntdll.dll and kernel.dll both have RtlMoveMemory and some other functions.
With such macro no errors will be in case of import all of those DLL's contents. So it is enough to use some DLL converter programm which will make whole DLL contents import file in FASM syntax without need to modify such file almost always.
Here is the code :
format PE GUI 4.0
entry Main
include "win32a.inc"
; Updated import macro
; Here additional forward-referenced constants are set in order to
; detect direct/indirect call needed in stdcall/invoke
; it also exclude earlier imported functions with same name, for example
; ntdll.dll and kernel.dll both have RtlMoveMemory and some other functions
; with such macro no errors will be in case of import all of those DLL's
; contents
macro import name,[label,string]
{
common
DONE equ NO
; check, if we have at least one function which is not
; defined in earlier DLL imports
forward
match any , label#_importdone
\{
restore DONE
DONE equ YES
\}
common
; if we have at least one function which is not
; defined in earlier DLL imports - make import table
match =YES, DONE
\{
if defined name\#.referred
name#.lookup:
forward
match any , label\#_importdone
\\{
if used label
if string eqtype ''
local _label
dd RVA _label
else
dd 80000000h + string
end if
end if
\\}
common
if $ > name\#.lookup
name\#.redundant = 0
dd 0
else
name\#.redundant = 1
end if
name\#.address:
forward
match any , label\#_importdone
\\{
if used label
if string eqtype ''
label dd RVA _label
else
label dd 80000000h + string
end if
label\\#_dllimport = 1 ; mark function as DLL-imported
end if
\\}
common
if ~ name\#.redundant
dd 0
end if
forward
match any , label\#_importdone
\\{
if used label & string eqtype ''
_label dw 0
db string,0
rb RVA $ and 1
end if
; mark function name as imported in order not to
; process it in next possible imports
label\\#_importdone equ
\\}
common
end if
\}
restore DONE
}
; macro to choose call type based on imported constant definition
macro call_by_declare name
{
; match is used here to get proper name in cases like this:
; MessageBox equ MessageBoxA
; ...
; import user32 ,\
; MessageBoxA, 'MessageBoxA',\
; MessageBoxW, 'MessageBoxW'
match _name, name
\{
; if function is imported - make indirect call
if defined _name\#_dllimport
call near [_name]
; otherwise - direct call
else
call near _name
end if
\}
}
; updated function call macroses with direct/indirect call detection
macro stdcall proc,[arg] ; directly call STDCALL procedure
{ common
match all, arg
\{
reverse
pushd arg
common
\}
call_by_declare proc}
macro invoke proc,[arg] ; indirectly call STDCALL procedure
{ common
match all, arg
\{
reverse
pushd arg
common
\}
call_by_declare proc}
macro ccall proc,[arg] ; directly call CDECL procedure
{ common
size@ccall = 0
match all, arg
\{
reverse
pushd arg
size@ccall = size@ccall+4
common
\}
call_by_declare proc
if size@ccall
add esp,size@ccall
end if }
macro cinvoke proc,[arg] ; indirectly call CDECL procedure
{ common
size@ccall = 0
match all, arg
\{
reverse
pushd arg
size@ccall = size@ccall+4
common
\}
call_by_declare proc
if size@ccall
add esp,size@ccall
end if }
; now we are free to use stdcall or invoke with all functions in code -
; appropriate call type will be chosen automatically
; now let use UNICODE name to control ASCII/Unicode function calls
; if "UNICODE equ " is not specified - we have ASCII versions
; UNICODE equ
match =UNICODE, UNICODE
{
MessageBox equ MessageBoxA
}
match , UNICODE
{
MessageBox equ MessageBoxW
}
; just a test function
proc TestFunction
; actually used MessageBox version depends on UNICODE name
invoke MessageBox, 0, szOk, szTitle, MB_ICONINFORMATION
ret
endp
Main:
invoke TestFunction ; <- here stdcall actually used, so - no error till execution
invoke ExitProcess, 0
; if we are not use Unicode
match =UNICODE, UNICODE
{
szTitle db "Test",0
szOk db "Call is successful.",0
}
; if Unicode is used
match , UNICODE
{
szTitle du "Test",0
szOk du "Call is successful.",0
}
align 16
data import
library kernel32, 'kernel32.dll',\
user32, 'user32.dll'
include "api\kernel32.inc"
; here we are free to import all contents of DLL
; but for example - only MessageBox'es
import user32 ,\
MessageBoxA, "MessageBoxA",\
MessageBoxW, "MessageBoxW"
end data
Thanks.