Nasm:在 bmp 文件中隐藏 messagem
Posted
技术标签:
【中文标题】Nasm:在 bmp 文件中隐藏 messagem【英文标题】:Nasm: Hide messagem in bmp file 【发布时间】:2021-01-17 22:46:04 【问题描述】:我在汇编中制作了这个程序,它应该从终端接收一个文件 txt(味精在哪里),一个文件 bmp 和文件 bmp 应该具有的名称(文件等于原始文件,但带有隐藏的味精) !
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
我是这样运行的:
$ nasm -F dwarf -f elf64 hiddeMsg.asm
$ ld -o HideMsg hiddeMsg.o
$ ./HiddeMsg msg.txt img.bmp img_mod.bmp
我期待“生成”一个名为 img_mod.bmp 的图像等于原始图像(又名 img.bmp),但隐藏了 msg.txt 中的味精……但是当我编译并运行它时,它不会显示任何错误但也不执行任何操作,我不知道为什么?
文件 msg 包含以下文本:«一条短信»
原图: img.bmp
【问题讨论】:
strace ./HiddeMsg msg.txt img.bmp img_mod.bmp
或在 GDB 等调试器和单步调试器下运行时,您会看到什么?好像你 haven't done any debugging (或者没有告诉我们你发现了什么,就 SO 而言这是等价的)。此外,就minimal reproducible example而言,此代码远非最小。
@PeterCordes 我不知道如何调试 nasm 项目...从来没有在课堂上学习/完成它,据我了解,我认为老师说调试一个程序有点不同使用来自不...的程序的命令行...
在 GDB 中,starti msg.txt img.bmp img_mod.bmp
使用 args 运行它,在 _start
的第一条指令之前停止。学习使用调试器将更容易弄清楚其他所有内容,非常值得您花时间。 (并且浪费其他人的时间来询问您没有使用调试器调试过的代码,strace
,甚至是调试打印函数调用。我强烈建议使用调试器,因为调试打印调用很难编写汇编)
【参考方案1】:
您的程序再次提前终止,因为第一次检查没有正确比较 argc。
当您的程序启动时 (HiddeMsg msg.txt img.bmp img_mod.bmp
),堆栈包含以下内容:
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
检查参数的数量:
mov rbp, rsp
mov rax, [rbp] ; argc
cmp rax, 4
jne fim
其他参数是指向文件名的指针。像您的程序调用 converte 那样将这些指针转换为十进制表示是没有用的。只需将指针存储在本地以供以后使用:
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
打开消息文件变成
mov rsi, O_RDONLY
mov rdi, [msg_url]
mov rax, SYS_open
syscall
test rax, rax
js errorOnOpen
mov [msgDesc], rax
您在从消息文件和位图文件读取的部分中有一个混搭,由于某种原因,您将读取的这两个内容都归零。
您将消息的零放在与位图相同的偏移量处!此操作将破坏位图的 1 个字节!
继续阅读和归零,以便您使用正确的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
不要像这样终止您的 64 位程序。使用正确的 SYS_exit syscall
:
fim:
xor edi, edi
mov eax, SYS_exit
syscall
由于有这么多错误,您最好不要对 escrever 的内容过分坚持。首先练习打开和关闭文件,并从消息文件中打印消息。更简单的事情。只有在效果良好时才能继续...
【讨论】:
以上是关于Nasm:在 bmp 文件中隐藏 messagem的主要内容,如果未能解决你的问题,请参考以下文章
我的训练数据集中的隐藏文件使 tensorflow 返回“未知的图像文件格式。需要 JPEG、PNG、GIF、BMP 之一。”
用C或C++怎样提取出bmp图像的像素点信息值?用LSB算法做信息隐藏,位图是24位的。