Взлом приложений Python: реверсирование и полезные нагрузки
Наша цель - игра pygame в комплекте с pyinstaller. Как мы можем взломать эту игру, ничего не зная о том, как она написана? Что ж, есть несколько приемов, которые мы можем использовать, чтобы узнать немного больше о том, что происходит за кулисами.
Глобальные переменные
Один из самых мощных инструментов в нашем арсенале - функция Python globals(). Она вернет словарь, содержащий символы в глобальной области как ключи, а объекты, которым они сопоставлены, как значения. Рассмотрим следующий код.
def someFunc():
localVar = 22
something = "nothing"
Если бы мы получили глобальные переменные из этого скрипта, наша переменная something
была бы возвращена. Но локальная переменная нашей функции - нет. Единственный способ получить переменные из локальной области видимости - это использовать функцию python locals() из целевой функции. Тем не менее, мы можем получить довольно важную информацию только из глобальных переменных. Глобальные переменные часто используются как флаги, поэтому обратите особое внимание на целые и логические значения.
Сборка мусора и объекты
Учитывая, что сборщик мусора python включен (он включен по умолчанию), мы можем получить список всех отслеживаемых в настоящее время объектов. Мы можем сделать это, импортировав модуль «gc» и используя функцию «gc.get_objects()».
Дизассемблер
Дизассемблер - важный инструмент для обращения функций, хотя его можно использовать во многих других типах экземпляров. Чтобы дизассемблировать функцию, нам нужно импортировать модуль dis и использовать функцию dis.dis(). Пример вывода следующий.
def printMe(thing):
print(thing)
===========
Turns into
===========
2 0 LOAD_GLOBAL 0 (print)
2 LOAD_FAST 0 (thing)
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
Вы можете найти полный список инструкций по разборке и их значения здесь.
Перечисление дочерних экземпляров
Когда дело доходит до перечисления дочерних элементов экземпляра, у нас есть несколько вариантов. Если мы хотим получить атрибуты класса, мы можем использовать dir(), vars() или gc.get_referents(). Функции dir и vars не требуют импорта. 'dir' вернет словарь, содержащий атрибуты нашего класса и его базовые классы. 'vars' вернет только словарь, содержащий атрибуты указанного класса.
'gc.get_referents' вернет список, содержащий каждый объект, на который ссылается объект, включая его атрибуты и методы.
И так далее...
Существует множество других методов, которые вы могли бы использовать, чтобы получить больше информации о своей цели. Мы даже не коснулись pdb. Тем не менее, если вы используете каждый из вышеперечисленных методов в комбинации, вы начнете получать очень четкое представление о данных, которыми можно манипулировать, и базовое понимание потока некоторых функций и методов.
Полезные нагрузки Pynject
Вот здесь-то и пригодятся связанные полезные нагрузки. Что, если бы я сказал вам, что я написал полезные нагрузки, которые позволяют легко использовать все вышеперечисленные приемы? Ну ... у меня они есть. Они идут в комплекте с pynject.
Исполнитель
Это сценарий, который я написал, чтобы упростить управление вашими сценариями и их выполнение без необходимости вызывать функции C API. Ваши скрипты будут выполняться в локальной области. Это означает, что если вам нужно изменить глобальную переменную, вам нужно сначала объявить ее в области видимости следующим образом.
myGlobal = "This didn't work..."
global myGlobal
myGlobal = "Now it works!"
Исполнитель перенаправляет вывод консоли в собственное окно консоли, чтобы упростить отладку скриптов. У исполнителя также есть ряд собственных API-функций. Они позволяют внедрять модули в приложения с ограниченными путями (например, pyinstaller), фильтровать собственные объекты из глобальных переменных и находить экземпляры объектов по типу. В качестве дополнительного бонуса исполнитель очень хорошо убирает за собой. Он также появляется в собственном потоке.
Инспектор
Это сценарий, который автоматизирует проверку объектов в целевом процессе. Все упомянутые выше методы выполняются в фоновом режиме, а результаты вставляются в деревья. Об этом особо нечего сказать, кроме того, что вы можете увидеть сами. Он все еще находится на ранней стадии разработки, как и большая часть этого проекта, и я единственный разработчик. Мне известно о нескольких сбоях, но он справится со своей задачей.
Заключение
Итак, мы вооружены практическими знаниями в области обратного проектирования процессов Python. Что теперь? Что ж, теперь мы взломали Rift Wizard!