MSNP15(MSN8.1)协议分析
MSN是微软推出的一款聊天工具,它的通信协议是微软自己提出的MSNP(即MSN Protocol)。MSNP目前还不是因特网标准协议,但却发展迅速,被广泛地应用到各种聊天工具的开发中。MSNP更新很快,当前的最新版本为MSNP15(即版本15)。MSN8.1所使用的协议就是MSNP15。
MSNP15支持即时消息、文件传输、语音通信、视频通信和远程协助等通信方式。其中文件传输、语音通信和视频通信等是直接的点对点通信,而即时消息等是经过服务器中转通信的。即时消息和文件传输是基于TCP的,而语音通信和视频通信是基于UDP的。
MSNP15的通信很多是通过服务器中转的,所以它的服务器架构比较复杂。协议的客户端与服务端的交互有两种形式:命令和消息。当客户端发送的命令执行出错时,服务器用错误代码来通知对方。因此,下面将依次讲述服务器、命令、消息和错误。这是协议分析的基础。
MSNP15的服务器有三种。
派遣服务器(Dispatch Server, DS)——客户端最先连接的服务器。派遣服务器与客户端连接后,首先根据从客户端处得出的的信息,给客户端分配合适的通知服务器,然后断开与客户端的连接。派遣服务器的端口号是1863。
通知服务器(Notification Server, NS)——客户端需要一直连接的服务器。通知服务器负责大部分非中转的交互,包括登陆,改变状态(隐身、在线等),获取用户列表,修改用户列表,发起聊天等。通知服务器的服务端口号由派遣服务器指定,一般为1863。
接线服务器(Switchboar Server, SB)——客户端间通信所使用的中转服务器。每开一个聊天窗口,客户端就与服务器建立一个TCP会话。文件传输和语音聊天等,为发起点对点的会话,也需要从接线服务器上得到对方的IP地址等信息。接线服务器的服务端口由通知服务器指定,一般为1863。
命令是服务器与客户交互的一种方式。MSNP15的命令使用纯ASCII码,对非ASCII码使用URL编码。命令的一般格式是:
XXX[<SP>TrID<SP>PARAM1<SP>PARAM2…]<CRLF>
其中,<SP>是空白字符,<CRLF>是回车换行,XXX是一个3字符的命令串,TrID是一个流水号,PARAMx是参数,[ ]内是可选项。最简单的命令没有流水号和参数。为了方便起见,下面讨论时用" "代表<SP>,"/r/n"代表<CRLF>,"/x??"代表一个值为0x??字节。红色表示由客户端发出,蓝色表示由服务器发出。一个比较常见的命令如下。“USR 14 OK [email protected] 1 0 ” 就是一个比较常见的命令。
MSN Messenger消息符合MIME 1.0标准,由消息头与消息体组成,通常使用UTF-8编码。一个MSN Messenger消息的例子如下:
MIME-Version: 1.0/r/nContent-Type: text/plain; charset=UTF-8/r/nX-MMS-IM-Format: FN=%E5%AE%8B%E4%BD%93; EF=; CO=0; CS=86; PF=0/r/n/r/nbhw98/xE4/xBD/xA0/xE5/xA5/xBD/xEF/xBC/x81
经简单分析可知,"%E5%AE%8B%E4%BD%93"是"宋体"的UTF-8加URL编码,而"bhw98/xE4/xBD/xA0/xE5/xA5/xBD/xEF/xBC/x81"是"bhw98你好!"的UTF-8编码。
无论是由于客户端发出的命令无效,参数无效,还是其他什么原因,服务器可以返回一个错误。错误的格式为
XXX[<SP>TrID]<CRLF>
其中,XXX是一个3位数字的串。如“ADD 21 AL [email protected] [email protected]/r/n205 21/r/n”。其中,[email protected]是一个不存在的账号。
为了理解后文中给出的例子,这里给出一些常用命令,如表 1 常用命令所示。需要注意的是,表 1 常用命令中的命令是针对MSNP10的,所以这些命令仅供参考。
命令 |
来源 |
去向 |
说明 |
备注 |
ACK |
SS |
Client |
确认,做出肯定回答。 |
acknowledgement |
ADD |
Client |
NS |
发出添加新联系人到列表的请求。 |
add user |
NS |
Client |
返回添加新联系人请求的应答。 |
||
ADG |
Client |
NS |
发出添加新联系人组请求。 |
add group |
NS |
Client |
返回添加新联系人组请求的应答。 |
||
ANS |
Client |
SS |
接受聊天连接请求。 |
answer |
BLP |
Client |
NS |
设置对尚未列入明确允许/禁止的联系人列表的保密策略。 |
block list privacy |
NS |
Client |
返回设置保密策略请求的应答。 |
||
BYE |
SS |
Client |
通知客户端结束会话。 |
bye |
CAL |
Client |
SS |
发出建立聊天连接的请求。 |
call |
SS |
Client |
返回建立聊天连接请求的应答。 |
||
CHG |
Client |
NS |
发出改变状态的请求。 |
change state |
NS |
Client |
返回改变状态的应答。 |
||
CHL |
NS |
Client |
服务器发出验证要求。 |
challenge |
SS |
Client |
|||
CVR |
Client |
NS |
发出客户端的OS、语言、MSN Messenger版本等信息。 |
client version |
Client |
SS |
|||
NS |
Client |
返回推荐的MSN Messenger版本、升级软件需要的下载地址等信息。 |
||
SS |
Client |
|||
FLN |
NS |
Client |
通知有联系人列表中的用户下线。 |
off-line |
GTC |
Client |
NS |
设置当有联系人列表中的用户状态改变时给出的提示。 |
greeting to changes? |
NS |
Client |
返回设置请求的应答。 |
||
INF |
Client |
NS |
询问服务器所支持的认证方式。 |
information? |
Client |
SS |
|||
NS |
Client |
返回服务器所支持的认证方式。 |
||
SS |
Client |
|||
ILN |
NS |
Client |
当客户端登录或添加联系人到列表时,通知列表中的联系人的状态。 |
initial online state |
IRO |
SS |
Client |
当有新用户加入聊天连接时,通知客户端该连接中的用户名单。 |
initial roster information |
JOI |
SS |
Client |
通知客户端已经同另外的用户建立了聊天连接。 |
jion |
LSG |
Client |
NS |
发出获取联系人组列表的请求。 |
list groups |
NS |
Client |
返回获取联系人组列表请求的应答。 |
||
LST |
Client |
NS |
发出获取联系人列表的请求。 |
list |
NS |
Client |
返回获取联系人列表请求的应答。 |
||
MSG |
Client |
SS |
发送消息到其他用户(聊天对象)。 |
message |
NS |
Client |
传递服务器(系统) 的消息到客户端。 |
||
SS |
Client |
传递其他用户(聊天对象)的消息到客户端。 |
||
NAK |
SS |
Client |
做出否定回答。 |
negative acknowledgement |
NLN |
NS |
Client |
通知客户端联系人上线或改变状态。 |
on-line |
OUT |
All |
All |
结束客户端-服务器的连接。 |
out |
PNG |
Client |
NS |
测试TCP连接状态。 |
ping |
Client |
SS |
|||
PRP |
Client |
NS |
发出设置个人电话号码的请求。 |
personal phone number |
NS |
Client |
返回设置请求的应答 |
||
PNG |
Client |
NS |
测试TCP连接状态。 |
ping |
Client |
SS |
|||
QNG |
NS |
Client |
返回测试TCP连接状态的应答。 |
quiz ping? |
SS |
Client |
|||
QRY |
Client |
NS |
客户端回答服务器的验证要求。 |
quiz reply? |
Client |
SS |
|||
REA |
Client |
NS |
发出修改用户昵称的请求。 |
rename nickname |
NS |
Client |
返回修改用户昵称请求的应答。 |
||
REG |
Client |
NS |
发出修改联系人组的请求。 |
rename group |
NS |
Client |
返回修改联系人组请求的应答。 |
||
REM |
Client |
NS |
发出从联系人列表中删除用户的请求。 |
rename user |
NS |
Client |
返回删除用户请求的应答。 |
||
RMG |
Client |
NS |
发出删除联系人组的请求。 |
remove group |
NS |
Client |
返回删除联系人组请求的应答。 |
||
RNG |
NS |
Client |
通知客户端有人要建立聊天连接。 |
ring |
SYN |
Client |
NS |
客户端-服务器同步。 |
synchronization |
NS |
Client |
|||
URL |
Client |
NS |
发出获取MSN服务URL的请求。 |
URL |
NS |
Client |
返回获取URL请求的应答。 |
||
USR |
All |
All |
声明、传递、鉴别用户身份。 |
user |
VER |
Client |
DS |
协商MSN Messenger协议版本。 |
version |
Client |
NS |
|||
DS |
Client |
|||
NS |
Client |
|||
XFR |
DS |
Client |
向客户端分配NS(通知客户端转向连接指定的NS)。 |
transfer |
Client |
NS |
发出分配SS的请求。 |
||
NS |
Client |
返回分配SS请求的应答。 |
表 1 常用命令
以即时消息通信来说明整个通信过程。一个典型的通信过程如下。
1) 客户端与DS建立连接。DS与客户端协商参数,给客户端指定NS,然后断开与客户端的连接。
2) 客户端与NS建立连接。NS与客户端进行各种非中转的交互,如登录、获取用户列表和更新个人信息等。客户端与NS是一直连接的,除非客户推出MSN。当然,当客户端打开一个聊天窗口,发出聊天请求时,NS会给客户端分配一个SB,然后3)和2)就并行运行了。
3) 客户端通过接线服务器SB与好友间接聊天。聊天过程中,客户端与SB间的交互如图 1所示。图中的通信过程一直持续到某客户端关闭聊天窗口。
客户端A |
SB服务器 |
客户端B |
聊天请求 |
转发请求 |
响应请求 |
转发响应 |
聊天内容 |
转发内容 |
图 1 即时信息聊天的通信模型
C :2698 > 1863 [SYN] Seq=0 Len=0 MSS=1420 /* 客户端发起与DS的连接 */
DS:1863 > 2698 [SYN, ACK] Seq=0 Ack=1 Win=16384 Len=0 MSS=1460
C :2698 > 1863 [ACK] Seq=1 Ack=1 Win=65535 Len=0
C :VER 1 MSNP15 MSNP14 MSNP13 CVR0 /* 与DS协商MSN版本 */
DS:VER 1 MSNP15 MSNP14 MSNP13 CVR0 /* 与DS协商MSN版本 */
C : CVR 2 0x0804 winnt 5.1 i386 MSNMSGR 8.1.0178 MSFT [email protected] /* 发出客户端的OS、语言、MSN Messenger版本等信息 */
DS:CVR 2 8.5.1302 8.5.1302 8.1.0178 http://msgr.dlservice.microsoft.com/download/ 5/6/4 / 5646481F -33EF-4B08-AF00 -4904F 7677B89/ZH-CHS/Install_WLMessenger.exe http://get.live.com/cn /* 返回推荐的MSN Messenger版本、升级软件需要的下载地址等信息 */
DS: XFR 3 NS 207.46.111.40:1863 U D /* 给客户分配NS服务器 */
C :2698 > 1863 [ACK] Seq=148 Ack=243 Win=65293 Len=0
DS:1863 > 2698 [FIN, ACK] Seq=243 Ack=148 Win=65388 Len=0 /* DS与客户断开连接 */
C :2698 > 1863 [ACK] Seq=148 Ack=244 Win=65293 Len=0 /**/
C :2698 > 1863 [FIN, ACK] Seq=148 Ack=244 Win=65293 Len=0
DS:1863 > 2698 [ACK] Seq=244 Ack=149 Win=65388 Len=0 /* DS与客户已断开连接 */
C :2701 > 1863 [SYN] Seq=0 Len=0 MSS=1420 /* 客户与NS建立连接 */
NS:1863 > 2701 [SYN, ACK] Seq=0 Ack=1 Win=16384 Len=0 MSS=1460
C :2701 > 1863 [ACK] Seq=1 Ack=1 Win=65535 Len=0 /* 客户与NS已建立连接 */
C : VER 4 MSNP15 MSNP14 MSNP13 CVR0 /* 与NS协商MSN版本 */
NS: VER 4 MSNP15 MSNP14 MSNP13 CVR0 /* */
C : CVR 5 0x0804 winnt 5.1 i386 MSNMSGR 8.1.0178 MSFT [email protected] /* 发出客户端的OS、语言、MSN Messenger版本等信息 */
NS:CVR 5 8.5.1302 8.5.1302 8.1.0178 http://msgr.dlservice.microsoft.com/download/ 5/6/4 / 5646481F -33EF-4B08-AF00 -4904F 7677B89/ZH-CHS/Install_WLMessenger.exe http://get.live.com/cn /* 返回推荐的MSN Messenger版本、升级软件需要的下载地址等信息 */
NS:GCF 0 5277 /* 向客户发送一些包含安全策略,并经BASE64编码了的XML档案 */
C :USR 7 SSO S t=EwBwAswbAQAUs1/VcBU2sH7… /* 包含了一大串单点登录的认证信息 */
NS:USR 7 OK [email protected] 1 0 /* 登录成功 */
NS:SBS 0 null /* ??? */
C :2701 > 1863 [ACK] Seq=1172 Ack=5640 Win=64365 Len=0
DS:MSG Hotmail Hotmail 1277 /* 返回客户端的基本信息 */
C :BLP 8 BL /* 请求下载好友分组信息 */
DS:BLP 8 BL
C : ADL 9 241 /* 将什么加入列表?? */
DS:PRP 10 MFN [email protected] /* 返回昵称、个性签名和头像等 */
DS:BLP 13 BL
C :2701 > 1863 [ACK] Seq=1619 Ack=7001 Win=65477 Len=0 /* 确认 */
DS:ADL 9 OK
DS:MSG Hotmail Hotmail 544 /* 传递服务器系统信息 */
C :2701 > 1863 [ACK] Seq=1619 Ack=7580 Win=64898 Len=0 /* 确认 */
DS:CHG 11 NLN 1984741420 /* 更新在线状态 */
DS:UUX 12 0 /* 个性签名 之后一段是下载好友个性签名及正在收听的音乐 */
C :2701 > 1863 [ACK] Seq=1619 Ack=7613 Win=64865 Len=0 /* 确认 */
DS:ILN 11 NLN [email protected] /* 初始信息通告(此处连接MSN自带的英汉通) */
DS:UBX [email protected] 1 0 /* 下载好友个性签名 */
C : 2701 > 1863 [ACK] Seq=1619 Ack=8011 Win=64467 Len=0 /*确认*/
C :CHG 14 NLN 1985789996 /* 请求更新在线状态 */
DS:CHG 14 NLN 1985789996 /* 响应请求 */
C :UUX 16 139 /* 请求下载正在收听的音乐 */
DS:UUX 16 139 /* 响应请求 */
DS: CHL 0 15146222442235123732 /* 服务器发出验证请求 */
C :QRY 17 PROD0114ES4Z%Q5W 32 /* 响应验证请求 */
DS:QRY 17 /* 验证成功?? */
DS: MSG Hotmail Hotmail 206 /* 传递服务系统信息 */
C :XFR 18 SB /* 请求接线服务器(打开了一个新的聊天窗口) */ DS:XFR 18 SB 207.46.27.38:1863 CKI 1845347529.250161188.72151200 U messenger.msn.com 1 /* 响应请求 */
C :2763 > 1863 [SYN] Seq=0 Len=0 MSS=1420 /* 客户端向SB服务器发起连接 */
SB:1863 > 2763 [SYN, ACK] Seq=0 Ack=1 Win=16384 Len=0 MSS=1460
C :2763 > 1863 [ACK] Seq=1 Ack=1 Win=65535 Len=0 /* 客户端已经与SB服务器建立了连接 */
C :USR 1 [email protected] 1845347529.250161188.72151200 /* 发送身份信息 */
SB:USR 1 OK [email protected] [email protected] /* 身份确认成功 */
C :CAL 2 [email protected] /* 请求与en-cn@hotmail聊天 */
SB:CAL 2 RINGING 1845347529 /* 服务器响应请求 */
SB:JOI [email protected] /* 服务器通知客户端已做好了接线准备 */
SB:MSG [email protected] /* 服务器转发过来了[email protected]的信息 */
C :MSG 3 D 142 /* ?? */
SB:ACK 3
C :MSG 4 D 533 /* ?? */
SB:ACK 4
SB:MSG [email protected] /* 接收到信息 */
C :MSG 5 U 97 /* ?? */
C :MSG 6 U 97 /* ?? */
C :MSG 7 U 97 /* ?? */
C :MSG 8 N 154 /* 向[email protected]发送信息 */
SB:MSG [email protected] /* 接收到[email protected]的翻译信息 */
C : PNG /* 测试与NS的连接状态 */
NS:QNG 41 /* 返回连接状态 */
SB: BYE [email protected] /* 结束聊天(关闭了聊天窗口) */
C:OUT /* 退出与NS的连接 */
C:OUT /* 退出与SB的连接 */
NS:1863 > 2701 [FIN, ACK] Seq=8427 Ack=1900 Win=65254 Len=0 /* 客户端与NS准备断开连接 */
C :2701 > 1863 [ACK] Seq=1900 Ack=8428 Win=65527 Len=0
NS:2701 > 1863 [FIN, ACK] Seq=1900 Ack=8428 Win=65527 Len=0
C :1863 > 2701 [ACK] Seq=8428 Ack=1901 Win=65254 Len=0 /* 客户端已断开与 NS的连接*/
SB:1863 > 2763 [FIN, ACK] Seq=1915 Ack=1288 Win=64248 Len=0/* 客户端与SB准备断开连接 */
C :2763 > 1863 [ACK] Seq=1288 Ack=1916 Win=65056 Len=0
C :2763 > 1863 [FIN, ACK] Seq=1288 Ack=1916 Win=65056 Len=0
SB:1863 > 2763 [ACK] Seq=1916 Ack=1289 Win=64248 Len=0 /* 客户端已断开与SB的连接*/
对于这个例子,有如下几点说明。
1) 例子给出的是这样一个示意性的过程:用户[email protected]登录MSN,然后与[email protected]聊天(即时信息聊天),紧接着登出(退出)MSN。
2) 限于篇幅,例子中仅给出命令和消息行的基本信息,省略了命令和消息的具体内容,并省掉了一些ACK响应。
3) “C :”开头的行代表客户端发出的数据,“DS:”开头的行代表派遣服务器发来的数据,“NS:”开头的行代表通知服务器发来的数据,“SB:”开头的行代表接线服务器发来的数据。
从前面的叙述知,MSNP15的大部分通信都是经服务器中转的。如果不从功能上让服务器各自负责一部分的话,将会导致每个服务器的功能十分庞大。这样,服务器的复杂度就太大而难以实现。相反,从功能上,将服务器分为三种类型,让每种类型的服务器仅负责一部分工作,大大降低了单个服务器的复杂度,提高了单个服务器的可靠性,并且更有利于服务器体系结构的架构。
MSN的登录采用的是单点登录,即在NS登录后(获取到一个通行证序列),与其它服务器连接不需要再登录(虽然也有用户验证的步骤,但该步骤仅仅是输入通行证序列)。
UTF-8是一种简单的编码。winhex和SmartConvert等字符编/解码工具都能对其解码。
协议分析的要求如表 2 协议分析要求所示。
ID |
Protocol |
Captured contents |
|||||||
account |
password |
nickname |
Opponents |
Chat contents |
Login |
Logout |
Friendslist |
||
8 |
MSN 8.1 |
√ |
|
|
|
√ |
√ |
√ |
|
表 2 协议分析要求
提取发往服务器(端口一般是1863)的CVR包即可获得。
监视发往MSN服务器(端口一般是1863)的TCP SYN包即可。
监视发往或来自MSN服务器(端口一般是1863)的TCP FIN包即可。
提取与MSN服务器(端口一般是1863通信的数据包即可。通过分析数据包中的关键字(如命令名和MSG)和具体内容,可获得所需要的信息。
[1] http://blog.csdn.net/bingwen0210/archive/ 2007/03/30 /1546475.aspx,该文较好地讲述了MSNP9/MSNP10
[2] http://msnpiki.msnfanatic.com/index.php/MSN_Protocol_Version_15,该英文网站有很多MSNP8-MSNP15的资料。
[3] http://www.hypothetic.org/docs/msn/index.php,该英文网站算得上MSNP的官方网站了,但是目前提供的资料还只到MSNP10
[4] http://bbs.intercn.net/viewthread.php?tid=34,该文较好地讲述了MSNP的各种通信过程。
[5] http://www.cncert.net/tec/ours/ 2007-7-18 /114.html, 该文以实例的形式较好地分析了MSNP15的通信过程