一、MSN协议分析部分

1.1 基本介绍

MSN是微软推出的IM工具,他的通信协议是微软自己提出的MSNP(即MSN Protocol)。当前MSN协议最高版本为MSNP18,但可获取的资料很少。这里仅仅以MSNP12做说明。

命令是服务器与客户交互的一种方式。MSNP12的命令使用纯ASCII码,对非ASCII码使用URL编码。命令的一般格式是:

XXX TrID PARAM1 PARAM2…

其中,XXX是一个3字符的命令串,TrID是一个流水号,PARAMx是参数。最简单的命令没有流水号和参数。一个典型的MSNP命令形如

VER 1 MSNP18 MSNP17 MSNP16 CVR0

每个发送的MSN命令以回车换行作为一条命令的结束。具体命令的含义和使用参数可以参见参考资料[1]所示的MSN协议非官方wiki。

1.2 利用VER命令测试当前服务器支持版本

在服务器的messenger.hotmail.com的1863端口发送命令VER来测试。在本文中用”>”符号表示发送的命令,用”<”符号表示收到的命令。

>VER 1 MSNP18 CVR0

<VER 1 MSNP18

由以上可以看出,服务器当前支持MSNP18。类似的,可以发送多个参数的VER命令到服务器

>VER 1 MSNP18 MSNP12 CVR0

<VER 1 MSNP18 MSNP12

1.3 MSN登陆过程

MSN登录可以分为2个步骤:

(1)    向服务器messenger.hotmail.com的1863端口请求实际登录地址

(2)    在获得的新的服务器上进行登录

因此,在MSN登录过程可以看到2次产生登录请求,MSN服务器在第二次登陆时才真正去做用户认证。2次登陆过程是都是向服务器发送VER, CVR和USR这3个命令,然后处理服务器反馈的命令来进行下一步处理。

发送信息和返回信息的过程可以是异步的,也可以是同步的。这意味着用户可以发送一个命令后,进行阻塞等待回复。客户端收到回复后,再发出第二个命令。客户端也可以连续发送3个命令至服务器,而后再进行阻塞等待,获取服务器的回复后再进行后续处理。

两次登陆的不同点在于两次发送USR命令后得到的回复命令。在第一个服务器(messenger.hotmail.com)上发送USR命令后,服务器反馈时返回XFR命令。XFR命令表示连接中止。XFR的参数中包含了客户端第二次需要登陆的MSN服务器地址。而后客户端可以进行在新服务器上进行登录。在第二个服务器上发送USR命令后,服务器不再返回XFR命令,而是返回USR命令。返回的USR命令要求客户端提供用户名和密码,需要在认证服务器上进行登录,而后返回认证相关信息。

第一次登陆过程的过程的收发命令类似如下

>VER 1 MSNP12 CVR0

<VER 1 MSNP12

>CVR 2 0x0804 winnt 5.1 i386 MSNMSGR 8.1.0178 MSMSGS csdnjay@hotmail.com

<CVR 2 8.1.0178 8.1.0178 8.1.0178 http://msgruser.dlservice.microsoft.com/download/5/6/4/5646481F-33EF-4B08-AF00-4904F7677B89/ZH-CHS/Install_WLMessenger.exe http://get.live.com/cn

>USR 3 TWN I csdnjay@hotmail.com

<XFR 3 NS 207.46.108.93:1863 0 207.46.28.94:1863

这里得知第二次欲登陆的服务器为207.46.108.93,端口为1863

第二次登陆过程收发命令类似如下

>VER 1 MSNP12 CVR0

<VER 1 MSNP12

>CVR 2 0x0804 winnt 5.1 i386 MSNMSGR 8.1.0178 MSMSGS csdnjay@hotmail.com

<CVR 2 8.1.0178 8.1.0178 8.1.0178 http://msgruser.dlservice.microsoft.com/download/5/6/4/5646481F-33EF-4B08-AF00-4904F7677B89/ZH-CHS/Install_WLMessenger.exe http://get.live.com/cn

>USR 3 TWN I csdnjay@hotmail.com

<USR 3 TWN S ct=1225934765,rver=5.5.4177.0,wp=FS_40SEC_0_COMPACT,lc=1033,id=507,ru=http:%2F%2Fmessenger.msn.com,tw=0,kpp=1,kv=4,ver=2.1.6000.1,rn=1lgjBfIL,tpf=b0735e3a873dfb5e75054465196398e0

>USR 4 TWN S t=9zmW8WUaNGes6RPIvobJZxog26Re6uEiF8NfCot1WADagYV*xBD!yobWolu4iQma712fndE2L0cI1t0zCErX*yCKKFA9SnStf5SgUDBm3c7wxTEphaA*Wy*bZdj1nfiuu!&p=9m2c8ZG8!FTK82I9Gd15dopRFWPlLk3mpIJ2*PdD3!IP8CFu8I5wWGkLslOu1QC3EEaZQnIqwBZTtzpWWzu18FYFFY75fcvzb85e649MYCwu8Mi3AyIv8R9PsyYdTrE6tbUo3fzlu5RZmE2X0RXv!yO8yemZ!Xwm8s2nYsh3E3HqmNNRBEBPKZ7g$$

<USR 4 OK csdnjay@hotmail.com 1 0

<SBS 0 null

<MSG Hotmail Hotmail 537

[ size = 537, num = 537]

MIME-Version: 1.0

Content-Type: text/x-msmsgsprofile; charset=UTF-8

LoginTime: 1225934767

EmailEnabled: 1

MemberIdHigh: 442365

MemberIdLow: -1451244322

lang_preference: 2052

preferredEmail:

country: CN

PostalCode:

Gender:

Kid: 0

Age:

BDayPre:

Birthday:

Wallet:

Flags: 1073742915

sid: 507

MSPAuth: 9zmW8WUaNGes6RPIvobJZxog26Re6uEiF8NfCot1WADagYV*xBD!yobWolu4iQma712fndE2L0cI1t0zCErX*yCKKFA9SnStf5SgUDBm3c7wxTEphaA*Wy*bZdj1nfiuu!&p

ClientIP: 222.191.237.170

ClientPort: 22030

ABCHMigrated: 1

MPOPEnabled: 0

由以上的收发消息列表可以看出,第二次登陆在发送USR命令后,服务器不在返回XFR消息,而是返回USR命令。注意在返回的USR命令中包含类似的字符串

ct=1225934765,rver=5.5.4177.0,wp=FS_40SEC_0_COMPACT,lc=1033,id=507,ru=http:%2F%2Fmessenger.msn.com,tw=0,kpp=1,kv=4,ver=2.1.6000.1,rn=1lgjBfIL,tpf=b0735e3a873dfb5e75054465196398e0

客户端可以利用这个字符串做MSN认证具体获取ticket的方法,参见第二部分Java实现。若认证成功,客户端收到类似的USR 4 OK csdnjay@hotmail.com 1 0的命令。这时服务器将会再次返回SBS 0 null命令和MSG Hotmail Hotmail 537命令。MSG命令的第2个参数537表示,服务器将发送537个字节来进一步该账户相关信息。

此时MSN登陆过程的全过程已经结束。

1.4 获取好友列表和分组信息

为了获取MSN帐户好友以及改帐户分组的相关信息,还要发送SYN命令进行数据同步,这样MSN服务器才能发送好友列表信息。

>SYN 5 0 0

<SYN 5 2008-10-29T03:24:39.063-07:00 2008-10-27T23:57:40.58-07:00 2 3

<GTC A

<BLP BL

<PRP MFN ?

<PRP MBE N

<PRP WWE 0

<LSG 朋友 c274104c-8db9-47fc-9d0d-07d6fbea0ff1

<LSG 家人 24a9c4c5-221a-43b2-bc80-9935e35cf11c

<LSG 同事 4c60904d-8a23-42d8-a340-b1033e6877ef

<LST N=csdnss@hotmail.com F=CSDNss@hotmail.com C=83c611d9-1f58-4577-b70c-3cb154e3a8a0 11 1 c274104c-8db9-47fc-9d0d-07d6fbea0ff1

<BPR HSB 1

<LST N=chx1477@hotmail.com F=chx1477@hotmail.com C=1c0bf657-7ded-4837-a69d-cc6803543929 11 1 4c60904d-8a23-42d8-a340-b1033e6877ef

以上便是发送SYN命令后和发送后的服务器反馈信息。由此可以分析出该帐号的好友列表和分组信息。LSG表示该MSN用户分组信息,后面的字符串(例如,第一个LST中csdnss@hotmail.com 最后的c274104c-8db9-47fc-9d0d-07d6fbea0ff1)表示分组ID。LST表示联系人信息,其中N表示好友的邮件,F表示可能的昵称,整条消息最后的字符串(例如c274104c-8db9-47fc-9d0d-07d6fbea0ff1)表示该联系人所在的分组。在上例中,该帐号有三个分组,分别为朋友、家人和同事。字符串c274104c-8db9-47fc-9d0d-07d6fbea0ff1表示朋友分组,联系人csdnss@hotmail.com在朋友分组中。4c60904d-8a23-42d8-a340-b1033e6877ef表示同事分组,联系人chx1477@hotmail.com在同事分组中。

1.5 获取好友具体信息

当然仅仅依靠SYN返回联系人的信息是不够全面的。SYN命令仅返回所有的组,联系人列表以及部分联系人的昵称。若要想进一步获取更多联系人的相关信息,可以继续发送CHG 命令,以获取联系人昵称和签名信息。

>CHG 6 NLN 0x5004802C

<BPR HSB 1

<CHG 6 NLN 0

<MSG Hotmail Hotmail 289

[MIME-Version: 1.0

Content-Type: text/x-msmsgsinitialmdatanotification; charset=UTF-8

Mail-Data: <MD><E><I>1</I><IU>0</IU><O>0</O><OU>0</OU></E><Q><QTM>409600</QTM><QNM>204800</QNM></Q></MD>

Inbox-URL: /cgi-bin/HoTMaiL

Folders-URL: /cgi-bin/folders

Post-URL: http://www.hotmail.com

]

<ILN 6 NLN csdn_jay@163.com Jin%20Jian 2254295084 %3Cmsnobj%20Creator%3D%22csdn_jay%40163.com%22%20Type%3D%223%22%20SHA1D%3D%22dlhdylsYA70%2Fzci5JUbQo5OYd1o%3D%22%20Size%3D%227064%22%20Location%3D%220%22%20Friendly%3D%22agBhAHkAAAA%3D%22%2F%3E

<UBX csdn_jay@163.com 123

[<Data><PSM>AGAIN</PSM><CurrentMedia></CurrentMedia><MachineGuid>{6B9562F0-1957-432A-8ACD-A04CD7961841}</MachineGuid></Data>]

<ILN 6 NLN chx1477@hotmail.com (R)流浪狗 1985859628 %3Cmsnobj%20Creator%3D%22chx1477%40hotmail.com%22%20Type%3D%223%22%20SHA1D%3D%22cmJCJjUVJ%2Bx1g5BUj5TlTOAoFIo%3D%22%20Size%3D%2218476%22%20Location%3D%220%22%20Friendly%3D%220W5%2FZwAA%22%2F%3E

<UBX chx1477@hotmail.com 118

[<Data><PSM></PSM><CurrentMedia></CurrentMedia><MachineGuid>{7840D262-7F06-46B8-9573-114AEE3530F5}</MachineGuid></Data>]

以上便是在发送CHG和发送后的服务器反馈信息。ILN命令中第2个参数为联系人email,第3个参数为联系人的昵称。UBX命令后面跟着的XML数据表示联系人的具体信息,其中在PSM数据段中表示就是联系人签名。在本例中chx1477@hotmail.com联系人的昵称为(R)流浪狗,这个联系人没有签名。csdn_jay@163.com联系人的昵称为Jin Jian,而签名为AGAIN。

这里需要说明的是UBX命令后面的数字是指XML数据的字节数。有的联系人的签名中可能存在非英文字符(例如中文字符,法文字符或日文字符等),这样在程序读取时候需要做特殊处理。

二、Java核心实现

2.1 Socket连接部分

Socket socket = new Socket(address, port);

InputStream socketInputStream = new DataInputStream(socket.getInputStream());

OutputStream socketOutputStream = socket.getOutputStream();

OutputStream buffered = new BufferedOutputStream(socketOutputStream);

OutputStreamWriter writer = new OutputStreamWriter(buffered, "ASCII");

2.2 发送消息部分

void writeCommandToSocket(String command)

throws IOException, UnsupportedEncodingException {

writer.write(command + "/r/n");

writer.flush();

}

2.3 获取消息部分

String readLine() throws IOException {

byte[] ba = new byte[1024];

int n = 0;

while(n < 1024) {

int b = getSocketInputStream().read();

if((b == '/r') || (b == '/n')) {

if(b == '/r') {

getSocketInputStream().skip(1);

}

break;

} else {

ba[n] = (byte)b;

n ++;

}

}

return new String(ba, 0, n, "UTF-8");

}

2.4 获取ticket部分

客户端通过https连接MSN认证服务器login.live.com,之后便可以获取登陆凭证ticket。

在连接时需要设置Authorization属性为

Passport1.4 OrgVerb=GET,OrgURL=https%3A%2F%2Flogin.live.com%2Flogin2.srf,sign-in=csdnjay%40hotmail.com,pwd=abcdefg,ct=1226474476,rver=5.5.4177.0,wp=FS_40SEC_0_COMPACT,lc=1033,id=507,ru=http:%2F%2Fmessenger.msn.com,tw=0,kpp=1,kv=4,ver=2.1.6000.1,rn=1lgjBfIL,tpf=b0735e3a873dfb5e75054465196398e0

上述字符串由如下部分组成

Passport1.4 OrgVerb=GET,OrgURL=" + encode(visitUrl) + ",sign-in=" + encode(passport) + ",pwd=" + encode(password) + "," + challengeStr

其中chanllengeStr即在收到在第二次登陆服务器发送USR命令后返回的USR命令的中的字符串(具体内容参见1.3节所示),visitUrl为https://login.live.com/login2.srf。若这一过程认证失败,则ticket获取失败。

具体的代码如下

private String getLoginTicket(String visitUrl, String passport,

String password, String challengeStr)

throws IOException {

Pattern ticketPattern = Pattern.compile(".*from-PP='([^']*)'.*");

HttpsURLConnection conn = null;

try {

conn = (HttpsURLConnection) new URL(visitUrl).openConnection();

conn.setUseCaches(false);

conn.setRequestProperty("Authorization",

"Passport1.4 OrgVerb=GET,OrgURL="

+ encode(visitUrl)

+ ",sign-in="

+ encode(passport)

+ ",pwd="

+ encode(password) + ","

+ challengeStr);

switch (conn.getResponseCode()) {

case 200: //success

Matcher matcher = ticketPattern.matcher(conn

.getHeaderField("Authentication-Info"));

if (matcher.matches()) {

return matcher.group(1);

}

return null;

case 302: //redirect

visitUrl = conn.getHeaderField("Location");

return getLoginTicket(visitUrl, passport, password, challengeStr);

case 401: //failed

return null;

default:

}

} finally {

if (conn != null) {

conn.disconnect();

}

}

return null;

}

三、注意事项

【注意事项一】关于DataInputStream

在socket收到消息时,需要注意返回的内容可能有非英文字符,例如1.5节所提及到的UBX命令。在收到UBX消息时候,该消息已经指定了下面将要收到的字节数目。由于中文字符的是双字节或三字节,若直接利用socket. getInputStream方法进行读取,获取的中文部分出错或者造成读取阻塞。因此在2.1节所示的连接部分需要把InputStream利用DataInputStream进行封装。

InputStream socketInputStream = new DataInputStream(socket.getInputStream());

【注意事项二】关于发送命令

做MSN协议实现的时候,需要在命令结束发送/r/n以表示命令结束,如2.2节所示的实现,在命令后追加/r/n。

【注意事项三】关于接收命令

由于MSN服务器有时发送来的消息的数目是不确定的,例如1.4节所示的发送SYN命令后反馈得到的LSG和LST命令和1.5节所示的发送CHG命令后反馈得到的ILN命令。因此,读取服务器发送来的消息时,又不能以/r/n作为消息的结束标志。这样如果一直等待,就会在读取过程造成阻塞。

解决这个问题有2种方式。第一是利用多线程建立事件响应来处理收到的反馈。第二是先判断数据流中是否有可用信息。若无可用信息,则等待一段时间,再进行下一次判断。若连续多次都无可用信息,则退出循环。

下面给出第二种方式的具体实现

int n = 0;

while(true) {

if(getSocketInputStream().available() > 0) {

n = 0;

String command = readLineFromSocket();

//收到命令做处理

} else {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

n ++;

System.out.println("等待" + n +"秒");

if(n >= waitingSeconds) break;

}

}

上面这个程序表示在连续等待waitingSeconds秒后,此时仍然没有可以读取的数据,程序退出且不在读取。

【注意事项四】关于socket接收和发送

在做socket发送命令给服务器的时候,发送端要有唯一的入口。这就意味着在实现时只能从一个统一控制的地方获取inputStream和writer,而不能在程序中随时通过socket.getInputStream或经过包装过的reader中获取相应的数据。最后需要指出的是reader是面向字符的,而InputStream是面向字节的。

四、参考资料以及相关文档

[1] 介绍MSN协议非官方wiki http://msnpiki.msnfanatic.com/index.php/Main_Page

[2] 介绍DataInputStream的使用 http://www.javanb.com/j2se/1/5298.html

[3] 介绍MSN协议简介http://blog.csdn.net/bripengandre/archive/2008/03/20/2199924.aspx

[4] 介绍 MSNP12 的一种 Java 实现 http://java-jml.sourceforge.net/

MSN协议分析以及Java实现MSN登陆相关推荐

  1. MSN Media协议分析

    整理记录 版本 时间 内容 整理人 V1.0 2008-04-09 MSN Media协议分析初稿 彭令鹏 MSN Media协议分析 第1章.     文档说明 本文档建立在另一篇文章--<M ...

  2. 百度登陆协议分析!!!用libcurl来模拟百度登陆

    有空就分析了下百度的登陆协议. 大家看代码: size_t CURLWriteDataCallbak(char *data, size_t size, size_t nmemb, string *wr ...

  3. Skype 协议分析(2006版)

    Skype 协议分析(2006版) 整理翻译:袁建明 Angel_YY@126.com 概要: Skype是创建Kazaa的组织在2003年开发的一个基于Peer-to-Peer(对等网络)的VoIP ...

  4. webqq2协议分析和qq聊天机器人简单实现(转)

    webqq2协议分析和qq聊天机器人简单实现 转之http://hfutxf.javaeye.com/blog/800866 通过webqq接口,可以实现发送qq消息接收qq消息等,这样,想实现一个q ...

  5. Android逆向分析案例——某点评APP登陆请求数据解密

    今天,七夕,单身23载的程序汪,默默地写着博客~ 上一次的逆向分析案例中讲了如何去分析某酒店的APP登陆请求,为了进一步学习如何逆向分析以及学习其他公司的网络传输加解密,本次案例将继续就登陆请求的数据 ...

  6. 微信安卓协议分析笔记

    一.查资料 网上没找到SDK可以分析,关于微信安卓协议的文章也比较少,比较有用的是<微信交互协议和加密模式研究>,这篇论文里介绍了微信使用RSA2048与AES-CBC-128结合的加密算 ...

  7. 中国移动飞信协议分析

    登录 POST /nav/getsystemconfig.aspx HTTP/1.1 User-Agent: IIC2.0/PC 2.2.0230 Content-Type: application/ ...

  8. 飞信的协议分析(转)

      飞信的协议分析 转自:http://hi.baidu.com/nathan2007/blog/category/%B7%C9%D0%C5%D0%AD%D2%E9%B7%D6%CE%F6 作者:na ...

  9. oracle监听协议是什么意思,【ORACLE|ORACLE-TNS协议分析】TNS|协议|分析-傻大方

    『傻大方知识库摘要_ORACLE|ORACLE-TNS协议分析』TNS协议传输可以使用TCP/IP协议.使用SSL的TCP/IP协议.命名管道和IPC协议传输,其中TCP/IP协议传输是使用明文传送. ...

最新文章

  1. html标签ref,HTML: param 标签
  2. python 复制、移动文件到指定目录并修改名字
  3. C语言中指针的地址和内容
  4. discuz 版块导航function_forumlist.php,Discuz! X2“扩建”左侧版块导航 让社区层次一目了然...
  5. 从ncbi下载数据_如何从NCBI下载所有细菌组件
  6. leetcode104. 二叉树的最大深度(dfs)
  7. 使用一个程序同时启动多个程序(c#)
  8. 【codevs1074】食物链
  9. 【kafka】Kafka JMX监控报错 Failed to get broker metrics for BrokerIdentity
  10. linux 编程 调度,Linux的进程线程及调度
  11. E站账号cookie分享_58云账号跨域实践总结
  12. windows如何设定定时关机和取消定时
  13. powerbuilder mysql_powerbuilder+mysql5.0的连接过程 | 学步园
  14. c语言入门这一篇就够了-学习笔记(一万字)
  15. python3.6 exe_详解Python3.6的py文件打包生成exe
  16. 大数据平台运维之Hbase
  17. 防火墙NAT综合实验——nat控制,豁免,远程,DMZ区域(带命令)
  18. C# 小数位修约(保留小数位有效数位)
  19. 海尔微型计算机硬盘如何拆卸,海尔xqb507288拆解图
  20. 基于Matlab/Simulink的简单三相交流系统扫频仿真

热门文章

  1. 拼多多的搜索的参数anti_content怎么破
  2. 揭开三星手机CPU的神秘面纱
  3. 福建计算机会考试题及答案,福建省信息技术会考笔试201006试题答案
  4. 装机秘籍:Windows10与deepin v20双系统装机(电脑小白也能看哦!!)
  5. MATLAB实现智能计算方法实验:实验一 模糊聚类分析
  6. 基于圆展开自适应三边测量算法的室内定位
  7. 计算机下棋简史|AlphaZero完爆世界棋类冠军背后
  8. 垃圾面试官让我回去等通知!
  9. 【语音识别】基于mfcc特征模板匹配算法实现声纹识别matlab源码含GUI
  10. Appium-Python-Client下载