RFB協議解析

簡介

VNC(Virtual Network Computing)是基於RFB(Remote Frame Buffer)協議進行通信的,是一個基於平臺無關的簡單顯示協議的超級瘦客戶系統,

由Cambridge的AT&T實驗室設計開發的。

vnc的缺省端口是main:5900(C/S)和http:5800(B/S)端口。

RFB (遠程幀緩存) 是一個遠程圖形用戶的簡單協議,因爲它工作在幀緩存級別上,所以它可以應用於所有的窗口系統,例如:X11,Windows和Mac系統。

遠程終端用戶使用機器(比如顯示器、鍵盤、鼠標)的叫做RFB客戶端,提供幀緩存變化的被稱爲RFB服務器。

RFB是基於tcp的一個應用層協議。

clip_image002

RFB 是真正意義上的“瘦客機”協議。RFB協議設計的重點在於減少對客戶端的硬件需求。這樣客戶端就可以運行在許多不同的硬件上,客戶機的任務實現上就會盡量的簡單。

RFB協議對於客戶端是無狀態的。也就是說:如果客戶端從服務器端斷開,那麼如果它重新連接相同的服務器,客戶端的狀態會被保存。甚至,一個不同的客戶端可以用來連接相同的RFB服務器。而在新的客戶端已經能夠獲得與前一個客戶端相同的用戶狀態。因此,用戶的應用接口變的非常便捷。

只要合適的網絡連接存在,那麼用戶就可以使用自己的應用程序,並且這些應用會一直保存,即使在不同的接入點也不會變化。這樣無論在哪,系統都會給用戶提供一個熟悉、獨特的計算環境。

顯示協議

顯示協議是建立在“把像素數據放在一個由x,y 定位的方框內”這單一圖形基礎之上的。

乍一看上去,把這麼多的用戶接口組件繪製出來是非常低效的方法。但是,允許不同的像素數據編碼方式,使得我們在處理不同的參數(如:網絡帶寬,客戶端的繪製速度,服務器處理速度)有了很大程度的靈活性。

通過矩形的序列來完成幀緩存的更新。一次更新代表着從一個可用幀緩存狀態轉換到另一個可用,因此有點和視頻的楨類似。儘管矩形的更新一般是分開的,但是並不是必須的。

顯示協議的更新部分是由客戶端通過命令驅動的。也就是說,更新只是在服務器端響應客戶端的請求時發生的。這樣就讓協議更新質量是可變的。客戶端/網絡越慢,更新速度也就越慢。對於一些應用來說,相同區域的更新是連續不斷的。如果用一個慢的客戶端,那麼幀緩存的緩存狀態是可以被忽略的。這樣也可以減少對客戶端網絡速度和繪製速度的要求。

輸入協議

輸入協議是基於標準工作站的鍵盤和鼠標等設備的連接協議。

輸入事件就是通過把客戶端的輸入發送到服務器端。

這些輸入事件也可以通過非標準的I /O 設備來綜合。

例如,手寫筆引擎可能產生一個鍵盤事件。

像素數據的表示

初始的交互涉及到RFB客戶端和服務器之間傳輸像素數據格式和編碼方式的協調。這種協調被設計的讓客戶端的工作儘量簡單。而設計的底線是:服務器必須按照客戶端的要求格式來提供像素數據。如果客戶端可以同樣的處理多種數據格式或編碼格式,那麼一般會選擇服務器端易於生成的格式。

像素格式涉及如何通過像素值來實現不同顏色的重現。最常用的一般像素格式是24 位或16 位的“真彩色”,它通過位來直接實現像素值到紅、綠、藍亮度的轉換。8 位“顏色映射”可以任意映射像素值到RGB亮度的轉換。

編碼指一個矩形的像素數據如何通過網線傳輸。每個像素數據的矩形都加上了一個頭,給定矩形在屏幕上的X、Y座標、矩形的寬和高,以及指定的編碼類型。而後數據本身就是採用這種特定的編碼方式。

數據本身遵循特定的編碼。目前的編碼方式主要有Raw、CopyRect、RRE、Hextile 和ZRLE.在實際應用中我們一般使用ZRLE、Hextile 和CopyRect,因爲它們提供了典型桌面的最好壓縮。其他可能的編碼方式還包括,用於靜態圖片的JPEG和用於動態圖像有效傳輸的MPEG。

協議可以通過增加新的編碼方式來進行擴展。

協議擴展

協議可以通過以下方式進行擴展:

新的編碼方式

一種新的協議可以通過與現存的客戶端和服務端進行相關兼容的添加。因爲現存的服務器將會忽略它們所不支持的新編碼方式。所以客戶端通過新的編碼方式進行請求也就不會有結果返回。

僞編碼方式

除了真正的編碼方式,客戶端也可以請求“僞編碼”通告服務器,它支持某一協議的擴展。服務器如果不支持這種擴展,那麼它將忽略。值得注意的是:客戶端必須先假設服務器端不支持這種擴展,直到它獲得服務器端支持的確認。

新的安全方式

添加一個新型的安全方式會帶來無限的靈活性,它通過修改協議的一些行爲,但是並沒有犧牲現存客戶端和服務器端的兼容性。客戶端和服務器端可以通過協議好的安全方式進行交流,當然並不一定與RFB協議類似。

無論如何你都不應使用不同的版本號。

RFB協議的版本是由RealVNC公司來制定的。如果你使用一個不同的協議版本可能與RFB/VNC不兼容,要保證協議的兼容性,請聯繫RealVNC公司。這樣會減少在編碼方式和安全類型上的衝突。

協議消息

RFB協議可以進行可靠的傳輸,如字節流或基於消息的。和大多數協議一樣,它也是通過TCP /IP協議簇連接。協議由三步完成連接。首先是握手報文,目的是對協議版本和加密方式進行協商。第二步是初始化報文,主要用於客戶和服務器的初始化消息。最後就是正常協議的交互,客戶端可以按需發送消息,然後可以獲得服務器的回覆。

所有的消息以消息類型開始,接下來是特定的消息數據。

協議消息描述的基本類型有:U8、U16、U32、S8、S16、S32。

U表示無符號整數,S表示有符號整數。

所有字節整數(除了像素值本身)遵從big endian順序。

big endian或者little endian跟cpu有關,從而影響整數在內存中的排列順序。big endian是高字節在前,little endian是低字節在前,網絡字節序一般是big-endian。

PIXEL代表一個像素值bytesPerPixel字節,8XbytesPerPixel = bits-per-pixel。

協議流程

clip_image004

消息說明

握手消息

1、vnc服務器發送所能夠支持的最高RFB協議版本號給客戶端,比如:“RFB 003.006/n”,即版本號爲3.6,版本號固定格式爲×××.×××,不足部分前面補零。

clip_image006

2、客戶端回覆將要使用的版本號,格式如上。客戶端的版本號必須小於或等於服務器版本號。這樣服務器可以實現向後兼容。

3、目前發佈的協議版本主要有3.3、3.7、3.8(3.5版本被報告存在問題),最高版本號爲4.0。

協商安全類型

(一)v3.7以上版本安全類型

服務器發送所支持的安全類型列表

如果客戶端能支持服務器的某一安全類型,那麼客戶端就會發送一個字節來確認連接clip_image008

的安全類型:

clip_image010

如果安全類型數是0,那麼連接失敗(例如服務器不支持客戶請求版本號),這樣就

會有字符串來描述失敗原因:

clip_image012

服務器在發送原因字串後,就會關閉連接。

(二)3.7以下版本(以vnc認證爲例)

1、服務器發送一個無符號的32位整數標識一個安全類型(與認證有關)。

clip_image014

安全類型:

clip_image016

其他認證類型:

clip_image018

說明:

①0,連接失敗(例如服務器不支持客戶請求版本號),這樣就會有字符串來描述失敗原因:

clip_image012[1]

服務器發送完reason-string就關閉連接。

②NONE,不需要認證(不要輸密碼),協議數據將被使用明文發送。

V3.8 以上版本, 還會帶有安全結果的消息。

V3.3 和 3.7 協議直接進入初始報文.

③VNC認證,協議數據將採用明文發送,服務器發送一個16 字節的隨機數。

clip_image020

客戶端使用DES對驗證進行加密,使用用戶密碼作爲密鑰,把16 字節的回覆返回到服務器。

clip_image022

隨之而來的就是安全結果消息。

2、服務器發送16位隨機數。

3、客戶端使用DES對驗證進行加密,使用用戶密碼作爲密鑰,把加密後的16字節返回給服務器。

4、服務器對安全認證進行確認,返回值爲無符號32位整數,如果爲0則表示成功,1表示失敗。如果不成功,服務器直接關閉連接。

clip_image024

V3.8 以上版本 如果不成功,就會有字符串來描述失敗原因,並關閉連接。clip_image026

對於V3.8以下,如果不成功,服務器直接關閉連接。

初始化消息

1、客戶端發送一個字節的初始化消息。

clip_image028

如果允許服務器其他客戶繼續連接,那麼共享標誌應該是非零(真)。否則,服務器將

斷開其他客戶的連接。

2、服務器發送初始化消息,主要告知客戶端服務器的幀緩存的高、寬、象素格式和桌面相關的名稱。

clip_image030

這個跟實現有關,有些實現是先發送24個字節,然後再發送桌面名字字符串。名稱字符串格式如:sh-yinghua -1 ( 192.168.70.69 )。

幀緩存寬度一般爲水平分辨率的大小,幀緩存高度一般是垂直分辨率的大小,比如1024×768等。

象素格式主要包括以下段:

clip_image032

服務器象素定義服務器本來的象素格式,這種象素格式會被一直使用,除非客戶端使

用設置象素格式消息來請求另一種象素格式。bits-per-pixel是表示每個像素值需要的位數。這個數字必須大於等於depth,而depth用來表示像素值中有用的位數。目前位每象素必須是8,16 或32——小於8 位象素不被支持。如果多字節象素被看做big-endian,那麼Big-endian 標誌非零。當然了,這對8 位每象素沒有任何意義。

如果真彩標誌非零,那麼最後6 項規定如何按照象素值來確定紅、綠、藍的亮度。紅的最

大值是紅色的最大值(=2 ^n - 1, n 表示用在紅色上的位數)。注意這個值一般在big endian

的順序中。紅色-替換表示要得到最低明顯bit 所需要的替換個數。綠色最大值、綠色-替換和藍色最大值、藍色-替換和紅色類似。要在0—紅色最大值之間找一個紅色值,按照以下步驟進行:

• 遵循big-endian 標誌進行象素值。(例如:如果big-endian 標誌爲0,主機的字節順序是big endian,然後交換)。

• 使用紅色—替換將右邊替換。

• 和紅色最大值進行邏輯與(按照主機字節順序)。

如果真彩標誌是零,那麼服務器使用的象素值不是直接由紅、綠、藍的亮度組成,但是

服務爲索引到顏色圖中去。顏色圖中的項目是由服務器使用“設置顏色面板條目” (FixColourMapEntries)消息進行設置的。

說明:位/象素一般爲顯示設置的顏色質量位數。

目前的任何服務器都還不能支持FixColourMapEntries消息,只有基於X的服務器才能支持顏色映射。實際上,爲了能夠完全支持顏色映射,客戶端大概需要能夠指定特殊的、服務器不會使用的像素值。這可能會加在未來的協議版本里。

客戶端到服務器的消息

所有客戶端到服務器的消息第一個字節都爲消息類型,數據類型U8。

客戶到服務器的消息在本文中有如下定義:

clip_image034

其餘的註冊消息類型有:

clip_image036

值得注意的是:如果要發送未在本文中定義的消息,那麼必須得到服務器端的消息確認。

設置象素格式消息

“幀緩存更新”消息中設置什麼格式的象素值如何設置。

如果客戶端沒有發送“設置象素格式”消息,那麼服務器發送的象素值將遵循在服務器初始化消息中所包括的象素格式。

如果真彩標誌是零,那麼意味着使用“顏色面板”,只要客戶端發送顏色面板空的消息,或者是面板項被服務器端重設,服務器可以使用設置顏色面板項目進行顏色面板的設置。

clip_image038

注:其中的象素格式如在上文中的描述。

設置編碼格式

設置編碼方式可以來確定服務器發送象素數據的類型。消息中編碼方式的順序是客戶端

按照優先級來排列(第一個擁有最高的優先級)。服務器可能選擇這種順序,也可能不選擇。

象素數據也可以使用“原始編碼”如果沒有具體說明。

除了基本的編碼方式,客戶端也可以請求“僞編碼”通告服務器它支持某一種擴展協議。如果服務器不支持這種擴展,它就會忽略這種僞編碼。注意:這意味着客戶端在得到服務器的確認之前都要假設服務器並不支持它的擴展。

clip_image040

接下來就是編碼數目個編碼類型的重複

clip_image042

由編碼類型決定編碼格式。

請求幀緩存更新

通知服務器,客戶對幀緩衝區中的某個區域感興趣,這個區域由x座標、y座標、寬度和高度幾個參數限定。

服務器通常對FramebufferUpdateRequest消息的響應,是發送一條FramebufferUpdate消息。

注意,可以發送一條FramebufferUpdate消息用來回復幾條FramebufferUpdateRequest消息。

服務器假定客戶保留了幀服務器中它感興趣的所有部分的副本。這意味着,服務器通常只需要向客戶發送增量部分的更新。

但是,如果由於某種原因,客戶丟失了它所需要的一個特定區域的內容,就發送一條FramebufferUpdateRequest消息,把消息中的incremental置爲0(false)。這要求服務器把指定區域的全部內容儘可能快地發送過來。這個區域的更新不會使用copy rectangle編碼方式。

如果客戶沒有丟失它感興趣區域的任何內容,就發送一條FramebufferUpdateRequest消息,把消息中的incremental設爲非零(true)。當幀緩衝區中的指定區域發生變化時,服務器會發送一條FramebufferUpdate消息。

注意,在FramebufferUpdateRequest和FramebufferUpdate之間可能會有一段不確定長的間隔。

對於速度快的客戶,它可能希望以固定頻率發送增量的FramebufferUpdateRequests消息,以避免佔用網絡資源。

clip_image044

增量標誌爲0時,表示必須發送完整內容過來。

按鍵事件

某一個鍵的按下與釋放。如果某一個鍵被按下,那麼按下標誌非零。釋放的時候變爲零。

在X Window 系統中鍵本身被賦值爲“keysym”。

clip_image046

對於大多數鍵來說,“keysym”與ASCII碼相對應,具體參考《The Xlib ReferenceManual》或者參考。在Linux上爲/usr/include/X11/keysymdef.h。

對於大多數普通鍵,“keysym”和ASCII碼的值是一致的(前面3個字節爲0,最後一個字節爲ASCII碼)。其他的命令鍵爲:

clip_image048

鼠標(指針)事件

檢測指針移動或者某一個鍵的按下或釋放。指針目前在(x座標、y 座標),鼠標按鈕的各鍵採用1到8位掩碼標識,0 表示鬆開,1 表示按下。

拿普通鼠標來說,全零表示鼠標移動,第1,2,3 分別對應左、中、右鍵。對於滑輪鼠標來說,滾輪向上對應第4位,滾輪向下對應第5位。

拖動操作是不斷的發送左鍵按下的消息,並變換鼠標的座標。

clip_image050

客戶端文本剪切

客戶端有新的ISO8859 - 1(Latin - 1) 文本在它的剪切緩存裏,行的末尾通過新行字符(值爲10)來表示。 需要無回車(值爲13)。目前還沒有找到傳輸非Latin - 1 字符集的方法。

clip_image052

服務器到客戶消息

服務器到客戶消息在本文中定義如下:

clip_image054

其餘註冊的消息類型:

clip_image056

注意在服務器發送消息之前必須確認客戶端支持相關擴展,通常在請求“僞編碼”的

時候使用。

幀緩存更新

幀緩存更新是由一系列像素數據矩形而組成,這些矩形會被客戶端送入它的幀緩存中。

它是對客戶端幀緩存更新請求的響應。而在請求和響應之間有可能存在不確定時期。

clip_image058

隨着像素數據矩形的個數,每個矩形包括以下內容:

clip_image060

後面就是特定編碼的數據。

設置顏色面板條目

當像素格式使用“顏色面板”時,消息告訴客戶端對應像素值如何映射爲RGB亮度。

clip_image062

下面就是重複具體的色彩

clip_image064

目前對顏色映射的支持還很少甚至沒有。這方面已經做了一些初步的工作,但是還沒有完成。

目前,只有基於X 的服務器能夠完全支持顏色映射。

響鈴

如果有響鈴事件,就在客戶端上響鈴。

clip_image066

服務器剪切文本

如果服務器的剪切板有新內容,服務器主動發送該消息給客戶端

clip_image068

編碼格式

本文的編碼類型

clip_image070

其他編碼類型

clip_image072

原始編碼( Raw 編碼)

即採用原始的像素數據,而不進行任何的加工處理。在這種情況下,對於一個寬度乘以高度(即面積)爲N的矩形,數據就由N個像素值組成,這些值表示按照掃描線順序從左到右排列的每個像素。很明顯,這種編碼方式是最簡單的,也是效率最低的。

RFB要求所有的客戶都必須能夠處理這種原始編碼的數據,並且在客戶沒有特別指定需要某種編碼方式的時候,RFB服務器就默認生成原始編碼。

clip_image074

複製矩形編碼( CopyRect編碼)

CopyRect 編碼方式對於客戶端在某些已經有了相同的象素數據的時候是非常簡單和有效的。這種編碼方式在網絡中表現爲x,y 座標。讓客戶端知道去拷貝那一個矩形的象素數據。它可以應用於很多種情況。最明顯的就是當用戶在屏幕上移動某一個窗口的時候,還有在窗口內容滾動的時候。在優化畫的時候不是很明顯,一個比較智能的服務器可能只會發送一次,因爲它知道在客戶端的幀緩存裏已經存在了。

複製矩形編碼並不是完全獨立地發送所有的數據矩形,而是對於像素值完全相同的一組矩形,只發送第一個矩形全部數據,隨後的矩形則只需要發送左上角X、Y座標。實際上,複製矩形編碼主要指的就是隨後的這一系列X、Y座標,而對於第一個矩形具體採用何種編碼類型並沒有限制,僅僅需要知道第一個矩形在幀緩衝區中的位置,以便於完成複製操作。因此,往往是把複製矩形編碼和其它針對某一個矩形的編碼類型結合使用。

接下來使用CopyRect 編碼方式發送相同的式樣。

clip_image076

二維行程編碼( rise-and-run-length,RRE)

RRE表示提升和運行長度,正如它名字暗示的那樣,它實質上表示二維向量的運行長度編碼。RRE把矩形編碼成可以被客戶機的圖形引擎翻譯的格式。RRE不適合複雜的桌面,但在一些情況下比較有用。

RRE的思想就是把像素矩形的數據分成一些子區域,和一些壓縮原始區域的單元。最近最佳的分區方式一般是比較容易計算的。

編碼是由像素值組成的,Vb(基本上是在矩形中最常用的像素值)和一個計數N,緊接着是N的子矩形列表,這些裏面由數組組成,(x,y)是對應子矩形的座標,表示子矩形上-左的座標值,(w,h) 則表示子矩形的寬高。客戶端可以通過繪製使用背景像素數據值,然後再根據子矩形來繪製原始矩形。

二維行程編碼本質上是對行程編碼的一個二維模擬,而其壓縮度可以保證與行程編碼相同甚至更好。而且更重要的是,採用RRE編碼的矩形被傳送到客戶端以後,可以立即有效地被最簡單的圖形引擎所還原。

在傳輸中,數據以下面的頭開始描述:

clip_image078

後面跟隨重複的子矩形結構:

clip_image080

CoRRE 編碼

CoRRE是RRE的變體,它把發送的最大矩形限制在255×255個像素以內,用一個字節就能表示子矩形的維度。如果服務器想要發送一個超出限制的矩形,則只要把它劃分成幾個更小的RFB矩形即可。“對於通常的桌面,這樣的方式具有比RRE更好的壓縮度”。

實際上,如果進一步限制矩形的大小,就能夠獲得最好的壓縮度。“矩形的最大值越小,決策的尺度就越好”。但是,如果把矩形的最大值限制得太小,就增加了矩形的數量,而由於每個RFB矩形都會有一定的開銷,結果反而會使壓縮度變差。所以應該選擇一個比較恰當的數字。在目前的實現中,採用的最大值爲48×48。

Hextile 編碼

Hextile 是RRE編碼的變種,矩形被分割成16×16 小片,允許每個小片的維數爲4位,

總共16 位。

把原始矩形劃分成小塊是預定義的,這意味着每個塊的位置與大小不需要明確地指定。

矩形被分割的小片從上開始,遵守自左到右,自頂向下的順序。小片的編碼內容按照預定的順序進行編碼。如果整個矩形的寬度不是16 的整數倍,那麼每行最後的小片也相應減少。高度也類似。

每個小片可以使用raw 編碼,也可以是RRE編碼的變種,用一個類型字節來進行說明即可。每個小片有一個背景像素值。但是,如果小片的背景像素值和前一個小片相同,那麼就不需要明確定義。如果小片的子矩形有相同的像素值,那麼前景像素值就可以只定義一次。和背景像素值一樣,前景像素值也可以通過前一個小片獲得。

因此由小片組成的數據是按照順序進行編碼的。每一個小片以子編碼類型的字節開始。它是位數的掩碼組成。

clip_image082

如果Raw 位被設置,那麼其餘的位就無效;接着是寬X高像素值(寬和高是小片的寬

高)。否則其他的位就有效。

背景定義-如果設置,那麼像素值就會跟着小片的背景色:

clip_image084

在矩形中的第一片非Raw 小片必須設置這一位,如果不設置,那麼它的背景就會和上

一片相同。

前景定義-如果設置,那麼像素值就會定義小片中所有子矩形的前景色。

clip_image086

如果這一位被設置,那麼子矩形着色位必須爲0。

任意子矩形-如果設置,那麼一個字節包含着子矩形的個數。

clip_image088

如果這一位不設置,那麼就不會有子矩形。(例如,整個小片就是背景顏色)

子矩形着色-如果設置,那麼任意子矩形的像素值的優先級都高於子矩形的顏色定義,

因此子矩形是:

clip_image090

如果不設置,所有子矩形都是前景色的顏色,如果前景定義沒有設置,那麼前景色和

前一個片的相同。子矩形就是:

clip_image092

每一個子矩形的位置和大小都是使用兩位進行定義,x - and - y - position 和width -

And - height。最重要的四位x - an d - y - posi tion 定義X的位置,不重要的定義Y位置。最

重要的四位width - and - height 定義寬度- 1,不重要的定義高度- 1。

ZRLE 編碼

ZRLE(Zlib Run - Length Encoding),它結合了zlib 壓縮,片技術、調色板和運行長度

編碼。在傳輸中,矩形以4 字節長度區域開始,緊接着是zlib 壓縮的數據,一個單一的

zlib“流”對象被用在RFB協議的連接上,因此ZRLE矩形必須嚴格的按照順序進行編碼和

譯碼。

clip_image094

zlibData 在沒有壓縮之前,代表了由64x64 像素組成的從左到右,從高到低的順序

的片,和hextile 編碼有點類似。如果整個矩形的寬度不是64 的整數倍,那麼每行最後的

小片也相應減少。高度也類似。

ZRLE編碼利用了一種新的壓縮像素CPIXEL(Compres se d PIXEL)。這個和PIXEL有着

相同的像素格式,除了真彩標誌是非零,位每像素是32,色深不大於24。所有的位組成紅,

綠和藍的亮度填充最不重要的或最重要的三字節。如果CPIXEL只有3 字節長,並且包含有

合適的最不重要或最重要3 字節。那麼bytesPerCPixel 就是CPIXEL的字節數。

每片都是以子編碼類型字節開始,如果片被使用運行長度編碼,那麼本字節的最高位

就會被設置。其餘7 位表示繪圖樣式-零表示沒有樣式,1 表示片爲單色,2 - 127 表示對應

的樣式。可能的子編碼值如下:

0 - Raw 像素數據 寬X高像素值(寬和高爲對應片的寬和高,對應像素值如下:

clip_image096

2 - 16 -打包的樣式類型。對應像素值是由palet teSize(=子編碼)像素值,打包像素值組

成,每個打包像素值表示爲一位區域服從樣式索引(0 表示第一個條目),對應

palet teSize 2,1 位被使用,palet teSize 3,4 有兩位被使用,從5 - 16 均有4 位區域被

使用。位的區域被打包成字節,最重要的位表示最左邊像素。因爲片並不是8,4,2 像素寬的

乘積,所以填充位被用來按照字節數排列每一個行。

clip_image098

m 表示打包像素的字節數。對於palet teSize 2 就是floor((width + 7) / 8) x height,

相應3,4 就是floor((width + 3) / 4) x height,而5 - 16 就是floor((width + 1) / 2)x

height。

17 - 127 未使用(對於palet te RLE並沒有什麼優勢)。

128 -簡單RLE 它由一些不斷重複的執行組成,一直到片結束。執行可能從一行的結束到另一行的開始。每一次運行是通過一個像素值和像素值長度來表示的。長度一般爲1 個或多個字節。經過計算多於所有字節總和+ 1 作爲長度。除了255 任何字節值都隱含最後的字節。例如長度1 表示爲[0],255 表示爲[254],256 表示爲[255,0],257 表示爲[255,1],510 表示爲[255,254],511 表示爲[255,255,0]等等。

clip_image100

129 -未使用

130 - 255 調色RLE。調色緊跟其後,由palet teSize = (subencoding - 128) 像素值組成:

clip_image102

接下來就合簡單RLE相似,一些不斷重複的執行組成,一直到片結束。執行長度通過

調色板索引來表示。

clip_image104

如果執行長度使用多於一位來表示調色板索引,並且最高位被設置。那麼就會帶有執行長度。

clip_image106

僞編碼
指針/鼠標僞編碼

如果客戶端請求指針/鼠標僞編碼,那麼就是說它有能力進行本地繪製鼠標。這樣就可以明顯改善傳輸性能。服務器通過發送帶有僞鼠標編碼的僞矩形來設置鼠標的形狀作爲更新的一部分。僞矩形的x 和y 表示鼠標的熱點,寬和高表示用像素來表示鼠標的寬和高。包含寬X高像素值的數據帶有位掩碼。位掩碼是由從左到右,從上到下的掃描線組成,而每一掃描線被填充爲floor((width +7) / 8)。對應每一字節最重要的位表示最左邊像素,對應1 位表示相應指針的像素是正確的。

clip_image108

桌面大小僞編碼

如果客戶端請求桌面大小僞編碼,那麼就是說它能處理幀緩存寬/高的改變。服務器通過發送帶有桌面大小僞編碼的僞矩形作爲上一個矩形來完成一次更新。僞矩形的x 和y 被忽略,而寬和高表示幀緩存新的寬和高。沒有其他的數據與僞矩形有關。

協議漏洞及解決方法

RealVNC VNC Server採用的RFB(遠程幀緩衝區)協議允許客戶端與服務端協商合適的認證方法,協議的實現上存在設計錯誤,遠程攻擊者可以繞過認證無需口令實現對服務器的訪問。

具體操作細節如下:

1) 服務端發送其版本“RFB 003.008/n”

2) 客戶端回覆其版本“RFB 003.008/n”

3) 服務端發送1個字節,等於所提供安全類型的數量

3a) 服務端發送字節數組說明所提供的安全類型

4) 客戶端回覆1個字節,從3a的數組中選擇安全類型

5) 如果需要的話執行握手,然後是服務端的“0000”

RealVNC 4.1.1或之前版本在實現RFB 003.008協議時沒有檢查判斷在上面第4步中客戶端所發送的字節是否爲服務器在3a步中所提供的,因此認證就從服務端轉移到了客戶端。攻擊者可以強制客戶端請求“Type 1 - None”爲安全類型,無需口令字段便可以訪問服務器。

危害:遠程攻擊者可以繞過認證無需口令實現對服務器的訪問。

解決方法:檢查客戶端請求的安全類型是否爲服務器支持的類型之一,否則斷開連接,或者禁止無認證的安全類型。


轉自:http://blog.csdn.net/forever_feng/article/details/4703088

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章