LINUX.ORG.RU

[C] Интересуют кое-какие извраты.

 


0

1

Мне было интересно во время выполнения поменять константу в скомпилированной функции. После определения относительного адреса константы в теле функции я попытался сделать вот что:

// here we set the constant:
((float *)func)[156] = 0.0;

Компилятор съел, но при попытке запустить сегфолт именно в этой строчке.

Как я понял, нельзя менять код во время выполнения.

Ну ладно, я выделил кусок памяти и скопировал туда содержимое по указателю func, привёл к нужному типу и попытался выполнить.

Снова сегфолт. Наша скопированная функция не хочет выполнятся. И что, получается я не могу выполнить кусок кода, сформированный в рантайме?

Собственно вопрос: Наверное я хочу странного, но как сделать то что я хочу? Это возможно в принципе? А как же работают JIT-компиляторы? А как тогда могут существовать полиморфные вирусы?

Ссылки на статьи/книги/мануалы приветствуются.

Код хранится в сегменте кода (если так можно выразиться) - он только для чтения. Удачи.

vertexua ★★★★★
()

И что, получается я не могу выполнить кусок кода, сформированный в рантайме?

Можете. У вас скорее всего ошибка в смещениях. Например, откуда в

((float *)func)[156] = 0.0;
взялось 156?

anon_666
()

man mprotect, см. флаг защиты страницы PROT_EXEC

dmitry_vk ★★★
()
Ответ на: комментарий от anon_666

>Можете.

Да, но только сперва надо для страниц с кодом разрешить выполнение кода из них.

dmitry_vk ★★★
()
Ответ на: комментарий от anon_666

> взялось 156?

Я написал функцию и подбором узнал какой индекс надо брать, чтобы получить нужную мне переменную.

Можете.

Обнадёжили, ща буду пробовать.

vladimir-vg ★★
() автор топика

YEAH!!!!

Да, оно выполняется в памяти выделенной malloc. =)

vladimir-vg ★★
() автор топика

И при малейшем изменении кода функции это смещение 156 придется заново подсматривать вручную. Не лучше ли изначально задать для константы некоторое ненулевое значение, а затем найти нужное смещение поиском в памяти соответствующих байтов?

amomymous ★★★
()
Ответ на: комментарий от amomymous

Или лучше сразу переписать эту ф-ю на асм, так будет проще.

anon_666
()
Ответ на: комментарий от amomymous

> Не лучше ли изначально задать для константы некоторое ненулевое значение, а затем найти нужное смещение поиском в памяти соответствующих байтов?

Именно так и делаю. Просто я немного накосячил с поиском.

Или лучше сразу переписать эту ф-ю на асм, так будет проще.

Это не для дела, а эксперимента ради.

Кстати, а как мне это же самое (c malloc'ом) написать в асме? Ведь у полученной функции не будет имени? Как мне её вызвать?

call адрес ?

vladimir-vg ★★
() автор топика
Ответ на: комментарий от vladimir-vg

Кажется, ассемблерные вставки компиляторо-зависимы. Но будет нечто вроде
void func()
{ __asm__
push ebp
mov ebp, esp
...
mov [some_var], 0 ; считаем байты до сюда
}
А вызываться все будет стандартно, в С-шном коде func() и все. Только надо посмотреть стандарт вызова, параметры в прямом или обратном порядке передаются и все такое..

amomymous ★★★
()
Ответ на: комментарий от amomymous

Нет, у меня вопрос немного другой.

К примеру написал я программу на асме (вообще без сей), которая делает malloc и записывает в эту память какую-то программу. Как мне вызвать эту программу из асма, если у меня есть только указатель на память.

Может что-то напутал, или натупил, я асм недавно начал изучать. (gcc , AT&T)

vladimir-vg ★★
() автор топика
Ответ на: комментарий от vladimir-vg

>какую-то программу. Как мне вызвать эту программу из асма

Тут зависит как эта программа оформлена - если как функция, с аллокацией стека и тп - тогда call, если просто набор инструкций - то long jmp. Кроме того нужно подумать о смещении адресов, или писать код базонезависимым.

anon_666
()
Ответ на: комментарий от anon_666

> с аллокацией стека и тп

аллокация стека — это как?

Разве не один стек на всё-провсё? Или тут подразумевается другое?

vladimir-vg ★★
() автор топика
Ответ на: комментарий от vladimir-vg

Каждая ф-я выделяет локальные переменные на стеке, при выходе из неё указатель стека восстанавливается. Плюс, мы должны восстановить(либо это делает ф-я) указатель стека, по той причине, что параметры на х86 передаются на стеке.

anon_666
()
Ответ на: комментарий от anon_666

>мы должны восстановить(либо это делает ф-я)

Это определяется соглашением о передаче аргументов - stdcall cdecl etc.

anon_666
()
Ответ на: комментарий от anon_666

имхо наиболее простой и не замороченный вариант - использовать при вызове call, для возврата из процедуры ret, а внутри нее обращаться только по абсолютным адресам(к глобальным переменным). Потом уже, когда надо стыковать с кодом на языках высокого уровня или обеспечивать реентерабельность, нужна и передача через стек и прочее

amomymous ★★★
()

>Мне было интересно во время выполнения поменять константу в скомпилированной функции.

такое конечно можно, только надо юзать не константу, а переменную + volatile. Причина - оптимизация кода компилятором.

И что, получается я не могу выполнить кусок кода, сформированный в рантайме?

Можешь! Копируй код в стек или играйся атрибутами страниц, как тебе указали раньше.

AF ★★★
()
Ответ на: комментарий от AF

>Копируй код в стек

Стек-то обычно делается не executable.

dmitry_vk ★★★
()

>((float *)func)[156] = 0.0;
этf запись аналогична следующей
*(float *)( ((char *)func) + 156 * sizeof (float) ) = 0.0;

тебе по всей видимости нужно так:
*(float *)( ((char *)func) + 156 ) = 0.0;

xydo ★★
()
Ответ на: комментарий от namezys

>Интересно, а кто вам разрешит выполнять код, который вы не лету соберете?

Разрешит MMU процессора. А ему разрешение даст ядро, о чем его программа попросит вызовом mprotect.

dmitry_vk ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.