对Msn协议的一点点研究

这个也是好奇msn的协议还是2011年的时候写的, 就在网上找啊找啊, 可惜要不是不能用就是C++代码还有就是不完整, 到最后我也没弄成功,只到了下面这步就挂掉了......

登录成功
<=SBS 0 null
<=MSG Hotmail Hotmail 1261
=>BLP 8 BL
<=BLP 8 BL
=>ADL 9 11 <ml l="1"/>
断开与->64.4.44.92

现在公布出来吧, 代码写得不是很好, 有三个函数是改自某位老大的,不记得地方了,太久没碰了, 现在能不能用我都不知道了

  1. unit MSNClass;
  2. interface
  3. uses
  4. Windows, Classes, SysUtils, IdTCPConnection, IdTCPClient,
  5. xmldom, XMLIntf, msxmldom, XMLDoc, ComObj, Variants, wcrypt2, Forms, CnDebug;
  6. type
  7. tagMSGUSRKEY = record
  8. uStructHeaderSize: ULONG;
  9. uCryptMode: ULONG;
  10. uCipherType: ULONG;
  11. uHashType: ULONG;
  12. uIVLen: ULONG;
  13. uHashLen: ULONG;
  14. uCipherLen: ULONG;
  15. aIVBytes: array[0..07] of Byte;
  16. aHashBytes: array[0..19] of Byte;
  17. aCipherBytes: array[0..71] of Byte;
  18. end;
  19. TMSGUSERKEY = tagMSGUSRKEY;
  20. PMSGUSERKEY = ^TMSGUSERKEY;
  21. const
  22. STDKEYHDRSIZE = 12;
  23. cKeyStdHeader: array[0..11] of Byte = ($08, $02, $00, $00, $03, $66, $00, $00,
  24. $18, $00, $00, $00);
  25. type
  26. TMSN = class(TObject)
  27. private
  28. //FIdTcp: TIdTCPClient; {连接服务器和收发的}
  29. //FXML  : TXMLDocument; {xml文档处理}
  30. FServer: string; //服务器地址
  31. FPort: Integer; //端口
  32. FStream: TMemoryStream;
  33. FPassport_url: string; //密码登录地址
  34. FProtocol: string; //协议
  35. FBuildver: string; //编译版本号
  36. Fprod_key: string; //应该是个密题之类的
  37. Fprod_id: string;
  38. //Flogin_method: string;  //登录方式
  39. //      Fclientid: DWORD;       //客户id
  40. Fpassport_policy: string;
  41. //FBinarySecurityToken:string;
  42. //FBinarySecret:string;
  43. function HtmlSpecialChars(s: string): string;
  44. public
  45. Fuser: string;
  46. Fpassword: string;
  47. FBinarySecurityToken: string;
  48. FBinarySecret: string;
  49. constructor Create(UserName, PassWord: string);
  50. destructor Destroy; override;
  51. function http_Get(url: PAnsiChar): string;
  52. function http_Post(url, Param: PAnsiChar): string;
  53. function http_Post2(url, Param: PAnsiChar): Boolean;
  54. function PostXMLFile(UserName, Password: string): string;
  55. function GetXMLFile: Boolean; //这里应试返回一个结构体
  56. function Get_passport_ticket: Boolean;
  57. function GetSSOKey(Nonce: string): string;
  58. function GenerateLoginBlob(key: string; Challenge: string): string;
  59. end;
  60. function CryptStringToBinary(pszString: PChar; cchString: DWORD; dwFlags: DWORD;
  61. pbBinary: PByte; pcbBinary: PDWORD; pdwSkip: PDWORD; pdwFlags: PDWORD): BOOL;
  62. stdcall; external CRYPT32 Name 'CryptStringToBinaryA';
  63. function CryptDuplicateKey(hKey: HCRYPTKEY; pdwReserved: PDWORD; dwFlags: DWORD;
  64. phKey: PHCRYPTKEY): BOOL; stdcall; external ADVAPI32 Name 'CryptDuplicateKey';
  65. function CryptBinaryToString(pbBinary: PByte; cbBinary: DWORD; dwFlags: DWORD;
  66. pszString: PChar; pcchString: PDWORD): BOOL; stdcall; external CRYPT32 Name
  67. 'CryptBinaryToStringA';
  68. //function HMACHash(hProvider: HCRYPTPROV; hKey: HCRYPTKEY;HashAlgId: ALG_ID; pBytesOut: Pointer; dwLengthOut: DWORD; pBytesIn1: PByte; dwLengthIn1: DWORD; pBytesIn2: PByte; dwLengthIn2: DWORD):BooL;stdcall;external 'MSNSSOKey.dll' Name 'HMACHash';
  69. //function DeriveLoginKey(key: PByte; dwKeySize: DWORD; magic:string; pOutBytes: PBYTE; dwOutLen: DWORD):BooL;stdcall;external 'MSNSSOKey.dll' Name 'DeriveLoginKey';
  70. implementation
  71. constructor TMSN.Create(UserName, PassWord: string);
  72. begin
  73. CoInitializeEx(nil, 2); //nil, 2;
  74. Fuser := UserName;
  75. Fpassword := PassWord;
  76. //Client_Id := $7000800C;
  77. FServer := 'messenger.hotmail.com';
  78. FPort := 1863;
  79. FPassport_url := 'https://login.live.com/RST.srf';
  80. FProtocol := 'MSNP15';
  81. FBuildver := '8.1.0178';
  82. Fprod_key := 'PK}_A_0N_K%O?A9S';
  83. Fprod_id := 'PROD0114ES4Z%Q5W';
  84. Fpassport_policy := 'MBI_KEY_OLD';
  85. FStream := TMemoryStream.Create;
  86. {
  87. messengerclear.live.com:用于msn的认证
  88. messenger.msn.com:msn网页认证
  89. contacts.msn.com:Contact server 的认证
  90. spaces.msn.com:msn spaces 的认证
  91. }
  92. end;
  93. destructor TMSN.Destroy;
  94. begin
  95. FStream.Free;
  96. //FreeAndNil(FXML);
  97. //FreeAndNil(FIdTcp);
  98. //FreeAndNil(FIdhtp);
  99. //FreeAndNil(FHandle);
  100. inherited;
  101. end;
  102. (*转换特殊字符到html标记*)
  103. function TMSN.HtmlSpecialChars(s: string): string;
  104. var
  105. TEMP: string;
  106. begin
  107. TEMP := StringReplace(s, '&', '&', [rfReplaceAll]);
  108. TEMP := StringReplace(TEMP, '"', '"', [rfReplaceAll]);
  109. TEMP := StringReplace(TEMP, '''', ''', [rfReplaceAll]);
  110. TEMP := StringReplace(TEMP, '<', '<', [rfReplaceAll]);
  111. TEMP := StringReplace(TEMP, '>', '>', [rfReplaceAll]);
  112. Result := TEMP;
  113. end;
  114. (*post操作,保存为string*)
  115. function TMSN.http_Post(url, Param: PAnsiChar): string;
  116. var
  117. PostVar: Variant;
  118. begin
  119. Result := '';
  120. try
  121. PostVar := CreateOleObject('MSXML2.XMLHTTP');
  122. try
  123. PostVar.Open('POST', AnsiString(url), False);
  124. PostVar.SetRequestHeader('Accept', 'text/html, */*');
  125. PostVar.SetRequestHeader('User-Agent',
  126. 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)');
  127. PostVar.SetRequestHeader('Accept-Language', 'zh-cn');
  128. PostVar.SetRequestHeader('Content-Type', 'text/html');
  129. PostVar.SetRequestHeader('Connection', 'keep-Alive');
  130. PostVar.Send(AnsiString(Param));
  131. //if ChrType = TO_ANSI then
  132. // Result := PAnsiChar(Utf8ToAnsi(PostVar.ResponseText))
  133. //else
  134. Result := AnsiString(PostVar.ResponseText);
  135. finally
  136. PostVar := Unassigned;
  137. end;
  138. except
  139. on E: Exception do
  140. Result := E.message;
  141. end;
  142. end;
  143. (*post操作,保存为流*)
  144. function TMSN.http_Post2(url, Param: PAnsiChar): Boolean;
  145. var
  146. PostVar: Variant;
  147. s: PChar;
  148. begin
  149. Result := False;
  150. try
  151. PostVar := CreateOleObject('MSXML2.XMLHTTP');
  152. FStream.Clear;
  153. try
  154. PostVar.Open('POST', AnsiString(url), False);
  155. PostVar.SetRequestHeader('Accept', 'text/html, */*');
  156. PostVar.SetRequestHeader('User-Agent',
  157. 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)');
  158. PostVar.SetRequestHeader('Accept-Language', 'zh-cn');
  159. PostVar.SetRequestHeader('Content-Type', 'text/html');
  160. PostVar.SetRequestHeader('Connection', 'keep-Alive');
  161. PostVar.Send(AnsiString(Param));
  162. s := PChar(AnsiString(PostVar.ResponseText));
  163. FStream.Seek(0, soBeginning);
  164. FStream.Write(s^, Length(s));
  165. Result := True;
  166. finally
  167. PostVar := Unassigned;
  168. end;
  169. except
  170. on E: Exception do
  171. OutputDebugString(PChar(E.Message));
  172. //Result := E.message;
  173. end;
  174. end;
  175. (*网络get*)
  176. function TMSN.http_Get(url: PAnsiChar): string;
  177. var
  178. GetVar: Variant;
  179. begin
  180. Result := '';
  181. try
  182. GetVar := CreateOleObject('MSXML2.XMLHTTP');
  183. try
  184. GetVar.Open('GET', AnsiString(url), False);
  185. GetVar.SetRequestHeader('Accept', 'text/html, */*');
  186. GetVar.SetRequestHeader('User-Agent',
  187. 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)');
  188. GetVar.SetRequestHeader('Accept-Language', 'zh-cn');
  189. GetVar.SetRequestHeader('Content-Type', 'text/html');
  190. GetVar.SetRequestHeader('Connection', 'keep-Alive');
  191. GetVar.Send('');
  192. //if ChrType = TO_ANSI then
  193. // Result := PAnsiChar(Utf8ToAnsi(GetVar.ResponseText))
  194. //else
  195. Result := AnsiString(GetVar.ResponseText);
  196. finally
  197. GetVar := Unassigned;
  198. end;
  199. except
  200. end;
  201. end;
  202. (*够造一个xml文档*)
  203. function TMSN.PostXMLFile(UserName, Password: string): string;
  204. var
  205. Param: TStringList;
  206. begin
  207. Result := '';
  208. Param := TStringList.Create;
  209. Param.Clear;
  210. try
  211. Param.Add('<?xml version="1.0" encoding="UTF-8" ?> ');
  212. Param.Add('<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/06/secext" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" ');
  213. Param.Add('xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" ');
  214. Param.Add('xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" xmlns:wssc="http://schemas.xmlsoap.org/ws/2004/04/sc" xmlns:wst="http://schemas.xmlsoap.org/ws/2004/04/trust">');
  215. Param.Add('<Header>');
  216. Param.Add('<ps:AuthInfo xmlns:ps="http://schemas.microsoft.com/Passport/SoapServices/PPCRL" Id="PPAuthInfo">');
  217. Param.Add('  <ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp> ');
  218. Param.Add('  <ps:BinaryVersion>4</ps:BinaryVersion> ');
  219. Param.Add('  <ps:UIVersion>1</ps:UIVersion> ');
  220. Param.Add('  <ps:Cookies /> ');
  221. Param.Add('  <ps:RequestParams>AQAAAAIAAABsYwQAAAAyMDUy</ps:RequestParams> ');
  222. Param.Add('  </ps:AuthInfo>');
  223. Param.Add('<wsse:Security>');
  224. Param.Add('<wsse:UsernameToken Id="user">');
  225. Param.Add('  <wsse:Username>' + UserName + '</wsse:Username> ');
  226. Param.Add('  <wsse:Password>' + Password + '</wsse:Password> ');
  227. Param.Add('  </wsse:UsernameToken>');
  228. Param.Add('  </wsse:Security>');
  229. Param.Add('  </Header>');
  230. Param.Add('<Body>');
  231. Param.Add('<ps:RequestMultipleSecurityTokens xmlns:ps="http://schemas.microsoft.com/Passport/SoapServices/PPCRL" Id="RSTS">');
  232. Param.Add('<wst:RequestSecurityToken Id="RST0">');
  233. Param.Add('  <wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType> ');
  234. Param.Add('<wsp:AppliesTo>');
  235. Param.Add('<wsa:EndpointReference>');
  236. Param.Add('  <wsa:Address>http://Passport.NET/tb</wsa:Address> ');
  237. Param.Add('  </wsa:EndpointReference>');
  238. Param.Add('  </wsp:AppliesTo>');
  239. Param.Add('  </wst:RequestSecurityToken>');
  240. Param.Add('<wst:RequestSecurityToken Id="RST1">');
  241. Param.Add('  <wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType> ');
  242. Param.Add('<wsp:AppliesTo>');
  243. Param.Add('<wsa:EndpointReference>');
  244. Param.Add('  <wsa:Address>messengerclear.live.com</wsa:Address> ');
  245. Param.Add('  </wsa:EndpointReference>');
  246. Param.Add('  </wsp:AppliesTo>');
  247. Param.Add('  <wsse:PolicyReference URI="MBI_KEY_OLD" /> ');
  248. Param.Add('  </wst:RequestSecurityToken>');
  249. Param.Add('<wst:RequestSecurityToken Id="RST2">');
  250. Param.Add('  <wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType> ');
  251. Param.Add('<wsp:AppliesTo>');
  252. Param.Add('<wsa:EndpointReference>');
  253. Param.Add('  <wsa:Address>messenger.msn.com</wsa:Address> ');
  254. Param.Add('  </wsa:EndpointReference>');
  255. Param.Add('  </wsp:AppliesTo>');
  256. Param.Add('  <wsse:PolicyReference URI="?id=507" /> ');
  257. Param.Add('  </wst:RequestSecurityToken>');
  258. Param.Add('<wst:RequestSecurityToken Id="RST3">');
  259. Param.Add('  <wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType> ');
  260. Param.Add('<wsp:AppliesTo>');
  261. Param.Add('<wsa:EndpointReference>');
  262. Param.Add('  <wsa:Address>contacts.msn.com</wsa:Address> ');
  263. Param.Add('  </wsa:EndpointReference>');
  264. Param.Add('  </wsp:AppliesTo>');
  265. Param.Add('  <wsse:PolicyReference URI="MBI" /> ');
  266. Param.Add('  </wst:RequestSecurityToken>');
  267. Param.Add('<wst:RequestSecurityToken Id="RST4">');
  268. Param.Add('  <wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType> ');
  269. Param.Add('<wsp:AppliesTo>');
  270. Param.Add('<wsa:EndpointReference>');
  271. Param.Add('  <wsa:Address>messengersecure.live.com</wsa:Address> ');
  272. Param.Add('  </wsa:EndpointReference>');
  273. Param.Add('  </wsp:AppliesTo>');
  274. Param.Add('  <wsse:PolicyReference URI="MBI_SSL" /> ');
  275. Param.Add('  </wst:RequestSecurityToken>');
  276. Param.Add('<wst:RequestSecurityToken Id="RST5">');
  277. Param.Add('  <wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType> ');
  278. Param.Add('<wsp:AppliesTo>');
  279. Param.Add('<wsa:EndpointReference>');
  280. Param.Add('  <wsa:Address>spaces.live.com</wsa:Address> ');
  281. Param.Add('  </wsa:EndpointReference>');
  282. Param.Add('  </wsp:AppliesTo>');
  283. Param.Add('  <wsse:PolicyReference URI="MBI" /> ');
  284. Param.Add('  </wst:RequestSecurityToken>');
  285. Param.Add('<wst:RequestSecurityToken Id="RST6">');
  286. Param.Add('  <wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType> ');
  287. Param.Add('<wsp:AppliesTo>');
  288. Param.Add('<wsa:EndpointReference>');
  289. Param.Add('  <wsa:Address>storage.msn.com</wsa:Address> ');
  290. Param.Add('  </wsa:EndpointReference>');
  291. Param.Add('  </wsp:AppliesTo>');
  292. Param.Add('  <wsse:PolicyReference URI="MBI" /> ');
  293. Param.Add('  </wst:RequestSecurityToken>');
  294. Param.Add('  </ps:RequestMultipleSecurityTokens>');
  295. Param.Add('  </Body>');
  296. Param.Add('  </Envelope>');
  297. //返回结果
  298. Result := Param.Text;
  299. finally
  300. Param.Free;
  301. end;
  302. end;
  303. (*解析返回来的xml文档*)
  304. function TMSN.GetXMLFile: Boolean;
  305. var
  306. XML: TXMLDocument;
  307. Root, Parent, Child, SChild, BinarySecurityTokenNode, BinarySecretNode:
  308. IXMLNode;
  309. begin
  310. Result := False;
  311. if FStream.Size > 0 then
  312. begin
  313. XML := TXMLDocument.Create(Application);
  314. try
  315. try
  316. FStream.SaveToFile('test1.xml');
  317. XML.LoadFromStream(FStream);
  318. XML.Active := True;
  319. Root := XML.DocumentElement;
  320. Parent := Root.ChildNodes.First;
  321. while Parent <> nil do
  322. begin
  323. if Parent.NodeName = 'S:Body' then //第二个节点
  324. begin
  325. Child := Parent.ChildNodes.First;
  326. //第一个节点wst:RequestSecurityTokenResponseCollection
  327. if Child <> nil then
  328. begin
  329. SChild := Child.ChildNodes.First; //然后是指向父节点的子节点
  330. SChild := SChild.NextSibling;     //第一个不是需要的所以下一个
  331. while SChild <> nil do
  332. begin
  333. if SChild.NodeName = 'wst:RequestSecurityTokenResponse' then
  334. begin
  335. BinarySecurityTokenNode :=
  336. SChild.ChildNodes.FindNode('wst:RequestedSecurityToken');
  337. BinarySecretNode :=
  338. SChild.ChildNodes.FindNode('wst:RequestedProofToken');
  339. if (BinarySecurityTokenNode <> nil) and (BinarySecretNode <>
  340. nil) then
  341. begin
  342. FBinarySecurityToken :=
  343. BinarySecurityTokenNode.ChildNodes.First.NodeValue;
  344. FBinarySecret :=
  345. BinarySecretNode.ChildNodes.First.NodeValue;
  346. Result := True;
  347. end;
  348. //临时加上
  349. Break;
  350. end;
  351. SChild := SChild.NextSibling;
  352. end;
  353. end;
  354. Break;
  355. end;
  356. Parent := Parent.NextSibling;
  357. end;
  358. XML.Active := False;
  359. finally
  360. XML.Free;
  361. end;
  362. except
  363. end;
  364. end;
  365. end;
  366. (*取得认证的Key*)
  367. function TMSN.Get_passport_ticket: Boolean;
  368. var
  369. user, password, passport_url: string;
  370. begin
  371. Result := False;
  372. user := Fuser;
  373. password := HtmlSpecialChars(Fpassword);
  374. passport_url := FPassport_url;
  375. try
  376. Result :=
  377. http_Post2(PChar(passport_url), PChar(PostXMLFile(user, password)));
  378. except
  379. on E: Exception do
  380. OutputDebugString(PChar(E.Message));
  381. end;
  382. end;
  383. (*返回登录的SSO验证*)
  384. function TMSN.GetSSOKey(Nonce: string): string;
  385. begin
  386. Result := GenerateLoginBlob(FBinarySecret, Nonce);
  387. end;
  388. ///=============================================================================
  389. function HMACHash(hProvider: HCRYPTPROV; hKey: HCRYPTKEY; HashAlgId: ALG_ID;
  390. pBytesOut: Pointer; dwLengthOut: DWORD; pBytesIn1: PByte; dwLengthIn1: DWORD;
  391. pBytesIn2: PByte; dwLengthIn2: DWORD): Boolean;
  392. var
  393. hHash: HCRYPTHASH;
  394. hmcinfo: HMAC_INFO;
  395. dwHashSize, dwParamSize: DWORD;
  396. begin
  397. Result := False;
  398. if CryptCreateHash(hProvider, CALG_HMAC, hKey, 0, @hHash) then
  399. begin
  400. ZeroMemory(@hmcinfo, sizeof(HMAC_INFO));
  401. hmcinfo.HashAlgid := HashAlgId;
  402. CryptSetHashParam(hHash, HP_HMAC_INFO, PBYTE(@hmcinfo), 0);
  403. if CryptHashData(hHash, pBytesIn1, dwLengthIn1, 0) then
  404. begin
  405. if (dwLengthIn2 <> 0) and (pBytesIn2 <> nil) then
  406. CryptHashData(hHash, pBytesIn2, dwLengthIn2, 0);
  407. dwParamSize := 4;
  408. if CryptGetHashParam(hHash, HP_HASHSIZE, PBYTE(@dwHashSize), @dwParamSize,
  409. 0) then
  410. begin
  411. if dwHashSize <= dwLengthOut then
  412. begin
  413. dwParamSize := dwLengthOut;
  414. if CryptGetHashParam(hHash, HP_HASHVAL, pBytesOut, @dwParamSize, 0)
  415. then
  416. Result := True;
  417. end;
  418. end;
  419. end;
  420. CryptDestroyHash(hHash);
  421. end;
  422. end;
  423. function DeriveLoginKey(key: PByte; dwKeySize: DWORD; magic: string; pOutBytes:
  424. PBYTE; dwOutLen: DWORD): Boolean;
  425. var
  426. hProvider: HCRYPTPROV;
  427. hCryptKey1: HCRYPTKEY;
  428. pImportKey: array of Byte;
  429. bHash1, bHash2, bHash3, bHash4: array[0..19] of Byte;
  430. begin
  431. Result := False;
  432. if CryptAcquireContext(@hProvider, nil, nil, PROV_RSA_FULL, 0) then
  433. begin
  434. SetLength(pImportKey, dwKeySize + STDKEYHDRSIZE);
  435. MoveMemory(pImportKey, @cKeyStdHeader[0], STDKEYHDRSIZE);
  436. MoveMemory(@pImportKey[STDKEYHDRSIZE], key, dwKeySize);
  437. pImportKey[2] := dwKeySize;
  438. if CryptImportKey(hProvider, PByte(pImportKey), dwKeySize + STDKEYHDRSIZE,
  439. 0, CRYPT_SF, @hCryptKey1) then
  440. begin
  441. HMACHash(hProvider, hCryptKey1, CALG_SHA1, @bHash1, 20,
  442. PBYTE(PChar(magic)), Length(magic), nil, 0);
  443. HMACHash(hProvider, hCryptKey1, CALG_SHA1, @bHash2, 20, @bHash1[0], 20,
  444. PBYTE(PChar(magic)), Length(magic));
  445. HMACHash(hProvider, hCryptKey1, CALG_SHA1, @bHash3, 20, @bHash1[0], 20,
  446. nil, 0);
  447. HMACHash(hProvider, hCryptKey1, CALG_SHA1, @bHash4, 20, @bHash3[0], 20,
  448. PBYTE(PChar(magic)), Length(magic));
  449. if dwOutLen >= 24 then
  450. begin
  451. MoveMemory(pOutBytes, @Bhash2[0], 20);
  452. Inc(pOutBytes, 20);
  453. MoveMemory(pOutBytes, @Bhash4[0], 4);
  454. Result := True;
  455. end;
  456. CryptDestroyKey(hCryptKey1);
  457. end;
  458. SetLength(pImportKey, 0);
  459. CryptReleaseContext(hProvider, 0);
  460. end;
  461. end;
  462. function TMSN.GenerateLoginBlob(key: string; Challenge: string): string;
  463. var
  464. key1, key2, key3: array[0..23] of Byte;
  465. hash: array[0..19] of Byte;
  466. Randomdata: array[0..7] of Byte;
  467. szRet: string;
  468. dwBase64Size: DWORD;
  469. hProvider: HCRYPTPROV;
  470. hCryptKey1, hCryptKey2: HCRYPTKEY;
  471. pImportKey: array of Byte;
  472. hKeyDupe1, hKeyDupe2: HCRYPTKEY;
  473. hHash: HCRYPTHASH;
  474. dwMode: DWORD;
  475. hmcinfo: HMAC_INFO;
  476. dwDataLen, dwData: DWORD;
  477. pEncryptBytes: array of Byte;
  478. usrkey: tagMSGUSRKEY;
  479. buffer: PChar;
  480. const
  481. CRYPT_STRING_BASE64 = $00000001;
  482. begin
  483. with usrkey do
  484. begin
  485. uStructHeaderSize := 28;
  486. uCryptMode := CRYPT_MODE_CBC;
  487. uCipherType := CALG_3DES;
  488. uHashType := CALG_SHA1;
  489. uIVLen := sizeof(aIVBytes);
  490. uHashLen := sizeof(aHashBytes);
  491. uCipherLen := sizeof(aCipherBytes);
  492. end;
  493. CryptStringToBinary(PChar(key), 0, CRYPT_STRING_BASE64, nil, @dwBase64Size,
  494. nil, nil);
  495. ASSERT(dwBase64Size <= 24);
  496. if dwBase64Size > 24 then
  497. begin
  498. Result := '';
  499. Exit;
  500. end;
  501. dwBase64Size := 24;
  502. CryptStringToBinary(PChar(key), 0, CRYPT_STRING_BASE64, @key1, @dwBase64Size,
  503. nil, nil);
  504. DeriveLoginKey(@key1[0], 24, 'WS-SecureConversationSESSION KEY HASH', @key2,
  505. 24);
  506. DeriveLoginKey(@key1[0], 24, 'WS-SecureConversationSESSION KEY ENCRYPTION',
  507. @key3, 24);
  508. if CryptAcquireContext(@hProvider, nil, nil, PROV_RSA_FULL, 0) then
  509. begin
  510. SetLength(pImportKey, 24 + STDKEYHDRSIZE);
  511. MoveMemory(pImportKey, @cKeyStdHeader[0], STDKEYHDRSIZE);
  512. MoveMemory(@pImportKey[STDKEYHDRSIZE], @key2[0], 24);
  513. CryptImportKey(hProvider, PByte(pImportKey), 24 + STDKEYHDRSIZE, 0,
  514. CRYPT_SF, @hCryptKey2);
  515. MoveMemory(@pImportKey[STDKEYHDRSIZE], @key3[0], 24);
  516. if CryptImportKey(hProvider, Pbyte(pImportKey), 24 + STDKEYHDRSIZE, 0,
  517. CRYPT_SF, @hCryptKey1) then
  518. begin
  519. CryptDuplicateKey(hCryptKey1, nil, 0, @hKeyDupe1);
  520. dwMode := CRYPT_MODE_CBC;
  521. CryptSetKeyParam(hKeyDupe1, KP_MODE, @dwMode, 0);
  522. if CryptCreateHash(hProvider, CALG_HMAC, hCryptKey2, 0, @hHash) then
  523. begin
  524. ZeroMemory(@hmcinfo, sizeof(HMAC_INFO));
  525. hmcinfo.HashAlgid := CALG_SHA1;
  526. CryptSetHashParam(hHash, HP_HMAC_INFO, @hmcinfo, 0);
  527. dwDataLen := Length(Challenge);
  528. CryptDuplicateKey(hKeyDupe1, nil, 0, @hKeyDupe2);
  529. CryptEncrypt(hKeyDupe2, 0, TRUE, 0, nil, @dwDataLen, 0);
  530. CryptDestroyKey(hKeyDupe2);
  531. if dwDataLen > 0 then
  532. begin
  533. CryptGenRandom(hProvider, 8, @RandomData);
  534. CryptSetKeyParam(hKeyDupe1, KP_IV, @RandomData[0], 0);
  535. SetLength(pEncryptBytes, dwDataLen);
  536. ZeroMemory(pEncryptBytes, dwDataLen);
  537. MoveMemory(pEncryptBytes, PChar(Challenge), Length(Challenge));
  538. dwData := Length(Challenge);
  539. if CryptEncrypt(hKeyDupe1, hHash, TRUE, 0, PByte(pEncryptBytes),
  540. @dwData, dwDataLen) then
  541. begin
  542. ASSERT(dwData = 72);
  543. dwData := 20;
  544. //我想死了,检查了N遍都没有检查出来少了下面一句
  545. CryptGetHashParam(hHash, HP_HASHVAL, @hash, @dwData, 0);
  546. MoveMemory(@usrkey.aIVBytes[0], @RandomData[0], 8);
  547. MoveMemory(@usrkey.aHashBytes[0], @hash[0], 20);
  548. MoveMemory(@usrkey.aCipherBytes[0], pEncryptBytes, 72);
  549. CryptBinaryToString(@usrkey, Sizeof(tagMSGUSRKEY),
  550. CRYPT_STRING_BASE64, nil, @dwBase64Size);
  551. GetMem(buffer, dwBase64Size);
  552. try
  553. CryptBinaryToString(@usrkey, sizeof(tagMSGUSRKEY),
  554. CRYPT_STRING_BASE64, buffer, @dwBase64Size);
  555. szRet := StringReplace(buffer, #13#10, '', [rfReplaceAll]);
  556. finally
  557. FreeMem(buffer);
  558. end;
  559. end;
  560. SetLength(pEncryptBytes, 0);
  561. end;
  562. CryptDestroyHash(hHash);
  563. end;
  564. CryptDestroyKey(hKeyDupe1);
  565. CryptDestroyKey(hCryptKey1);
  566. end;
  567. SetLength(pImportKey, 0);
  568. if hCryptKey2 > 0 then
  569. CryptDestroyKey(hCryptKey2);
  570. CryptReleaseContext(hProvider, 0);
  571. end;
  572. Result := szRet;
  573. end;
  574. end.
    1. unit UMain;
    2. interface
    3. uses
    4. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    5. Dialogs, ScktComp, StdCtrls, ComObj, CnDebug, Sockets, StrUtils, MsnClass,
    6. IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;
    7. type
    8. TForm1 = class(TForm)
    9. btn1: TButton;
    10. mmo1: TMemo;
    11. btn2: TButton;
    12. btn4: TButton;
    13. clntsckt1: TClientSocket;
    14. btn3: TButton;
    15. IdTCPClient1: TIdTCPClient;
    16. btn5: TButton;
    17. lbl1: TLabel;
    18. edt1: TEdit;
    19. lbl2: TLabel;
    20. edt2: TEdit;
    21. edt3: TEdit;
    22. mmo2: TMemo;
    23. btn6: TButton;
    24. procedure btn1Click(Sender: TObject);
    25. procedure btn4Click(Sender: TObject);
    26. procedure btn2Click(Sender: TObject);
    27. procedure clntsckt1Connect(Sender: TObject; Socket: TCustomWinSocket);
    28. procedure clntsckt1Connecting(Sender: TObject;
    29. Socket: TCustomWinSocket);
    30. procedure clntsckt1Disconnect(Sender: TObject;
    31. Socket: TCustomWinSocket);
    32. procedure clntsckt1Error(Sender: TObject; Socket: TCustomWinSocket;
    33. ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    34. procedure btn3Click(Sender: TObject);
    35. procedure clntsckt1Read(Sender: TObject; Socket: TCustomWinSocket);
    36. procedure IdTCPClient1Connected(Sender: TObject);
    37. procedure IdTCPClient1Disconnected(Sender: TObject);
    38. procedure btn5Click(Sender: TObject);
    39. procedure btn6Click(Sender: TObject);
    40. private
    41. { Private declarations }
    42. public
    43. { Public declarations }
    44. end;
    45. type
    46. TClientListen = class(TThread)
    47. private
    48. MSN: TMSN;
    49. FSecond: string;
    50. ProtocolNum: Integer;
    51. NSAddress: string;
    52. NSPort: Integer;
    53. FNonce: string;
    54. FSSOKey: string;
    55. FGivenPolicy :string;
    56. UserName, Password: string;
    57. //    FSocket: TClientSocket;
    58. { Private declarations }
    59. public
    60. Msg: string;
    61. procedure SendCmd(Cmd: string; Params: string);
    62. function IncProNum: Integer;
    63. function GetCmd(s: string): string;
    64. function GetSecondCmd(s: string): string;
    65. procedure GetNSAddr(s: string);
    66. procedure GetNonce(s: string);
    67. function GetPolicySize(s:string):Cardinal;
    68. function GetMsn(s:string; Postion: integer):Variant;
    69. protected
    70. procedure Execute; override;
    71. procedure Start;
    72. end;
    73. var
    74. Form1: TForm1;
    75. ttclnt: TClientListen;
    76. MessageInfo: string;
    77. implementation
    78. uses Unit2;
    79. {$R *.dfm}
    80. //{$L File1.obj}
    81. function GenerateLoginBlob(key: PChar; challenge: PChar):PChar;stdcall; external 'MSNSSOKey.dll';// Name 'GenerateLoginBlob';
    82. procedure TClientListen.Execute;
    83. begin
    84. //  FSocket : = TClientSocket.Create(nil);
    85. //  FSocket.Service := '';
    86. // FSocket.Port := ;
    87. // FSocket.Active := True;
    88. MSN := TMSN.Create(UserName , Password);
    89. FreeOnTerminate := True;
    90. ProtocolNum := 1;
    91. while not Terminated do
    92. begin
    93. Start;
    94. Sleep(300);
    95. end;
    96. MSN.Free;
    97. // FreeAndNil(FSocket);
    98. end;
    99. procedure TClientListen.Start;
    100. var
    101. cmd, s, s2: string;
    102. begin
    103. try
    104. MessageInfo := '';
    105. MessageInfo := form1.IdTCPClient1.ReadLn();
    106. except
    107. Terminate;
    108. end;
    109. if MessageInfo <> '' then
    110. begin
    111. s := MessageInfo;
    112. cmd := GetCmd(s);
    113. //if cmd <> 'GCF' then
    114. Form1.mmo1.Lines.Add('<=' + s);
    115. if cmd = 'VER' then
    116. SendCmd('CVR', '0x0804 winnt 5.1 i386 MSG80BETA 8.5.1238 msmsgs ' +
    117. MSN.FUser);
    118. if cmd = 'CVR' then
    119. SendCmd('USR', 'SSO I ' + MSN.FUser);
    120. if cmd = 'XFR' then
    121. begin
    122. GetNSAddr(s);
    123. //if Form1.clntsckt1.Socket.Connected then
    124. //  Form1.clntsckt1.Close;
    125. if form1.IdTCPClient1.Connected then
    126. form1.IdTCPClient1.Disconnect;
    127. Sleep(1000) ;
    128. // Form1.clntsckt1.Host := '';
    129. // Form1.clntsckt1.Address := NSAddress;
    130. // Form1.clntsckt1.Port := NSPort;
    131. Form1.IdTCPClient1.Host := NSAddress;
    132. form1.IdTCPClient1.Port := NSPort;
    133. repeat
    134. //if not Form1.clntsckt1.Socket.Connected then
    135. //begin
    136. //  Form1.clntsckt1.Open;
    137. //end;
    138. if not Form1.IdTCPClient1.Connected then
    139. form1.IdTCPClient1.Connect(8000);
    140. Sleep(1500);
    141. // until (Form1.clntsckt1.Socket.Connected) or (Terminated);
    142. until (form1.IdTCPClient1.Connected) or (Terminated);
    143. SendCmd('VER', 'MSNP15 CVR0');
    144. end;
    145. if cmd = 'USR' then
    146. begin
    147. FSecond := GetSecondCmd(s);
    148. // CnDebugger.LogMsg(FSecond + '  二级登录');
    149. if FSecond = 'OK' then
    150. Form1.mmo1.Lines.Add('登录成功')
    151. else if FSecond = 'SSO' then
    152. begin
    153. MSN.Get_passport_ticket;
    154. MSN.GetXMLFile;
    155. if Form1.IdTCPClient1.Connected then
    156. begin
    157. GetNonce(s);
    158. if FNonce <> '' then
    159. begin
    160. FSSOKey := MSN.GetSSOKey(FNonce);
    161. // FSSOKey := GenerateLoginBlob(PChar(MSN.FBinarySecret), PChar(FNonce));
    162. // FSSOKey := StringReplace(FSSOKey, #13#10, '', [rfReplaceAll]);
    163. //FSSOKey := StringReplace(FSSOKey, 'k', 'g', [rfIgnoreCase]);
    164. //s2 := LeftStr(FSSOKey, Pos('k', FSSOKey) - 1) + 'g' + RightStr(FSSOKey, Length(FSSOKey) - 23);
    165. SendCmd('USR', 'SSO S ' + MSN.FBinarySecurityToken + ' ' + FSSOKey);
    166. end;
    167. end;
    168. end;
    169. end ;
    170. if cmd = 'GCF' then
    171. begin
    172. FGivenPolicy := form1.IdTCPClient1.ReadString(GetPolicySize(s));
    173. end;
    174. if cmd = 'MSG' then
    175. begin
    176. FGivenPolicy := Form1.IdTCPClient1.ReadString(GetMsn(s, 4));
    177. SendCmd('BLP', 'BL');
    178. form1.mmo2.Lines.Add(FGivenPolicy);
    179. end;
    180. if cmd = 'BLP' then
    181. SendCmd('ADL','11 <ml l="1"/>');
    182. end;
    183. end;
    184. procedure TClientListen.SendCmd(Cmd: string; Params: string);
    185. var
    186. s:string;
    187. begin
    188. //if Form1.clntsckt1.Socket.Connected then
    189. if form1.IdTCPClient1.Connected then
    190. begin
    191. s := Format('%s %d %s'{#13#10}, [Cmd, IncProNum,Params]);
    192. form1.IdTCPClient1.WriteLn(s);
    193. //form1.clntsckt1.Socket.SendText(s);
    194. form1.mmo1.Lines.Add('=>' + s);
    195. end;
    196. end;
    197. function TClientListen.IncProNum: Integer;
    198. begin
    199. Inc(ProtocolNum);
    200. Result := ProtocolNum;
    201. end;
    202. function TClientListen.GetCmd(s: string): string;
    203. begin
    204. Result := '';
    205. if s <> '' then
    206. Result := Trim(Copy(s, 1, 3));
    207. // CnDebugger.LogFmt('%s->%s', [Result, s]);
    208. end;
    209. function TClientListen.GetSecondCmd(s: string): string;
    210. begin
    211. Result := Trim(Copy(s, 7, 3));
    212. //CnDebugger.LogMsg(Result + '第二个命令:');
    213. end;
    214. procedure TClientListen.GetNSAddr(s: string);
    215. var
    216. p1, p2, p3, code: integer;
    217. s1: string;
    218. begin
    219. p1 := PosEx('NS ', S, 2);
    220. p2 := PosEx(' U D', s, p1);
    221. if (p1 > 0) and (p2 > 0) then
    222. begin
    223. s1 := Copy(s, p1 + 3, p2 - p1 - 3);
    224. p3 := Posex(':', s1, 2);
    225. if p3 > 0 then
    226. begin
    227. NSAddress := Trim(Copy(s1, 1, p3 - 1));
    228. Val(Copy(s1, p3 + 1, Length(s1) - p3), NSPort, code);
    229. end;
    230. end;
    231. end;
    232. procedure TClientListen.GetNonce(s: string);
    233. var
    234. p1: Integer;
    235. s1:string;
    236. begin
    237. s1 := 'MBI_KEY'; //MBI_KEY_OLD
    238. p1 := PosEx(s1, s, 2);
    239. if p1 > 0 then
    240. FNonce := Trim(Copy(s, p1 + Length(s1) + 1, Length(s) - p1 - Length(s1)));
    241. end;
    242. function TClientListen.GetPolicySize(s:string):Cardinal;
    243. var
    244. Code:Integer;
    245. List:TStringList;
    246. begin
    247. Result := 0;
    248. if s <> '' then
    249. begin
    250. List := TStringList.Create;
    251. try
    252. ExtractStrings([' '], [], PChar(s), List);
    253. if List.Count >= 3 then
    254. begin
    255. Val(List.Strings[2], Result, Code);
    256. end;
    257. finally
    258. List.Free;
    259. end;
    260. end;
    261. end;
    262. function TClientListen.GetMsn(s:string; Postion: integer):Variant;
    263. var
    264. List: TStringList;
    265. begin
    266. list := TStringList.Create;
    267. try
    268. ExtractStrings([' '], [], PChar(s), List);
    269. if list.Count >= Postion then
    270. Result := Trim(List.Strings[Postion - 1]);
    271. finally
    272. list.Free;
    273. end;
    274. end;
    275. //...........................................................................
    276. procedure TForm1.btn1Click(Sender: TObject);
    277. begin
    278. //clntsckt1.Active := true;
    279. IdTCPClient1.Connect(12000);
    280. ttclnt := TClientListen.Create(true);
    281. ttclnt.UserName := Trim(edt1.Text);
    282. ttclnt.Password := Trim(edt2.Text);
    283. ttclnt.Resume;
    284. end;
    285. procedure TForm1.btn4Click(Sender: TObject);
    286. var
    287. M: TMSN;
    288. begin
    289. M := TMSN.Create(<a target="_blank" href="mailto:'ying_32@','">'',''</a>);
    290. //mmo1.Text := M.http_Post('https://login.live.com/RST.srf', PChar(mmo2.Text));
    291. //mmo1.Text := m.Get_passport_ticket;
    292. // m.http_Post2('https://login.live.com/RST.srf', PChar(mmo2.Text));
    293. M.Get_passport_ticket;
    294. M.GetXMLFile();
    295. mmo1.Lines.Add(M.FBinarySecurityToken);
    296. mmo1.Lines.Add('------------------------------------');
    297. mmo1.Lines.Add(m.FBinarySecret);
    298. m.Free;
    299. end;
    300. procedure TForm1.btn2Click(Sender: TObject);
    301. begin
    302. IdTCPClient1.Disconnect;
    303. // clntsckt1.Active := False;
    304. ttclnt.Terminate;
    305. end;
    306. procedure TForm1.clntsckt1Connect(Sender: TObject;
    307. Socket: TCustomWinSocket);
    308. begin
    309. mmo1.Lines.Add('连接成功');
    310. end;
    311. procedure TForm1.clntsckt1Connecting(Sender: TObject;
    312. Socket: TCustomWinSocket);
    313. begin
    314. mmo1.Lines.Add('连接中。。');
    315. end;
    316. procedure TForm1.clntsckt1Disconnect(Sender: TObject;
    317. Socket: TCustomWinSocket);
    318. begin
    319. mmo1.Lines.Add('断开服务器');
    320. //  Form1.clntsckt1.Active := False;
    321. //    Form1.clntsckt1.Address := NSAddress;
    322. //    Form1.clntsckt1.Port := NSPort;
    323. //    Form1.clntsckt1.Active :=True;
    324. end;
    325. procedure TForm1.clntsckt1Error(Sender: TObject; Socket: TCustomWinSocket;
    326. ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    327. begin
    328. mmo1.Lines.Add('Error: ' + IntToStr(ErrorCode));
    329. ErrorCode := 0;
    330. end;
    331. procedure TForm1.btn3Click(Sender: TObject);
    332. var
    333. m:TMSN;
    334. s1:string;
    335. begin
    336. m := TMSN.Create('', '');
    337. s1 :=
    338. m.GenerateLoginBlob('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=', 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=');
    339. // s1 := LeftStr(s1, Pos('k', s1) - 1) + 'g' + RightStr(s1, Length(s1) - 23);
    340. mmo1.Lines.Add(s1);
    341. m.Free;
    342. mmo1.Lines.Add('-----------------------------------------------------');
    343. mmo1.Lines.Add(GenerateLoginBlob('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=', 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB='));
    344. end;
    345. procedure TForm1.clntsckt1Read(Sender: TObject; Socket: TCustomWinSocket);
    346. begin
    347. MessageInfo := '';
    348. MessageInfo := Socket.ReceiveText;
    349. CnDebugger.LogMsg(MessageInfo);
    350. end;
    351. procedure TForm1.IdTCPClient1Connected(Sender: TObject);
    352. begin
    353. mmo1.Lines.Add('已连接至->' + IdTCPClient1.Host);
    354. if IdTCPClient1.Host = 'messenger.hotmail.com' then
    355. begin
    356. IdTCPClient1.WriteLn('VER 1 MSNP15 MSNP14 MSNP13 CVR0');
    357. mmo1.Lines.Add('=>VER 1 MSNP15 MSNP14 MSNP13 CVR0');
    358. end;
    359. end;
    360. procedure TForm1.IdTCPClient1Disconnected(Sender: TObject);
    361. begin
    362. mmo1.Lines.Add('断开与->' + IdTCPClient1.Host)
    363. end;
    364. procedure TForm1.btn5Click(Sender: TObject);
    365. begin
    366. if IdTCPClient1.Connected then
    367. begin
    368. IdTCPClient1.WriteLn(Trim(edt3.Text));
    369. mmo1.Lines.Add('=>' + Trim(edt3.Text));
    370. end;
    371. //IdTCPClient1.WriteLn('OUT');
    372. end;
    373. procedure TForm1.btn6Click(Sender: TObject);
    374. begin
    375. Form2.Show;
    376. end;
    377. end.

http://blog.csdn.net/zyjying520/article/details/26161653

上一篇:OpenRTSP的使用


下一篇:request, session, application辨析(待更新)