FC47
FC47

Reputation: 11

Nasm: Hide messagem in bmp file

I made this program in assembly that should receive from the terminal one file txt (where's the msg is), one file bmp and the name of that the file bmp should have (file equal to the original but with the hidden msg)!

section .data
; -----
; Define standard constants.
LF equ 10 ; line feed
NULL equ 0 ; end of string
TRUE equ 1
FALSE equ 0
EXIT_SUCCESS equ 0 ; success code
STDIN equ 0 ; standard input
STDOUT equ 1 ; standard output
STDERR equ 2 ; standard error
SYS_write equ 1; write
SYS_read equ 0 ; read
SYS_open equ 2 ; file open
SYS_close equ 3 ; file close
SYS_exit equ 60 ; terminate
SYS_creat equ 85 ; file open/create
SYS_time equ 201 ; get time
O_CREAT equ 0x40
O_TRUNC equ 0x200
O_APPEND equ 0x400
O_RDONLY equ 000000q ; read only
O_WRONLY equ 000001q ; write only
S_IRUSR equ 00400q
S_IWUSR equ 00200q
S_IXUSR equ 00100q
; -----
; Variables/constants for main.
MSGBUFF_SIZE equ 256
IMGBUFF_SIZE equ 24000
NEWBUFF_SIZE equ 24000

newLine db LF, NULL
db LF, LF, NULL

msgDesc dq 1
imgDesc dq 1
newDesc dq 1


errMsgOpen db "Error opening the file.", LF, NULL
errMsgRead db "Error reading from the file.", LF, NULL

img_url db '-----------------',0
msg_url db '-----------------',0
new_img db '-----------------',0
nullstr     db '(null)',0

;offset db 1
;size db 1
; -------------------------------------------------------
section .bss
readMsgBuffer: resb MSGBUFF_SIZE
readImgBuffer: resb IMGBUFF_SIZE
readNewBuffer: resb NEWBUFF_SIZE



offset      resq 1
size        resq 1
; -------------------------------------------------------

section .text
global _start
_start:

mov rbp, rsp
mov rax, [rbp+8]    ; argc
cmp rax, 4
jne fim

;read args
mov rax, [rbp+8*3]   ;argv[1]
mov rdi, msg_url     ;
call converte

mov rax, [rbp+8*4]   ;argv[2]
mov rdi, img_url     ;
call converte

mov rax, [rbp+8*5]   ;argv[3]
mov rdi, new_img     ;
call converte


;open file msg
openMsg:
mov rax, SYS_open     ; file open
mov rdi, msg_url      ; file name string
mov rsi, O_RDONLY     ; read only access
syscall               ; call the kernel
cmp rax, 0           ; check for success
jl errorOnOpen
mov qword [msgDesc], rax

;open file img
openImg:
mov rax, SYS_open     ; file open
mov rdi, img_url      ; file name string
mov rsi, O_RDONLY     ; read only access
syscall               ; call the kernel
cmp rax, 0           ; check for success
jl errorOnOpen
mov qword [imgDesc], rax

;open file new image
openNewImg:
mov rax, SYS_open     ; file open
mov rdi, new_img      ; file name string
mov rsi, O_APPEND     ; append
syscall               ; call the kernel
cmp rax, 0           ; check for success
jl errorOnOpen
mov qword [newDesc], rax


;read msg
mov rax, SYS_read
mov rdi, qword [msgDesc]
mov rsi, readMsgBuffer
mov rdx, MSGBUFF_SIZE
syscall
cmp rax, 0
jl errorOnRead

;read img
mov rax, SYS_read
mov rdi, qword [imgDesc]
mov rsi, readImgBuffer
mov rdx, IMGBUFF_SIZE
syscall
cmp rax, 0
jl errorOnRead


mov rsi, readImgBuffer
mov byte [rsi+rax], NULL
mov rdi, readImgBuffer

mov rsi, readMsgBuffer
mov byte [rsi+rax], NULL
mov r8, readMsgBuffer
call escrever


;close files
mov rax, SYS_close
mov rdi, qword [msgDesc]
syscall

mov rax, SYS_close
mov rdi, qword [imgDesc]
syscall

mov rax, SYS_close
mov rdi, qword [newDesc]
syscall




fim:
mov     rsp, rbp
pop     rbp

mov     rax, 1
xor     rbx, rbx
int     0x80
ret


errorOnOpen:
mov rdi, errMsgOpen
call printString
jmp fim

errorOnRead:
mov rdi, errMsgRead
call printString
jmp fim



escrever:
push rbp
mov rbp, rsp
push rbx

; first 10 bytes
mov rax, SYS_write  ; code for write()
mov rsi, rdi        ; addr of characters
mov rdi, newDesc    ; file descriptor
mov rdx, 10
syscall             ; system call


mov rbx, readImgBuffer
mov rdx, 0
add rbx, 10


;eax = offset
offsetBit:
cmp rdx, 4
je loop

mov r9b, byte[rbx]
add rax, r9
mov rcx, 10
mul rcx
inc rdx
jmp offsetBit

mov r9, rax

mov rax, SYS_write  ; code for write()
mov rsi, rbx        ; addr of characters
mov rdi, newDesc    ; file descriptor
mov rdx, r9
syscall             ; system call


mov r12, 0          ;count byte pixel, to jump the 4ºbit
mov r13, 0          ;size file
mov rdi, readImgBuffer  ;have position of content

loop:
cmp byte [r8], NULL     ;not done
je done
inc r13                 ;count one byte

mov rdx, 0              ;count bit character msg

caracter:
mov sil, byte[r8]       ;read one byte of the pixel
cmp rdx, 8              ;end of last bit
je loop
cmp r12, 4              ;4º byte pixel
jne continue
mov r12, 0              ;reset byte pixel

continue:
mov al, byte[rdi]       ;have byte of pixel
mov cl, 10
shr al, 1
mul cl
shl sil, 1
adc al, 0
mov byte[rdi], al       ;modify last bit
inc rdx                 ;change bit of character
inc r8                  ;change byte of pixel
jmp caracter

done:
mov rdi, readImgBuffer
add rdi, r9               ; offset position

mov rax, SYS_write  ; code for write()
mov rsi, rdi        ; addr of characters
mov rdi, newDesc    ; file descriptor newImage
mov rdx,  r13
syscall

pop rbx
pop rbp
ret

global printString
printString:
push rbp
mov rbp, rsp
push rbx
; Count characters in string.
mov rbx, rdi
mov rdx, 0

strCountLoop:
cmp byte [rbx], NULL
je strCountDone
inc rdx
inc rbx
jmp strCountLoop

strCountDone:
cmp rdx, 0
je prtDone
; Call OS to output string.
mov rax, SYS_write ; code for write()
mov rsi, rdi ; addr of characters
mov rdi, STDOUT ; file descriptor
; count set above
syscall ; system call
; String printed, return to calling routine.

prtDone:
pop rbx
pop rbp
ret


converte:
push rbx
push rcx
push rdx

mov rbx, 10
xor rcx, rcx
.J1:
xor rdx, rdx
div rbx
push dx
add cl, 1
or eax, eax
jnz .J1
mov rbx, rcx
.J2:
pop ax
or al, 00110000b            ; to ASCII
mov [rdi], al               ; Store AL to [EDI] (EDI is a pointer to a buffer)
add rdi, 1                  ; = inc edi
loop .J2                    ; until there are no digits left
mov byte [rdi], 0           ; ASCIIZ terminator (0)
mov rax, rbx                ; Restore Count of digits

pop rdx
pop rcx
pop rbx
ret

I run it like:

$ nasm -F dwarf -f elf64 hiddeMsg.asm
$ ld -o HideMsg hiddeMsg.o
$ ./HiddeMsg msg.txt img.bmp img_mod.bmp

and I was expecting to "generate" one image with name img_mod.bmp equal to the original (aka img.bmp) but with the msg in msg.txt hidden... But as I compile and run it doesn't show any errors but also don't do anything and I don't have any idea why?

the file msg has the text: «one text message»

the original image: img.bmp

Upvotes: 1

Views: 156

Answers (1)

Sep Roland
Sep Roland

Reputation: 39191

Your program once more terminates prematurely because the very first check does not compare the argc correctly.
When your program starts (HiddeMsg msg.txt img.bmp img_mod.bmp), the stack contains the following:

at RSP+32  argv3  pointer to 'img_mod.bmp'
at RSP+24  argv2  pointer to 'img.bmp'
at RSP+16  argv1  pointer to 'msg.txt'
at RSP+8   argv0  pointer to the program name
at RSP     argc   4

Check the number of arguments:

mov rbp, rsp
mov rax, [rbp]       ; argc
cmp rax, 4
jne fim

The other arguments are pointers to the file names. It's not useful to convert these pointers to their decimal representation like your program is doing with calling converte. Just store the pointers locally for later use:

mov rax, [rbp+8*2]   ; argv[1]
mov [msg_url], rax

mov rax, [rbp+8*3]   ; argv[2]
mov [img_url], rax

mov rax, [rbp+8*4]   ; argv[3]
mov [new_img], rax

Opening the message file becomes

  mov rsi, O_RDONLY
  mov rdi, [msg_url]
  mov rax, SYS_open
  syscall
  test rax, rax
  js errorOnOpen
  mov [msgDesc], rax

You have a mash-up in the part that reads from the message file and the bitmap file, where, for some reason, you zero-terminate both these contents that were read.
You are putting the zero for the message at the same offset as you used for the bitmap! This action will destroy 1 byte of the bitmap!
Keep reading and zeroing together so you use the correct RAX:

mov edx, MSGBUFF_SIZE
mov rsi, readMsgBuffer
mov rdi, [msgDesc]
mov rax, SYS_read
syscall                 ; -> RAX
test rax, rax
js errorOnRead
mov rsi, readMsgBuffer
mov byte [rsi+rax], NULL

fim:
mov     rsp, rbp
pop     rbp

mov     rax, 1
xor     rbx, rbx
int     0x80
ret

Don't terminate your 64-bit program like this. Use the correct SYS_exit syscall:

fim:
  xor edi, edi
  mov eax, SYS_exit
  syscall

With this many errors you should better not insist too much on the contents of escrever. First exercise opening and closing files, and printing the message from the message file. Simpler things. Only move on once this works good...

Upvotes: 1

Related Questions