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

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.

Related

Print hexa value in masm

I do a MapViewOfFile to get a pointer on the begin of my file, after that I want to print the value of it in hexa.
When I print it as string I get "MZ" which is the good value (the magic number) but I want it in hexa (5A4D).
I tried to format with %x in wsprintf but it doesn't work, I got 230000 as value..
EDIT the tried for %x:
.data
header_format db "The header is: %x",0
buffer db 256 dup(?) ; File data
.data?
pMemory DWORD ? ; Pointer to the data in the source file
getData:
;pMemory is the ptr which is correctly printed with %s
invoke wsprintf, ADDR buffer, ADDR header_format, [pMemory] ;
invoke MessageBox, NULL, Addr buffer, Addr header_test, MB_OK
Have you any suggestions ?
Thanks.
It finally works by using this solution :
push STD_OUTPUT_HANDLE
call GetStdHandle
mov eax, pMemory
push eax
print right$(uhex$(eax),2),13,10
pop eax
mov eax, pMemory
push eax
print right$(uhex$([eax]),2),13,10
pop eax

Detecting Key Events

I am having trouble trying to detect key events in the x86 assembly language. When I run my program, I get this generic error:
key.exe has encountered a problem and needs to close. We are sorry for the inconvenience.
fasm, my assembler, generates a .bin file, a .exe file, and a .com file. If I try running the .com file, a message box pops up saying that the image file is valid, but is for a machine type other than the current machine.
Here is my code:
include 'include/win32ax.inc'
section '.data' data readable writeable
inchar DB ?
numwritten DD ?
numread DD ?
outhandle DD ?
inhandle DD ?
char DB ?
section '.text' code readable executable
start:
;set up the console
invoke AllocConsole
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov [outhandle],eax
invoke GetStdHandle,STD_INPUT_HANDLE
mov [inhandle],eax
;get key press
mov ah,1h
int 21h
mov [char],AL
;print out the key pressed
invoke WriteConsole,[outhandle],char,15,numwritten,0
invoke ReadConsole,[inhandle],inchar,1,numread,0
invoke ExitProcess,0
.end start
I am using a x64 edition of windows xp, but it is compatible with 32-bit applications.
If you are creating Win32 program, you can't use DOS API ( int 21h ) in order to get pressed keys.
You should use ReadConsoleInput function and check for keyboard events.
Here is how this can be done:
include '%fasminc%/win32ax.inc'
section '.data' data readable writeable
struc KEY_EVENT_RECORD {
.fKeyDown dd ?
.Repeat dw ?
.VirtKeyCode dw ?
.VirtScanCode dw ?
.res dw ?
.char dd ?
.ctrl dd ?
}
struc INPUT_RECORD {
.type dw ?
.event KEY_EVENT_RECORD
}
KEY_EVENT = 1
inchar DB ?
numwritten DD ?
numread DD ?
outhandle DD ?
inhandle DD ?
input INPUT_RECORD
count dd ?
section '.text' code readable executable
start:
;set up the console
invoke AllocConsole
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov [outhandle],eax
invoke GetStdHandle,STD_INPUT_HANDLE
mov [inhandle],eax
.loop:
invoke ReadConsoleInput, [inhandle], input, 1, count
cmp [count], 1
jne .loop
cmp [input.type], KEY_EVENT
jne .loop
;print out the key pressed
invoke WriteConsole,[outhandle],input.event.char,1,numwritten,0
invoke ReadConsole,[inhandle],inchar,1,numread,0
invoke ExitProcess,0
.end start

Assembly : Dealing with user input in windows nasm

I'm a newbie to asm and trying to make a simple hello world which awaits for the user to press a key to end. For now the hello world is all good, but the .exe console program i got from this just close instantly while i want it to stay on screen untill the user press a key.
Now the problem i have is that for some reason, the program keep looping, searching for user input, but when i force close the program (^C) i can see all the keys i pressed are written on the next console line, like if it was using the wrong buffer (?)
I've been searching a fix all over the internet for a few days and finally I'm asking for help cuz this is driving me crazy ^^
Everything i found is mostly based on int system or under linux, while i have to deal with the windows api...
Thank you very much, any help or hint is welcome!
Code :
STD_OUTPUT_HANDLE equ -11
STD_INPUT_HANDLE equ -10
NULL equ 0
global start
extern ExitProcess, GetStdHandle, WriteConsoleA, ReadConsoleInputA
section .data
msg db "Hello World!", 13, 10, 0
msg.len equ $ - msg
consoleInHandle dd 1
section .bss
buffer resd 2
buffer2 resd 2
section .text
start:
push STD_OUTPUT_HANDLE
call GetStdHandle
push NULL
push buffer
push msg.len
push msg
push eax
call WriteConsoleA
read:
push STD_INPUT_HANDLE
call GetStdHandle
mov [consoleInHandle],eax
push consoleInHandle
push dword[buffer2]
push 1
push NULL
call ReadConsoleInputA
cmp eax,1
jge exit
jmp read
exit:
push NULL
call ExitProcess
Moar info about windows functions can be found here:
ReadConsoleInput
WriteConsole
push consoleInHandle pushes the address, not the handle. You want push dword [consoleInHandle]. Conversely, for the buffer you want to pass the address, so you need push buffer2 there. Also, this buffer should be the size of an INPUT_RECORD structure, which I believe is 32 bytes.
Update: As Frank commented, the argument order was also wrong.
This code works for me (note I had to add the #xx stdcall decorations due to how my environment is set up - apparently you don't need those):
STD_OUTPUT_HANDLE equ -11
STD_INPUT_HANDLE equ -10
NULL equ 0
global start
extern ExitProcess#4, GetStdHandle#4, WriteConsoleA#20, ReadConsoleInputA#16
section .data
msg db "Hello World!", 13, 10, 0
msg.len equ $ - msg
consoleInHandle dd 1
section .bss
buffer resd 2
buffer2 resb 32
section .text
start:
push STD_OUTPUT_HANDLE
call GetStdHandle#4
push NULL
push buffer
push msg.len
push msg
push eax
call WriteConsoleA#20
read:
push STD_INPUT_HANDLE
call GetStdHandle#4
mov [consoleInHandle],eax
push NULL
push 1
push buffer2
push dword [consoleInHandle]
call ReadConsoleInputA#16
exit:
push NULL
call ExitProcess#4

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

Resources