Русский
Русский
English
Статистика
Реклама

Как следить (наблюдать) за компьютером. Часть 1 делаем скриншоты пользователей

Делаем скриншоты пользователей. Обсудим реализацию на языке программирования C#.

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

Необходимый функционал:

  1. Программа должна делать скриншоты

  2. Программы не должно быть видно на панели задач

  3. Возможность задавать интервал в секундах между выполнением скриншота

  4. Возможность задавать путь к директории хранилища скриншотов

  5. Возможность задавать максимальный размер хранилища скриншотов

  6. Очистка самых старых файлов из хранилища скриншотов при достижении максимума в хранилище

  7. Логирование работы программы

Алгоритм работы программы:

Код работы метода Main программы:

 static void Main(string[] args) {     Log.Instance.Info($"started");     // Скрыть окно программы     var handle = GetConsoleWindow();     ShowWindow(handle, SW_HIDE);     // Чтение конфигурации     ReadSettings();     // Запуск бесконечной работы скриншотов      while (true)     {          // Проверить хранилище          CheckStorage();          // Выполнить скриншот          DoScreen();          // Подождать интервал времени          Thread.Sleep(_interval * 1000);     } }

Далее необходимо разработать следующие методы:

ReadSettings - Чтение конфигурации
CheckStorage - Проверить хранилище
DoScreen - Выполнить скриншот

ReadSettings (чтение конфигурации)

Для создания файла конфигурации необходимо в Visual Studio открыть свойства проекта и перейти в меню Параметры. Здесь необходимо прописать какие переменные будут вынесены в файл конфигурации и задать их типы и значения.
interval - Как часто делать скриншот, в секундах
limit - Размер хранилища скриншотов, в MB
path - Путь к хранилищу скриншотов, пример C:\temp

Для удобства создадим свойства для доступа к настройкам.

/// <summary>/// Как часто делать скриншот, в секундах/// </summary>static int _interval { get; set; }/// <summary>/// Размер хранилища скриншотов, в MB/// </summary>static int _limit { get; set; }/// <summary>/// Путь к хранилищу скриншотов, пример C:\temp/// </summary>static string _path { get; set; }

Затем прочитаем настройки программы из файла конфигурации Screenshoter.exe.config который лежит около исполняемого файла приложения Screenshoter.exe. Запишем прочитанные настройки в выше созданные поля.

/// <summary>/// Чтение настроек из файла конфигурации/// </summary>static void ReadSettings(){    _interval = 10;    if (Properties.Settings.Default.interval > 0) _interval = Properties.Settings.Default.interval;    Log.Instance.Info($"set interval = {_interval} sec");    _limit = 20;    if (Properties.Settings.Default.limit > 0) _limit = Properties.Settings.Default.limit;    Log.Instance.Info($"set storage = {_limit} Mb");    _path = @"C:\temp";    if (!string.IsNullOrEmpty(Properties.Settings.Default.path)) _path = Properties.Settings.Default.path;    Log.Instance.Info($"set path = {_path}");}

CheckStorage (Проверка хранилища)

Алгоритм проверки хранилища: если хранилище заполнено, то необходимо рассчитать насколько хранилище заполнено больше чем установленный лимит в настройках и затем соответственно очистить хранилище.

/// <summary>/// Проверка доступного места в хранилище/// </summary>static void CheckStorage(){    var currentSize = StorageSize();    if (currentSize > _limit)    {        // Сколько нужно очистить MB        var totalToTrash = currentSize - _limit;        // Очистить необходимое кол-во KB        StorageClear(totalToTrash * 1024);    }}

Дополнительно приведу методы StorageSize и StorageClear.

StorageSize принимает аргумент насколько нужно очистить в KB. Почему в KB (килобайтах), а не в MB (мегабайтах) ? 1 скриншот занимает в хранилище размер меньший чем 1 Мегабайт, а значит корректнее удалять в Килобайтах чтобы не удалять за 1 раз например 5 скриншотов чтобы после этого в хранилище был записан всего 1 скриншот.

Метод StorageSize подсчитывает размер всех файлов в директории хранилища, без учета вложенных директорий (не сложно добавить если нужно).

/// <summary>/// Заполненность хранилища, в MB/// </summary>/// <returns></returns>static long StorageSize(){    long i = 0;    try    {        DirectoryInfo directory = new DirectoryInfo(_path);        FileInfo[] files = directory.GetFiles();        foreach (FileInfo file in files)        {            i += file.Length;        }    }    catch (Exception ex)    {        Log.Instance.Error(3, ex.Message);        return _limit;    }    return i /= (1024 * 1024);}

StorageClear принимает аргумент сколько нужно в хранилище очистить Килобайт. Метод считывает список файлов в хранилище, отсортировывает полученную коллекцию по времени создания файла, удаляет файлы начиная с самых старых пока размер удаленных файлов не будет больше чем нужно удалить.

/// <summary>/// Очистка хранилища/// </summary>/// <param name="sizeKb"></param>static void StorageClear(long sizeKb){    try    {        Log.Instance.Info($"clear = {sizeKb} Kb");        DirectoryInfo directory = new DirectoryInfo(_path);        FileInfo[] files = directory.GetFiles().OrderBy(f => f.CreationTime).ToArray();        foreach (FileInfo file in files)        {            var size = file.Length / 1024;            File.Delete(file.FullName);            sizeKb -= size;            if (sizeKb <= 0) break;        }    }    catch (Exception ex)    {        Log.Instance.Error(2, ex.Message);    }}

DoScreen (Создание скриншота)

Данный метод пытается создать скриншот в хранилище скриншотов. Формат создаемых файлов - PNG. В файл попадает весь экран основного монитора пользователя. Если создать файл не удалось, то отправка в класс Log сообщения об ошибке.

/// <summary>/// Создание скриншота/// </summary>static void DoScreen(){    try    {        Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);        Graphics graphics = Graphics.FromImage(printscreen as Image);        graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size);        printscreen.Save(Path.Combine(_path, GetFileName()), System.Drawing.Imaging.ImageFormat.Png);    }    catch (Exception ex)    {        Log.Instance.Error(1, ex.Message);    }}/// <summary>/// Имя файла создаваемого скриншота/// </summary>/// <returns></returns>static string GetFileName(){    var time = DateTime.Now;    return $"{time.ToString("yyyy_MM_dd__HH_mm_ss")}.png";}

Чтобы программы не было видно на панели задач необходимо окно программы спрятать. Вызов данного функционала происходит из метода Main.

#region DllImport[DllImport("kernel32.dll")]static extern IntPtr GetConsoleWindow();[DllImport("user32.dll")]static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);const int SW_HIDE = 0;const int SW_SHOW = 5;#endregion

Логирование действий программы состоит в виде статического класса Log сделанного согласно паттерну Singleton (одиночка).

public sealed class Log{    private static volatile Log _instance;    private static readonly object SyncRoot = new object();    private readonly object _logLocker = new object();    private Log()    {        CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;        LogDirectory = Path.Combine(CurrentDirectory, "log");    }    public string CurrentDirectory { get; set; }    public string LogDirectory { get; set; }    public static Log Instance    {        get        {            if (_instance == null)            {                lock (SyncRoot)                {                    if (_instance == null) _instance = new Log();                }            }            return _instance;        }    }    public void Error(int errorNumber, string errorText)    {        Add($"Ошибка {(errorNumber.ToString()).PadLeft(4, '0')}: {errorText}", "[ERROR]");    }    public void Info(string log)    {        Add(log, "[INFO]");    }    private void Add(string log, string logLevel)    {        lock (_logLocker)        {            try            {                if (!Directory.Exists(LogDirectory))                {                    // Создание директории log в случае отсутствия                    Directory.CreateDirectory(LogDirectory);                }                // Запись в лог файл вместе с датой и уровнем лога.                string newFileName = Path.Combine(LogDirectory, String.Format("{0}.txt", DateTime.Now.ToString("yyyyMMdd")));                File.AppendAllText(newFileName, $"{DateTime.Now} {logLevel} {log} \r\n", Encoding.UTF8);            }            catch { }        }    }}


Код программы здесь

Источник: habr.com
К списку статей
Опубликовано: 18.02.2021 00:06:58
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Информационная безопасность

Программирование

Net

C

Разработка под windows

Слежка за пользователями

Скриншот

Скриншотер

Разработка приложений

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru