Исправление исполняемого файла ELF - PullRequest
1 голос
/ 31 октября 2011

У меня есть общий объект программы, для которого мне нужно изменить инструкцию с 'jne / je' на jmp.Я, например, попытался осмотреться, как это сделать, возможно, с помощью LD_PRELOAD или что-то безрезультатно.

Ответы [ 3 ]

5 голосов
/ 31 октября 2011

Технически возможно ли это, зависит от нескольких вещей:

  1. jne / je инструкции бывают разной длины:

    • one-байтовый код операции (0x74 / 0x75) плюс 8-битное смещение со знаком (т.е. всего два байта)
    • двухбайтовый код операции (0xf0 плюс 0x84 / 0x85,) плюс подпись32-разрядное смещение (т.е. всего шесть байтов)

    то же самое для инструкции jmp (в 64-битном режиме, всего пять различных кодировок между двумя и девятью байтами, в зависимости от того, является ли jmp является относительным / абсолютным).
    Это означает, что вы можете заменить jne / je на jmp, только если цель вашего jmp "достаточно близка", чтобы выбрать код операции, совместимый с размером.Для 32-битного относительного jne / je вы обычно можете заменить, но для почти (8-битного), который обычно не возможен, так как не будет «свободного места для инструкций» в пределах +/- 128 байт.

  2. , если у вас есть «совместимая возможность» в отношении.в соответствии с размером инструкции у вас есть две задачи для решения, о которых вы уже упоминали:

    • перехватывает загрузку разделяемого объекта, чтобы вы могли заменить его до использования библиотеки.
    • поиск адреса функции, которую вы хотите исправить (при условии, что она изменится).

    Как это можно сделать, зависит от вашей операционной системы;в UN * X-like вы можете попробовать использовать LD_PRELOAD для загрузки пользовательской библиотеки вашей собственной , которая не делает ничего, кроме dlopen() библиотеки, которую вы хотите изменить, затем dlsym(), чтобы найти подпрограмму, затем подставьте код, но никогда не вызывайте dlclose(), чтобы убедиться, что измененная копия хранится (то есть не выгружается) вместо оригинала, когда позже (через динамическое связывание) доступ к библиотеке снова.

Системный администратор обычно может смягчить (или даже отключить) LD_PRELOAD (и для исполняемых файлов setuid, запускаемых от имени root, он всегда игнорируется), поскольку он имеет очевидные последствия для целостности / безопасности системы.То, может ли эта техника использоваться или нет, зависит от конкретной установки.

Если все вышеперечисленные условия выполнены, то что-то вроде:

int patch_je_jne(void *instr, void *tgt_address)
{
    char *je_jne = (char*)instr;
    char *iaddr = je_jne;

    switch (je_jne[0]) {
    case JE_8BIT_OP:
    case JNE_8BIT_OP:
        iaddr += 2;
        tgt_address -= iaddr;        /* adjust pc-relative */
        if ((char*)tgt_address > (char*)0xFF)
            return CANNOT_PATCH_LARGE_OFFSETS;
        je_jne[1] = (char)tgt_address;
        je_jne[0] = JMP_OP;
        return PATCH_SUCCESS;

    case 0xF0:                       /* marker for a 32bit-relative JE/JNE */
        if (je_jne[1] != JE_32BIT_OP && je_jne[1] != JNE_32BIT_OP))
            break;
        iaddr += 6;
        tgt_address -= iaddr;        /* adjust pc-relative */
        *((char**)(je_jne + 2)) = tgt_address;
        je_jne[1] = JMP_32BIT_OP;
        return PATCH_SUCCESS;
    }
    return CANNOT_PATCH_THIS_INSTR;
}

может сделать это.Как уже говорилось, в этом коде нет проверки / подтверждения, кроме проверки совместимости кодов команд по адресу, который должен быть исправлен.

Основная работа, как уже упоминалось, заключается в , надежно определяющем где / как вам нужно применить ловушку.

Как уже было предложено, комментарий по исправлению бинарной библиотеки вместо работающей (загруженной) библиотеки: Ключевой вопрос здесь: Какова цель jmp, вы можете знать это заранее ?
В двоичном исправлении необходимо определить это во время изменения двоичного файла, который вместе с поведением операционной системы, например ASLR (макет адресного пространстварандомизация) трудно или невозможно - вам нужен заранее известный неизменяемый целевой адрес в вашем исполняемом файле, но обычно у вас есть только относительный jmp, т. е. заранее неизвестно, какое расположение кода это 'в конечном итоге из-за ASLR.Все зависит от , где вы хотите, чтобы jmp пошел.

0 голосов
/ 31 октября 2011

Добавление к приведенным выше ответам о том, как найти инструкцию в обновленных двоичных файлах более или менее автоматически.

Если вы знаете, где находится инструкция в одной версии двоичного файла, вы можете разобрать кусок кода вокруг него (возможно, включить некоторый код, который передает управление туда или передает управление оттуда?), И сохранить эту разборку. Удалите адреса команд из разборки и из непосредственных операндов инструкций jmp / call, поскольку они в любом случае могут меняться от версии к версии.

Аналогичным образом разберите более новую версию, найдите место, которое лучше всего соответствует тому, что вы уже разобрали ранее, и исправьте его. Для сопоставления вы можете использовать какой-либо инструмент сравнения.

Это, конечно, будет работать, только если этот код вокруг интересующей инструкции не изменяется и является уникальным.

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

0 голосов
/ 31 октября 2011

Может быть, вы можете просто Hex редактировать свой объект? Получите правильное смещение и код операции с помощью objdump и отредактируйте файл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...