Перейти к содержанию

Лидеры

  1. keng

    keng

    Ветераны


    • Баллы

      1

    • Постов

      1 635


  2. skip123

    skip123

    Пользователи+


    • Баллы

      1

    • Постов

      258


Популярный контент

Показан контент с высокой репутацией 25.06.2017 во всех областях

  1. Привет, читатель! Ты сейчас читаешь это, потому что в тебе есть интерес ко взлому игр и низкоуровневому программированию, ибо этот мини-блог будет посвящен как раз этой тематике. Если конкретнее, то я постараюсь показать и рассказать о том, как пишутся движки для трейнеров. Если ты вдруг не в курсе, то трейнер - это программа, позволяющая всячески изменять поведение компьютерной игры. Например, сделать ГГ (главного героя) бессмертным или же выдать ему миллион игровых очков. В общем, сделать нечто такое, чего штатный игровой процесс не подразумевает. Если ты вообще не понимаешь, о чем идет речь, то сначала поищи в интернете, как создаются читы для игр, а потом уже возвращайся сюда. Я буду предполагать, что взламывать игры (искать значения в памяти и немного пользоваться отладчиком/дизассемблером) ты уже умеешь. Итак, поехали! Весь исходный код я буду хранить в репозитории на github, ссылку на него и на нужный коммит буду выдавать в конце статей, если это потребуется. С чего начнем? А начнем мы с выбора инструментов. Мои коллеги по цеху давно и очень успешно создают подобные этому обучающие материалы, но на высокоуровневых языках - C++ и C#, а местами и на Delphi. К счастью, мы от подобного избавлены, так что выбор у нас один - Ассемблер. Первая проблема заключается в том, что их много и они местами сильно различаются, так что отныне и в обозримом будущем я буду использовать [flat assembler]. Идешь на сайт в раздел "Download" и качаешь последнюю версию flat assembler for Windows (на момент написания этой статьи - 1.71.63). Скачанный архив нужно куда-то распаковать и можно запускать местную среду разработки - fasmw.exe. А вот и код на сегодня: ; main.asm format PE GUI 4.0 include 'win32wxp.inc' invoke ExitProcess,0 data import library kernel32,'KERNEL32.DLL' import kernel32,\ ExitProcess,'ExitProcess' end data Что происходит? ААА! Да ну, все в порядке. Разберем построчно. Символ точки с запятой обозначает комментарий. Сразу берем за правило, что в каждом файле исходного кода первой же строчкой будет идти его имя. В местной среде разработке (как и в любой другой) есть возможность запустить программу на исполнение, предварительно ее скомпилировав (если язык разработки является компилируемым). В твоем случае нужно выбрать меню "Run->Run" или ткнуть F9. Если звезды сложатся удачно, то с виду ничего не произойдет. Отсутствие ошибок - это половина успеха! Но вернемся к разбору исходного кода. Первой осмысленной с точки зрения компилятора строчкой идет вторая. Она указывает, что же за формат такой должен получиться на выходе. Формат, в смысле - исполняемого файла. EXE, то есть. В Windows основным таким форматом является PE, он же Portable Executable. Подробнее про него можно почитать в Интернете, например [тут]. GUI говорит компилятору о том, что это будет приложение с графическим интерфейсом пользователя, а не консольно-текстовое, что нам и нужно. И пока хватит с этой строчки, подробности про нее можно почитать на сайте ассемблера в разделе Documentation. Далее у нас идет директива include. Тут все просто - компилятор ищет файл с таким именем и банально вставляет вместо всей этой строчки его содержимое, как есть. Или ругается, если что-нибудь пошло не так. Если ты очень любопытен, то можешь найти этот файл в папке с ассемблером и посмотреть, что в нем написано. Пока что я скажу, что в нем описываются функции WinAPI - это такой здоровенный набор функций Windows, из которых и состоят, по факту, все программы. Запустить программу? WinAPI! Открыть файл? WinAPI! Поменять картинку на рабочем столе? WinAPI! И вот так всегда. Все в Windows сводится к большой стопке разных функций WinAPI, вызванных в нужном порядке. Хочешь подробнее прямо сейчас - ищи в Интернете (подсказка: MSDN). Что там идет дальше? Точно! Единственный, на самом деле, кусочек реального кода программы, а не какой-то вспомогательной фигни. invoke - это вызов функции. После этой команды идет имя функции и ее аргументы, если они есть. Самая настоящая команда ассемблера! На самом деле, конечно, это макрос, но об этом потом. Как бы это выглядело в реальной жизни? Представь, что надо заварить 10 чашек чая. И даже есть функция (по сути - просто набор действий) под названием "СделатьЧай". Что должна делать эта функция? Взять чашку, насыпать в нее чай, налить кипяток, добавить сахар, перемешать. Так и пишем: СделатьЧай: 0. Взять чашку 1. Насыпать в чашку чай 2. Налить в чашку кипяток 3. Добавить в чашку сахар 4. Перемешать Допустим, что мы пишем на ассемблере программу, которая заваривает чай. И что "СделатьЧай" - это функция WinAPI. Вот так будет выглядеть ее вызов: invoke СделатьЧай Ага! Ты сразу спросишь - "а нафига ноль в конце той строчки? что еще за аргументы такие?". Аргумент - это просто некое значение, передаваемое функции в момент ее вызова. Например, "СделатьЧай, 10 раз". Если бы наша функция, делающая чай, принимала аргумент "Количество" и была бы написана так, что был бы в ней цикл - "делать чай, пока количество не станет равным 0, после каждой чашки отнимать от количества 1", то делала бы она за один вызов 10 чашек и вместо: invoke СделатьЧай ; 0 чашка invoke СделатьЧай ; 1 чашка invoke СделатьЧай ; 2 чашка invoke СделатьЧай ; 3 чашка invoke СделатьЧай ; 4 чашка invoke СделатьЧай ; 5 чашка invoke СделатьЧай ; 6 чашка invoke СделатьЧай ; 7 чашка invoke СделатьЧай ; 8 чашка invoke СделатьЧай ; 9 чашка Можно было бы написать всего лишь: invoke СделатьЧай,10 ; 10 раз И оно бы внутри в цикле 10 раз вызвалось. Удобно ведь? Конечно! И места меньше занимает. Функция у нас вызывается всего одна - "ExitProcess" с аргументом в виде нуля. Знатоки английского языка могут догадаться, что эта функция делает. Завершает процесс. Выходит. Совсем. Да, все так - все, что программа делает на данный момент - это успешно завершает свою работу. Успешно, потому что аргумент у нее "0". Аргумент этой функции - это так называемый код возврата. Он сильно нужен (зачем-то) Windows и она решает именно по коду возврата, хорошо ли было программе во время работы или плохо. Вот случись ошибка - завершаешь программу с не-нулевым кодом возврата и все, Windows об этом будет знать. Когда-то давно это была единственная возможность узнать результат работы - эти самые коды возврата были описаны в документации к программам. Так-то! Итак, выяснилось, что оно начинает работу и сразу же ее завершает, зато успешно. Ну а что, надо ведь начинать с чего-то, верно? Остался последний кусок. Кусок этот отвечает за предоставление нашей программе доступа к WinAPI. Эти все функции - не магия и не само собой оно работает, а где-то в системе хранится. Если точнее, то хранится в библиотеках, которые имеют расширение DLL, хотя тоже являются исполняемыми файлами. Да, они тоже исполняемые, просто не умеют сами запускаться - их должен загрузить в себя другой процесс (работающий EXE файл) и можно будет вызывать функции загруженной библиотеки. То, какие функции можно вызывать, а какие нельзя, определяется библиотекой, а процесс, загрузивший ее, может только попросить указать ему место, где в библиотеке нужные ему функции лежат. Этим и занимается секция data import - end data. Мы указываем, что нам нужно загрузить библиотеку kernel32.dll, а из нее - функцию по имени ExitProcess. Что происходит при запуске? EXE-файл загружает библиотеку. Та сообщает ему, где искать адрес функции ExitProcess. После этот самый адрес и подставляется команде invoke. Такой вот компилятор умный. На этом пока закончим. [Репозиторий] на github. [Коммит].
    1 балл
×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.