现在的位置: 首页 > 综合 > 正文

远控软件屏幕传输算法研究

2016年08月11日 ⁄ 综合 ⁄ 共 5057字 ⁄ 字号 评论关闭

发一下以前研究过的屏幕传输算法,垫垫底。

屏幕监控是远程控制中的一项主要功能,有了此功能能使操作远程电脑像操作本地电脑一样方便。
实现方法很多,原理就是不断地把远程电脑屏幕的图像发送到本地电脑,本地电脑把图像显示出来。
最早期的实现方法只是不断地传送bmp图像,这样做不仅传输延时很大,且cpu特别是服务端的cpu占用率很大。
为了解决以上两个问题,可以采用传输屏幕变化的部分,传输过程中压缩解压缩的方法。

传输屏幕变化的部分:应用得比较好的有3种方式,1.驱动级的Mirror Driver 、2.GDI+下的算法方式,3.RDP传输协议(远程桌面)

Mirror Driver
大名鼎鼎的VNC就是采用这种技术,屏幕传输像看电影一样非常流畅且cpu占用率为0%~1%。
传统截取屏幕采用api hook方式,调用bitblt截取的是ddb位图,要用getbits转换为dib格式的位图,不仅增加截屏的时间消耗,而且会截取未变化的区域,产生冗余数据。
而使用Mirror Driver的图形驱动技术 ,应用程序调用win32 gdi 函数进行图形输出请求,这个请求通过核心模式gdi发送。核心模式gdi把这些请求发送到相应的图形驱动程序。如,显示器驱动程序,通信流程图如下:
请输入图片描述
使用这种截屏技术较API Hook截屏方式的优越性在于:
1。驱动截屏技术是一种标准技术,为微软公司所推荐,而API Hook截屏是一种非标准的技术,不为微软公司所推荐。
2。API Hook技术在实际截屏时,采用API函数实现,截取DDB位图,必须经过一次DDB到DIB的转换;而驱动技术直接从其管理的DIB位图(表面)中将截取区域的图形数据拷贝到应用程序,显著的降低了一次截屏的时间消耗。
3。如果屏幕图形小区域范围变化较快,屏幕变化区域矩形坐标R1、R2、R3……、Rn相继到达,由于一次截屏时间消耗降低,区域矩形坐标叠加的概率变小,这样屏幕变化区域及时的得到了处理,不仅增加了连续性,而且产生的数据量很小。
所以无论是做远程桌面还是屏幕录制,基于MirrorDriver的屏幕截取将会是一个不错的选择,无论从性能,占用资源的大小来说都要优于API Hook的截屏方式。

Mirror  Dirver 技术涉及核心图形驱动的编写,实现上较为复杂,网络上也没有开源的driver ,但可以利用免费的driver,如Tight  VNC中提供的Mirage  Driver,UtralVNC中提供的Winvnc   video  hook  driver,下载安装程序安装即可。安装后可以在设备管理器中看到如下所示的图:

请输入图片描述

调用Mirror  Driver 的代码可以从VNC源代码中去挖掘,VNC中都封装好了与Mirror  Driver 的调用关系,我们只用关心VNC中封装的一个指向变化矩形的RECT结构和一个指向变化数据的指针。
在我们的屏幕传输模块中,服务端发送一个RECT结构,发送一个由数据指针指向的byte[]数组,客户端接收到数据,按RECT结构中的4个点把byte[]数组Paint到Picture控件中,然后再重复上面的操作,即可发送屏幕的变化部分。
虽然使用Mirror  Driver 技术cpu占用率小、网络传输数据量小,但是需要安装驱动程序,每次截屏的时候屏幕会出现明显的刷新,且有时处理不当会出现BSOD(Blue  Screen Of  Death)。对于一个具有高隐蔽性的木马来说Mirror  Driver技术来做屏幕传输是不适合的。

**GDI下 的算法方式**:
算法是程序的灵魂,在这里可以看到算法在优化屏幕传输上所起的作用。应用得比较好的算法分为分块异或屏传,固定块隔行扫描,动态分块隔行扫描。

分块异或屏传
原理:前后保存两次bmp位图,把屏幕分成若干块(局域网一般为4~6块,广域网一般为8~32块)并编号,前后两副位图分别按对应编号块逐个像素点做异或(XOR)操作,若异或后的结果全是零,证明两个被分块的位图相等,不为零则两个被分块的位图不相等,不相等则把异或的结果进行压缩,并发送。
每个块处理完后,则把后一副图像记为前一副图像,再保存一副bmp位图作为后一副图像,再执行前面的分块异或发送操作。
请输入图片描述
注意这里为什么要每个像素点做异或操作,再压缩发送,而不是每块图像做CRC32,不相同则直接发送图像呢?
因为屏幕上的变化在很短的时间内,往往都是小范围的变化,这就意味着有很多相同的像素点,那么两块图像异或的结果就会有很多的零。
这么多的零经过压缩算法压缩,数据量会减少很多。比如 经过压缩后,10000001 可以表示为10*61的形式,当然压缩算法不只是压缩连续的0或1。
经过以上算法优化传输屏幕变化,实际的网络传输量会变得很小,屏幕传输流畅,著名的灰鸽子屏幕传输就采用此算法。

固定块隔行扫描,动态分块隔行扫描
Radmin影子远程控制系统相信很多人都知道,用到4899端口,早期系统管理员用来管理远程的计算机。速度很快,特别是屏幕传输,可以和3389远程桌面媲美。
Radmin是俄罗斯人编写的收费软件,没有开源的代码,隔行扫描算法最初是受到其反汇编代码启发得来的。
原理:前后保存两次bmp位图,把屏幕分成若干块并编号,前后两副位图分别按对应编号块对比,对比的方法是,隔若干行(一般是10行)对比前后两幅图像的一行中的像素点是否相同,若不同则压缩发送当前块中的图像。
因为是隔若干行对比一行,所以叫隔行扫描。只用扫描少数的行,就可以判断屏幕变化的部分,速度是很快的。
接着,有人提出这样每次只能扫描那些固定的行,所以每次重新扫描时会对上次扫描的行编号+n行,这样就避免了总是扫描相同的行,称为“百叶窗”技术。
随后算法经过优化,出现了“动态分块隔行扫描”算法,应用此算法,速度更快。
原理:在固定块隔行扫描的基础上,改“把屏幕分成若干块”为“由屏幕的变化区域动态确定要发送的矩形”。当扫描到有不相同的行时,由一个恒定的值确定变化矩形的宽,然后在这个宽度范围内向左和向右对比像素点,确定变化矩形的长,再把矩形的坐标点和矩形的图像(byte[]数组)保存到发送队列,接着由之前 扫描行的编号+矩形的宽度所得的行编号开始扫描,重复上面的操作,扫描到屏幕的最后一行为止,最后服务端传输发送队列的数据到客户端。客户端按矩形的坐标和数据,把矩形paint到picture控件上。
动态分块隔行扫描示意图:
请输入图片描述
近期,在动态隔行扫描算法的基础上,又发展起来“热点追踪”的思想,即跟踪鼠标的操作,因为这是最容易引起变化的地方,因为鼠标的移动,鼠标的点击,屏幕都会变化。

在我开发的程序中,使用了“动态分块隔行扫描+热点追踪”的算法,速度流畅,cpu占用率小。

远程传输屏幕图象,有人知道比 hook ,还快的吗?

 (2) API Hook技术在实际截屏时,采用API函数实现,截取DDB位图,必须经过一次DDB到DIB的转换;而驱动技术直接从其管理的DIB位图(表面)中将截取区域的图形数据拷贝到应用程序,显著的降低了一次截屏的时间消耗
  计算机屏幕图像的截取在屏幕的录制、计算机远程控制以及多媒体教学软件中都是关键术,基于Windows操作系统有多种截屏方法,研究的重点集中在如何快速有效的截取DBI(Device-Independent Bitmap)格式的屏幕图形数据现在商业软件流行的截屏技术主要采取的Api Hook技术,但这种技术一次截屏仍有较大的时间消耗,这样就对运行软件的硬件仍有较多的限制,而且是一种非标准的技术,不为微软公司所推荐 
  1截屏技术 
  1.1使用api hook技术 
  使用api hook技术截屏基于一下的原理;多数屏幕图形的绘制都是通过调用用户态gdi32.dll中的绘图函数实现的,如果利用api hook技术拦截系统中所有对这些函数的调用,就可以得到屏幕图形刷新或变化的区域坐标;然后使用api函数bitblt将刷新或者变化后的屏幕区域的ddb格式的位图拷贝到内存中,接着使用函数getbits将ddb位图转换为dbi位图,最后压缩、存储或者传输 
  这种方案只有捕捉到变化,才进行截屏这样每次截屏都是有效的操作每次(第一次除外)仅截取了栓新或变化部分,从根本上解决了数据量大的问题但是这种技术仍然有一下缺点:1实际截屏采用的api函数,截取的是ddb位图,要经过一次格式转换,耗时较大2如果屏幕变化区域矩形的坐标r1、r2、……rn相继到达,为了不是屏幕变化的信息丢失,通常不是逐个截取,而是将矩形坐标合并,这样就可以截取并未变化的区域,不经增加截屏的时间消耗,而且产生冗余数据3该技术不支持directdraw技术,由于应用程序可能使用directdraw驱动程序进行直接操纵显示内存、硬件位块转移,硬件重叠和交换表面等图形操作,而不必进行gdi调用,所以此时api
hook技术将失去效用,不能捕捉屏幕变化4api hook技术在屏幕取词,远程控制和多媒体教学中都有实际的应用,但是这种技术是一种非标准的技术,微软公司并不推荐使用 
  1.2 使用图形驱动技术 
  该技术的原理:应用程序调用win32 gdi 函数进行图形输出请求,这个请求通过核心模式gdi发送核心模式gdi把这些请求发送到相应的图形驱动程序如,显示器驱动程序,通信流如图现将该技术详细解释如下: 
   
  http://www.cnblogs.com/images/cnblogs_com/niukun/a .JPG(图片地址) 
  (1)显示器驱动输出一系列设备驱动程序接口DDI(Device Driver Interface)函数供GDI调用信息通过这些入口点的输入/输出参数在GDI和驱动程序之间传递 
  (2) 在显示器驱动加载时,GDI调用显示器驱动程序函数DrvEnableDriver,在这里我们向GDI提供显示器驱动支持的,可供GDI调用的DDI函数入口点,其中部分时将要Hook的图形输出函数 
  (3) 在GDI调用函数DrvEnableDriver成功返回后,GDI调用显示器驱动的DrvEnablePDEV函数,在这里可以设置显示器的显示模式,然后创建一个PDEV结构,PDEV结构是物理显示器的逻辑表示 
  (4) 在成功创建PDEV结构之后,显示驱动为视频硬件创建一个表面,该表面可以是标准的DIB位图管理表面,然后驱动程序使该表面与一个PDEV结构相关联,这样显示驱动支持的所有绘画操作都将在该DIB位图表面上进行 
  (5) 当应用程序调用用户态GDI32.DLL中的绘图函数发出图形请求时,该请求将图形引擎通过相应的DDI函数发送到显示驱动,显示驱动程序将这次图形变化事件通知应用程序 
  (6) 应用程序接受到通知后,调用函数ExtEscape发出一个请求,并通过参数传递一个缓冲区Buffer,图形引擎调用DDI函数DrvEscape处理应用层的ExtEscape调用,将变化部分的图形数据从其创建的表面拷贝Buffer,这样数据就从核心层图形驱动传到应用层 
  (7) 应用程序接收到的图形数据已是DIB标准格式,所以可以直接进行压缩传输或储存 
  1.3图形驱动技术的特点 
  上面叙述了采用图形驱动实现屏幕实现截屏的原理和过程,可以看出这种技术涉及核心图形驱动的编写,实现上较为复杂,而其具备的优点主要为: 
  (1) 驱动技术只截取变化的屏幕区域,这一点与API Hook技术相当;但驱动技术是一种标注技术,为微软公司所推荐 
  (3) 如果屏幕图形小区域范围变化较快,屏幕变化区域矩形坐标R1、R2、R3……、Rn相继到达,由于一次截屏时间消耗降低,区域矩形坐标叠加的概率变小,这样屏幕变化区域及时的得到了处理,不仅增加了连续性,而且截屏时间消耗和产生的数据量一般不会出现峰值,这也是这种技术的优越之处 
  经过以上对比,无论是做远程桌面还是屏幕录制,基于MirrorDriver的屏幕截取将会是一个不错的选择,无论从性能占用资源的大小(主要是cpu),取得的数据量来说都要优于Hook 
  最近在做远程桌面的传输,所以有必要研究一下Mirror,这项技术在很多软件中都有应用但是开源的driver我还没有看见过,因为没有精力去编写所以才用网上的免费的driver同时也提供了api文档 
  driver内部实现的原理大致就是把显示输出拷贝到一个缓冲区当中,并且记录每次屏幕更新的矩形区域根据这些输出,应用程序就很容易得到缓冲区中的数据了

抱歉!评论已关闭.