Избегайте использования сегмента .data - PullRequest
0 голосов
/ 21 февраля 2020

Есть ли способ избежать использования в скомпилированном коде сегмента .data? Можно ли написать код C и использовать параметры компилятора, чтобы все было в формате .text? Причина, по которой я спрашиваю, заключается в том, что я хочу поместить код сборки другой программы в стек и запустить код оттуда. Так что это не будет работать, если эта программа использует сегмент данных.

Ответы [ 2 ]

5 голосов
/ 21 февраля 2020

Есть ли способ избежать использования в скомпилированном коде сегмента .data?

Было бы несколько способов - написать код, который просто не использует данные; с использованием спецификаций компилятора c (например, "__attribute__((section("name")))" в G CC), написание сценария компоновщика, который заставляет все элементы в секциях .data и .rodata входного файла помещаться в .text выходного файла раздел; имея совершенно новый раздел под названием .myData, который не называется .data, et c.

Можно ли написать код C и использовать параметры компилятора, чтобы заставить все быть в .text?

Да, все возможно, если вы хотите потратить годы на написание собственного компилятора и т. д. c.

Проблема в том, что речь идет о разрешениях. Современные процессоры позволяют ОС говорить «эта область памяти не является исполняемой» или «эта область памяти не модифицируется», и имеют аппаратное обеспечение, позволяющее обнаруживать ошибки и избегать сбоев безопасности. Разделы - это то, как вы сообщаете операционной системе, какими должны быть разрешения (например, исполняемый файл и только для чтения .text, не исполняемый и только для чтения .rodata, не исполняемый и изменяемый .data). Преодолев это, вы получите нечто худшее, чем необходимо (меньше шансов на обнаружение ошибок, больше шансов на аварийные ситуации в системе безопасности).

Это также может привести к проблемам с производительностью процессора (половина «кэша инструкций L1» приводит к бесполезному кешированию). данные, половина «кэша данных L1» потратила впустую инструкции кеширования, процессор считает, что это самоизменяющийся код, потому что вы записали что-то в той же строке кэша или на той же странице, что и инструкции).

Причина, по которой я спрашиваю потому что я хочу поместить ассемблерный код другой программы в стек и запустить его оттуда.

Как правило, стек не "исполняемый", поэтому он, вероятно, просто взломает sh. Чтобы исправить это, вам, вероятно, понадобится специальный код, чтобы изменить разрешение области памяти, используемой стеком, но если вы можете изменить другую программу, чтобы сделать это, то вы также можете изменить другую программу, чтобы включить сборку напрямую и избежать потребность в глупой глупости.

3 голосов
/ 21 февраля 2020

Звучит так, как будто вы хотите использовать вывод компилятора для создания шелл-кода, который можно использовать для внедрения кода. (например, путем переполнения стекового буфера в устаревшей программе с исполняемым стеком).

Да, все должно быть в одном двоичном блоке, в основном в плоском двоичном файле и независимо от позиции.

Вы можете вручную отредактировать вывод asm компилятора, чтобы поместить .rodata и даже .data в .text. Вы можете проверить это в автономном исполняемом файле, скомпилировав ссылку с ld -N (--omagic), чтобы сделать .text доступной для записи.

Конечно, это работает, только если ISA, для которого вы компилируете, имеет P C -относительная адресация, например, x86-64, но не 32-битная x86. Использование меток для операндов памяти в 32-битном x86 приведет к абсолютным адресам в машинном коде, что, очевидно, не может работать при вставке в стек по неизвестному адресу.

(Связано: -zexecstack делает все исполняемый в памяти, поэтому атаки с внедрением кода могут работать. Это не по умолчанию; внедрение кода не работает в системах, поддерживающих W ^ X (нет страниц, которые могут быть записаны и выполняемы).)


Так что на самом деле вам следует просто не использовать библиотечные функции и не использовать глобальные переменные или static переменные. т.е. писать код, который не использует никакие переменные с классом хранения stati c, только автомат c. Используйте локальный массив, если вам нужен небольшой буфер.

Вам также необходимо использовать встроенные макросы asm-оболочки для системных вызовов, а не обычные функции оболочки lib c.

...