Да, x86's mov
завершен по Тьюрингу. Я добавил этот тег к вашему вопросу, потому что он может быть неверным для других ISA с инструкцией под названием mov
, а компилятор movfuscator нацелен только на x86.
Это не сам "mov", выполняющий вычисление , это x86 режимы адресации , которые могут добавлять (и сдвигать бит). Я не посмотрел подробно, как это работает, но он во многом зависит от справочных таблиц и таких вещей, как mov eax, [base + eax*4]
, загружая одно из двух возможных значений в зависимости от того, что EAX равно 0 или 1.
Также помните, что x86 mov
имеет несколько форм : между памятью и регистром (загрузка, сохранение или reg <-reg) или непосредственно в память или регистр. И с режимами адресации, включая абсолютный и косвенный регистр. </p>
Я не думаю, что это зависит от самоизменяющегося кода, но поправьте меня, если я ошибаюсь. (И если это произойдет, я думаю / надеюсь, что movfuscator по крайней мере не будет создавать инструкции, отличные от mov
. Это было бы обманом.)
Кроме того, это только своего рода правда; вам нужен какой-то способ l oop основной программы , при условии, что исходный источник не является прямолинейным без циклов - readme Movfuscator github говорит об этом:
В то время как документ Долана требуется инструкция jmp, M / o / Vfuscator - нет , она использует ошибочную инструкцию mov для достижения бесконечного выполнения l oop. Если вы беспокоитесь о том, что это все еще «скачок», того же эффекта можно достичь с помощью страниц, наложенных на один и тот же адрес, обтекания выполнения вокруг верхнего диапазона памяти, обработки исключений кольца 0 или просто повторения mov l oop на неопределенный срок. В настоящее время jmp используется для отправки внешних функций - если это проблема, избегайте использования внешних функций или компилируйте библиотеки с помощью M / o / Vfuscator.
При создании среды пользовательского пространства для запуска только кода mov я предполагаю, что он создает обработчик SIGSEGV (в операционных системах POSIX), который перезапускает выполнение сверху. Таким образом, любая сбойная нагрузка может перезапустить основную l oop.
Возможность выполнения выполнения также упоминается как возможность:
Обтекание IP может хорошо работать в 16-битном режиме, где IP 16-битный, но CS: IP формирует 20-битный линейный адрес (реальный режим) или в 16-битном защищенном режиме где-то 64-килобайтное окно где-то в линейном адресном пространстве то есть вы можете иметь блок инструкций размером 64 КБ только в части вашего адресного пространства, с другим пространством, оставленным для данных. Сегмент DS может использовать другую базу. (32-разрядные режимы адресации в 16-разрядном режиме возможны, поэтому вы по-прежнему имеете полную мощность любого режима адресации и адресации с масштабируемым индексом.) Обратите внимание, что мнемони c для чтения и записи сегментных регистров также mov
.
Но сложнее в 32-битном режиме, где EIP 32-битный, и поэтому линейные адреса после вычисления seg + off. Если нет какой-то другой хитрости, обход может происходить только по всему адресному пространству, независимо от того, что вы делаете с сегментацией. Это не оставляет места без кода для данных. Установка нижнего предела сегмента может привести к ошибке выборки кода, но это не вызывает обхода (если вы не установили обработчик сигнала, или на голом металле не установите адрес обработчика прерывания).
И в любом случае, даже x86 -64 имеет только 64-битные указатели (в теории; 48 или 57-битные на практике), , поэтому пространство ограничено, в отличие от реальной машины Тьюринга с бесконечной лентой.