Why does "MessageboxA" function not receive input from "section .data"? - windows

Following code was supposed to display a simple "Hello world!" message box. But for some reason gets no message box displayed. Code compiles, builds and executes without error. Debugger shows four parameter passing registers RCX, RDX, R8, R9 registers with supposedly correct values just before function call and function itself returns 0 in RAX.
%include "io64.inc"
; hellow.asm
;%include "win32n.inc"
extern ExitProcess
extern MessageBoxA
section .data
msg db 'Welcome to Windows World!',0
cap db "Windows 10 says:",0
UINT dd "0x00000040",0
section .text
global main
main:
push rbp
mov rbp,rsp
;int MessageBoxA(
; HWND hWnd, owner window
; LPCSTR lpText, text to display
; LPCSTR lpCaption, window caption
; UINT uType window behaviour
; )
mov rcx,0 ; no window owner
lea rdx,[msg] ; lpText
lea r8,[cap] ; lpCaption
lea r9d,[UINT] ; window with OK button
sub rsp,32 ; shadowspace
call MessageBoxA ; returns IDOK=1 if OK button selected
add rsp,32
leave
ret

Thanks to Michael Petch I got reason for message box not displaying. At section .data "UINT dd 0x00000040" is given as a "character encoding". Such a stupid mistake! To correct that I have to convert that to absolute value. "equ" just does that. So "UINT equ 0x00000040" is the correct input expected by the function in question.
corrected code is:
%include "io64.inc"
; hellow.asm
;%include "win32n.inc"
extern ExitProcess
extern MessageBoxA
section .data
msg db 'Welcome to Windows World!',0
cap db "Windows 10 says:",0
UINT equ 0x00000040
section .text
global main
main:
push rbp
mov rbp,rsp
;int MessageBoxA(
; HWND hWnd, owner window
; LPCSTR lpText, text to display
; LPCSTR lpCaption, window caption
; UINT uType window behaviour
; )
mov rcx,0 ; no window owner
lea rdx,[msg] ; lpText
lea r8,[cap] ; lpCaption
lea r9d,[UINT] ; window with OK button
sub rsp,32 ; shadowspace
call MessageBoxA ; returns IDOK=1 if OK button selected
add rsp,32
leave
ret
As per Peter Cordes suggestion, more appropriate coding:
%include "io64.inc"
; hellow.asm
;%include "win32n.inc"
extern ExitProcess
extern MessageBoxA
section .data
msg db 'Welcome to Windows World!',0
cap db "Windows 10 says:",0
MsgBoxOK equ 0x00000040
section .text
global main
main:
push rbp
mov rbp,rsp
;int MessageBoxA(
; HWND hWnd, owner window
; LPCSTR lpText, text to display
; LPCSTR lpCaption, window caption
; UINT uType window behaviour
; )
mov rcx,0 ; no window owner
lea rdx,[msg] ; lpText
lea r8,[cap] ; lpCaption
mov r9d,MsgBoxOK ; window with OK button and i icon
sub rsp,32 ; shadowspace
call MessageBoxA ; returns IDOK=1 if OK button selected
add rsp,32
leave
ret

Related

Assembly MASM32 push and pop

This is a basic win32 program that I found online. So far I get everything, but what I don't get are those two lines:
push hInstance
pop wc.hInstance
Can someone explain to me what they do and if there is another way to do whatever is done by them using another instruction.
I tried to use google and other documentation and they explained very well what the push and pop instructions do, but I can't fit my understanding of them in the context of this program.
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib ; calls to functions in user32.lib and kernel32.lib
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
.DATA ; initialized data
ClassName db "SimpleWinClass",0 ; the name of our window class
AppName db "Our First Window",0 ; the name of our window
.DATA? ; Uninitialized data
hInstance HINSTANCE ? ; Instance handle of our program
CommandLine LPSTR ?
.CODE ; Here begins our code
start:
invoke GetModuleHandle, NULL ; get the instance handle of our program.
; Under Win32, hmodule==hinstance mov hInstance,eax
mov hInstance,eax
invoke GetCommandLine ; get the command line. You don't have to call this function IF
; your program doesn't process the command line.
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT ; call the main function
invoke ExitProcess, eax ; quit our program. The exit code is returned in eax from WinMain.
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX ; create local variables on stack
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX ; fill values in members of wc
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc ; register our window class
invoke CreateWindowEx,NULL,\
ADDR ClassName,\
ADDR AppName,\
WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
NULL,\
NULL,\
hInst,\
NULL
mov hwnd,eax
invoke ShowWindow, hwnd,CmdShow ; display our window on desktop
invoke UpdateWindow, hwnd ; refresh the client area
.WHILE TRUE ; Enter message loop
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam ; return exit code in eax
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY ; if the user closes our window
invoke PostQuitMessage,NULL ; quit our application
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam ; Default message processing
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
It's pushing hInstance onto the stack, and then popping it into the memory location of wc.hInstance.
The programmer could have equivalently written:
mov eax, hInstance
mov wc.hInstance, eax
if they knew they didn't need to preserve EAX.

Visual C++ always builds succeeded but no output is created. Problem with the highlight asm extension VS2019 [duplicate]

I'm here to ask you some stuff about VS2017.
In the past I had used WinAsm for MASM and I never got problems with it.
However, when I'm trying to do something with MASM in VS2017, I always gonna get problems and stuff...
I've checked the whole internet about "how to set up VS for MASM", but nothing has helped me as I'm always getting troubles...
Is there any way to use Visual Studio 2017 for MASM32/64bit without any kind of headache?
Can someone give me the ultimate guide to set up VS2017 for assembly programming?
Thanks you very much and sorry for my weak english.
How to build a x64/x86-project with a standalone x64/x86 assembly file
1) Start Visual Studio (Community) 2017 and choose FILE - New - Project.
2) In the next window choose Empty Project.
3) Make sure, that the project is highlighted in the Solution Explorer and and choose PROJECT - Build Customizations....
4) In the next window tick masm(.targets,.props) and click on OK.
5) Choose PROJECT - Add New Item from the menu.
6) In the next window choose C++File(.cpp) and - IMPORTANT! - give it a name with an .asm extension. Click on Add.
7) Now you can fill the file with content.
Source.asm:
EXTERN GetStdHandle : PROC
EXTERN WriteFile : PROC
EXTERN ExitProcess : PROC
.DATA?
hFile QWORD ?
BytesWritten DWORD ?
.DATA
hello BYTE 'Hello world!', 13, 10
.CODE
main PROC
; https://blogs.msdn.microsoft.com/oldnewthing/20160623-00/?p=93735
sub rsp, 40 ; Shadow space (4 * 8) & 1 parameter (8 bytes)
; https://learn.microsoft.com/en-us/cpp/build/stack-allocation
and spl, -16 ; Align to 16
; https://msdn.microsoft.com/library/windows/desktop/ms683231.aspx
mov ecx, -11 ; DWORD nStdHandle = STD_OUTPUT_HANDLE
call GetStdHandle ; Call WinApi
mov hFile, rax ; Save returned handle
; https://msdn.microsoft.com/library/windows/desktop/aa365747.aspx
mov rcx, hFile ; HANDLE hFile (here: Stdout)
lea rdx, hello ; LPCVOID lpBuffer
lea r9, BytesWritten ; LPDWORD lpNumberOfBytesWritten
mov r8d, LENGTHOF hello ; DWORD nNumberOfBytesToWrite
mov qword ptr [rsp+32], 0 ; LPOVERLAPPED lpOverlapped = NULL
call WriteFile ; Call WinAPI
exit:
; https://msdn.microsoft.com/library/windows/desktop/ms682658.aspx
xor ecx, ecx ; Set RCX to null for return value
call ExitProcess ; Call WinAPI to exit
main ENDP
end
This is a 64-bit Console application that starts at the procedure main.
8) Change the Solution Platforms to x64
9) Choose PROJECT - Properties.
10) In the Properties window you have to complete two linker options:
Entry Point: main
SubSystem: Console (/SUBSYSTEM:CONSOLE)
Choose at the left side Configuration Properties - Linker - All Options , change both options at once and click OK.
11) Build and run the .exe with CTRL-F5. The application will be opened in a new window.
Now overwrite Source.asm with a 32-bit Console application:
.MODEL flat, stdcall
; https://learn.microsoft.com/en-us/cpp/assembler/masm/proto
GetStdHandle PROTO STDCALL, ; https://learn.microsoft.com/en-us/windows/console/getstdhandle
nStdHandle: SDWORD
WriteFile PROTO STDCALL, ; https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-writefile
hFile: DWORD, ; output handle
lpBuffer: PTR BYTE, ; pointer to buffer
nNumberOfBytesToWrite: DWORD, ; size of buffer
lpNumberOfBytesWritten: PTR DWORD, ; num bytes written
lpOverlapped: PTR DWORD ; ptr to asynchronous info
ExitProcess PROTO STDCALL, ; https://learn.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-exitprocess
dwExitCode: DWORD ; return code
.DATA ; https://learn.microsoft.com/en-us/cpp/assembler/masm/dot-data
Hallo db "Hello world!",13,10
.DATA? ; https://learn.microsoft.com/en-us/cpp/assembler/masm/dot-data-q
lpNrOfChars dd ?
.CODE ; https://learn.microsoft.com/en-us/cpp/assembler/masm/dot-code
main PROC ; learn.microsoft.com/en-us/cpp/assembler/masm/proc
invoke GetStdHandle, -11 ; -> StdOut-Handle into EAX
invoke WriteFile, eax, OFFSET Hallo, LENGTHOF Hallo, OFFSET lpNrOfChars, 0
invoke ExitProcess, 0
main ENDP
END main ; https://learn.microsoft.com/en-us/cpp/assembler/masm/end-masm
Change the Solution Platforms to x86 (No. 8 above) and complete the project properties with SubSystem: Console (/SUBSYSTEM:CONSOLE) (No. 10 above). You must not set the Entry point, because ml32 expects the entry point after the END directive (END main). Build and run the .exe with CTRL-F5.

Size of shadow area on the stack in assembler language

I found the sample program below somewhere on the Web. Various copies of it abound, usually with small differences. But my question concerns the size of the shadow area at the top of the stack when calling a function from the Windows API. This program works perfectly as shown, with decimal 40 subtracted from the stack pointer, to allow room for the 4 parameters that are passed in registers, plus one more. However, in this case there is no 5th parameter, and yet if the sub rsp, 40 is changed to sub rsp, 32, and no other changes are made, the 'Hello world' window is no longer displayed! Is there some reason why when only 4 parameters are involved, all of which are passed in registers, it's still necessary to reserve 40 (5*8) bytes at the top of the stack rather than only 32 (4*8)?
; Sample x64 Assembly Program
; Chris Lomont 2009 www.lomont.org
; command to assemble is:
; ml64 hello.asm /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Start
extrn ExitProcess: PROC ; in kernel32.lib
extrn MessageBoxA: PROC ; in user32.lib
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
sub rsp, 40 ; shadow space, aligns stack
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, message ; LPCSTR lpText
lea r8, caption ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA ; call MessageBox API function
mov ecx, eax ; uExitCode = MessageBox(...)
call ExitProcess
Start ENDP
End

Failed to create a main window using Windows API and x86 assembly

The program compiles fine, but it fails to create the main window. Specifically, CreateWindowEx fails and prints "Failed to create window".
Would anyone happen to know what I'm doing wrong? I'm following Kip Irvine's book on assembly almost exactly, but it seems I'm missing something.
EDIT: I updated the code based on the recommendations. Now the program fails to register the window class, and the specific error is that a "Parameter is incorrect". I looked over the parameters of my WNDCLASSEX struct, and couldn't fine anything wrong.
EDIT2: I removed the "Ex" from WNDCLASS and RegisterClass and the window shows up and works fine now. So I guess it was some kind of weird redefinition or inconsistency of structs and functions in the masm32rt library?
INCLUDE \masm32\include\masm32rt.inc
.data
windowName BYTE "ASM Windows App",0
className BYTE "ASMWin",0
MainWinClass WNDCLASSEX <NULL,CS_HREDRAW + CS_VREDRAW,WinProc,NULL,NULL,NULL,NULL,NULL,COLOR_WINDOW+1,NULL,className,NULL>
windowHandle DWORD ?
hInstance DWORD ?
.code
WinMain PROC
; Get a handle to the current process.
INVOKE GetModuleHandle, NULL
mov hInstance, eax
mov MainWinClass.hInstance, eax
; Check if the handle was received.
.IF eax == 0
pushad
print "Failed to get handle on current process"
popad
call ErrorHandler
jmp ExitProgram
.ENDIF
; Load the program's icon and cursor.
INVOKE LoadIcon, NULL, IDI_APPLICATION
mov MainWinClass.hIcon, eax
INVOKE LoadCursor, NULL, IDC_ARROW
mov MainWinClass.hCursor, eax
; Create the window class.
INVOKE RegisterClassEx, ADDR MainWinClass
; Check if the class was registered.
.IF eax == 0
pushad
print "Failed to register class."
popad
call ErrorHandler
jmp ExitProgram
.ENDIF
; Create the window.
INVOKE CreateWindowEx, 0, ADDR className, ADDR windowName, WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL
; Check if window was created successfully.
.IF eax == 0
pushad
print "Failed to create window"
popad
call ErrorHandler
jmp ExitProgram
.ENDIF
; Save the window handle and use it to show the window.
mov windowHandle, eax
INVOKE ShowWindow, windowHandle, SW_SHOW
INVOKE UpdateWindow, windowHandle
; Message Loop
;MessageLoop:
; INVOKE GetMessage, ADDR msg, NULL, NULL, NULL
; INVOKE DispatchMessage, ADDR msg
; jmp MessageLoop
ExitProgram:
;CALL ReadChar
INVOKE ExitProcess, 0
WinMain ENDP
; Window Procedure
WinProc PROC,
hWnd:DWORD, localMsg:DWORD, wParam:DWORD, lParam:DWORD
mov eax, localMsg
.IF eax == WM_CREATE
;call WriteString
jmp WinProcExit
.ELSEIF eax == WM_CLOSE
;call WriteString
jmp WinProcExit
.ELSE
;call WriteString
INVOKE DefWindowProc, hWnd, localMsg, wParam, lParam
jmp WinProcExit
.ENDIF
WinProcExit:
ret
WinProc ENDP
ErrorHandler PROC
.data
pErrorMsg DWORD ?
messageID DWORD ?
.code
INVOKE GetLastError
mov messageID, eax
; Get the corresponding message string.
INVOKE FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER + \
FORMAT_MESSAGE_FROM_SYSTEM,NULL,messageID,NULL,
ADDR pErrorMsg,NULL,NULL
; Display the error message.
INVOKE MessageBox, NULL, pErrorMsg, NULL,
MB_ICONERROR+MB_OK
; Free the error message string.
INVOKE LocalFree, pErrorMsg
ret
ErrorHandler ENDP
END WinMain
WNDCLASSEX requires WNDCLASSEX.cbSize to be set. The mistake I made was that I assumed it could be NULL.
So I added this piece of code before registering the class:
; Initializing other parameters of the window class.
mov eax, SIZEOF MainWinClass
mov MainWinClass.cbSize, eax
In addition, Kip Irvine's functions cause errors when used along side some functions of the user interface section of the Windows API. I'm not exactly sure why that happens but it could be that some register values are changed around.

Win32 Assembly - WriteFile() to console don't show output

I'm now programming some Windows native assembly, using NASM 2.12.01 and GCC 4.8.1 as a linker.
However, this simple HelloWorld program compiles & links without any complaints, but doesn't output anything to console screen.
It seems that GetStdHandle doesn't return a valid handle to a current console, so the output doesn't get shown up.
But problem might be some other.
Code:
; Name: hello.asm
; Assemble: nasm.exe -fwin32 hello.asm
; Link: gcc -mwindows -o hello hello.obj -lkernel32 -lmsvcrt
; Run: a.exe
BITS 32
extern _GetStdHandle#4
extern _WriteFile#20
extern _ExitProcess#4
extern __getch
extern _puts
SECTION .data
str: db `Hello world!\n` ; C-like strings in NASM with backticks
strlen equ $-str
pause: db "Do you know where the ANY key is? :-)",0
SECTION .text
GLOBAL _main
_main:
; Stack frame for NumberOfBytesWritten
push ebp
sub esp, 4
; http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231.aspx
; HANDLE WINAPI GetStdHandle(
; _In_ DWORD nStdHandle
; );
push -11
call _GetStdHandle#4
; http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747.aspx
; BOOL WINAPI WriteFile(
; _In_ HANDLE hFile,
; _In_ LPCVOID lpBuffer,
; _In_ DWORD nNumberOfBytesToWrite,
; _Out_opt_ LPDWORD lpNumberOfBytesWritten,
; _Inout_opt_ LPOVERLAPPED lpOverlapped
; );
push 0 ; lpOverlapped,
lea ebx, [ebp-4] ; EBX: address of NumberOfBytesWritten
push ebx ; lpNumberOfBytesWritten,
push strlen ; nNumberOfBytesToWrite
push str ; lpBuffer,
push eax ; hFile (result from GetStdHandle
call _WriteFile#20
; msvcrt.dll (C library)
push pause
call _puts ; http://msdn.microsoft.com/library/tf52y4t1.aspx
add esp, 4
call __getch ; http://msdn.microsoft.com/library/078sfkak.aspx
; ExitProcess (0)
push 0
call _ExitProcess#4
In order to generate a console application, you must use the -mconsole option to GCC. See the online documentation, section 3.18.55, x86 Windows Options.
You're using -mwindows which creates a GUI application. Windows does not create a console or set the standard handles when launching GUI applications.
You never set up the stack frame correctly!
This is not the proper way:
push ebp
sub esp, 4
Are you missing something? Your stack is messed up!
The prolouge should be :
push ebp
mov ebp, esp
sub esp, 4
For the epilouge, just reverse that.

Resources