Windows Assembly (x86) Read from Stdin and output to Stdout - windows

I recently figured out how to write to stdout in assembly but am now having trouble reading from stdin, and outputting what I read back to stdout. This is the code I have so far:
.386
.model flat, stdcall
WriteFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
ReadFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
GetStdHandle PROTO STDCALL:DWORD
.data
.data?
input DW ?
input_size DD ?
read DD ?
.code
main:
INVOKE GetStdHandle, -10
INVOKE ReadFile, eax, OFFSET input, input_size, read, 0
INVOKE GetStdHandle, -11
INVOKE WriteFile, eax, OFFSET input, OFFSET input_size, read, 0
RET
END main
I'm pretty sure I'm reading it wrong. I am pretty sure that input_size and read are not behaving as expected (if I replace input_size with a number it displays a space number times) which is contributing to my problem (when I enter my input and hit return it simply displays nothing).
I have fumbled around with this for quite some time and would appreciate any help. (I am doing this just to learn this is not homework).
My question essentialy is what am I doing wrong?

You are allocating only two bytes for the input buffer:
input DW ?
Your input size is zero, causing ReadFile to read a maximum of 0 bytes:
input_size DD ?
nNumberOfBytesToRead should be passed as a value and not a pointer. And you want to write as many bytes as were input in the Readfile:
INVOKE WriteFile, eax, OFFSET input, OFFSET input_size, read, 0
INVOKE WriteFile, eax, OFFSET input, read, read, 0

Related

ReadConsoleInputA throws an Access Violation

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
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

why is this masm assembly code not working in a loop, code works perfectly the first time but in a loop does not work

hey I have been using masm for 2 weeks now and I am trying to read from a text file line by line that has paths of files in them
example of text file
C:\a.rar
C:\a.txt
C:\a.png
then I want to read in the whole contents of the file path and get the md5 check sum of the file path
the below code works perfectly for the first time(the first message box is the file path,the second is the contents of the file and the third is the md5 check sum)
but then after the first loop it reads the second files path but can not read the contents of the second file and then crashes because it has nothing to md5 check sum.
it must be a easy mistake of not resetting something or not closing something but I have spent like 20 hours on this and can not get it to work
for example the below code is in a button and when you press the button this is what it is supposed to do
message box C:\a.rar
message box "contents of file"
message box 44644af7515bc4870d44fa688684798
message box C:\a.txt
message box "contents of file"
message box 6057f13c496ecf7fd777ceb9e79ae285
message box C:\a.png
message box "contents of file"
message box 01654ab48d84f484z446ba48453cb48
but this is what happens
message box C:\a.rar
message box "contents of file"
message box 44644af7515bc4870d44fa688684798
message box C:\a.txt
blank contents cant read the contents of the file on loop (this is the problem)
message box blank because it cant md5 no contents
crash
can someone please help
LOCAL Buffer3 :DWORD
invoke CreateFile, ADDR filestoscan, GENERIC_READ, 0, 0,OPEN_EXISTING, 0, 0
mov hFile, eax
invoke GetFileSize,hFile,NULL
mov Byteforstreamreader,eax
streamreader2:
.if Byteforstreamreader != 0
invoke ReadFile, hFile, ADDR Buffer2,1, ADDR BytesWritten, 0
.if Buffer2 == 13
invoke CreateFile, ADDR StringBuffer, GENERIC_READ, 0, 0,OPEN_EXISTING, 0, 0
mov hFile2, eax
invoke GetFileSize,hFile2,NULL
mov Bytes,eax
invoke ReadFile, hFile2, ADDR FileBuffer,Bytes, ADDR BytesWritten, 0
invoke CloseHandle,hFile2
invoke MessageBoxA, NULL, addr StringBuffer, offset BoxCaption, NULL
invoke MessageBoxA, NULL, addr FileBuffer, offset BoxCaption, NULL
invoke MD5_Startup
invoke MD5_Init, offset ctxt
invoke MD5_Read, offset ctxt, offset FileBuffer, Bytes
invoke MD5_Digest, offset ctxt, offset filehash
invoke MD52String, offset filehash, offset strn, 1
invoke MessageBoxA, NULL, addr strn, offset BoxCaption, NULL
mov FileBuffer,0
mov StringBuffer,0
dec Byteforstreamreader
jmp streamreader2
.endif
mov eax,offset Buffer2
mov Buffer3,eax
invoke lstrcat,ADDR StringBuffer,addr Buffer2
dec Byteforstreamreader
jmp streamreader2
.endif
.if Byteforstreamreader == 0
invoke CloseHandle,hFile
.endif
.data
filestoscan db "myfiles.txt",0
FileBuffer DB 50000 DUP(?)
Bytes dd ?
Bytes2 dd ?
BytesWritten dd ?
BytesWritten3 dd ?
hFile dd ?
hFile2 dd ?
.data ?
hFile dd ?
Byteforstreamreader dd ?
BytesWritten2 dd ?
StringBuffer DB 100 DUP(?)
Buffer2 db 500 dup (?)
ctxt db 1000 dup (?)
filehash db 1000 dup (?)
strn db 33 dup(?) ; use dw for unicode
also as a side question if someone could please answer it does not seem right to me to have to reserve 50000 bytes on filebuffer so I can open a 50000 bytes or smaller file. how can I open any file size without reserving all that memory because some of these files may be 100 mb or more
thank you
Here's a somewhat annotated version of your streamreader2 loop:
streamreader2:
.if Byteforstreamreader != 0
invoke ReadFile, hFile, ADDR Buffer2,1, ADDR BytesWritten, 0
; check for end-of-line (CR)
.if Buffer2 == 13
; open the file named in Buffer2 and
; do a bunch of stuff to it to get the MD5
;
; ...
mov FileBuffer,0
mov StringBuffer,0
dec Byteforstreamreader
jmp streamreader2
.endif
; I don't know what the purpose of these two lines are
mov eax,offset Buffer2
mov Buffer3,eax
; append the character just read from hFile to StringBuffer
invoke lstrcat,ADDR StringBuffer,addr Buffer2
dec Byteforstreamreader
jmp streamreader2
.endif
So no characters read from hFile are handled specially except for 13 (CR). However, I think there's a good chance that the line endings in that file are CRLF so when the next file is opened the name will have a LF control character at the start of it. So the CreateFile or fopen call will fail to open the file.

Windows (x86) Assembly Append Null Terminator To Inputted String

I am currently trying to append a null terminator to an(a?) user inputted string:
.386
.model flat, stdcall
WriteFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
ReadFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
GetStdHandle PROTO STDCALL:DWORD
.data
buff DB 100h DUP(?)
stdInHandle DWORD 0
bytesRead DWORD ?
.code
start:
;read string from stdin
INVOKE GetStdHandle, -10
MOV stdInHandle, eax
INVOKE ReadFile, stdInHandle, BYTE PTR[buff], 100, ADDR bytesRead, 0
;append null terminator on CR,LF
MOV eax, bytesRead
MOV edx, BYTE PTR[buff]
SUB eax, 2
AND BYTE PTR [eax+edx], 0
RET
END start
It refuses to assemble at MOV edx, BYTE PTR[buff] and gives me an error:
error: Invalid combination of opcode and operands (or wrong CPU setting).
So I'm assuming I cannot MOV the value of BYTE PTR[buff] into register edx. So I can't even begin to test if this method of trying to apply a NULL terminator to a string will even work.
My question is, what is wrong with the above code (should I use a different register instead of edx?)
What is the best way to apply a NULL terminator to the string?
You can't move a byte value into a dword sized register. You either need to use a byte sized register such as dl, or zero-extend it with movzx. As you are working with bytes, I suggest you go with the first option.
When I had to create methods for strings without using anything from good ole Irvine, I got the length of the string, incremented what the length returned as (you need to include an extra +1 for the null-terminator) by 1, and then added 0h to the end of the string where the pointer was where the counter is.
MOV EAX, SIZEOF lpSourceString + 1 ; Get the string length of string, add 1 to include null-terminator
INVOKE allocMem, EAX ; Allocate memory for a target to copy to
LEA ESI, [lpSourceString] ; put source address in ESI
MOV EDI, EAX ; copy the dest address to another register we can increment
MOV ECX, SIZEOF lpSourceString ; Set up loop counter
We have the size of the string. Now we can add the null-terminate to it. To do that, we need to make sure that we have a pointer looking at the end of the string. So if we have a method that returns a string in EAX, EAX needs to point to the start of the string (so we leave the allocMem unmodified, instead incrementing a copy in EDI). Let's say that we are putting characters in a string:
nextByte: ; Jump label, get the next byte in the string until ECX is 0
MOV DL, [ESI] ; Get the next character in the string
MOV [EDI], DL ; Store the byte at the position of ESI
INC ESI ; Move to next char in source
INC EDI ; INCrement EDI by 1
loop nextByte ; Re-loop to get next byte
MOV byte ptr[EDI], 0h ; Add null-terminator to end of string
; EAX holds a pointer to the start of the dynamically-allocated
; 0-terminated copy of lpSourceString
MOV requires the byte ptr size specifier because neither the [EDI] memory operand nor the 0 immediate operand would imply a size for the operation. The assembler wouldn't know if you meant a byte, word, or dword store.
I have this in my MASM, but I use a String_length stdcall method I had written due to a class requirement.
This is so common that the MASM32 runtime supplies this functionality as part of its runtime. All you need to do is include the relevant code:
include \masm32\include\masm32rt.inc
Then use the StripLF function as so:
invoke StripLF, addr buff
To fix your current problem (if you want to do it manually) , you need to move the address of buff to edx instead.
mov edx, offset buff

Assembly and Win32API input output

I am trying to figure this out but am stumped a bit. What I am trying to do is to use the ReadConsole/WriteConsole functions from the win32 lib and got it to work a degree but just not there. I am having trouble getting the second write console working correctly. I don't think I am sending the buffer to the variable right. I must be missing something here and I dont know what it is.
Here is what I have so far
TITLE MASM Template (main.asm)
; Description:
;
; Revision date:
INCLUDE Irvine32.inc
BufSize = 80
.data
endl EQU <0dh,0ah> ; end of line sequence
;variable holders
firstN db ?
fNSize db ($-firstN)
;messages for getting input
fName LABEL BYTE
BYTE "Enter your first name", endl
fNameSize DWORD ($-fName)
;output handlers
consoleHandle HANDLE 0 ; handle to standard output device
bytesWritten DWORD ? ; number of bytes written
;input handlers
buffer BYTE BufSize DUP(?)
stdInHandle HANDLE ?
bytesRead DWORD ?
.code
main PROC
; Get the console output handle:
INVOKE GetStdHandle, STD_OUTPUT_HANDLE
mov consoleHandle,eax
; Write a string to the console:
INVOKE WriteConsole,
consoleHandle, ; console output handle
ADDR fName, ; string pointer
fNameSize, ; string length
ADDR bytesWritten, ; returns num bytes written
0 ; not used
; Get handle to standard input
INVOKE GetStdHandle, STD_INPUT_HANDLE
mov stdInHandle,eax
; Wait for user input
INVOKE ReadConsole, stdInHandle, ADDR buffer,
BufSize, ADDR bytesRead, 0
;cheack to see if read consol worked
mov esi, OFFSET buffer
mov ecx, bytesRead
mov ebx, TYPE buffer
call DumpMem
;move the input into the variable
mov firstN, TYPE buffer
; Write a string to the console:
INVOKE WriteConsole,
consoleHandle, ; console output handle
ADDR firstN, ; string pointer
fNSize, ; string length
ADDR bytesWritten, ; returns num bytes written
0 ; not used
INVOKE ExitProcess,0
main ENDP
END main
Thanks for any help :)
firstN and fNSize are each a single byte and that's not what you want. Simply do this for the second WriteConsole call:
INVOKE WriteConsole,
consoleHandle, ; console output handle
ADDR buffer, ; string pointer
bytesRead, ; string length
ADDR bytesWritten, ; returns num bytes written
0 ; not used

MASM32 Assembly - Reading a number from Console

Sorry if this question is really simple, but I tried all that I know and coudn't figure it out.
I'm trying to make a simple procedure which takes a string and a Count from the console and print the string number of times specified by the Count.
Everything is fine, but when I mov the Count to eax for a loop, the value get's messed up and I end up with an infinite loop of print.
I tried to change the Count to DWORD with atodw, but didn't work.
here's the code :
PrintString PROTO :DWORD, :DWORD
.data
String db 100 DUP(0)
Count db 10 DUP(0)
.code
start:
;1- get user input
invoke StdIn, addr String, 99
invoke StdIn, addr Count, 10
;2- Remove the CRLF from count
invoke StripLF, addr Count
;3- Convert the count to DWORD
invoke atodw, addr InputCount
mov Counter, eax
;4- Call the Printer function
invoke Printer, addr String, addr Count
Printer PROC StringToPrint:DWORD, count:DWORD
mov eax,count ;;;;;; This is the problem I think
Looppp:
push eax
invoke StdOut, StringToPrint
pop eax
dec eax
jnz Looppp
ret
Printer endp
You’re passing addr Count – the address of the string – as the second argument to Printer. But it expects an integer, so you want to pass Counter instead.
Since you’re using a language without type checking, adopting a naming convention such as Hungarian notation for your identifiers could help you see and avoid this kind of problem. With the variables here named strCount and dwCount, for example, it would be more obvious that you were using the wrong one.
As an aside, eax must eventually reach zero so your printing loop won’t be infinite – just rather longer than you intended…

Resources