ReadConsoleInputA throws an Access Violation

1

I am trying to learn how to use the windows api (instead of just using C calls, irvine32 or masm32) And are running into issues with ReadConsoleInputA (WriteConsoleA works fine).

Also, I don't get why in the PROC prototype for the function, most examples append either an A or a W at the end of ReadConsoleInput/WriteConsole, can you explain why?

.data
consoleOutHandle dd ?
consoleInHandle dd ?
bufferlen dd ?
buffer db ?
bufferSize DWORD ?
message db "Enter a number:", 0
lmessage equ $-message


.code
main PROC

    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov consoleOutHandle, eax

    invoke ReadConsoleInputA, consoleOutHandle, offset buffer, 128, bufferSize
main endp
end main

It throws: Access violation writing location 0x00000004.

Following the advice from Michael Petch, I have this code now:

.data
consoleOutHandle dd ?
consoleInHandle dd ?
byteswritten dd ?
bufferlen dd ?
buffer db 128 DUP(?)
bufferSize dd ?
message db "Enter a number:", 0
lmessage equ $-message


.code
main PROC
    invoke GetStdHandle, STD_INPUT_HANDLE
    mov consoleInHandle, eax
    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov consoleOutHandle, eax
    mov eax, lmessage
    invoke WriteConsoleA, consoleOutHandle, offset message, eax, bytesWritten, 0

    invoke ReadConsoleInputA, consoleInHandle, offset buffer, 128, offset bufferSize
main endp
end main

And now it throws "triggered a breakpoint".

Disassembly:

invoke ReadConsoleInputA, consoleInHandle, offset buffer, 128, offset bufferSize
00E71066  push        offset bufferSize (0E74090h)  
00E7106B  push        80h  
00E71070  push        offset buffer (0E74010h)  
00E71075  push        dword ptr [consoleInHandle (0E74004h)]  
00E7107B  call        _ReadConsoleInputA@16 (0E7100Ah)  
--- No source file -------------------------------------------------------------
00E71080  int         3    **---> Breakpoint here**
00E71081  int         3  
windows
winapi
assembly
x86
masm
asked on Stack Overflow Aug 2, 2019 by Wolfeius • edited Aug 2, 2019 by Wolfeius

1 Answer

2

You asked what the A and W suffix on the end of the WinAPI functions are for. Functions ending with A denote Ansi, and functions ending with W are Wide. Microsoft documents them this way:

Unicode and ANSI Functions When Microsoft introduced Unicode support to Windows, it eased the transition by providing two parallel sets of APIs, one for ANSI strings and the other for Unicode strings. For example, there are two functions to set the text of a window's title bar:

  • SetWindowTextA takes an ANSI string.
  • SetWindowTextW takes a Unicode string.

In the first version of the code

  • You don't allocate space necessary for buffer. You had:

    buffer db ?
    

    That allocated a single byte to the buffer. It should have been:

    buffer db 128 DUP(?)
    
  • You used STD_OUTPUT_HANDLE instead of STD_INPUT_HANDLE

  • The last parameter to ReadConsoleInputA is a pointer to a DWORD that will return the number of events read. Changing the variable name bufferSize might make the code more readable. From the ReadConsoleInputA documentation:

    BOOL WINAPI ReadConsoleInput(
     _In_  HANDLE        hConsoleInput,
     _Out_ PINPUT_RECORD lpBuffer,
     _In_  DWORD         nLength,
     _Out_ LPDWORD       lpNumberOfEventsRead
    );
    
  • If you are reading just the keyboard you should be using ReadConsoleA as ReadConsoleInputA will process keyboard and mouse events and may prematurely return before your string is read. ReadConsoleA takes one extra parameter and you can set it to NULL:

    BOOL WINAPI ReadConsole(
     _In_     HANDLE  hConsoleInput,
     _Out_    LPVOID  lpBuffer,
     _In_     DWORD   nNumberOfCharsToRead,
     _Out_    LPDWORD lpNumberOfCharsRead,
     _In_opt_ LPVOID  pInputControl
    );
    
  • To exit the program you need to invoke ExitProcess .


In the second version of the code

  • Your code does:

    invoke WriteConsoleA, consoleOutHandle, offset message, eax, bytesWritten, 0
    

    bytesWritten needs to be a pointer because that is an output parameter. From WriteConsoleA documentation:

    BOOL WINAPI WriteConsole(
     _In_             HANDLE  hConsoleOutput,
     _In_       const VOID    *lpBuffer,
     _In_             DWORD   nNumberOfCharsToWrite,
     _Out_            LPDWORD lpNumberOfCharsWritten,
     _Reserved_       LPVOID  lpReserved
     );
    

A version of the code that uses ReadConsoleA instead of ReadConsoleInputA based on your second code example could look like:

.data
consoleOutHandle dd ?
consoleInHandle dd ?
bytesWritten dd ?
bufferlen dd ?
buffer db 128 DUP(?)
numEvents dd ?
message db "Enter a number:", 0
lmessage equ $-message

.code
main PROC
    invoke GetStdHandle, STD_INPUT_HANDLE
    mov consoleInHandle, eax
    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov consoleOutHandle, eax
    mov eax, lmessage
    invoke WriteConsoleA, consoleOutHandle, offset message, eax, offset bytesWritten, 0

    invoke ReadConsoleA, consoleInHandle, offset buffer, 128, offset numEvents, 0
    invoke ExitProcess, 0
main endp
end main

This code can be cleaned up a bit by using MASM's sizeof operator. The code could be written as:

.data
consoleOutHandle dd ?
consoleInHandle dd ?
buffer db 128 DUP(?)
bytesWritten dd ?
numEvents dd ?
message db "Enter a number:", 0

.code
main PROC
    invoke GetStdHandle, STD_INPUT_HANDLE
    mov consoleInHandle, eax
    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov consoleOutHandle, eax
    invoke WriteConsoleA, consoleOutHandle, offset message, sizeof message, offset bytesWritten, 0
    invoke ReadConsoleA, consoleInHandle, offset buffer, sizeof buffer, offset numEvents, 0
    invoke ExitProcess, 0
main endp
end main
answered on Stack Overflow Aug 2, 2019 by Michael Petch • edited Aug 2, 2019 by Michael Petch

User contributions licensed under CC BY-SA 3.0