где сегменты памяти хранятся в сборке x86
У меня есть следующая сборочная команда x86 от gdb:
mov eax, gs:0x14
Когда я набираю, (gdb) info registersзначение gs оказывается 0x63. Из того, что я прочитал, чтобы добраться до самого адреса, мне нужно умножить gs на 0x10 и добавить смещение (0x14).
Как и ожидалось, адрес не может быть прочитан из памяти, потому что это относительный адрес. Я попытался objdumpнайти в файле какую-либо значимую начальную точку, к которой я должен добавить 0x644, чтобы получить реальный адрес памяти, но ничего не появилось. Когда я запускаю файл в gdb, адреса всегда равны 0x056555XXX, но добавление 0x644 к 0x56555000 попадает прямо в середину кода.
Где на самом деле находится этот сегмент памяти?
edit: Я запускаю это на 64-битной виртуальной машине Kali Linux, но файл взят из какого-то CTF и является 32-битным файлом i386 elf. Не знаю, в защищенном или реальном режиме ...
Ответы
В защищенном режиме регистр сегмента в основном просто содержит индекс в таблице дескрипторов, а не фактический адрес сегмента. Таблица дескрипторов будет содержать базовый адрес и размер сегмента. Фактическая разбивка - это 13 бит индекса, 1 бит локального / глобального селектора и 2 бита уровня разрешений.
В вашем случае значение gs 0x63 разбивается как уровень разрешений 3 (нижние два бита), что фактически является самым низким (пользовательским) уровнем разрешений; бит 0, выбирающий глобальный дескриптор, и индекс 12 в GDT (таблица глобальных дескрипторов). К сожалению, нет простого способа прочитать GDT из gdb, но фактический адрес, используемый для этой инструкции, будет вычисляться из базового адреса с индексом 12 в GDT с добавленным смещением 0x14.
В длинном (64-битном) режиме значение в сегментном регистре полностью игнорируется - вместо этого базовый адрес берется из регистра GSBASE. В gdb вы можете проверить это, используя имя регистра $ gs_base:
(gdb) p /x $gs_base
Досадно, что это не отображается info registers(или даже info registers all), поэтому вы должны знать, чтобы печатать это специально.