Мой батут не будет подпрыгивать (обход, C++, GCC)

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

Код (ниже) настолько прост, насколько возможно, но проблема не в этом. Я успешно реализовал обходной путь (то есть привязку к своей собственной функции), но я не смог реализовать батут.

Всякий раз, когда я вызываю батут, в зависимости от смещения, которое я использую, я получаю либо "ошибку сегментации", либо "недопустимую инструкцию". Оба случая заканчиваются одинаково; "ядро сброшено". Я думаю, это потому, что я перепутал "относительный адрес" (примечание: я довольно новичок в Linux, поэтому я далеко не освоил GDB).

Как указано в коде, в зависимости от sizeof(jmpOp) (в строке 66) Я получаю недопустимую инструкцию или ошибку сегментации. Извините, если это что-то очевидно, я встаю слишком поздно...

// Header files
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include "global.h" // Contains typedefines for byte, ulong, ushort etc...
#include <cstring>

bool ProtectMemory(void * addr, int flags)
{
    // Constant holding the page size value
    const size_t pageSize = sysconf(_SC_PAGE_SIZE);

    // Calculate relative page offset
    size_t temp = (size_t) addr;
    temp -= temp % pageSize;

    // Update address
    addr = (void*) temp;

    // Update memory area protection
    return !mprotect(addr, pageSize, flags);
}

const byte jmpOp[] = { 0xE9, 0x00, 0x00, 0x00, 0x00 };

int Test(void)
{
    printf("This is testing\n");
    return 5;
}

int MyTest(void)
{
    printf("This is ******\n");
    return 9;
}

typedef int (*TestType)(void);

int main(int argc, char * argv[])
{
    // Fetch addresses
    byte * test = (byte*) &Test;
    byte * myTest = (byte*) &MyTest;

    // Call original
    Test();

    // Update memory access for 'test' function
    ProtectMemory((void*) test, PROT_EXEC | PROT_WRITE | PROT_READ);

    // Allocate memory for the trampoline
    byte * trampoline = new byte[sizeof(jmpOp) * 2];

    // Do copy operations
    memcpy(trampoline, test, sizeof(jmpOp));
    memcpy(test, jmpOp, sizeof(jmpOp));

    // Setup trampoline
    trampoline += sizeof(jmpOp);
    *trampoline = 0xE9;

    // I think this address is incorrect, how should I calculate it? With the current
    // status (commented 'sizeof(jmpOp)') the compiler complains about "Illegal Instruction".
    // If I uncomment it, and use either + or -, a segmentation fault will occur...
    *(uint*)(trampoline + 1) = ((uint) test - (uint) trampoline)/* + sizeof(jmpOp)*/;
    trampoline -= sizeof(jmpOp);

    // Make the trampoline executable (and read/write)
    ProtectMemory((void*) trampoline, PROT_EXEC | PROT_WRITE | PROT_READ);

    // Setup detour
    *(uint*)(test + 1) = ((uint) myTest - (uint) test) - sizeof(jmpOp);

    // Call 'detoured' func
    Test();

    // Call trampoline (crashes)
    ((TestType) trampoline)();
    return 0;
}

В случае интереса это вывод во время обычного запуска (с точным кодом выше):

Это тестирование
Это **
Нелегальная инструкция (ядро сброшено)
И это результат, если я использую +/- sizeof(jmpOp) в строке 66:

 Это тестирование
Это ******
Ошибка сегментации (ядро сброшено)

ПРИМЕЧАНИЕ: я использую Ubuntu 32 бит и компилирую с g++ global.cpp main.cpp -o main -Iinclude

1 ответ

Решение

Вы не сможете без разбора скопировать первые 5 байтов Test() в свой батут, а затем перейти к 6-му байту инструкции Test(), потому что вы не знаете, содержат ли первые 5 байтов целое число команд x86 переменной длины. Чтобы сделать это, вам нужно будет выполнить хотя бы минимальный объем автоматической разборки функции Test(), чтобы найти границу инструкции, которая находится на расстоянии 5 или более байтов от начала функции, а затем скопировать соответствующее число. байтов к вашему батуту, и ТО добавьте свой прыжок (который не будет с фиксированным смещением в пределах вашего батута). Обратите внимание, что на типичном RISC-процессоре (например, PPC) у вас не возникнет этой проблемы, поскольку все инструкции имеют одинаковую ширину.

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