Objcopy --writable-text не делает двоичный текстовый раздел эльфа доступным для записи?

Я пытался сделать раздел .text двоичного файла elf доступным для записи, используя objcopy --writable-text executable_name. Команда выполняется нормально, без ошибок.

При проверке разрешения раздела через readelf я вижу, что текстовый раздел по-прежнему имеет разрешения только на чтение и выполнение.

При просмотре objcopy справочных страниц для этой конкретной опции упоминается, что эта опция не имеет смысла для всех двоичных форматов. (По этой причине я не могу этого сделать?).

Может ли кто-нибудь указать, что мне здесь не хватает.

Спасибо

(Ubuntu x86_64-битная машина, GNU objcopy (GNU Binutils для Ubuntu) 2.22.90.20120924)


person abhi    schedule 07.02.2014    source источник


Ответы (3)


При просмотре man-страниц objcopy для этой конкретной опции упоминается, что эта опция не имеет смысла для всех двоичных форматов. (По этой причине я не могу этого сделать?).

да.

При этом достаточно подробное описание специальных разделов формата ELF, вы видите, что .text имеет атрибуты SHF_ALLOC + SHF_EXECINSTR (для него выделено место и в нем находится исполняемый код), но не SHF_WRITE (в пространство можно записать). То, о чем вы просите objcopy, просто недопустимо для разделов ELF .text.

person ldav1s    schedule 08.02.2014

В Debian я могу просто связать с -N, и это создаст исполняемый файл с доступным для записи .text

так: ld -N obj.o

person Torsten    schedule 21.05.2014

Сначала выполните это: objcopy --writable-text --set-section-flags .text=CONTENTS,ALLOC,LOAD,CODE

Затем objdump -x или readelf -a для просмотра таблицы разделов загрузки, которая обычно находится после заголовка программы. Пожалуйста, смотрите справочную страницу для ELF. Например, для 32-битных исполняемых файлов:

Откройте двоичный файл с помощью hexedit и просмотрите значение по смещению файла 0x1C (часто 0x34), затем просмотрите структуры 0x20 байт (размер указан по смещению файла 0x2a), пока не найдете ту, которую вы определили в предыдущем дампе как содержащую .текстовый раздел. Предпоследнее длинное значение будет 00000005 (05 00 00 00), и к нему необходимо добавить запись, которая станет таким образом 00000007 (07 00 00 00). Теперь он будет работать, как и ожидалось, без каких-либо ограничений, таких как проблемы с разделяемой библиотекой с -Wl,--omagic. Немного технический, но занимает несколько секунд.

Несмотря на это, этот однобитовый флаг вызвал бесчисленное количество проблем, и никакие объяснения не прояснили этот небольшой момент, который позволяет ему работать безупречно.

Кодовое решение можно легко скомпилировать с помощью GCC, чтобы внести изменения, что, вероятно, проще и лучше, если делать это регулярно:

#include <stdlib.h>
#include <stdio.h>
#include <elf.h>

int main(int argc, char** argv)
{
    if (argc <= 1) return -1;
    FILE* fp = fopen(argv[1], "r+");
    Elf64_Ehdr teh;
    fread(&teh, sizeof(teh), 1, fp);
    fseek(fp, 0, SEEK_SET);
    if (teh.e_ident[EI_CLASS] == ELFCLASS64) {
        Elf64_Ehdr eh;
        fread(&eh, sizeof(eh), 1, fp);
        Elf64_Phdr* ph = malloc(eh.e_phnum * eh.e_phentsize);
        Elf64_Shdr* sh = malloc(eh.e_shnum * eh.e_shentsize);
        fseek(fp, eh.e_phoff, SEEK_SET);
        fread(ph, eh.e_phentsize, eh.e_phnum, fp);
        fseek(fp, eh.e_shoff, SEEK_SET);
        fread(sh, eh.e_shentsize, eh.e_shnum, fp);
        for (int i = 0; i < eh.e_phnum; i++) {
            if (ph[i].p_vaddr <= eh.e_entry && ph[i].p_vaddr + ph[i].p_memsz > eh.e_entry) {
            fseek(fp, eh.e_phoff + i * eh.e_phentsize + (unsigned int)&((Elf64_Phdr*)0)->p_flags, SEEK_SET);
            ph[i].p_flags |= PF_W;
            fwrite(&ph[i].p_flags, sizeof(ph[i].p_flags), 1, fp);
            }
        }
        for (int i = 0; i < eh.e_shnum; i++) {
            if (sh[i].sh_addr <= eh.e_entry && sh[i].sh_addr + sh[i].sh_size > eh.e_entry) {
            fseek(fp, eh.e_shoff + i * eh.e_shentsize + (unsigned int)&((Elf64_Shdr*)0)->sh_flags, SEEK_SET);
            sh[i].sh_flags |= SHF_WRITE;
            fwrite(&sh[i].sh_flags, sizeof(sh[i].sh_flags), 1, fp);
            }       
        }
        free(ph);
        free(sh);
    } else {
        Elf32_Ehdr eh;
        fread(&eh, sizeof(eh), 1, fp);
        Elf32_Phdr* ph = malloc(eh.e_phnum * eh.e_phentsize);
        Elf32_Shdr* sh = malloc(eh.e_shnum * eh.e_shentsize);
        fseek(fp, eh.e_phoff, SEEK_SET);
        fread(ph, eh.e_phentsize, eh.e_phnum, fp);
        fseek(fp, eh.e_shoff, SEEK_SET);
        fread(sh, eh.e_shentsize, eh.e_shnum, fp);
        for (int i = 0; i < eh.e_phnum; i++) {
            if (ph[i].p_vaddr <= eh.e_entry && ph[i].p_vaddr + ph[i].p_memsz > eh.e_entry) {
            fseek(fp, eh.e_phoff + i * eh.e_phentsize + (unsigned int)&((Elf32_Phdr*)0)->p_flags, SEEK_SET);
            ph[i].p_flags |= PF_W;
            fwrite(&ph[i].p_flags, sizeof(ph[i].p_flags), 1, fp);
            }
        }
        for (int i = 0; i < eh.e_shnum; i++) {
            if (sh[i].sh_addr <= eh.e_entry && sh[i].sh_addr + sh[i].sh_size > eh.e_entry) {
            fseek(fp, eh.e_shoff + i * eh.e_shentsize + (unsigned int)&((Elf32_Shdr*)0)->sh_flags, SEEK_SET);
            sh[i].sh_flags |= SHF_WRITE;
            fwrite(&sh[i].sh_flags, sizeof(sh[i].sh_flags), 1, fp);
            }       
        }
        free(ph);
        free(sh);
    }
    fflush(fp);
    fclose(fp);
    return 0;
}
person Gregory Morse    schedule 09.07.2017
comment
Это работает как шарм. Я не понимаю, почему мы не можем получить то же самое с objcopy. - person fuujuhi; 14.02.2020