создание проблем шеллкода с mov reg to reg - PullRequest
2 голосов
/ 29 апреля 2020

Хорошо, поэтому я пытаюсь создать функцию, которая создает шелл-код.

У меня много проблем при разработке материала для rex / mod.

Мой текущий вид кода работает.

Пока что регистры меньше, чем R8, все работает нормально.

Если я использую один рег, который меньше, чем R8, то это хорошо.

Проблема в том, что когда мне нужно, чтобы регистры были меньше r8 и те же или если sr c меньше, у меня возникают проблемы

enum Reg64 : uint8_t {
    RAX = 0, RCX = 1, RDX = 2, RBX = 3,
    RSP = 4, RBP = 5, RSI = 6, RDI = 7,
    R8 = 8, R9 = 9, R10 = 10, R11 = 11,
    R12 = 12, R13 = 13, R14 = 14, R15 = 15
};

inline uint8_t encode_rex(uint8_t is_64_bit, uint8_t extend_sib_index, uint8_t extend_modrm_reg, uint8_t extend_modrm_rm) {
    struct Result {
        uint8_t b : 1;
        uint8_t x : 1;
        uint8_t r : 1;
        uint8_t w : 1;
        uint8_t fixed : 4;
    } result{ extend_modrm_rm, extend_modrm_reg, extend_sib_index, is_64_bit, 0b100 };
    return *(uint8_t*)&result;
}
inline uint8_t encode_modrm(uint8_t mod, uint8_t rm, uint8_t reg) {
    struct Result {
        uint8_t rm : 3;
        uint8_t reg : 3;
        uint8_t mod : 2;
    } result{ rm, reg, mod };
    return *(uint8_t*)&result;
}

    inline void mov(Reg64 dest, Reg64 src) {
        if (dest >= 8)
            put<uint8_t>(encode_rex(1, 2, 0, 1));
        else if (src >= 8)
            put<uint8_t>(encode_rex(1, 1, 0, 2));
        else
            put<uint8_t>(encode_rex(1, 0, 0, 0));

        put<uint8_t>(0x89);

        put<uint8_t>(encode_modrm(3, dest, src));
    }

    //c.mov(Reg64::RAX, Reg64::RAX); // works
    //c.mov(Reg64::RAX, Reg64::R9); // works
    //c.mov(Reg64::R9, Reg64::RAX); // works
    //c.mov(Reg64::R9, Reg64::R9); // Does not work returns (mov r9,rcx)

Также, если есть более короткий способ сделать это без всех, если было бы замечательно.

1 Ответ

1 голос
/ 29 апреля 2020

Между прочим, большинство людей создают шелл-код, собирая его с помощью обычного ассемблера, такого как NASM, и затем шифруя этот двоичный файл в строку C. Написание собственного ассемблера может быть забавным проектом, но в основном это отдельный проект.


Ваш encode_rex выглядит несколько разумно, принимая четыре аргумента за четыре бита. Но код в mov, который вызывает его, иногда проходит 2, который усекается до 0!

Кроме того, есть 4 возможности для 2 соответствующих битов расширения (b и x), которые вы ' используется для регулярных ходов. Но ваша цепочка if / else if / else охватывает только 3 из них, игнорируя возможность dest>=8 && src >= 8 => x:b = 3

Поскольку эти два бита ортогональны, вы должны просто рассчитать их отдельно, как это:

put<uint8_t>(encode_rex(1, 0, dest>=8, src>=8));

Поле SIB-index x всегда должно быть 0, потому что у вас нет байта SIB, просто ModRM для reg-reg mov.

Ваш инициализатор структуры в encode_rex перепутан, с extend_modrm_reg, вторым, где он инициализирует поле x вместо r. Ваши имена битовых полей совпадают https://wiki.osdev.org/X86-64_Instruction_Encoding#Encoding, но у вас неправильные переменные C ++, инициализирующие их. См. Эту ссылку для описания.


Возможно, у меня есть порядок dest, sr c в обратном порядке, в зависимости от того, используете ли вы код операции mov r/m, r или mov r, r/m. Я не проверял дважды, что именно.

Проверка работоспособности от NASM: я собрал с nasm -felf64 -l/dev/stdout, чтобы получить список:

     1 00000000 4889C8                  mov rax, rcx
     2 00000003 4889C0                  mov rax, rax
     3 00000006 4D89C0                  mov r8, r8
     4 00000009 4989C0                  mov r8, rax
     5 0000000C 4C89C0                  mov rax, r8

Вы используете тот же 0x89 код операции, который использует NASM, поэтому ваши префиксы REX должны совпадать.


return *(uint8_t*)&result; является UB со строгим псевдонимом и небезопасен вне MSV C.

Используйте memcpy для безопасного тип-каламбур. (Или объединение; большинство реальных компиляторов C ++, включая gcc / clang / MSV C, определяют поведение объединения типов объединения, как в C99, в отличие от ISO C ++).

...