Какая польза от самоизменяющегося кода? - PullRequest
49 голосов
/ 05 февраля 2009

Есть ли реальное применение для самоизменяющегося кода ?

Я знаю, что их можно использовать для создания червей / вирусов, но мне было интересно, есть ли какая-то веская причина, по которой программист может использовать самоизменяющийся код.

Есть идеи? Гипотетические ситуации тоже приветствуются.

Ответы [ 14 ]

48 голосов
/ 05 февраля 2009

Оказывается, что в записи в Википедии " самоизменяющийся код " есть отличный список:

  1. Полуавтоматическая оптимизация цикла, зависящего от состояния.
  2. Генерация кода времени выполнения , или специализация алгоритма в время выполнения или время загрузки (что является популярным, например, в области графика в реальном времени), такие как общие утилита сортировки готовит код для выполнения сравнение ключей описано в конкретный вызов.
  3. Изменение встроенного состояния объекта или имитация высокого уровня строительство затворов.
  4. Исправление адреса подпрограммы, вызывающей , как обычно делается во время загрузки динамических библиотек, или, на каждом вызов исправления подпрограммы внутренние ссылки на его параметры чтобы использовать их фактические адреса. Считается ли это «самоизменяющийся код» или нет это дело терминологии.
  5. Эволюционные вычислительные системы , такие как генетическое программирование.
  6. Сокрытие кода до предотвращает обратный инжиниринг , как при использовании дизассемблер или отладчик.
  7. Скрытие кода в Уклонение от обнаружения с помощью программного обеспечения для сканирования на наличие вирусов и шпионских программ и и тому подобное.
  8. Заполнение 100% памяти (в некоторых архитектурах) шаблоном прокрутки повторяющихся кодов операций, чтобы стереть все программы и данные , или до выгорания аппаратное обеспечение .
  9. Сжатие кода для распаковки и выполнения во время выполнения, например, когда память или дисковое пространство ограничено.
  10. Некоторые очень ограниченные наборы инструкций не оставляют выбора, кроме как использовать самоизменяющийся код для достижения определенного функциональность . Например, «Один Инструкция "Компьютер" использует только вычитать-и-ветви, если отрицательным «инструкция» не может сделать косвенный копия (что-то вроде эквивалента «* a = ** b» в программировании на C язык) без использования самоизменения Код.
  11. Изменение инструкций для отказоустойчивость

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

В течение нескольких обновлений прошивки DirectTV медленно собирал на своей смарт-карте программу для уничтожения взломанных карт с целью незаконного получения неоплаченных каналов. См. Статью Джеффа «Кодирующий ужас» о Black Sunday Hack для получения дополнительной информации.

12 голосов
/ 05 февраля 2009

Я видел самоизменяющийся код, используемый для:

  1. оптимизация скорости, благодаря программе, пишущей больше кода для себя на лету

  2. обфукация, чтобы сделать реверс-инжиниринг намного сложнее

11 голосов
/ 05 февраля 2009

В прежние времена, когда объем ОЗУ был ограничен, для экономии памяти использовался самоизменяющийся код. В настоящее время, например, утилиты сжатия приложений, такие как UPX , используются для распаковки / изменения собственного кода после загрузки сжатого образа приложения.

6 голосов
/ 17 сентября 2011

Языки ассемблера 1960-х годов использовали самоизменяющийся код для реализации вызовов функций без стека.

Кнут, v1, 1-е стр.182:

MAX100  STJ   EXIT   ;Subroutine linkage
        ENT3  100    ;M1. Initialize
        JMP   2F
1H      CMPA  X,3    ;M3. Compare
        JGE   *+3
2H      ENT2  0,3    ;M4. Change m
        LDA   X,3    ;(New maximum found)
        DEC3  1      ;M5. Decrease k
        J3P   1B     ;M2. All tested?
EXIT    JMP   *      ;Return to main program

В более крупной программе, содержащей это кодирование в качестве подпрограммы, одиночная инструкция "JMP MAX100" заставит регистр A установить текущее максимальное значение местоположений от X + 1 до X + 100, а позиция максимума будет появляются в R2. Связывание подпрограмм в этом случае достигается с помощью инструкций «MAX100 STJ EXIT», а затем «EXIT JMP *». Из-за того, как работает J-регистр, инструкция выхода затем перейдет в место, следующее за местом, где была сделана первоначальная ссылка на MAX100.

Редактировать: Может быть трудно увидеть, что происходит, даже с кратким объяснением здесь. В строке MAX100 STJ EXIT, MAX100 - метка для инструкции (и, следовательно, для всей процедуры), STJ означает STORE регистр перехода (куда мы только что пришли из ), EXIT означает, что ячейка памяти с надписью «EXIT» является целью хранилища. EXIT, мы увидим позже ярлык для последней инструкции. Так что это переписывает код! Но многие инструкции (включая STJ здесь) неявно перезаписывают только часть операнда командного слова. Таким образом, JMP остается нетронутым, а * является фиктивным токеном, поскольку на самом деле в нем нет ничего значимого, он будет только перезаписан.


Самоизменяющийся код также используется в тех случаях, когда косвенная адресация в регистре недоступна, а нужный вам адрес находится прямо в реестре. PDP-1 LISP:

dap .+1  ;deposit address part of accumulator in (IP+1)
lac xy   ;load accumulator with (ADDRESS) [xy is a dummy symbol, just like * above]

Эти две инструкции выполняют ACC := (ACC), изменяя операнд инструкции загрузки.

Такие модификации относительно безопасны, а на старинных архитектурах они необходимы.

6 голосов
/ 06 января 2010

Потому что это действительно круто, а иногда и этого достаточно.

6 голосов
/ 05 февраля 2009

Поскольку Commodore 64 не имеет много регистров и имеет процессор 1 МГц. Когда вам нужно прочитать смещение адреса памяти по значению, проще изменить источник.

@Reader:
LDA $C000
STA $D020
INC Reader+1
JMP Reader

Это последний раз, когда я в любом случае писал самоизменяющийся код: -)

5 голосов
/ 05 февраля 2009

Искусственный интеллект?

5 голосов
/ 05 февраля 2009

Множество причин. С макушки головы:

  • Построение классов исполнения и метапрограммирование. Например, наличие фабрики классов, которая берет соединение с таблицей SQL и генерирует клиентский класс, специализированный для этой таблицы (со средствами доступа к столбцам, методам поиска и т.

  • Тогда, конечно, есть известный пример bitblt и аналоги регулярных выражений.

  • Динамическая оптимизация на основе информации RT с отслеживанием JIT

  • Специализация подтипов универсальных функций стиля ада в аккреционной среде.

- MarkusQ

4 голосов
/ 05 февраля 2009

Динамическое связывание - это своего рода самомодификация (исправление абсолютного и / или относительного местоположения перехода) ... хотя обычно это выполняется загрузчиком программ O / S.

3 голосов
/ 05 февраля 2009

LOL - я написал самоизменяющийся код в двух случаях:

  1. при первом изучении ассемблера, прежде чем я понял косвенный индексированный доступ
  2. случайно, как ошибки указателя на ассемблере и C

Я могу представить, что могут быть сценарии, в которых самоизменяющийся код будет более эффективным, чем альтернативы, но ничего очевидного не приходит на ум. В общем, этого следует избегать - отладка кошмара и т. Д. - если только вы не пытаетесь преднамеренно запутать, как упоминалось выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...