Это может быть точный дубликат Возможно ли выполнить 32-разрядный код в 64-разрядном процессе путем переключения режима?, но этот вопрос относится к году назад и имеет только один ответ, который не работает 't дать какой-либо исходный код. Я надеюсь получить более подробные ответы.
Я запускаю 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-битный код в прологе/эпилоге, который выполняет эту настройку.
Но могу ли я сделать эту настройку в Linux в usermode? (Ответы BSD/Darwin также будут приняты.) Здесь я начинаю получать очень туманные понятия. Я думаю, что решение включает в себя добавление нового дескриптора сегмента в GDT (или это LDT?), А затем переход на этот сегмент с помощью команды lcall
. Но может ли это быть сделано в usermode?
Здесь примерная функция, которая должна возвращать 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
};