MSNP18协议分析(二)--- MSN登录身份认证

 这一篇开始主要介绍MSN登录部分的协议分析,总体来说,登陆这一块是整个MSNP协议的一大块,也是比较复杂的一部分。整个登录的过程主要包括:连接服务器,身份验证,获取用户信息和联系人列表,把联系人列表发送给服务器,发送个人信息和状态,上线通知。我也打算按照登录的顺序去进行介绍。

 

这里我主要关注的是如何成功的登录,但是因为大多数都是抓包,也没有权威的官方资料参考,所以不能保证完全正确和详细,有些也不能给出合理的解释,但还是尽可能的介绍登录中会出现的各种情况,以及登录中用到的命令。

 

在使用命令之前,我们需要注意的时,普通命令后面都带有/r/n结尾。而palyload命令是根据数据长度找到结尾。我们在发送时必须注意这一点,如果发送的数据没有结尾标识,服务器会断开连接。另外发送的命令都需要以UTF8格式发送。

 

 


 .

 

 

一 连接服务器

登录最终的目的是登录到NS服务器,与之建立连接并进行交互。一直到用户退出或注销时,才断开与服务器的连接。在登录到NS服务器之前,我们需要先连接到DS服务,并获得NS服务器的地址。

.

 

1 连接到DS服务器

DS服务器的地址是:messenger.hotmail.com ,端口号是1863在通过Socke连接之前需要对这个域名进行解析,而且解析的IP是不固定的,所以不建议使用固定的IP去连接DS服务器。以下是MSN Live 2009登录时和DS服务器之间的交互数据。

 

>>>VER 1 MSNP18 MSNP17 CVR0/r/n

 

<<<VER 1 MSNP18/r/n

 

>>>CVR 2 0x0804 winnt 5.1 i386 MSNMSGR 14.0.8089.0726 msmsgs test@live.cn/r/n

 

>>>USR 3 SSO I test@live.cn/r/n

 

<<<CVR 2 14.0.8089 14.0.8089 14.0.8089 http://msgruser.dlservice.microsoft.com/download/0/9/7/0974F7CD-D082-46FE-922D-806670345793/zh-chs/wlsetup-cvr.exe http://download.live.com/?sku=messenger/r/n

<<<XFR 3 NS 207.46.124.241:1863 U D/r/n

 

VER命令:

这是和DS服务器发送的第一条消息,他是告诉服务器客户端支持的MSNP版本。MSNP版本功能在上一篇文章有所介绍,发送的版本号可以是多个版本。发送的版本号是区分大小写的。最后一个参数是CVR0,他实际是(CVQ, VER) 的命令集合,用来设置客户端版本,使得客户端能够升级。但具体作用不详,不发送也是可以的。最后要注意的是最后一个参数结尾要带上"/r/n"。服务器在接受到命令后,会从我们发送的协议版本中选一个他支持的最高本版,如果我们发送的协议版本他不支持,就返回一个0。目前最新的协议支持到了MSNP21。

.

 

CVR命令:

这是是CVR命令的格式CVR trid lcid osName osVersion processorType clientName clientVersion [brandId] [userHandle]。聪从名字就能看出每个参数的作用。 lcid是地区编码,0x804表示的是中国。 clientVersion我们可以根据MSNP对应的官方版本来确定; brandID官方客户端是msmsgs ,最后一个就是登陆用户的账号。服务器会返回给你版本信息,最新的MSN下载地址,这些可以无视,我们又不是用MS的客户端。哈

.

 

USR命令:

USR命令是在登录过程中用来身份验证的一个命令,会多次使用,在连接DS服务器时比较简单。第一个参数是SSO,表示身份验证方式。从MSNP15开始就是用此方法验证,而之前的版本使用TWN。所以要支持多个协议方式登陆,首先要区分身份验证的方式。第二个参数是 (I = Initiate, S = Respond to Challenge). 我们这里第一次使用,发送I,最后一个参数还是用户的账号。USR还有多种用法,后面用到时继续介绍。

.

 

XFR命令:

服务器返回的XFR命令的作用是通知你NS服务器的地址,另一个作用就是在聊天时返回给你一个SB服务器的地址。第一个参数NS表示这是发送的NS地址,第二个参数就是服务器的IP地址和端口号。最后的U D表示什么不知道。接受到XFR后,DS服务器会自动断开SOCKET连接。这里XFR是否会不返回NS地址,不太清楚,起码目前没有发生过,当然程序中还是需要对这种情况进行处理。

.

 

以上就是连接DS服务的全部过程,介绍了几个命令的用法。要注意的是,这里并没有太多的介绍可能返回的错误。比如你已经登陆了,在发送这里的USR命令就会出错;如果发送消息过于频繁也会出错等等。但是一般,我们不需要太过关注这些,而且错误情况太多也根本关注不过来。后面我会给出所有服务器返回的错误代码的列表,实际出现问题时在去解决。这里我们只关注登录过程。需要注意的是发送命令不一定需要发送一条,接受一条才能在发送一条。有些命令可以不需要等待上一条返回就发送的。

.

 

2 连接到NS服务器

从XFR获得到了NS服务器的IP地址很端口号以后,我们就能使用SOCKET连接到NS服务器了。

>>>VER 1 MSNP18 MSNP17 CVR0/r/n


>>>CVR 2 0x0804 winnt 5.1 i386 MSNMSGR 14.0.8089.0726 msmsgs test@live.cn/r/n


>>>USR 3 SSO I test@live.cn/r/n

 

<<<VER 1 MSNP18/r/n


<<<CVR 2 14.0.8089 14.0.8089 14.0.8089/r/n http://msgruser.dlservice.microsoft.com/download/0/9/7/0974F7CD-D082-46FE-922D-806670345793/zh-chs/wlsetup-cvr.exe http://download.live.com/?sku=messenger


<<<GCF 0 5521/r/n<Policies>省略</Policies>

 

<<<USR 3 SSO S MBI_KEY_OLD kVJy53UCBCupSu09gfE9rH47mtDGzmINva5/vEiYJIfxft+an0igQBC445kNyIkV/r/n

 

以上是MSN 2009连接NS服务时发送的前3条命令,我们可以看到这里没有等待上一条返回,而是一起发送了。这里的3条命令和DS服务器发送的一样,这里就不在过冬介绍了。但是发现我们发送的USR命令后,返回的和DS时不一样了。

 

GCF命令:

此命令是从服务器获得配置文件信息,可以看他是一个playLoad命令,命令后面是ID好和数据长度。数据是使用XML存放。 但是从MSNP13开始此命令已经不在使用,所以我么可以不处理这一条命令。

.

 

USR命令:

在前面我们发送过USR命令,在这里我们收到了服务器发送来的USR命令。这里我们要关注的是MBI_KEY_OLD 已经后面的一传值。这个就是SSO认证过程中需要用到的KEY。这里返回的类型可能是MBI、MBI_SSL 、MBI_KEY_OLD等类型。

.

 

3 断开服务器连接

断开服务器连接有多种方式,对于NS服务器,我们不需要主动断开,在获得XFR之后,服务器会主动断开SOCKET连接。对于NS服务器,我们退出时可以发送OUT命令,这个命令不需要ID和任何参数,服务器接收到OUT之后就会断开连接,这是一种比较好的断开方法。对于SB服务器一样,我们也只需要发送一个OUT命令。

 

我们还可以直接断开客户端的SOCKET连接,但是这样服务器不一定能马上改变我们的状态,好友也不一定马上能看到我们下线或退出对话。而如果我们发送的命令不正确,有些情况,服务求就会马上断开连接。有一些错误服务器在断开之前会返回错误代码。

.

 

OUT命令:

 我们能给服务器发送OUT表示我们退出,服务器有时也会在断开我们之前发送OUT通知我们。OUT [Reason]这是服务器发送OUT给我们时候的格式。当收到的与原因是OTH时,表示我们被其他登陆点注销,这可能是其他登陆点不支持多点登陆,也可能是被其他登陆点选择注销;当收到原因是RCT <delay> 的时候,表示服务器断开,指定的时间之后可以进行重连;SSD则表示服务器挂了;TME则表示登陆的终端太多,我们被服务器kick out了。我们可以根据不同情况进行处理。

.

 

UUN命令:UUN trid receiverHandle[;EPID] appID size/r/nBODY

从MSNP16之后,开始支持多点登陆,我们可以注销掉其他登陆点的MSN。使用的命令就是UUN。这个命令作用是发送客户端1对1的通知消息。使用这个命令注销其他登陆点只是其中的一个功能。第一个参数要通知的客户端用户的账号,第二个参数是EPID,这个是可选的。支持多点登陆的版本,每个登陆点会有一个GUID来表示终端。第三个参数是操作类型ID,我们注销其他登陆点使用4;最后是发送BODY的大小;注销其他终端,官方服务发送的是大小为14的一串字符ngoawyplzthxbye,没有尝试能否使用其他字符,我认为应该是可以的。服务器接受到这个消息后,会根据EPID向其他客户端发送OUT OTH命令。注意发送EPID时不要少了前面的分号。 发送成功服务器会返回UUN trid OK。

App IDDescription
0Debug App ID
12-share
2Voice conversation invites (never sent in UUN, only UBN)
3P2P bootstrapping
4Log off my remote endpoints
5Closing the conversation window
6Contact List Update
7Clear RL Prompt
8Forward non-session message (i.e. Offline IM)
9RESERVED
10TURN bridge notification
11Meta-data channel for audio calls
12Signaling channel for Voice over MSNP

以上是在UUN命令中使用到的AppID编号,同样这个编号也在UBN命令中使用。

 

UBN命令:UBN senderHandle;EPID appID size/r/nBody (>=MSNP 16)

在MSNP小于16的版本中,没有EPID这一项目。而这个命令从MSNP13开始支持。和UUN一样,他们的body内容最大长度为6144个字节,使用ASCII编码。这个命令接受到的可能是其他终端对UUN的返回结果,也可能是服务器发送来的邀请。

.

.

 

二 身份验证

从MSNP15开始,微软采用了新的身份认证方式SSO(Single Sign-On)。在MSN整个使用过程中,并不仅仅是登录需要身份验证,我们从WebService取得联系人列表,个人信息,用户头像,离线消息等等都需要身份验证。于是在登录的时候,我们进行身份验证的请求,服务会发送给我们一些列的ticket,他们对应了不同的服务请求。所以在开始登陆之前我们必须进行SSO认证,获得所需的ticket。SSO认证是通过WebServices服务完成的,SSO认证的地址为:https://login.live.com/RST.srf ,需要注意的是对于msn。com结尾的账号,需要提交到 https://msnia.login.live.com/pp550/RST.srf 进行认证。目前好像无法注册msn.com,也没有可用的账号,所以无法测试。

.

1 SSO认证方式

以上XML就是我们要提交到WebService的SOAP格式。首先我们需要填充自己的账号和密码到XML中。我们看到Body中有<wst:RequestSecurityToken Id="RSTn">...</wst:RequestSecurityToken>这样一个块,每一个代表一个你想要进行身份验证的域。RST0是必须的,我们添加对应的身份认证时,只需要构造从RST1开始节点块。这样你可以只提交一次,就获得多个不同的域的身份认证。 下面列出了所有域的相关信息。

RSTDimain域Policy RefPurpose
RST0http://Passport.NET/tb作用不明,但是必须包含才能请求成功
RST1messengerclear.live.comNS USR命令获得的Authentication for messenger.
目前在登录时使用
RST2messenger.msn.com?id=507Messenger website authentication。
目前在获得离线消息时使用
RST3contacts.msn.comMBI (used in WLM 8.5.1288.816)Authentication for the Contact server.
目前在操作联系人时使用
RST4messengersecure.live.comMBI_SSL未知
RST5spaces.msn.com spaces.live.comMBIAuthentication for the Windows Live Spaces
应该是登录到空间使用
RST6livecontacts.live.comMBILive Contacts API, a simplified version of the Contacts SOAP service
目前没有使用到
RST7storage.live.comMBIStorage REST API
目前获取用户头像时使用
 

我们只需要根据上表的内容,填充自己需要的域节点的内容,提交到服务器,就可以获得对应服务的ticket。RTS1的Policy Ref是我们前面USR命令所获得的MBI_KEY_OLD,前面说过了,这个参数可能有MBI、MBI_SSL等类型,所以要根据USR返回值填如XML中。网上有些地方是在NS连接前去进行SSO认证,这个是不正确的,因为我们还没获得Policy Ref。虽然目前基本发送的都是MBI_KEY_OLD。然后服务器会返回给我们如下的XML:

 

我们发送的XML中请求了几个认证的域,服务求就会返回对应的<wst:RequestSecurityTokenResponse>节点。其中<wsse:BinarySecurityToken Id="Compactn"> 和 RSTn 中的数字n对应,其节点值t就是对用的认证使用的ticket<wsse:BinarySecurityToken Id="PPTokenn">节点中包含ticket和profile,因为对用的服务需要使用到这两个值,目前我们在获取离线消息时需要使用。如果我们验证时的账户和密码不正确时,返回的XML会包含wsse:FailedAuthentication

 

至此我们已经完成了SSO认证的过程,我们可以把ticket 、profile保存下来,供后面使用,这里要注意,返回的XML中包含ticke的过期时间,如果过期了,必须从新进行请求。

.

 

2 登录验证

前面我们已经获得所有需要的ticket,当然登录需要的ticket也获得了。另外我们还需要从保存登录ticket节点下<wst:BinarySecret>节点中的值,我们叫做BinarySecret。以下是在完成SSO认证之后,进行的登录身份验证发送的命令。

 

<<<USR 3 SSO S MBI_KEY_OLD kVJy53UCBCupSu09gfE9rH47mtDGzmINva5/vEiYJIfxft+an0igQBC445kNyIkV/r/n

 

>>SSO认证---webservices

 

<<<获得各个服务的ticket

 

>>>USR 4 SSO S t=EwBoAswbAQAUs1/VcBU2sH7mwYy3BysWZ71CRDGAAP2ngxo5hiNLK0FzCGY1llPy8F5Uv8GQVTL2FDWo0UFZ2P4kDFk95WWhFl4ydSN8zJQVpzq5YlhSaTJc/JziNMZV0RBOaNDv0yuuGKPZ7gkaHLF5QDF5t0xChHLupla0+WYt5N3rnfRjU8QnYqgvkdMtEolkfInY0lxyyfmBSVeSA2YAAAhynJ+hLqBEy7gBZf6U97YpNCZdVsu8Uwr5GMs0FY8aWocMlSKU0V3rBP4igonwRPb/VLYGAztVZxFHZx/abNHOt/Sh83M7LWhqvPPbcWKuOIcevMzwParNhKZ2VWS1TymnQuqnA8igbYrDtAi1QcD6iEoQy/sM4cb7ryM/MjUZCbWQ6xg5CecLNlZT5onfqZ2IJJSZjrRO/9ZEU0rpH7N8nj/ycJVgiKJR8emWDec7eh1CbFltxtFz3ZCnWcwU+GCqhTU7IsTLrX6LYxjSTUm4eG8x19mxbJpjEv1Zpgqajdwfobu4FzKe0yF64hnVJd2Kv8hqnTq38XtcocSNexs/Sue4SknaOMG2u69Yu7b6CD/Ih+BOu4V2ZKn/EndfcW7tC7jh0x8qdTzy7sjJqQuz6sGMCr1uEt3Lx7tlT7nj+RDW5MG9MEMFid4ordfe2R1DV4bKB3D4xZWc7gT4rjfTcxtlRnrP6kOM6n9hPDScewrj4fknSzW1OKd8yCEtdQjb4pnvvmWRWqDO1ImQPLcK5Q3CqYb0BGf53w3fL/FEoWD3m0drktFlK3nGW4F3smsfdOkFGnYF/zSg7Jg9erW7Z8LlAQ==&p= HAAAAAEAAAADZgAABIAAAAgAAAAUAAAASAAAAAAAAAAAAAAAoHfdK2pjBY1wLTHXDzh9VtaqYOb2g4n+epmErFlCejBt2pMDFMNR4fFjknY6XsftT1qboX3K45VNK3ICTjEbPsvR1Sog3D14Rz2Q6JPKFrEAWZ23PEjCV6f8XJw= {95DC3D4B-7FBF-46B5-B670-FE0E75B89217}

 

<<<USR 4 OK test@live.cn 1 0

 

以上继续使用USR SSO S命令,最后一个参数的格式是t=...&p=...{epid} , 这里的t就是我们SSO中取得和登录有关的ticket,而p是由USR 3中那一长串nonce和上面取得的BinarySecret通过计算得到的,具体计算方法后面介绍,最后一个参数是客户端的ID,是一个GUID,用来唯一标识一个终端。如果重复,会导致之前登录的终端被踢下线。

 

发送此条命令之后,如果验证通过,服务器会发送USR OK通知客户端登录成果,如果发送的t和p不对,会返回错误代码:911 ERR_AUTHENTICATION_FAILED

.

 

3 生成登录是发送的p 

上面的USR 4命令中包含了p,这个p是由USR 3中得到的nonce和webservice请求获得的BinarySecret计算得到P。在介绍算法之前,我们需要一个结构体,我们最终的p就是这个结构体的值,发送给服务器。

算法是按一下步骤来的:http://msnpiki.msnfanatic.com/index.php/MSNP15:SSO#Computing_the_return_value

1. 对获得的BinarySecret进行BASE64编码,存放到key1中

 

2.使用SHA_HMAC加密key1,按一下方法进行

hash1 = SHA1-HMAC(key1,"WS-SecureConversationSESSION KEY HASH")
hash2 = SHA1-HMAC(key1,hash1+"WS-SecureConversationSESSION KEY HASH")
hash3 = SHA1-HMAC(key1,hash1)
hash4 = SHA1-HMAC(key1,hash3+"WS-SecureConversationSESSION KEY HASH")
然后把hash的20个字节,以及hash的前4个字节组成一个24字节的字符串存入 key2.

 

3.使用SHA_HMAC加密key2,按一下方法进行

hash1 = SHA1-HMAC(key2,"WS-SecureConversationSESSION KEY ENCRYPTION")
hash2 = SHA1-HMAC(key2,hash1+"WS-SecureConversationSESSION KEY ENCRYPTION")
hash3 = SHA1-HMAC(key2,hash1)
hash4 = SHA1-HMAC(key2,hash3+"WS-SecureConversationSESSION KEY ENCRYPTION")
然后把hash的20个字节,以及hash的前4个字节组成一个24字节的字符串存入 key3。

 

4. 使用SHA_HMAC加密key2和前面得到的nonoc,存入hash = SHA1-HMAC(key2, nonce)

 

5. 官方客户端会在nonce的后面追加8个字节的16进制数08

 

6. 创建8个字节随机数data

 

7. 使用TripleDes algorithm算法。模式设置为CBC,将上面的key3,随机数data 以及 第5步产生的nonce进行加密,存入encrypted_data

 

8. 填充结构体

aIVBytes使用第6步创建的随机数填充,aHashBytes使用第4步的hash填充,aCipherBytes使用第7步计算的encrypted_data填充。而其他节点的值则按照结构体注释中的填写,如果不想使用默认值进行相应调整

 

9. 对结构体进行BASE64编码

以下是用C++代码实现的整个计算过程,我们使用openssl提供的SHA_HMAC,TripleDes algorithm以及BASE64方法。

 

.

.

 

三 小结

自此,我们成功的完成了从连接DS服务器到MSN的登录身份验证,注意,这里仅仅是完成身份验证,并不是完成了实际的登录过程。除此之外,我们还获得了和面获取联系人列表、离线消息,联系人头像等操作时,请求Webservice服务所需要的ticket。整个登录过程复杂的就在于构建SSO请求的XML,以及计算p值。

 

在登录过程中可能出现的错误就是账号或密码错误导致SSO认证失败,也可能是计算P值出错,导致登录验证失败。所以在程序中必须对这两种错误进行处理。

 

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值