银狐远程桌面优化思路分享(一)——借鉴VNC的远程屏幕实现

admin 2026-04-10 03:06:57 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文分析RealVNC4.1.3远程桌面实现,详细解析屏幕像素抓取(三种更新模式)、数据压缩编码(Raw/RRE/Hextile/ZRLE四种编码器)和客户端渲染流程。核心发现是ZRLE编码在低带宽下压缩率可达20-50倍,文章为优化银狐远程桌面的传输效率提供了具体代码级参考方案。 综合评分: 82 文章分类: 安全工具,解决方案,技术标准,应用安全,其他


cover_image

银狐远程桌面优化思路分享(一)——借鉴VNC的远程屏幕实现

原创

安全研究员 安全研究员

CppGuide

2026年4月7日 10:40 浙江

前言

这几年来,我一直在研究远程桌面技术,市面上便宜好用的远程桌面软件并不多,因此我一直想做一套比较好的远程桌面系统。远程桌面的核心是抓屏、传输和渲染。

我为此储备了一些基于WebRTC的技术,由于这个目前还在学习中,思路不成熟,暂时不提。

另外一种就是基于传统的GDI抓屏,为此我很早就研究了VNC的源码(包括RealVNC和tigerVNC等源码),并且由于这款软件的代码的实用性比较大,我在《C/C++编程实战训练营》中也给小伙伴们拆解了这套源码,由于大多数同学的目的对Windows图形方面的内容不是特别关注,因此在训练营拆解这些源码时,这块的内容讲的比较简略。所以这篇文章也可以看作是对VNC源码中桌面渲染实现的补充。

银狐的一共提供了4个远程桌面功能,其中差异屏幕高速屏幕后台屏幕,前三种屏幕都是正常的屏幕截图技术,只不过在屏幕数据传输大小和渲染效率上做了不同的取舍,而后台屏幕不是正常的屏幕,它是一个限制了很多正常界面操作的不可见桌面。

老实说,银狐前三类屏幕的实现上效率一般,导致其远程屏幕的效果也不是非常好。这里也可以借鉴VNC源码中的远程桌面效果来优化。但是,如果你去读VNC的源码,你会发现它的代码风格比较晦涩难懂。因此,这篇文章作为VNC源码的一个导读篇,希望对有需要的同学提供一些参考。

以下是 RealVNC 4.1.3 远程桌面画面实现的详细分析:

以下是 RealVNC 4.1.3 远程桌面画面实现的详细分析:


一、屏幕像素抓取(服务端)

核心文件结构

| 文件 | 作用 | | — | — | | win/rfb_win32/SDisplay.cxx | 主显示抽象层,支持3种更新模式 | | win/rfb_win32/DeviceFrameBuffer.cxx | Win32 实际抓屏实现 | | win/rfb_win32/SDisplayCorePolling.cxx | 轮询式变化检测 | | common/rfb/SDesktop.h | 平台无关桌面接口 |

三种屏幕更新模式(SDisplay.cxx 第45-46行)

模式 0 – 轮询(Polling)SDisplayCorePolling.cxx

  • 将屏幕划分为 16 个水平条带(第29行 POLLING_SEGMENTS
  • 定时器每 50ms 触发一次,逐条带扫描(第39, 60-81行)
  • 比较新旧像素数据,检测变化区域

模式 1 – 应用钩子(默认)

  • 通过 WMHooks 拦截窗口消息,即时通知变化

模式 2 – 驱动钩子

  • 通过 DirectX/视频驱动获取变化通知

像素抓取实现(DeviceFrameBuffer.cxx 第107-120行)

BitBlt(memDC, ...)  ← Win32 GDI 抓屏
     ↓
PixelBuffer        ← 像素缓冲区存储
     ↓
ComparingUpdateTracker  ← 差异对比,生成变化矩形列表 (Region)

三种屏幕更新模式的详细细节后续文章会继续分析。

二、数据量压缩(编码层)

编码器工厂(common/rfb/Encoder.cxx 第67-75行)

支持的编码类型按压缩效率排列:

1. Raw 编码(common/rfb/RawEncoder.cxx

  • RawEncoder::writeRect() 第39行
  • 直接写入原始像素字节,无压缩,作为兜底编码

2. RRE 编码(common/rfb/RREEncoder.cxx + rreEncode.h

  • 第47行:将矩形像素读入缓冲区
  • 第58行:统计最高频颜色作为背景色
  • 第60-79行:将不同颜色区域编码为”背景色 + 子矩形列表”
  • 若编码后大于原始大小则回退到 Raw(第65-66行)

3. Hextile 编码(common/rfb/HextileEncoder.cxx + hextileEncode.h

  • 将矩形切分成 16×16 的小瓦片(tile)

  • 对每个 tile 分析颜色特征:

  • 单色 tile → 仅存储背景色标志

  • 多色 tile → 背景色 + 带颜色的子矩形列表

  • 标志位:hextileBgSpecified / hextileFgSpecified / hextileAnySubrects(第75-88行)

4. ZRLE 编码(common/rfb/ZRLEEncoder.cxx + zrleEncode.h

  • ZRLEEncoder.h 第48行:内含 ZlibOutStream 成员

  • 切分成 64×64 的瓦片,对每个 tile:

  • 建立调色板(最多128色)(第72-77行)

  • 对调色板索引做 游程编码(RLE)

  • 最终再经过 Zlib 压缩

  • 压缩率最高(20-50x),适合低带宽

数据流

PixelBuffer(屏幕截图)
  → ImageGetter::getImage()       [提取像素,格式转换]
  → Encoder::writeRect()          [选择编码方式]
  → SMsgWriter::writeRect()       [写入 RFB 协议头]
  → OutStream::writeBytes()       [网络发送]

三、客户端屏幕渲染

解码层(common/rfb/

| 文件 | 作用 | | — | — | | CMsgReader.h 第36-73行 | RFB 消息读取器 | | CMsgHandler.h 第34-68行 | 回调接口定义 | | Decoder.cxx 第60-68行 | 解码器工厂 |

各编码解码过程

RawDecoder (RawDecoder.cxx 第38-55行)

  • 第45行:分配图像缓冲区
  • 第50行:从网络流读取原始字节
  • 第51行:调用 handler->imageRect() 渲染

RREDecoder (rreDecode.h 第41-59行)

  • 第47行:读取子矩形数量(U32)
  • 第48行:读取背景色
  • 第52-57行:循环读取每个子矩形的颜色、坐标(U16)、尺寸(U16),调用 FILL_RECT() 填充

HextileDecoder (hextileDecode.h 第43行起)

  • 第53行:分配 16×16 像素缓冲区
  • 第61行:读取 tile 类型标志位
  • 第69-70行:按需读取背景/前景色
  • 第84-100行:解码子矩形(坐标/尺寸各4 bit 压缩存储)

ZRLEDecoder (ZRLEDecoder.cxx 第56-95行 + zrleDecode.h)

  • 第58-59行:创建 ZlibInStream 解压
  • 第70行:读取模式字节(bit7=RLE标志,bit0-6=调色板大小)
  • 逐 tile 解码后调用 IMAGE_RECT() 或 FILL_RECT() 渲染

Windows 客户端渲染(win/vncviewer/

DesktopWindow.cxx 核心渲染方法(第98-102行):

  • fillRect() — 填充纯色矩形
  • imageRect() — 渲染像素缓冲到屏幕
  • copyRect() — 服务端矩形复制优化(无需传像素数据,直接让客户端拷贝已有区域)
  • invertRect() — 鼠标光标渲染

底层使用 Win32 DIB(设备无关位图,DIBSectionBuffer.h)+ BitBlt/StretchBlt 最终呈现。

完整渲染流水线

网络流 (InStream)
  → CMsgReader::readMsg()        [解析 RFB 协议头]
  → Decoder::readRect()          [按编码类型解压/解码]
  → CMsgHandler 回调:
       handler->fillRect(rect, color)
       handler->imageRect(rect, pixels)
  → DesktopWindow 方法           [写入 DIB 位图缓冲]
  → Win32 BitBlt                 [呈现到屏幕]

压缩效率对比

| 编码 | 适用场景 | 压缩倍率 | 速度 | | — | — | — | — | | Raw | 兜底/测试 | 1x | 最快 | | RRE | 纯色UI元素 | 1-10x | 快 | | Hextile | 混合UI/图形 | 5-20x | 中 | | ZRLE | 复杂图形/低带宽 | 20-50x | 慢 |

所有编码均通过宏模板支持 8/16/32 bpp 三种像素深度(在各 *Encode.h/*Decode.h 中通过 #define BPP 多次 include 实现)。

推荐阅读

银狐远控问题排查与修复——Viusal Studio集成Google Address Sanitizer排查内存问题

银狐远控代码中差异屏幕bug修复

银狐远程屏幕内存优化方法探究

银狐远程软件bug修复记录 第03篇

银狐远程软件 UDP 断线无法重连的bug排查和修复

银狐远程软件代理映射功能优化思路分享

银狐远程软件去后门方法

银狐远控一键编译调试与开发教程

银狐远控免杀与shellcode修复思路分析 01

银狐ShellCode混淆怪招

详解银狐远控源码中那些C++编码问题

给银狐远控增加一个小功能01

银狐远控的被控端是如何隐藏和保护自己的


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:CppGuide 安全研究员 安全研究员《银狐远程桌面优化思路分享(一)——借鉴VNC的远程屏幕实现》

评论:0   参与:  0