The Windows application programming interface (API) is a set of functions that can be used by a developer to interact with the operating system. As mentioned in the previous chapter, syscalls are not a reliable way to communicate with the operating system, but Microsoft provides a large set of APIs to accomplish just about everything you could think of. The Windows API is written with the C programming language in mind, but if we comply with the calling conventions, we can easily use the Windows API in our assembler programs. The description of the Windows API can be found here (at the time of this writing): https://docs.microsoft.com/en-us/windows/win32/api/ .
Console Output
helloc.asm
The Windows API documentation uses thousands and thousands of symbolic constants. This makes the code more readable and makes it easier to use the Windows API, so we include the file win32n.inc at the beginning of our program. This is a list of all symbolic constants and their values. The win32n.inc file can be found here: http://rs1.szif.hu/~tomcat/win32/ . However, be aware that including this file in your source will make the executable much larger than it needs to be. If space is important, just include only the constants you need in your program. If you use SASM, find the folder where SASM is installed and manually copy the file into the SASM include directory on your system.
In the code we copy the structure of the Windows function calls in comments so that it is easy to follow what is happening. We put the arguments in registers according to the calling convention, provide shadow space on the stack, call the function, and then restore the stack pointer.
The function GetStdHandle returns a handle if everything goes well; otherwise, it returns INVALID_HANDLE_VALUE. To keep it simple, we do no error checking, but in real production programs, you are advised to implement comprehensive error checking in your programs. Failure to do so can crash your program or, worse, can be the cause of security breaches.
When we have a handle, we continue to WriteConsoleA, passing the handle, the string to write, the length of the string, a placeholder for the number of bytes written, and NULL for a reserved argument. The first four arguments are passed in the registers, and the fifth argument is pushed onto the stack. This push will cause the stack to be unaligned; we have to anticipate this before we push the argument to the stack. If we aligned after the push, the function called would not find the argument on the stack. Just before we do the call, we create the shadow space on the stack.
Our program uses two methods to write to the console; one uses WriteConsoleA, and the other uses WriteFile. The WriteFile uses the same handle and considers the console as just another file to write to. After WriteConsoleA, we restore the stack for the shadow space and the alignment. After WriteFile, we do not restore the stack, because that will be done by the leave instruction.
If you do not find WriteConsoleA in the Windows API documentation, look for WriteConsole . The documentation explains that there are two versions, WriteConsoleA for writing ANSI and WriteConsoleW for writing Unicode.
When you run this code in SASM, you will see that the first method with WriteConsoleA does not work. The function returns 0 in rax, hinting that something went wrong. That is because we are interfering with the SASM console itself. The method using WriteFile works fine.
Building Windows
Instead of using the console, we will now use the Windows GUI. We will not provide a full-fledged Windows program; we want to show you how to display a window. If you want to do more, you will have to dive into the Windows API documentation. Once you have seen how it works, it is just a matter of finding the right function in the Windows API documentation and passing the arguments in the registers and stack.
hellow.asm
Of course, you can question if assembly is the right programming language to build a GUI for your Windows program. It is much easier to use C or C++ for that purpose and call in assembly for the computation-intensive parts.
Anyway, you can take any good book on Windows programming in C or C++, where the Windows API is explained, and translate all the function calls into assembly by providing the correct registers and then calling the function as demonstrated. Of course, complicated functionality such as error checking is needed, and that is just so much easier to develop in a higher-level language.
Summary
How to use the Windows API
How to write a message to the Windows CLI (PowerShell)
How to use the instructions GetStdHandle, WriteConsole, and WriteFile
How to create a window with a button