Hey guys.

Please bare with me since I'm only learning asm for about 48 hours or so..

I've learned enough to open files, read from/write to them...
I know how to use the WIN API from within ASM and ..honestly, it's much simpler than C++ (IMHO)...

So..I've written this basic program wich should be pretty simple to read..
It(should) basically copy a file...

.386
.model flat, stdcall
option casemap :none

Include    windows.inc
Include    user32.inc
Include    kernel32.inc
IncludeLib    user32.lib
IncludeLib    kernel32.lib

.data
theFile DB "n_Copy.exe", 0
inputText DD 0
inputFile DB "C:\WINDOWS\NOTEPAD.EXE", 0

iFile DD 0
File DD 0
written DD 0
iwritten DD 0
fSize DD 0

.code
start:




;=================== open file ================;
        push 0
        push FILE_ATTRIBUTE_NORMAL
        Push OPEN_EXISTING
        push 0
        push FILE_SHARE_READ
        Push GENERIC_READ
        Push Offset inputFile
        call CreateFile
        Mov iFile, Eax
;=================== set write head at 0 ================;
        Push FILE_BEGIN
        push 0
        push 0
        Push iFile
        call SetFilePointer

        Push 0
           Push iFile
           Call GetFileSize
        ; at this point eax should be equal to the file size right?

;=================== read from file ================;
         Push 0
         Push Offset iwritten
         Push Eax ;
         Push Offset inputText
         Push iFile
         Call ReadFile
;=================== close file ================;
        Push iFile
        Call CloseHandle


;=================== create file ================;
        Push 0
        push FILE_ATTRIBUTE_NORMAL
        push OPEN_ALWAYS
        push 0
        push FILE_SHARE_READ
        push GENERIC_WRITE
        push offset theFile
        call CreateFile
        mov File,eax
;=================== set write head at 0 ================;
        push FILE_END
        push 0
        push 0
        push File
        call SetFilePointer
;=================== get string length ================;
        Push Offset inputText
        call lstrlen
;=================== write to file ================;
         push 0
         Push Offset written
         Push iwritten         ;iwritten how holds the number of bytes read...
         Push Offset inputText
         push File
         call WriteFile
;=================== close file ================;
        push File
        call CloseHandle
;=================== exit app ================;
        invoke ExitProcess,eax
        invoke PostQuitMessage,0
end start

the problem is that the code works great for a givven number of bytes to be read, but since I couldn't possibly compile my program everytime I copy another file, I tried using the GetFileSize API to ..well..get the file size :D
But there's something wrong in that GetFileSize area because the resulting file is always 0 byte in length...

if I change

Push 0
          Push Offset iwritten
          Push Eax ;
          Push Offset inputText
          Push iFile
          Call ReadFile

with

Push 0
          Push Offset iwritten
          Push 1048 ;just an example....
          Push Offset inputText
          Push iFile
          Call ReadFile

it works like a charm...

I would appreciate if someone would have a quick look and guide me on my way...
Cheers and thanks in advance

Recommended Answers

All 10 Replies

I can't see what's wrong, but, if you can't put it in a debugger and single step it, I would write a short procedure to display the contents of eax after each call. That way you should get a better idea of when things start going AWOL.

By the way, I notice you aren't clearing the stack after each call. In C the called procedure won't do it for you, so if you push n bytes before the call, you have got to pop them again afterwards.

invoke ExitProcess,eax
        invoke PostQuitMessage,0

I think you should delete the call to ExitProcess because it will not give the windows application a chance to do proper cleanup. I believe ExitProcess is intended only for console programs.

>>But there's something wrong in that GetFileSize area
I don't see your program calling GetFileSize() ????

invoke ExitProcess,eax
        invoke PostQuitMessage,0

I think you should delete the call to ExitProcess because it will not give the windows application a chance to do proper cleanup. I believe ExitProcess is intended only for console programs.

>>But there's something wrong in that GetFileSize area
I don't see your program calling GetFileSize() ????

Thanks for the advice...

I am calling GetFileSize here:

;=================== set write head at 0 ================;
        Push FILE_BEGIN
        push 0
        push 0
        Push iFile
        call SetFilePointer

        Push 0
           Push iFile
           Call GetFileSize
        ; at this point eax should be equal to the file size right?

Cheers

your program does not verify that CreateFile() returned an invalid file handle. It should check that the value stored in eax is greater than two (0, 1 and 2 are reserved handles).

By the way, I notice you aren't clearing the stack after each call. In C the called procedure won't do it for you, so if you push n bytes before the call, you have got to pop them again afterwards.

win32 api functions use __stdcall calling convention -- the called functions clean up the stack before returning. So stack cleanup is not necessary in his asm program.

After a little testing I got it (GetFileSize) to work when coded as inline assembly. After opening a file it is not necessary to move the file pointer to the beginning of the file because that is the default behavior unless stated otherwise in MSDN.

;=================== open file ================;
        push 0
        push FILE_ATTRIBUTE_NORMAL
        Push OPEN_EXISTING
        push 0
        push FILE_SHARE_READ
        Push GENERIC_READ
        push offset inputFile
        call dword ptr CreateFileA
        mov iFile, eax
;=================== set write head at 0 ================;
        Push FILE_BEGIN
        push 0
        push 0
        Push [iFile]
        call dword ptr SetFilePointer

        Push 0
        Push iFile
        Call dword ptr GetFileSize
        mov File,eax

;=================== close file ================;
        push iFile
        call dword ptr CloseHandle

ok..after a bit of searching the net I modified something I found and got it working as I want..as short as possible :D

There's only one thing..
the original code used masm32 syntax..
It makes life easier if you use the MACRO'S defined within MASM, but I want to do everything with direct instructions, not invoke's or stuff like that..(I know there no logic here..but heck...I just want to learn the hard way :) )
Here's the code:

.386
.model flat,stdcall
option casemap:none

Include    windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib

.data

szSrcFile       DB "C:\\WINDOWS\NOTEPAD.EXE", 0
szDestFile      DB "n_Copy.exe", 0
szBuffer        db 1024 dup (0)
hSrcFile HANDLE ?
hDestFile HANDLE ?
dwBytesReaden DWord ?
dwBytesWritten DWord ?


.Const
BUFFER_SIZE    Equ 1024

.Code

start:

;open file for reading
Push 0
Push 0
Push OPEN_EXISTING
Push 0
Push FILE_SHARE_READ
Push GENERIC_READ
Push Offset szSrcFile
Call CreateFile
Mov hSrcFile, Eax

;open file for writing
Push 0
Push 0
Push CREATE_ALWAYS
Push 0
Push FILE_SHARE_WRITE
Push GENERIC_WRITE
Push Offset szDestFile
Call CreateFile
Mov hDestFile, Eax

;read
.While TRUE
invoke ReadFile, hSrcFile,addr szBuffer, BUFFER_SIZE, addr dwBytesReaden,NULL
.Break .If (dwBytesReaden == 0)
Invoke WriteFile, hDestFile, Addr szBuffer, dwBytesReaden, Addr dwBytesWritten, NULL
.EndW


;clean up
Invoke CloseHandle, hSrcFile
invoke CloseHandle, hDestFile
Invoke ExitProcess, NULL

end start

Anyways..I've managed to translate the original MASM syntax to normal instructions, except this part:

;read
.While TRUE
invoke ReadFile, hSrcFile,addr szBuffer, BUFFER_SIZE, addr dwBytesReaden,NULL
.Break .If (dwBytesReaden == 0)
Invoke WriteFile, hDestFile, Addr szBuffer, dwBytesReaden, Addr dwBytesWritten, NULL
.EndW

Could anyone show me what would be a good "translation" of these MASM MACRO's ?
Thanks in advance
Cheers

Invoke is simply a shortcut to normal calling process. just push the parameters onto the stack, call the function, then do stack cleanup, if required. Nothing about it any different than the other code that has been posted in this thread.

Invoke is simply a shortcut to normal calling process. just push the parameters onto the stack, call the function, then do stack cleanup, if required. Nothing about it any different than the other code that has been posted in this thread.

Oh..I know about that..that's the way I converted the other lines, but I don't know how to convert the .if part...it has to be a loop until EOF, otherwise it will only read 1024 bytes*the bufer size), then write it to the file, then exit..so I end up as I started, only reading predefined byte length...

I guess it would come down to this:

;read
.While TRUE
Push 0
push offset dwBytesReaden
push offset BUFFER_SIZE
push offset szBuffer
push offset hSrcFile
call ReadFile
 
.Break .If (dwBytesReaden == 0)
push 0
push offset dwBytesWritten
push offset dwBytesReaden
push offset szBuffer
push offset hDestFile
call WriteFile
.EndW

I'm still left with the while loop...

Thanks guys

Cheers

just put a few compares and jumps in there.

lp: ; start of read/write loop
;read
Push 0
push offset dwBytesReaden
push offset BUFFER_SIZE
push offset szBuffer
push offset hSrcFile
xor eax,eax ; clear the register
call ReadFile
cmp eax,0 ; read error ?
jz done   ; yes, then go
cmp dwBytesReaden,0 ; end-of-file ?
jz done   ; yes, then go

push 0
push offset dwBytesWritten
push offset dwBytesReaden
push offset szBuffer
push offset hDestFile
call WriteFile
;;
;; now make similar error checking tests
;;
jmp lp ; back to top

done:
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.