关于RDP协议的分析(一)
关于RDP协议的分析和研究
-------------- leadgenius
写这个一是便于学习,再就是与网友们共同讨论,有一些我也不确定的,只是我的理解,希望看到这篇文章的人进行指正,并给我来信谢谢。再一就是这里只有有关4.0版本的内容,希望有高手补充5.1/5.2的协议文档。
RDP是微软终端服务应用的协议,服务端基于win2000/winNT。协议基于T.128(T.120协议族)提供多通道通信。在客户端支持多种资源缓冲和图片数据的压缩处理。
本文的内容主要是对Rdesktop源代码的分析,应用rdp4.0协议,可与win2000/winNT通信,也可与win2003(rdp5.1)通信,但不具备rdp5.1协议的特性。
协议通过TCP/IP进行数据传输,在实际数据前进行了ISO/MCS/SEC三层的包装,ISO/MCS两层为多点并发式通信提供了可靠的传输保障,SEC层提供对RDP详细数据的加解密处理。各层在数据的前端加有一段数据头,用于对数据、传输的控制。具体的数据控制由STREAM类型的结构体管理(这种方法很灵活、易懂,可作为网络编程者的参考),不同的数据头由不同的结构成员管理,层次清晰。
RDP协议将终端虚拟环境中的设备映射为不同的数据包,将对设备的输入输出(I/O)重定向到网络句柄中,不同设备的数据按不同格式组织成为小的数据包,并将多个小数据包封装成为一个大的数据包通过网络一次性发出,对方将网络解收的数据进行分解成为小包并按设备数据的类型进行不同的处理。
另一个值得注意的是使用了T.128协议族的ASN.1 BER(基本编码规则)。我记得网上有一篇文章提到中国的程序员很多,可是会网络编程的不多,懂得基本编码规则的就少之又少。其实基本编码规则很简单,可以到网上查询一些有关T.128&T.129的文章来看一下,很有用的。有时间我会协议篇关于此的贴子。
如果有想学网络编程的朋友,可以看一下RDESKTOP这个软件的代码,能学到不少的东西。
一、 网络包控制结构(STREAM定义于 prase.h :2 typedef struct stream *)
结构用于对收到的TCP包的数据进行初期分解,按照不同的协议逐步将包中的RDP数据分离出来,为RDP数据的进一步分解做准备。
typedef struct stream
{
unsigned char *p;
unsigned char *end;
unsigned char *data;
unsigned int size;
/* Offsets of various headers */
unsigned char *iso_hdr;
unsigned char *mcs_hdr;
unsigned char *sec_hdr;
unsigned char *rdp_hdr;
} *STREAM;
结构包含:
p指针:临时指针变量,用于计算定位。
data指针:TCP/IP数据的起始位置,是申请的一段内存,只当数据尺寸大于size时,进行realloc增大,不缩小。
size指针:TCP/IP数据的尺寸大小
end指针:TCP/IP数据的结束位置
//以上是tcp数据管理变量
iso_hdr指针:TCP/IP数据包中iso协议控制头的位置
mcs_hdr指针:TCP/IP数据包中mcs协议控制头的位置
sec_hdr指针:TCP/IP数据包中sec协议控制头的位置
rdp_hdr指针:TCP/IP数据包中rdp协议控制头的位置
主要结构只创建一遍(in & out),结构数据及缓冲由tcp.c模块维护。
ISO控制头:7字节
MCS控制头:8字节
SEC控制头:0(如果已经获得许可证—通信协定)、4(未获许可)
或12(进行加密时)字节
由SEC头控制的数据段即是RDP的主要数据,一般进行了加密。
二、 TCP
负责维护与服务器的连接和数据。
一下STREAM结构的成员负责维护TCP数据:
p指针:临时指针变量,用于计算定位。
data指针:TCP/IP数据的起始位置,是申请的一段内存,只当数据尺寸大于size时,进行realloc增大,不缩小。
size指针:TCP/IP数据的尺寸大小
end指针:TCP/IP数据的结束位置
p指针的作用:
在控制结构中,对于确定的发送数据和接收数据,其他各指针的含义和内容相对固定,而对于包中要计算、改动和提交到下一层处理的具体数据的定位工作就要靠p指针来完成。
在prase.h中定义了大量的关于使用p指针的运算用于对协议头段的处理,并且在各层协议处理模块中使用p指针定位、区分处理过和未处理的数据。
Tcp_init():初始out结构的数据缓冲和data、size、end、p变量
Tcp_connect():建立网络连接并创建输入和输出数据控制结构(in & out)、网络句柄sock
Tcp_disconnect():关闭网络句柄sock
Tcp_send():发送TCP数据(out控制)到sock
Tcp_recv():接受定长TCP数据由sock到in,维护in结构缓冲,并调整in.tcp管理变量
三、 ISO
TCP传输之上,基于ISO头的定义,我在这里将简单的数据传输协定分为控制和数据两种,由PDU头段数据区分,主要是Type2。
Type1:控制PDU,长11字节,用于连接控制
1字节:协议版本号 = 3
2字节:保留
3-4字节:包长度(由第一字节到包结束)
5字节:数据偏移 = 6(ISO头段结束的下一位距本字节的偏移量)
6字节:包类型 = ISO_PDU_CR = 0xE0(连接请求)
ISO_PDU_CC = 0xD0(连接建立)
ISO_PDU_DR = 0x80(中断请求)
ISO_PDU_ER = 0x70(错误)
7-8字节:dst_ref = 0(忽略)
9-10字节:src_ref = 0(忽略)
11字节:class = 0(忽略)
Type2:数据PDU,长度 = 数据长度 + 7字节,用于数据传输
1字节:协议版本号 = 3
2字节:保留
3-4字节:包长度(由第一字节到包结束)
5字节:数据偏移 =2(ISO头段结束的下一位距本字节的偏移量)
6字节:包类型 = ISO_PDU_DT = 0xF0(数据传送)
7字节:eot = 0x80
ISO数据开始
Iso_init():初始out控制结构,预留ISO头段空间,并将iso_hdr指向头段位置
Iso_send_msg():发送一个单一的控制消息数据包
Iso_recv_msg():接收数据的头段,分析包类型调整in结构指向数据位置,并传回包类型
Iso_send():填充ISO头段,并发送数据
Iso_recv():接收ISO数据包,去处头段,调整in结构指向数据位置
Iso_connect():建立ISO连接
Iso_disconnect():中断ISO连接