Эй, я Дэвид, и сегодня я хотел бы поговорить о различных методах, которые вы можете использовать для запутывания кода python. Запутывание-невероятно сложная и удивительная тема, и я надеюсь, что она вам понравится.
Основы: Что такое обфускация
Формально запутывание кода определяется как преднамеренный акт создания исходного или машинного кода, который трудно понять людям. Он обычно используется, потому что автор хочет:
- Сдерживание обратного инжиниринга
- Предотвращение вмешательства в программу
- Сделайте вызов для единомышленников-гиков
Хотя обфускация часто получает плохую репутацию из-за авторов вредоносных программ и плохих актеров в целом, у нее есть несколько законных целей. Кроме того, теория, лежащая в ее основе, довольно хороша, и возможности безграничны.
Как вы должны думать о схемах запутывания
Вы можете абстрагировать любую схему запутывания таким образом, чтобы схема принимала входные данные x на определенном языке и создавала эквивалентный массив инструкций, который либо в конечном итоге имеет тот же конечный результат, хотя способ получения этого конечного результата отличается, либо создает тот же массив инструкций, но удаляет не жизненно важную информацию, которая существует только для того, чтобы помочь людям. Большинство хороших схем запутывания сочетают в себе эти два.
Основная техника № 1: Удаление всей информации, которая бесполезна для интерпретатора/парсера
Основной способ запутать ваш код-просто переименовать все ваши именованные параметры (имена переменных, имена ключей словаря, все имена, которые имеют бессмысленную связь с данными, которые они содержат; будьте изобретательны).
Давайте взглянем на следующий код. Это простой фрагмент кода, чтобы найти медиану массива целых чисел, а также тестовый класс для указанного фрагмента кода.
Мы будем использовать этот код на протяжении всей статьи.
(кредиты на python wiki; https://wiki.python.org/moin/SimplePrograms)
import unittest def median(pool): copy = sorted(pool) size = len(copy) if size % 2 == 1: return copy[(size - 1) / 2] else: return (copy[size/2 - 1] + copy[size/2]) / 2 class TestMedian(unittest.TestCase): def testMedian(self): self.failUnlessEqual(median([2, 9, 9, 7, 9, 2, 4, 5, 8]), 7) if __name__ == '__main__': unittest.main()
Давайте переименуем все переменные в бессмысленные строки:
import unittest def a(b): c = sorted(b) d = len(c) if d % 2 == 1: return c[(d - 1) / 2] else: return (c[d/2 - 1] + c[d/2]) / 2 class e(unittest.TestCase): def e(self): self.failUnlessEqual(a([2, 9, 9, 7, 9, 2, 4, 5, 8]), 7) if __name__ == '__main__': unittest.main()
Это труднее читать, верно? Вы даже можете развить эту концепцию, переименовав все идентификаторы во что-то очень похожее, например, шаблон”0″и” O “или шаблон” l ” и “1”.
Основная техника № 2: Синтаксическое запутывание
Еще более простой способ запутать python-это отбросить все форматирование и вещи, которые существуют только для ваших глаз в коде. Это менее эффективно, чем в предыдущем примере, так как вы не уничтожаете какую-либо жизненно важную информацию, но это все равно не повредит, верно?
Давайте снова возьмем наш запутанный код и убьем форматирование:
import unittest def a(b): c=sorted(b);d = len(c); if d%2==1: return c[(d-1)/2] else: return (c[d/2-1]+c[d/2])/2 class e(unittest.TestCase): def e(self): self.failUnlessEqual(a([2,9,9,7,9,2,4,5,8]),7) if __name__=='__main__': unittest.main()
Хотя это и не большая перемена, сделать это не помешает.
Продвинутая техника № 1: Переписывание выражений
Переписывание арифметических выражений, литералов int и строковых литералов-хороший способ запутать, потому что он может скрыть истинное значение числа на первый взгляд. Это затрудняет просто grep для магических чисел, строк или выражений в целом. Например, мы можем переписать выражение ” 1 ” как ‘6+97+45-991+844*23+ 54/8/18575.75′, выражение; x’ как
import math;a=0;c=0;x=0;x|=0b0000001;y=0;y|=0b0000001 for i in range(max(int(math.log(y,2))+1, int(math.log(x,2))+1)+1): x1=int(x&(1<=2 else 0;c=z;a^=(-(z2%2)^a)&(1<
(https://en.wikipedia.org/wiki/Binary_number#Addition),
а выражение “Привет, мир!” как
''.join([chr((ord(__l11111) ^ ord(__111111))) for (__l11111, __111111) in zip('g-I@a¯£²9\nÖÄ', '/H%,\x0e\x8fôÝKf²å')])
(https://en.wikipedia.org/wiki/Exclusive_or)
Приложение А
Переписывание программы в виде лямбда-выражения
Это довольно продвинутый подход, и я решил не включать его в эту статью, но почти весь код python может быть переписан как лямбда-выражение. Давайте перепишем наш пример кода:
(lambda __g: [[[(lambda __after: (unittest.main(), __after())[1] if (__name__ == '__main__') else __after())(lambda: None) for __g['e'] in [((lambda b, d: d.get('__metaclass__', getattr(b[0], '__class__', type(b[0])))('e', b, d))((unittest.TestCase,), (lambda __l: [__l for __l['e'], __l['e'].__name__ in [(lambda self: (lambda __l: [(__l['self'].failUnlessEqual(a([2, 9, 9, 7, 9, 2, 4, 5, 8]), 7), None)[1] for __l['self'] in [(self)]][0])({}), 'e')]][0])({'__module__': __name__})))]][0] for __g['a'], a.__name__ in [(lambda b: (lambda __l: [[[(lambda __after: __l['c'][((__l['d'] - 1) / 2)] if ((__l['d'] % 2) == 1) else ((__l['c'][((__l['d'] / 2) - 1)] + __l['c'][(__l['d'] / 2)]) / 2))(lambda: None) for __l['d'] in [(len(__l['c']))]][0] for __l['c'] in [(sorted(__l['b']))]][0] for __l['b'] in [(b)]][0])({}), 'a')]][0] for __g['unittest'] in [(__import__('unittest', __g, __g))]][0])(globals())
А теперь посмотри на это! Удачи вам в этом!
(https://github.com/xoreaxeaxeax/reductio): Исследование гомеоморфизма кода. (https://github.com/xoreaxeaxeax/movfuscator): Компилятор C, способный переписывать каждую программу x86 в виде массива инструкций mov
. (https://github.com/csvoss/onelinerizer): Обфускатор, способный переписать почти каждую программу на python в одну строку
Надеюсь, вам всем понравилась эта статья.
Дэвид