© Jo Van Hoey 2019
J. Van HoeyBeginning x64 Assembly Programminghttps://doi.org/10.1007/978-1-4842-5076-1_40

40. Using the Windows API

Jo Van Hoey1 
(1)
Hamme, Belgium
 

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

Listing 40-1 shows a version of a “Hello, World” program that makes use of the Windows API to display a message on the screen.
; helloc.asm
%include "win32n.inc"
      extern WriteFile
      extern WriteConsoleA
      extern GetStdHandle
section .data
      msg            db       'Hello, World!!',10,0
      msglen  EQU    $-msg-1            ; leave off the NULL
section .bss
      hFile                   resq      1      ; handle to file
      lpNumberOfBytesWritten  resq      1
section .text
      global main
main:
push  rbp
mov   rbp,rsp
; get a handle to stdout
;HANDLE WINAPI GetStdHandle(
;  _In_ DWORD nStdHandle
;);
      mov   rcx, STD_OUTPUT_HANDLE
      sub   rsp,32               ;shadowspace
      call  GetStdHandle         ;returns INVALID_HANDLE_VALUE if no success
      add   rsp,32
      mov   qword[hFile],rax     ;save received handle to memory
;BOOL WINAPI WriteConsole(
;  _In_                    HANDLE      hConsoleOutput,
;  _In_      const VOID    *lpBuffer,
;  _In_            DWORD   nNumberOfCharsToWrite,
;  _Out_           LPDWORD        lpNumberOfCharsWritten,
;  _Reserved_      LPVOID         lpReserved
;);
      sub   rsp, 8                ;align the stack
      mov   rcx, qword[hFile]
      lea   rdx, [msg]            ;lpBuffer
      mov   r8, msglen            ;nNumberOfBytesToWrite
      lea   r9, [lpNumberOfBytesWritten]
      push  NULL                  ;lpReserved
      sub   rsp, 32
      call  WriteConsoleA         ;returns nonzero if success
      add   rsp,32+8
; BOOL WriteFile(
;            HANDLE       hFile,
;            LPCVOID      lpBuffer,
;            DWORD        nNumberOfBytesToWrite,
;      LPDWORD     lpNumberOfBytesWritten,
;      LPOVERLAPPED    lpOverlapped
;);
      mov   rcx, qword[hFile]    ; file handle
      lea   rdx, [msg]           ;lpBuffer
      mov   r8, msglen           ;nNumberOfBytesToWrite
      lea   r9, [lpNumberOfBytesWritten]
      push  NULL                 ;lpOverlapped
      sub   rsp,32
      call  WriteFile            ;returns nonzero of success
leave
ret
Listing 40-1

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.

Figure 40-1 shows the output.
../images/483996_1_En_40_Chapter/483996_1_En_40_Fig1_HTML.jpg
Figure 40-1

helloc.asm output

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.

Listing 40-2 shows the example code.
; hellow.asm
%include "win32n.inc"
extern ExitProcess
extern MessageBoxA
section .data
      msg    db 'Welcome to Windows World!',0
      cap    db "Windows 10 says:",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
      mov     r9d,MB_OK          ; window with OK button
      sub     rsp,32             ; shadowspace
      call    MessageBoxA        ; returns IDOK=1 if OK button selected
      add     rsp,32
leave
ret
Listing 40-2

hellow.asm

Figure 40-2 shows the output.
../images/483996_1_En_40_Chapter/483996_1_En_40_Fig2_HTML.jpg
Figure 40-2

hellow.asm output

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

In this chapter, you learned about the following:
  • 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

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.157.142