Записать в собственный исполняемый файл в программе 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")

Другие вопросы по тегам