CSC231 Homework 6 Solution

From dftwiki3
Revision as of 16:44, 4 November 2008 by Thiebaut (talk | contribs) (New page: <code><pre> ;;; hw6.asm ;;; Amy Gray ;;; This program reads a bmp file into memory and decodes a secret ;;; message hidden in the pixels via steganography ;;; %include "mytools2.inc" ; f...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
;;; hw6.asm
;;; Amy Gray
;;; This program reads a bmp file into memory and decodes a secret
;;; message hidden in the pixels via steganography
;;; 
%include "mytools2.inc"		; for basic printing to the screen
%include "fileio2.inc"		; for basic file operations
		
%assign SYS_EXIT	1
%assign MAXPIXEL	5000000

%assign RED             2
%assign GREEN           1
%assign BLUE            0       



;;; ---------------------------------------------------------
;;; data segments
;;; ---------------------------------------------------------
        section .data
errorMsg db     "Error accessing file!",0x0A
errorLen equ    $-errorMsg
message  db	0		;will be used to store decoded byte

	section	.bss
filename resb   255		; reserve 255 chars for filename
handle   resd	1		; file descriptor
noRead	 resd	1		; contains number of bytes read
lWidth	 resd	1		; the line width rounded to the nearest
      				; dword boundary lWidth=(((width-1)/4)+1)*4

;;; ----------------------------------------------------------
;;; bmp buffer starts here
;;; ----------------------------------------------------------
bmpBuf	equ	$
type	resw	1		; header
size	resd	1
resvd1	resw	1
resvd2	resw	1
offset	resd	1
;;;
size2	resd	1		; information header
width	resd	1
height	resd	1
planes	resw	1
xbits	resw	1
compr	resd	1
imgsize	resd	1
xres	resd	1
yres	resd	1
nocol	resd	1
impcol	resd	1
headLen equ	$-bmpBuf	; length of header
	
pixelBuf resb	MAXPIXEL*3	; times 3 bytes (RGB)

	
;;; ---------------------------------------------------------
;;; code area
;;; ---------------------------------------------------------
	section	.text
	global	_start

_start:
;;; --- check that user entered more than 1 argument on command line ---
	pop	ebx		; get # of arguments on command line
	cmp	ebx,1
	jg	process		; if user forgot file name, exit
	dumpStr "Syntax: progName filename"
	jmp	exit

;;; --- get filename from command line ---
process:	
	pop	ebx		; pointer to argv[0] (name of program)
	pop	ebx		; pointer to argv[1]
	mov	edi,filename	; pointer to filename
copy:	mov	al,[ebx]	; copy name of file from argv[1] to
	mov	[edi],al	; filename string, until \0 is copied
	inc	ebx
	inc	edi
	cmp	al,0
	jne	copy
	
;;; --- open file ---
        openFile filename, [handle], errorMsg, errorLen
        

;;; --- read file in buffer ---
        readFile [handle], bmpBuf, MAXPIXEL, noRead
        
;;; --- compute length of a line of pixel:
;;; line length = (( byte width+3)/4)*4 where
;;; byte width = 3 * width, since we have 3 bytes per pixel
;;; 
	mov	eax,[width]
	add	eax,[width]
	add	eax,[width]	; eax <-- 3 x width
	dec	eax		; eax
	shr	eax,2		; 
	inc	eax
	shl	eax,2
	mov	[lWidth],eax

;;; --------------------------------------------------------------
;;; Find the address of the first byte of the image and put
;;; it in ebx
;;; --------------------------------------------------------------

        mov	eax,0
        push 	eax
        push 	eax
        call  	hw2index

 
;;; -------------------------------------------------------------
;;; mainloop: 	Extract message hidden in the image's pixels. Goes
;;; 	    	through eight bytes from the image and stores the
;;; 		least significant bit from in a new byte, which is
;;; 		a character from the message. The message ends with
;;; 		a zero, so each newly formed byte is checked to see
;;; 		if it is equal to zero.  If yes, the program jumps
;;; 		to the end.  If no, the program prints the character
;;; registers modified: eax, ebx, ecx, edx
;;; -------------------------------------------------------------
	
	add	ebx, 7		;moves to eighth byte
				;bits are stored backwards from 7 to 0
	
	;; for some reason, when 'jmp mainloop' is called below, the program
	;; was jumping back to 'add ebx, 7' and adding 7 to ebx (causing everything
	;; to go wrong).  'add ebx, 0' is put in as a placeholder.  The program
	;; jumps back to here, does nothing and continues on to mainloop
	add	ebx, 0

mainloop:
	call 	decode1byte
	cmp 	byte[message], 0
	je 	theEnd

	push 	ebx 		;ebx needs to be saved for accessing pixels
	mov 	ecx, message
	mov	eax, SYS_WRITE
	mov	ebx, STDOUT
	mov	edx, 1
	int	0x80
	pop	ebx		;restore ebx
	jmp	mainloop	;repeat
	


	


	;; -----------------------------------
	;; end of pixel loop area
	;; -----------------------------------
theEnd:	
;;; --- position file pointer back to beginning of file ---
 	seek0	[handle]
	
;;; --- write contents back to file ---
 	writeBuf [handle], bmpBuf, noRead
	
;;; --- close file ---
	close	[handle]
	
;;; --- exit() ---
exit:	
	mov	eax,SYS_EXIT
	mov	ebx,0
	int	0x80		; final system call


	
;;; -------------------------------------------------------------
;;; hw2index:	converts height and width to pixel index
;;;             index returned in ebx.  Note that computation is
;;;             performed with lWidth which must be computed
;;;             separately and is the number of bytes in one line
;;;             of pixel, such that number of byte is a multiple of
;;;             4.
;;; registers modified:	 ebx
;;; -------------------------------------------------------------
hw2index:
	push	ebp
	mov	ebp,esp
	
	push	eax		; save eax and edx
	push	edx
	mov	eax,[lWidth]	
	xor	edx,edx
	mul	dword[ebp+12]	; eax = lWidth * h
	add	eax,[ebp+8]	; eax += 3*w
	add	eax,[ebp+8]
	add	eax,[ebp+8]
	mov	ebx,eax		; pass result in ebx
	
	pop	edx
	pop	eax
	pop	ebp
	
	ret	8


;;; --------------------------------------------------------
;;; decode1byte: runs through a series of eight bytes
;;; 		 and extracts the last bit from each.
;;; 		 Starts at the eighth bit and works backward
;;; 		 Each extracted bit is stored in edx as
;;; 		 a new byte. This byte is transferred into
;;;		 the variable 'message'
;;; registers modified: ebx
;;; -------------------------------------------------------
	
decode1byte:
	push	edx
	push	eax
	push	ecx
	
	mov 	edx, 0		;will hold secret byte
	mov 	eax, 0		;will hold byte to extract from
	mov 	ecx, 7

	;; the loop runs 7 times.  At the end of each run, the
	;; secret byte is shifted to the left to make room for
	;; the next new bit.  The eighth bit is then extracted
	;; outside the loop, so that no shift happens.  An
	;; eighth shift would cause the first bit to be lost
	;; and an extraneous zero to appear at the end.
forbyte:
	mov 	al, byte[ebx+pixelBuf] ;byte to extract from
	and 	al, 1	;clear all but least significant bit
	or 	dl, al	;add new bit to dl
	shl 	dl, 1		;make room for next bit
	dec	ebx		;move to next byte
	loop 	forbyte	

	mov 	al, byte[ebx+pixelBuf] ;get 8th bit
	and 	al, 1
	or 	dl, al
	mov	byte[message], dl ;store decoded byte in 'message'

	add	ebx, 15 	;jumps to next set of eight bytes
	
	pop 	ecx
	pop	eax
	pop	edx	
	
	ret