Assembly Language Programming

May 31, 2015

FASM – Using The C File Functions

Filed under: Assembly Language, C++ — Tags: , , , — programmer209 @ 11:39 am

This post contains a couple of simple programs that demonstrate how to use the C file functions within x86 assembly language code. The assembler used is FASM – the Flat Assembler. Both of the programs are Win32 programs with a dialog box as the main window.

The first program is a simple text to html converter and uses the functions: fopen(), fclose(), fgets() and fputs().

The second program is a Base64 encoder and uses: fopen(), fclose(), fread() and fwrite().

Related Post

FASM – A Simple Win32 Hex Editor

Importing The C Functions

In windows, all of the standard C functions are available through the MS Visual C Runtime DLL – MSVCRT.DLL.

FASM code includes an import data section where the libraries and the functions that will be imported from them are defined. For example to import from MSVCRT.DLL, first the library instruction is used:

library msvcrt,'MSVCRT.DLL'

Then a table of the functions to be imported is defined using the import instruction:

import msvcrt,\
	memset,'memset',\
	fopen,'fopen',\
	fclose,'fclose',\
	fgets,'fgets',\
	fputs,'fputs'

For each entry in the table, the value in quotes is the exact name of the function as exported by the DLL. The other value labels a pointer which addresses the exported function. The function is then able to be called by referencing this pointer in the code.

Cinvoke

The imported functions, being standard C functions that use the cdecl calling convention, are called using the cinvoke macro:

cinvoke fopen,…

Or alternatively:

ccall [fopen],…

Remember that fopen is a pointer to the address of the exported function ‘fopen’.

The imported Win32 API functions, on the other hand, use the stdcall calling convention, so are called using either invoke or stdcall.

invoke MessageBox,…

stdcall [MessageBox],…

Using The C File Functions

This C pseudo-code outlines how the functions fopen(), fclose(), fgets(), and fputs() might be used within a C prgram:

  FILE *fp;

  char file_name[MAX_PATH];

  char buffer[1000];

  ...

  fp = fopen(file_name,"r+");

  if(fp)
  {
   // read a string from the file

   fgets(buffer,1000,fp);

   ...

   // write a string to the file

   fputs(buffer,fp);

   fclose(fp);
  }

The equivalent in FASM:

  cinvoke fopen,szFileName,szMode

  test eax,eax
  
  jz .ERROR_HANDLING

  mov [fp],eax

  cinvoke fgets,szBuffer,1000,[fp]

  ...

  cinvoke fputs,szBuffer,[fp]

  cinvoke fclose,[fp]

By convention, functions return their result in the EAX register. So after fopen has been called, EAX is tested to see whether the file open operation was succesful. If EAX contains a valid pointer, then it is copied to the location addressed by fp, so that it can be referenced by any of the other functions that need to access the open file.

Base64 Encoding

The Base64 program uses the MIME Base64 encoding scheme. Data from the input file is read 3 bytes at a time. The 24 bits are broken up into four groups of 6 bits, which are then encoded to generate the 4 output bytes. A 6 bit value is encoded by using it as an index into the string:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789+/

So for example: string[111110] = ‘+’

In the case where the number of input bytes is not a multiple of 3, then at the end of the encoding process there will be either 1 or 2 bytes remaining.

If only 1 byte remains, then 4 zero bits are appended to obtain two 6 bit values. These are Base64 encoded and then two equals sign characters are appended to get the 4 output bytes.

If 2 bytes remain, then 2 zero bits are appended to obtain three 6 bit values. These are Base64 encoded and then one equals sign character is appended to get the 4 output bytes.

Example One – TEXT 2 HTML – FASM Code

To grab this code, select with the mouse and then copy and paste directly into the FASM IDE.

; -------------------------------------------------------------------------------------

 format PE GUI 4.0

 entry start

 include 'win32a.inc'

; -------------------------------------------------------------------------------------

 IDD_MY_DIALOG = 102
 IDC_TXT_FILE = 1000
 IDC_HTM_FILE = 1001
 IDC_BTN_TXT = 1002
 IDC_BTN_HTM = 1003
 IDC_BTN_CONVERT = 1004

; -------------------------------------------------------------------------------------

 section '.code' code readable executable

  start:

	invoke GetModuleHandle,0

	invoke DialogBoxParam,eax,IDD_MY_DIALOG,0,DialogProc,0

  exit:

	invoke	ExitProcess,0

; -------------------------------------------------------------------------------------

proc DialogProc uses esi edi ebx,hwnddlg,msg,wparam,lparam

	cmp [msg],WM_INITDIALOG
	je .wminitdialog

	cmp [msg],WM_COMMAND
	je .wmcommand

	cmp [msg],WM_CLOSE
	je .wmclose

	xor eax,eax
	jmp .quit

  .wminitdialog:

	invoke SetDlgItemText,[hwnddlg],IDC_TXT_FILE,""
	invoke SetDlgItemText,[hwnddlg],IDC_HTM_FILE,""

	jmp .done

  .wmcommand:

	cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_TXT
	je .TXT_PATH

	cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_HTM
	je .HTM_PATH

	cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_CONVERT
	je .CONVERT

	jmp .done

  .TXT_PATH:

	; get the path for the input text file

	stdcall File_Open,[hwnddlg]

	test eax,eax

	jz .done

	invoke SetDlgItemText,[hwnddlg],IDC_TXT_FILE,szTextPath

	jmp .done

  .HTM_PATH:

	; get the path for the output html file

	stdcall File_Save_As,[hwnddlg]

	test eax,eax

	jz .done

	invoke SetDlgItemText,[hwnddlg],IDC_HTM_FILE,szHtmlPath

	jmp .done

  .CONVERT:

	; do the conversion

	stdcall Text_2_Html,[hwnddlg]

	jmp .done

  .wmclose:

	invoke EndDialog,[hwnddlg],0

  .done:

	mov eax,1

  .quit:

	ret

endp

; -------------------------------------------------------------------------------------

proc File_Open,hwnd

  ; display the GetOpenFileName dialog to get the text file path

	; zero ofn - the OPENFILENAME struct

	mov eax,sizeof.OPENFILENAME

	cinvoke memset,ofn,0,eax

	; initialise the members of ofn

	mov eax,sizeof.OPENFILENAME

	mov [ofn.lStructSize],eax

	mov eax,[hwnd]

	mov [ofn.hwndOwner],eax

	; the filter

	mov eax,szTxtFilter

	mov [ofn.lpstrFilter],eax

	lea eax,[szTextPath]

	mov [ofn.lpstrFile],eax

	mov eax,MAX_PATH

	mov [ofn.nMaxFile],eax

	mov eax,OFN_EXPLORER
	or eax,OFN_FILEMUSTEXIST
	or eax,OFN_HIDEREADONLY

	mov [ofn.Flags],eax

	mov eax,szTxt

	mov [ofn.lpstrDefExt],eax

	; display the dialog to get szTextPath

	invoke GetOpenFileName,ofn

	ret

endp

; -------------------------------------------------------------------------------------

proc File_Save_As,hwnd

  ; display the GetSaveFileName dialog to get the html file path

	; zero ofn - the OPENFILENAME struct

	mov eax,sizeof.OPENFILENAME

	cinvoke memset,ofn,0,eax

	; initialise the members of ofn

	mov eax,sizeof.OPENFILENAME

	mov [ofn.lStructSize],eax

	mov eax,[hwnd]

	mov [ofn.hwndOwner],eax

	; the filter

	mov eax,szHtmlFilter

	mov [ofn.lpstrFilter],eax

	lea eax,[szHtmlPath]

	mov [ofn.lpstrFile],eax

	mov eax,MAX_PATH

	mov [ofn.nMaxFile],eax

	mov eax,OFN_EXPLORER
	or eax,OFN_PATHMUSTEXIST
	or eax,OFN_HIDEREADONLY
	or eax,OFN_OVERWRITEPROMPT

	mov [ofn.Flags],eax

	mov eax,szHtml

	mov [ofn.lpstrDefExt],eax

	; display the dialog to get szHtmlPath

	invoke GetSaveFileName,ofn

	ret

endp

; -------------------------------------------------------------------------------------

proc Text_2_Html,hwnd

  ; read the text file line by line, enclose each line in P tags,

  ; and write to the output html file

	; check that szTextPath is not an empty string

	invoke GetDlgItemText,[hwnd],IDC_TXT_FILE,szTextPath,MAX_PATH

	test eax,eax

	jz .INVALID_PATH

	; check that szHtmlPath is not an empty string

	invoke GetDlgItemText,[hwnd],IDC_HTM_FILE,szHtmlPath,MAX_PATH

	test eax,eax

	jz .INVALID_PATH

	; open the text file

	; set the mode to "r" - open for reading

	lea esi,[szMode]

	mov [esi],byte 'r'

	mov [esi+1],byte 0

	; FILE* fp_txt = fopen(szTextPath,"r")

	cinvoke fopen,szTextPath,szMode

	mov [fp_txt],eax

	test eax,eax

	jz .ERR_FOPEN_TXT

	; open the html file

	; set the mode to "w" - open for writing

	lea esi,[szMode]

	mov [esi],byte 'w'

	mov [esi+1],byte 0

	; FILE* fp_htm = fopen(szHtmlPath,"w")

	cinvoke fopen,szHtmlPath,szMode

	mov [fp_htm],eax

	test eax,eax

	jz .ERR_FOPEN_HTM

	; write the html file opening tags

	; fputs(szHeader,fp_htm)

	cinvoke fputs,szHeader,[fp_htm]

  .GET_LINE:

	; read a line from the text file

	; fgets(szLine,10000,fp_text)

	cinvoke fgets,szLine,10000,[fp_txt]

	; returns NULL when EOF

	test eax,eax

	jz .FINAL

	; if the line is empty, discard it

	stdcall IsLineEmpty

	test eax,eax

	jz .GET_LINE

	; enclose the line of text just read in p tags,

	; and write to the output file

	cinvoke fputs,szPTag,[fp_htm]

	cinvoke fputs,szLine,[fp_htm]

	cinvoke fputs,szPCloseTag,[fp_htm]

	jmp .GET_LINE

  .FINAL:

	; write the html file closing tags

	cinvoke fputs,szFinal,[fp_htm]

	cinvoke fclose,[fp_htm]

  .FCLOSE_TXT:

	cinvoke fclose,[fp_txt]

	jmp .DONE

  .ERR_FOPEN_TXT:

	invoke MessageBox,NULL,szFopenError,szTextPath,MB_ICONERROR+MB_OK

	jmp .DONE

  .ERR_FOPEN_HTM:

	invoke MessageBox,NULL,szFopenError,szHtmlPath,MB_ICONERROR+MB_OK

	jmp .FCLOSE_TXT

  .INVALID_PATH:

	invoke MessageBox,NULL,szPathError,szTitle,MB_ICONERROR+MB_OK

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc IsLineEmpty

  ; return 0 if the line contains nothing but whitespace

	xor eax,eax

	lea esi,[szLine]

  .TEST:

	mov dl,[esi]

	inc esi

	cmp dl,0

	je .DONE

	cmp dl,13

	je .DONE

	cmp dl,10

	je .DONE

	cmp dl,32

	jle .TEST

	mov eax,1

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

section '.idata' import data readable writeable

  library kernel,'KERNEL32.DLL',\
	  user,'USER32.DLL',\
	  comdlg32,'COMDLG32.DLL',\
	  msvcrt,'MSVCRT.DLL'

  import kernel,\
	 GetModuleHandle,'GetModuleHandleA',\
	 ExitProcess,'ExitProcess'

  import user,\
	 DialogBoxParam,'DialogBoxParamA',\ 
	 SetDlgItemText,'SetDlgItemTextA',\
	 GetDlgItemText,'GetDlgItemTextA',\
	 MessageBox,'MessageBoxA',\
	 EndDialog,'EndDialog'

  import comdlg32,\
	 GetOpenFileName,'GetOpenFileNameA',\
	 GetSaveFileName,'GetSaveFileNameA'

  import msvcrt,\
	 memset,'memset',\
	 fopen,'fopen',\
	 fclose,'fclose',\
	 fgets,'fgets',\
	 fputs,'fputs'

; -------------------------------------------------------------------------------------

section '.text' readable writeable

  szTextPath rb MAX_PATH

  szHtmlPath rb MAX_PATH

  szTxt TCHAR "txt",0

  szHtml TCHAR "html",0

  szMode rb 4

  ; Note that the filter strings are double null terminated:

  szTxtFilter TCHAR "Text Files",0,"*.txt",0,"All Files",0,"*.*",0,0

  szHtmlFilter TCHAR "Html Files",0,"*.html",0,"All Files",0,"*.*",0,0

  szTitle TCHAR "Error",0

  szPathError TCHAR "Invalid file path!",0

  szFopenError TCHAR "Call to fopen failed!",0

  ofn OPENFILENAME

  fp_txt dd 0

  fp_htm dd 0

  szLine rb 10000

  szHeader TCHAR "

“,10,”Text 2 Html”,10,\ “”,10,10,””,10,10,0 szFinal TCHAR “”,10,”

",10,0

  szPTag TCHAR "

“,10,0 szPCloseTag TCHAR ”

",10,10,0

; -------------------------------------------------------------------------------------

section '.rc' resource data readable

  directory RT_DIALOG,dialogs

  resource dialogs,\
	IDD_MY_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,my_dialog

  dialog my_dialog,\
  'TXT 2 HTML',30,30,300,108,\
  DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\
  0,0,"Lucida Console",11

  dialogitem 'BUTTON','Input Text File',-1,5,5,290,36,BS_GROUPBOX+WS_VISIBLE,0
  dialogitem 'BUTTON',"Output Html File",-1,5,46,290,36,BS_GROUPBOX+WS_VISIBLE,0

  dialogitem 'EDIT',0,IDC_TXT_FILE,10,17,240,16,ES_AUTOHSCROLL+WS_BORDER+WS_VISIBLE,0
  dialogitem 'EDIT',0,IDC_HTM_FILE,10,57,240,16,ES_AUTOHSCROLL+WS_BORDER+WS_VISIBLE,0

  dialogitem 'BUTTON',"...",IDC_BTN_TXT,256,17,30,16,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"...",IDC_BTN_HTM,256,57,30,16,BS_PUSHBUTTON+WS_VISIBLE,0

  dialogitem 'BUTTON',"TXT to HTML",IDC_BTN_CONVERT,5,86,80,16,BS_PUSHBUTTON+WS_VISIBLE,0

  enddialog

; -------------------------------------------------------------------------------------

Example Two – Base64 – FASM Code

To grab this code, select with the mouse and then copy and paste directly into the FASM IDE.

; -------------------------------------------------------------------------------------

 format PE GUI 4.0

 entry start

 include 'win32a.inc'

; -------------------------------------------------------------------------------------

 IDD_MY_DIALOG = 102
 IDC_BIN_FILE = 1000
 IDC_B64_FILE = 1001
 IDC_BTN_BIN = 1002
 IDC_BTN_B64 = 1003
 IDC_BTN_CONVERT = 1004

; -------------------------------------------------------------------------------------

 section '.code' code readable executable

  start:

	invoke GetModuleHandle,0

	invoke DialogBoxParam,eax,IDD_MY_DIALOG,0,DialogProc,0

  exit:

	invoke	ExitProcess,0

; -------------------------------------------------------------------------------------

proc DialogProc uses esi edi ebx,hwnddlg,msg,wparam,lparam

	cmp [msg],WM_INITDIALOG
	je .wminitdialog

	cmp [msg],WM_COMMAND
	je .wmcommand

	cmp [msg],WM_CLOSE
	je .wmclose

	xor eax,eax
	jmp .quit

  .wminitdialog:

	invoke SetDlgItemText,[hwnddlg],IDC_BIN_FILE,""
	invoke SetDlgItemText,[hwnddlg],IDC_B64_FILE,""

	jmp .done

  .wmcommand:

	cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_BIN
	je .BIN_PATH

	cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_B64
	je .B64_PATH

	cmp [wparam],BN_CLICKED shl 16 + IDC_BTN_CONVERT
	je .CONVERT

	jmp .done

  .BIN_PATH:

	; get the path for the input binary file

	stdcall File_Open,[hwnddlg]

	test eax,eax

	jz .done

	invoke SetDlgItemText,[hwnddlg],IDC_BIN_FILE,szBinaryPath

	jmp .done

  .B64_PATH:

	; get the path for the output Base64 file

	stdcall File_Save_As,[hwnddlg]

	test eax,eax

	jz .done

	invoke SetDlgItemText,[hwnddlg],IDC_B64_FILE,szBase64Path

	jmp .done

  .CONVERT:

	; do the conversion

	stdcall EncodeBase64,[hwnddlg]

	jmp .done

  .wmclose:

	invoke EndDialog,[hwnddlg],0

  .done:

	mov eax,1

  .quit:

	ret

endp

; -------------------------------------------------------------------------------------

proc File_Open,hwnd

  ; display the GetOpenFileName dialog to get the binary file path

	; zero ofn - the OPENFILENAME struct

	mov eax,sizeof.OPENFILENAME

	cinvoke memset,ofn,0,eax

	; initialise the members of ofn

	mov eax,sizeof.OPENFILENAME

	mov [ofn.lStructSize],eax

	mov eax,[hwnd]

	mov [ofn.hwndOwner],eax

	; the filter

	mov eax,szBinFilter

	mov [ofn.lpstrFilter],eax

	lea eax,[szBinaryPath]

	mov [ofn.lpstrFile],eax

	mov eax,MAX_PATH

	mov [ofn.nMaxFile],eax

	mov eax,OFN_EXPLORER
	or eax,OFN_FILEMUSTEXIST
	or eax,OFN_HIDEREADONLY

	mov [ofn.Flags],eax

	mov eax,szTxt

	mov [ofn.lpstrDefExt],eax

	; display the dialog to get szBinaryPath

	invoke GetOpenFileName,ofn

	ret

endp

; -------------------------------------------------------------------------------------

proc File_Save_As,hwnd

  ; display the GetSaveFileName dialog to get the base64 file path

	; zero ofn - the OPENFILENAME struct

	mov eax,sizeof.OPENFILENAME

	cinvoke memset,ofn,0,eax

	; initialise the members of ofn

	mov eax,sizeof.OPENFILENAME

	mov [ofn.lStructSize],eax

	mov eax,[hwnd]

	mov [ofn.hwndOwner],eax

	; the filter

	mov eax,szTxtFilter

	mov [ofn.lpstrFilter],eax

	lea eax,[szBase64Path]

	mov [ofn.lpstrFile],eax

	mov eax,MAX_PATH

	mov [ofn.nMaxFile],eax

	mov eax,OFN_EXPLORER
	or eax,OFN_PATHMUSTEXIST
	or eax,OFN_HIDEREADONLY
	or eax,OFN_OVERWRITEPROMPT

	mov [ofn.Flags],eax

	mov eax,szTxt

	mov [ofn.lpstrDefExt],eax

	; display the dialog to get szBase64Path

	invoke GetSaveFileName,ofn

	ret

endp

; -------------------------------------------------------------------------------------

proc EncodeBase64,hwnd

  ; read the input binary file bytes, encode to base64,

  ; and write the result to the output file

	; check that szBinaryPath is not an empty string

	invoke GetDlgItemText,[hwnd],IDC_BIN_FILE,szBinaryPath,MAX_PATH

	test eax,eax

	jz .INVALID_PATH

	; check that szBase64Path is not an empty string

	invoke GetDlgItemText,[hwnd],IDC_B64_FILE,szBase64Path,MAX_PATH

	test eax,eax

	jz .INVALID_PATH

	; open the input file

	; set the mode to "rb" - open for reading as a binary file

	lea esi,[szMode]

	mov [esi],byte 'r'

	mov [esi+1],byte 'b'

	mov [esi+2],byte 0

	; FILE* fp_bin = fopen(szBinaryPath,"rb")

	cinvoke fopen,szBinaryPath,szMode

	mov [fp_bin],eax

	test eax,eax

	jz .ERR_FOPEN_BIN

	; open the output file

	; set the mode to "wb" - open for writing as a binary file

	lea esi,[szMode]

	mov [esi],byte 'w'

	mov [esi+1],byte 'b'

	mov [esi+2],byte 0

	; FILE* fp_b64 = fopen(szBase64Path,"wb")

	cinvoke fopen,szBase64Path,szMode

	mov [fp_b64],eax

	test eax,eax

	jz .ERR_FOPEN_B64

	; the input and output buffer

	lea esi,[Buffer]

  .GET_BYTES:

	; read 3 bytes from the input file

	; fread(&Buffer,1,3,fp_bin)

	cinvoke fread,esi,1,3,[fp_bin]

	; if 0 bytes were read, then exit

	test eax,eax

	jz .FCLOSE_B64

	; if 1 byte was read:

	test eax,2

	jz .PAD_1

	; if 2 bytes were read:

	test eax,1

	jz .PAD_2

	; 3 bytes were read:

	xor eax,eax

	; reverse the byte order

	mov dl,[esi]

	mov dh,[esi+2]

	mov [esi],dh

	mov [esi+2],dl

	; load the 3 bytes into EDX

	mov edx,[esi]

	; get the lower 6 bits of DL

	mov al,dl

	and al,0x3f

	; encode the 6 bits

	stdcall BitsToChar

	; copy the base64 char to the IO buffer

	mov [esi+3],al

	; get the next 6 bits and encode

	shr edx,6

	mov al,dl

	and al,0x3f

	stdcall BitsToChar

	mov [esi+2],al

	; get the next 6 bits and encode

	shr edx,6

	mov al,dl

	and al,0x3f

	stdcall BitsToChar

	mov [esi+1],al

	; get the next 6 bits and encode

	shr edx,6

	mov al,dl

	and al,0x3f

	stdcall BitsToChar

	mov [esi],al

	jmp .WRITE

  .PAD_1:

	; only 1 byte was returned by fread()

	xor eax,eax

	mov dl,[esi]

	mov al,dl

	; get the upper 6 bits and encode

	shr al,2

	stdcall BitsToChar

	mov [esi],al

	; get the lower 2 bits

	mov al,dl

	; pad with 4 zero bits and encode

	shl al,4

	and al,0x30

	stdcall BitsToChar

	mov [esi+1],al

	; pad the IO buffer with the '=' char

	mov [esi+2],byte '='

	mov [esi+3],byte '='

	jmp .WRITE

  .PAD_2:

	; only 2 bytes were returned by fread()

	xor eax,eax

	mov dl,[esi+1]

	mov dh,[esi]

	; pad the 2 input bytes with 2 zero bits

	shl edx,2

	; there are now 18 bits to be encoded

	; encode the first 6 bits

	mov al,dl

	and al,0x3f

	stdcall BitsToChar

	mov [esi+2],al

	; get the next 6 bits and encode

	shr edx,6

	mov al,dl

	and al,0x3f

	stdcall BitsToChar

	mov [esi+1],al

	; get the next 6 bits and encode

	shr edx,6

	mov al,dl

	and al,0x3f

	stdcall BitsToChar

	mov [esi],al

	; pad the IO buffer with the '=' char

	mov [esi+3],byte '='

  .WRITE:

	; write the 4 encoded bytes to the output file

	; fwrite(&Buffer,1,4,fp_b64)

	cinvoke fwrite,esi,1,4,[fp_b64]

	jmp .GET_BYTES

  .FCLOSE_B64:

	cinvoke fclose,[fp_b64]

  .FCLOSE_BIN:

	cinvoke fclose,[fp_bin]

	jmp .DONE

  .ERR_FOPEN_BIN:

	invoke MessageBox,NULL,szFopenError,szBinaryPath,MB_ICONERROR+MB_OK

	jmp .DONE

  .ERR_FOPEN_B64:

	invoke MessageBox,NULL,szFopenError,szBase64Path,MB_ICONERROR+MB_OK

	jmp .FCLOSE_BIN

  .INVALID_PATH:

	invoke MessageBox,NULL,szPathError,szTitle,MB_ICONERROR+MB_OK

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc BitsToChar

  ; the 6 bit value is passed in AL

  ; use AL as an index into the string szBase64 to encode

  ; return the base64 char in AL

	lea edi,[szBase64]

	add edi,eax

	mov al,[edi]

	ret

endp

; -------------------------------------------------------------------------------------

section '.idata' import data readable writeable

  library kernel,'KERNEL32.DLL',\
	  user,'USER32.DLL',\
	  comdlg32,'COMDLG32.DLL',\
	  msvcrt,'MSVCRT.DLL'

  import kernel,\
	 GetModuleHandle,'GetModuleHandleA',\
	 ExitProcess,'ExitProcess'

  import user,\
	 DialogBoxParam,'DialogBoxParamA',\ 
	 SetDlgItemText,'SetDlgItemTextA',\
	 GetDlgItemText,'GetDlgItemTextA',\
	 MessageBox,'MessageBoxA',\
	 EndDialog,'EndDialog'

  import comdlg32,\
	 GetOpenFileName,'GetOpenFileNameA',\
	 GetSaveFileName,'GetSaveFileNameA'

  import msvcrt,\
	 memset,'memset',\
	 fopen,'fopen',\
	 fclose,'fclose',\
	 fread,'fread',\
	 fwrite,'fwrite'

; -------------------------------------------------------------------------------------

section '.text' readable writeable

  szBinaryPath rb MAX_PATH

  szBase64Path rb MAX_PATH

  szTxt TCHAR "txt",0

  szMode rb 4

  ; Note that the filter strings are double null terminated:

  szTxtFilter TCHAR "Text Files",0,"*.txt",0,"All Files",0,"*.*",0,0

  szBinFilter TCHAR "All Files",0,"*.*",0,0

  szTitle TCHAR "Error",0

  szPathError TCHAR "Invalid file path!",0

  szFopenError TCHAR "Call to fopen failed!",0

  ofn OPENFILENAME

  fp_bin dd 0

  fp_b64 dd 0

  szBase64 TCHAR "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",0

  Buffer dd 0

; -------------------------------------------------------------------------------------

section '.rc' resource data readable

  directory RT_DIALOG,dialogs

  resource dialogs,\
	IDD_MY_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,my_dialog

  dialog my_dialog,\
  'Base64',30,30,300,108,\
  DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\
  0,0,"Lucida Console",11

  dialogitem 'BUTTON','Input Binary File',-1,5,5,290,36,BS_GROUPBOX+WS_VISIBLE,0
  dialogitem 'BUTTON',"Output Base64 File",-1,5,46,290,36,BS_GROUPBOX+WS_VISIBLE,0

  dialogitem 'EDIT',0,IDC_BIN_FILE,10,17,240,16,ES_AUTOHSCROLL+WS_BORDER+WS_VISIBLE,0
  dialogitem 'EDIT',0,IDC_B64_FILE,10,57,240,16,ES_AUTOHSCROLL+WS_BORDER+WS_VISIBLE,0

  dialogitem 'BUTTON',"...",IDC_BTN_BIN,256,17,30,16,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"...",IDC_BTN_B64,256,57,30,16,BS_PUSHBUTTON+WS_VISIBLE,0

  dialogitem 'BUTTON',"Encode Base64",IDC_BTN_CONVERT,5,86,80,16,BS_PUSHBUTTON+WS_VISIBLE,0

  enddialog

; -------------------------------------------------------------------------------------
Advertisements

Blog at WordPress.com.

%d bloggers like this: