Записать в собственный исполняемый файл в программе Linux C, ошибка "Текстовый файл занят"
Для класса безопасности я должен написать самоизменяющийся код для программы, которая находит свой собственный исполняемый файл на диске, считывает двоичные данные и шифрует их часть перед записью обратно на диск. Предполагается, что это похоже на полиморфный вирус, который превращается в антивирусных сканеров, которые обнаруживают известные сигнатуры.
У меня все части в значительной степени на месте:
- Я нахожу исполняемый файл, используя
/proc/self/exe
, - Я использую простую реализацию AES для шифрования 16-байтовой строки в некотором фиктивном коде в исполняемом файле.
- Я могу прочитать двоичные данные и найти часть, которая мне нужна для шифрования.
Моя проблема в том, что единственный способ открыть исполняемый файл - это режим только для чтения. "rb"
, Если я попытаюсь открыть файл для записи в режиме "wb"
или же "r+b"
Я вернул ошибку "Text file busy"
, Могу ли я написать собственный исполняемый файл процесса в C? Могу ли я сделать это, изменив разрешения как-то?
РЕДАКТИРОВАТЬ: То, что я пытаюсь сделать, это иметь исполняемый файл, который будет шифровать часть себя каждый раз, когда он работает, так что он будет иметь новую контрольную сумму после каждого запуска.
После чтения данных из исполняемого двоичного файла, как я могу записать обратно или удалить его и заменить его новым файлом с тем же именем файла?
1 ответ
Вы не можете записать в файл, который в настоящее время отображается как исполняемый файл. Однако вы можете записать в файл, который имеет тот же путь, что и текущий исполняемый файл, при условии, что он на самом деле не тот же файл - попробуйте отсоединить файл, из которого вы выполняете, и создать новый файл на его месте, для пример.
Чтобы выполнить самостоятельную модификацию, я написал небольшой код в nasm (который можно использовать как заглушку), который открывает его самостоятельно, и в середине кода (рядом с mmap) у нас есть указатель, который указывает на байты исполняемого файла, который мы можем изменить.
Код выглядит так:
BITS 64
section .text
global _start
_start:
call _main__
mov rax, 60
mov rdi, 0x0
syscall ; exit(0);
_main__:
push rbp
mov rbp, rsp
sub rsp, 144 ; stat_file
mov rdi, [rbp+0x18]
lea rsi, [rsp]
call _open_self ; open self
push r12 ; len file
push rax ; addr
mov r14, rsi
mov rdi, [rbp+0x18] ; pathname
pop rsi ; addr
pop rdx ; len
push rdx
push rsi
call __create
mov r13, rax ; second fd
mov rdi, r14 ; fd
pop rsi ; addr -> mmap
pop rdx ; len_file
call __close_unmap
mov rax, 87
mov rdi, [rbp+0x18]
syscall
mov rax, 0x3 ; close(scnd_fd);
mov rdi, r13
syscall
mov rax, 86
push 'nasm'
lea rdi, [rsp]
mov rsi, [rbp+0x18]
syscall ; link tmp name to original name
mov rax, 87
lea rdi, [rsp]
syscall ; delete old tmp file
leave
ret
; ===============================
; Open himself
_open_self:
push rbp
mov rbp, rsp
mov r15, rsi ; &stat_file
mov r12, rdi ; *pathname
mov rax, 0x2
mov rsi, 0x0 ; 0_RD
mov rdx, 509
syscall
push rax ; fd
mov rdi, rax ; fd
mov rsi, r15 ; struct stat
mov rax, 5 ; fstat
syscall
xor rdi, rdi
mov rsi, qword [r15+48]
mov rdx, 0x4
mov r10, 0x2
pop r8
push r8
mov r9, 0x0
mov rax, 9
syscall ; mmap
; rax -> byte of the executable that we gonna dump
mov r12, qword [r15+48]
pop rsi ; fd
leave
ret
; ===============================
; int __create(const char *pathname, void *addr, ssize_t len_bytes_mapped);
__create:
push rbp
mov rbp, rsp
push rsi ; addr
push rcx ; len
push 'nasm'
lea rdi, [rsp]
mov rax, 0x2
mov rsi, 0x42 ; 0_CREAT | O_RDWR
mov rdx, 509
syscall ; sys_open
add rsp, 0x8 ; 'nasm'
mov r9, rax ; fd
mov rdi, rax ; fd
mov rax, 0x1
pop rdx
pop rsi
syscall ; sys_write
mov rax, r9 ; fd final
leave
ret
; int __close_unmap(int fd, unsigned lon addr, ssize_t len_file);
__close_unmap:
push rbp
mov rbp, rsp
push rdi
mov rdi, rsi
mov rsi, rdx
mov rax, 11
syscall ; munmap(addr, len_file)
pop rdi
mov rax, 3
syscall ; close(fd);
leave
ret
Это немного длинновато, но из него всего лишь:
-Открыть сам в режиме чтения (O_RD == 0x0)
-Проведите статистику (* путь, &buffer_struct_stat);
-И затем mmap (0, buffer_struct_stat.st_size, 0x4, MAP_PRIVATE, fd_read_only, 0);
-Здесь вы можете редактировать свой исполняемый файл, редактируя байты по адресу, возвращенному mmap
-Создайте файл tmp с именем "nasm"
-Запишите (fd_tmp, address_of_mmap, buffer_struct_stat.st_size)
-Закройте два файловых дескриптора и munmap mmap
-Теперь это круто: unlink(pathname) и link("nasm", "pathname")