Author Topic: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)  (Read 10096 times)

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Hello!

This is a demonstration: "How to Read File Into Memory Buffer?".

Things you find here,n can see here:
  • Visually attractive explanation of procedure ReadFileIntoBuffer.
  • Verify your Win64 Assembly skills, by following the explanation tags.
  • Relax and watch: Video demonstration of this source code and runtime.
  • Attachment of FULL example source code.

Formal description:

Code: [Select]
; ---------------------------------------------------------------------------
; This is: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
; Author: J.K. Encryptor256
; Date: October 27, 2013
; ---------------------------------------------------------------------------
; Description:
; Read file into memory buffer, then display message box of  buffer contents.
; (Im not using any macros, so, everything should be clear and strightforward)
; ---------------------------------------------------------------------------
; Procedures:
; 1. main
; 2. ReadFileIntoBuffer
; ---------------------------------------------------------------------------
; Using:
;
; 1. The Netwide Assembler, NASM (http://nasm.us/)
;        The Netwide Assembler, NASM: It is an 80x86 and x86-64 assembler
;        designed for portability and modularity.
;
; 2. Minimalist GNU for Windows, MinGW64 (http://mingw-w64.sourceforge.net/)
;        Mingw-w64: It delivers runtime, headers and libs for developing
;        both, 64 bit (x64) and  32 bit (x86) windows applications, using GCC and
;        other free software compilers.
;
;        GCC is a part of MINGW64 toolset.
;
; 3. GoLink, (http://www.godevtool.com/)
;
; ---------------------------------------------------------------------------
; How to compile:
;
; Like this, in the way i did:
;
; 1. NASM: "nasm.exe helloworld.asm -f win64 -o helloworld.obj"
; Output obj size: 1.54 KB (1,580 bytes)
;
; Choose your linker:
;
; 2.1. GCC: "gcc.exe helloworld.obj -m64 -o helloworld.exe"
; Output exe size: 45.2 KB (46,332 bytes)
;
; 2.2. GoLink: "golink.exe /entry main main.obj MSVCRT.dll kernel32.dll user32.dll"
; Output exe size: 2.00 KB (2,048 bytes), looks like some container size
;
; ---------------------------------------------------------------------------

Here goes, procedure ReadFileIntoBuffer:

ReadFileIntoBuffer:; PROCEDURE
; ---------------------------------------------------------------------------
; Read file conents into a buffer
; ---------------------------------------------------------------------------
; Arg's:
; ---------------------------------------------------------------------------
; 1. address, of file name
; 2. address, where to store "address to data"
; 3. address, where to store "data len"
; ---------------------------------------------------------------------------
; Returns:
; ---------------------------------------------------------------------------
; OnSuccess: RAX equals 1.
; OnError: RAX equals 0.
; ---------------------------------------------------------------------------
; Description:
; ---------------------------------------------------------------------------
; A. When entering a function:
; 1. Save registers in home space
mov qword [rsp+8],rcx
mov qword [rsp+16],rdx
mov qword [rsp+24],r8
mov qword [rsp+32],r9
; 2. Allocate stack space for 4x default args
; 3. Allocate stack space for 3x local variables
sub rsp,qword 8*7
; ---------------------------------------------------------------------------
; Info:
; 1. Local variable nr. 1, at address [rsp+8*4], file handle
; 2. Local variable nr. 2, at address [rsp+8*5], file size
; 3. Local variable nr. 3, at address [rsp+8*6], buffer address
; ---------------------------------------------------------------------------
; B. When exiting a function:
; 1. De-Allocate stack space of 4x default args
; 2. De-Allocate stack space of 3x local variables
; ---------------------------------------------------------------------------
         
; Label; Code; Description
; 1. [fopen]; Open target file
; 1.1. onerror: rax is 0
; 1.2. onsuccess: save file handle into local variable nr. 1
mov rdx,qword file_access_rb
call fopen; [1.]
cmp rax,qword 0; [1.1.]
jne .openSuccess
xor rax,rax; OnError: RAX equals 0.
add rsp,qword 8*7; [B.] Deallocate stack
ret
.openSuccess:
mov qword [rsp+8*4],rax; [1.2.]
2. [fseek]; Set file pointer to the end of file: SEEK_END
2.1. onsuccess: rax is 0
2.2. onerror: [fclose]; Close file handle, that were obtained at pt. 1.
mov r8,qword 2
xor rdx,rdx
mov rcx,rax
call fseek; [2.]
cmp rax,qword 0; [2.1.]
je .fseekEnd
mov rcx,qword [rsp+8*4]
call fclose; [2.2.]
xor rax,rax
add rsp,qword 8*7
ret
.fseekEnd:
; 3. [ftell]; Get's File size
; 3.1. onerror: rax is -1
; 3.2. onerror: [fclose]
; 3.3. onsuccess: save file size into local variable nr. 2
mov rcx,qword [rsp+8*4]
call ftell; [3.]
cmp rax,qword 0; [3.1.]
jg .ftellSuccess
mov rcx,qword [rsp+8*4]
call fclose; [3.2.]
xor rax,rax
add rsp,qword 8*7
ret
.ftellSuccess:
mov qword [rsp+8*5],rax; [3.3.]
; 4. [fseek]; Set file pointer to the start of file: SEEK_SET
; 4.1. onsuccess: rax is 0
; 4.2. onerror: [fclose]
mov r8,qword 0
xor rdx,rdx
mov rcx,qword [rsp+8*4]
call fseek; [4.]
cmp rax,qword 0; [4.1.]
je .fseekSet
mov rcx,qword [rsp+8*4]
call fclose; [4.2.]
xor rax,rax
add rsp,qword 8*7
ret
.fseekSet:
; 5. [malloc]; Allocate buffer of file size, file size were obtained at pt. 3.
; 5.1. onerror: rax is 0
; 5.2. onerror [fclose]
; 5.3. onsuccess: save buffer address into local variable nr. 3
mov rcx,qword [rsp+8*5]
call malloc; [5.]
cmp rax,qword 0; [5.1.]
jne .mallocSuccessSZ
mov rcx,qword [rsp+8*4]
call fclose; [5.2.]
xor rax,rax
add rsp,qword 8*7
ret
.mallocSuccessSZ:
mov qword [rsp+8*6],rax; [5.3.]
; 6. [fread]; Read data of file size in buffer address, that were obtained at pt. 5.
; 6.1. onsuccess: rax is equals to file size
; 6.2. onerror: [free]; Free allocated buffer address, that were obtained at pt. 5.
; 6.3. onerror: [fclose]
mov r9,qword [rsp+8*4]
mov r8,qword [rsp+8*5]
mov rdx,qword 1
mov rcx,rax
call fread; [6.]
cmp rax,qword [rsp+8*5] ; [6.1.]
je .freadSuccess
mov rcx,qword [rsp+8*6]
call free; [6.2.]
mov rcx,qword [rsp+8*4]
call fclose; [6.3.]
xor rax,rax
add rsp,qword 8*7
ret
.freadSuccess:
; 7. Success
; 7.1. Store allocated buffer address into arg nr. 2
; 7.2. Store size of allocated buffer into arg nr. 3
; 7.3. [fclose]
mov rdx,qword [rsp+8*6]
mov rax,qword [rsp+8*7+16]
mov qword [rax],rdx; [7.1.]
mov rdx,qword [rsp+8*5]
mov rax,qword [rsp+8*7+24]
mov qword [rax],rdx; [7.2.]
mov rcx,qword [rsp+8*4]
call fclose; [7.3.]
mov rax,qword 1; OnSuccess: RAX equals 1.
add rsp,qword 8*7
ret

How to call "ReadFileIntoBuffer" procedure: you can find on source code, at attachment: main.asm.



Video demonstration:
Watch on youtube, named: "Win64 Read File Into Memory Buffer Win64 API NASM GCC GoLink"
Link: http://youtu.be/AD7Kp934Un0

Added attachment, named:
"win64_readfileintomem_nasm_gcc_golink.zip",
contains files: input.txt, main.asm, main.exe, main.obj.

And that's it,
Encryptor256!!!
Encryptor256's Investigation \ Research Department.

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #1 on: November 02, 2013, 06:35:07 AM »
Here is another version:

; ###################################################### ;
; cmdAllocateBuffer - Allocates zero buffer of specified size
;
;   Usage:
;      ------------------------------------------
;      ; this will create new buffer of LIST_SIZE size.
;      ------------------------------------------
;      mov rcx,qword LIST_SIZE
;      call cmdAllocateBuffer
;
; Returns, pointer to buffer, returned in rax.
;
; ###################################################### ;

Code: [Select]
cmdAllocateBuffer:
mov qword [rsp+8*1],rcx ; buffer size
sub rsp,qword 8*5
call malloc
cmp rax,qword 0
jne .gotMem
add rsp,qword 8*5
ret
.gotMem:
mov r8,qword [rsp+8*5+8*1]
mov qword [rsp+8*5+8*1],rax
mov rdx,qword 0
mov rcx,rax
call memset
mov rax,qword [rsp+8*5+8*1]
add rsp,qword 8*5
ret

; ###################################################### ;
; cmdReadFileIntoBuffer - Reads file data into buffer
;
;   Usage:
;      mov rcx,qword addressOfFilename
;      call cmdReadFileIntoBuffer
;
; Returns address of buffer into rax.
; Returns buffer len into rcx.
; Clear's carry on success.
; Set's carry on failure.
;
; ###################################################### ;

Code: [Select]
cmdReadFileIntoBuffer:
mov qword [rsp+8*1],rcx; filename
mov qword [rsp+8*2],qword 0; (tmp) store file handle
mov qword [rsp+8*3],qword 0; (tmp) store file size
mov qword [rsp+8*4],qword 0; (tmp) store buffer address
sub rsp,qword 8*5
cmp rcx,qword 0
jne .gotSomeFileName
add rsp,qword 8*5
stc
ret
.gotSomeFileName:
mov qword [rsp+8*4],qword "rb"
lea rdx,[rsp+8*4]
call fopen
cmp rax,qword 0
jne .fileOpened
add rsp,qword 8*5
stc
ret
.fileOpened:
mov qword [rsp+8*5+8*2],rax
mov rcx,rax
xor rdx,rdx
mov r8,qword 2
call fseek
cmp rax,qword 0
je .fseekSuccessEnd
mov rcx,qword [rsp+8*5+8*2]
call fclose
add rsp,qword 8*5
stc
ret
.fseekSuccessEnd:
mov rcx,qword [rsp+8*5+8*2]
call ftell
cmp rax,qword 0
jne .ftellSuccess
mov rcx,qword [rsp+8*5+8*2]
call fclose
add rsp,qword 8*5
stc
ret
.ftellSuccess:
mov qword [rsp+8*5+8*3],rax
mov rcx,rax
call cmdAllocateBuffer
cmp rax,qword 0
jne .gotBuffer
mov rcx,qword [rsp+8*5+8*2]
call fclose
add rsp,qword 8*5
stc
ret
.gotBuffer:
mov qword [rsp+8*5+8*4],rax
mov rcx,qword [rsp+8*5+8*2]
xor rdx,rdx
mov r8,qword 0
call fseek
cmp rax,qword 0
je .fseekSuccessStart
mov rcx,qword [rsp+8*5+8*2]
call fclose
mov rcx,qword [rsp+8*5+8*4]
call free
add rsp,qword 8*5
stc
ret
.fseekSuccessStart:
mov rcx,qword [rsp+8*5+8*4]
mov rdx,qword 1
mov r8,qword [rsp+8*5+8*3]
mov r9,qword [rsp+8*5+8*2]
call fread
cmp rax,qword [rsp+8*5+8*3]
je .freadSuccess
mov rcx,qword [rsp+8*5+8*2]
call fclose
mov rcx,qword [rsp+8*5+8*4]
call free
add rsp,qword 8*5
stc
ret
.freadSuccess:
mov rcx,qword [rsp+8*5+8*2]
call fclose
mov rax,qword [rsp+8*5+8*4]
mov rcx,qword [rsp+8*5+8*3]
add rsp,qword 8*5
clc
ret

Define file access into stack:
Code: [Select]
...
        mov qword [rsp+8*4],qword "rb"
lea rdx,[rsp+8*4]
call fopen
...
Encryptor256's Investigation \ Research Department.

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #2 on: November 17, 2013, 10:37:24 AM »
Don't like previous versions? :D
Here!
Here is another, another version:

; -----------------------------------------------------------;
;
; Procedure: sysReadFileContents
;
; Reads file contents into buffer.
; If file size is zero, then error is set.
;
; Usage:
;
;           txt_filename: db "test.txt",0
;           ...
;           mov rcx,qword txt_filename
;           call sysReadFileContents
;           jc .quitError
;
;           mov rcx,rax
;           call sysFreeMemory
;           jc .quitError
;
;
; Returns a pointer to buffer into RAX.
; Returns a buffer len into RCX.
; Set's carry flag on error.
; Clear's carry flag on success.
;
; -----------------------------------------------------------;

; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; Imports n Exports:
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;


      global sysReadFileContents
      extern fopen, fclose, fread, ftell, fseek

; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; Section: CODE
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;
; =>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=> ;


Code: [Select]
; -----------------------------------------------------------;
;
; Procedure: sysReadFileContents
;
; -----------------------------------------------------------;

sysReadFileContents:

      ; Check arg
      cmp rcx,qword (0)
      jne .proceed
      stc
      ret
.proceed:

      ; Save arg
      mov qword [rsp+8*1],rcx; filename, null terminated
      mov qword [rsp+8*2],qword ("rb"); (unused)

      ; Create stack
      push rbp
      mov rbp,rsp
      push rbx; file buffer address
      push r12; file size
      push r13; file handle
      push r14; zero on success, nzero on error
      lea rsp,[rsp-(8*4)]

      ; Init file buffer address
      ; Init error indicator
      ; Init file handle
      xor rbx,rbx
      xor r14,r14
      xor r13,r13

      ; Try open file
      ; rcx is already set
      lea rdx,[rsp+8*4+8*5+8*2]
      call fopen
      cmp rax,qword (0)
      je .quitError

      ; Save file handle
      mov r13,rax

      ; fseek SEEK_END
      mov rcx,r13
xor rdx,rdx
mov r8,qword 2
call fseek
      cmp rax,qword (0)
      jne .quitError

      ; ftell
      mov rcx,r13
      call ftell
      cmp rax,qword 0
      je .quitError

      ; Save file size
      mov r12,rax

      ; fseek SEEK_SET
      mov rcx,r13
xor rdx,rdx
mov r8,qword 0
call fseek
      cmp rax,qword (0)
      jne .quitError

      ; Allocate buffer
      mov rcx,r12
      call sysAllocateMemory
      jc .quitError

      ; Save buffer address
      mov rbx,rax

      ; Read file
      mov rcx,rbx
mov rdx,qword (1)
mov r8,r12
mov r9,r13
call fread
cmp rax,r12
      je .quitSuccess

      ; ~Error:
.quitError:

      ; Set Error indicator
      sete r14b

      ; ~Success:
.quitSuccess:

      ; Close file
      cmp r13,qword (0)
      je .fileClosed
      mov rcx,r13
      call fclose
.fileClosed:

      ; Check for error:
      cmp r14b,byte (0)
      jne .onError
.onSuccess:

      ; Set return values
      mov rax,rbx
      mov rcx,r12

      ; Clear carry flag
      clc

      jmp .finalize
.onError:

      ; Release allocated buffer
      cmp rbx,qword (0)
      je .noBuffer
      mov rcx,rbx
      call sysFreeMemory
.noBuffer:

      ; Set carry flag
      stc

      ; Clear stack n quit
.finalize:
      lea rsp,[rsp+(8*4)]
      pop r14
      pop r13
      pop r12
      pop rbx
      pop rbp
      ret

Information about these procedures:
  • sysAllocateMemory
  • sysFreeMemory
You can find on thread, named: "Win64 Crypto API SHA1 MD5 (Example code)".
Link topic: http://forum.nasm.us/index.php?topic=1752.0
Link msg: http://forum.nasm.us/index.php?topic=1752.msg7550#msg7550

Bye,
Encryptor256!!!
« Last Edit: November 17, 2013, 10:39:49 AM by encryptor256 »
Encryptor256's Investigation \ Research Department.

Offline HD1920.1

  • Jr. Member
  • *
  • Posts: 40
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #3 on: February 05, 2014, 02:44:50 PM »
All programs are not Win64 API because they require MSVCRT.DLL (C library).

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #4 on: February 05, 2014, 04:14:04 PM »
All programs are not Win64 API because they require MSVCRT.DLL (C library).

The Windows API (Win32) is implemented in the C programming language.
The same for Win64 API.
Win64 API is built on C, so, it is permitted to use C Runtime Library,
if computer don't have a Current, Up to date, Runtime Libraries,
then it is considered to be an outdated system.

Roses are red,
Violets are blue,
So,
What was the point of your statement?

Encryptor256's Investigation \ Research Department.

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 430
  • Country: us
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #5 on: February 05, 2014, 09:25:49 PM »
The above mentioned code is most certainly Win64 - mainly due to the use of Win64's register calling convention.  In other words, it would not work on Win32, Linux, or any other OS except Win64.

The choice of using functions either exposed by the OS ( eg: contained in kernel32.dll/user32.dll ) or the use of Standard C library functions ( MSVCRT.DLL ) does not disqualify that code as Win64.  Encryptor256 has merely provided a way for someone to use said code to perform a small task specifically for Win64.

If the concern is the additional requirement of MSVCRT.DLL then simply substitute the C library calls with the appropriate OS-specific calls - problem solved.  I will, however, agree that the topic heading containing the word "API" could be somewhat misleading to someone expecting to see examples of system calls.  Perhaps "ABI" would have been more appropriate - or removed completely even more so...

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #6 on: February 06, 2014, 08:29:28 AM »

Well, what can i say...
Okay, fine, i'm quilty. :)


Encryptor256's Investigation \ Research Department.

Offline HD1920.1

  • Jr. Member
  • *
  • Posts: 40
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #7 on: May 11, 2014, 01:18:57 PM »
How to prevent that some random sh*t is displayed at the end of the message?

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #8 on: May 11, 2014, 10:48:17 PM »
How to prevent that some random sh*t is displayed at the end of the message?

Then don't "Read File Into Memory Buffer" that contains sh*t.

Random unexpected characters are caused by:
If buffer contains text and it is not null terminated.
If buffer that should contain text, actually contains some binary data.

If you want to read text file "mysh*t.txt", then:
Read file into buffer and terminate it with zero.

Easy peasy lemon squeezy, that's the problem for beginners, to discover and solve.
Encryptor256's Investigation \ Research Department.

Offline HD1920.1

  • Jr. Member
  • *
  • Posts: 40
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #9 on: May 12, 2014, 02:11:49 PM »
Then don't "Read File Into Memory Buffer" that contains sh*t.
This happened with your test file. I didn't modify anything (only unpacked the attached file).

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #10 on: May 12, 2014, 05:22:55 PM »
First time i uploaded - it worked!
Right now it works too - tried again.
Encryptor256's Investigation \ Research Department.

Offline HD1920.1

  • Jr. Member
  • *
  • Posts: 40
Re: Win64 Read File Into Memory Buffer (Win64 API, NASM, GCC, GoLink)
« Reply #11 on: May 13, 2014, 04:14:11 PM »
Right now it works too - tried again.
No, it doesn't.

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Encryptor256's Investigation \ Research Department.