Можете ли вы ввести x64 32-битный «подрежим длинной совместимости» вне режима ядра?
Это может быть точной копией Можно ли выполнить 32-битный код в 64-битном процессе, переключив режим?, но этот вопрос задан год назад и имеет только один ответ, который не дает никакого исходного кода. Я надеюсь на более подробные ответы.
Я использую 64-битную версию Linux (Ubuntu 12.04, если это имеет значение). Вот некоторый код, который выделяет страницу, записывает в нее некоторый 64-битный код и выполняет этот код.
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <sys/mman.h> // mprotect
#include <unistd.h> // sysconf
unsigned char test_function[] = { 0xC3 }; // RET
int main()
{
int pagesize = sysconf(_SC_PAGE_SIZE);
unsigned char *buffer = memalign(pagesize, pagesize);
void (*func)() = (void (*)())buffer;
memcpy(buffer, test_function, sizeof test_function);
// func(); // will segfault
mprotect(buffer, pagesize, PROT_EXEC);
func(); // works fine
}
Теперь, исключительно для развлечения, я бы хотел сделать то же самое, но сbuffer
содержащий произвольный 32-битный (ia32) код вместо 64-битного кода.Эта страница подразумевает, что вы можете выполнить 32-битный код на 64-битном процессоре, введя «подрежим длинной совместимости», установив биты дескриптора сегмента CS какLMA=1, L=0, D=1
, Я готов обернуть мой 32-битный код в пролог / эпилог, который выполняет эту настройку.
Ноcan Я делаю эту настройку, в Linux, в режиме пользователя? (Ответы BSD / Darwin также будут приняты.) Именно здесь я начинаю задумываться. Я думаю, что решение включает в себя добавление нового дескриптора сегмента к GDT (или это LDT?), А затем переключение на этот сегмент черезlcall
инструкция. Но можно ли все это сделать в пользовательском режиме?
Вот пример функции, которая должна возвращать 4 при успешном запуске в подрежиме совместимости и 8 при выполнении в длинном режиме. Моя цель состоит в том, чтобы получить указатель инструкции, чтобы взять этот путь и выйти на другую сторону с%rax=4
без перехода в режим ядра (или только через документированные системные вызовы).
unsigned char behave_differently_depending_on_processor_mode[] = {
0x89, 0xE0, // movl %esp, %eax
0x56, // push %{e,r}si
0x29, 0xE0, // subl %esp, %eax
0x5E, // pop %{e,r}si
0xC3 // ret
};