原理就是从webbrowser拿到Cookie
一般做网页登录,比如登录QQ空间,则要破解登录的相关的一系列加密算法。
在给客户维护以前登录QQ空间采集好友访客的一个软件时,发现2015年的空间密码加密方式变了,由以前的MD5改为了RSA,找到了加密的JS文件,但懒的转为C#代码。本来想用Interop.MSScriptControl.dll在C#中调用JS,但是直接调用这个JS文件会报错。实在不想继续找下去,一直在想着有什么简单方便的方法。终于功夫不负有心人,还真让我找到了。
原来的方式是,是从UI界面上获取用户要登录的用户名和密码,C#代码经过系统的加密,转换为TX需要的格式,并发包的服务器,服务器反回一些cookie和一些有用的值(比如g_tk),然后后续的一些操作要带上这些cookie和g_tk。现在既然这些过程解不了密,那么是否可以用Webbrowser控件来登录,登录完成后从webbrowser中拿到cookie,后续的操作带上这些cooke即可。
经过动手尝试,证明是可行的。对于QQ空间的登录,过程是这样的:
webbrowser中进行登录,登录完成后,在恰当的时机,拿到webbrowser的cookie,然后在cookieContainer中找到skey
至此,所有cookie和skey都拿到了。然后还有一个重要的参数g_tk, 这个参数是根据skey计算出来的。算法如下:
/// <summary>
/// 获取空间登录的g_tk
/// </summary>
/// <param name="skey"></param>
/// <returns></returns>
public long g_tk(string skey)
{
long hash = 5381;
for ( int i = 0; i < skey.Length; i++)
{
hash += (hash << 5) + skey[i];
}
return hash & 0x7fffffff;
}
试了下,能用,还好,g_tk的算法没有改动。
这样,项目维护完成,600块钱到手。
下面附上webbrowser登录过程以及拿到cookie和相cookie中取skey的所有代码:
public partial class QZoneWebLogin : Form
{
private bool flag = false;
private string _skey = string.Empty;
private CookieContainer _cookie = new CookieContainer();
public string skey
{
get { return _skey; }
}
public CookieContainer cookie
{
get { return _cookie; }
}
public QZoneWebLogin()
{
InitializeComponent();
}
private void webBrowser1_DocumentCompleted( object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (webBrowser1.Url.ToString().Contains( "http://user.qzone.qq.com/") && webBrowser1.Url.ToString().Contains("?ptsig=" ))
{
if (!flag)
{
flag = true;
_skey = GetSkey();
this.DialogResult = System.Windows.Forms. DialogResult.OK;
}
}
}
private string GetSkey()
{
string skey = string.Empty;
GetCookie();
List< Cookie> listCookie = GetAllCookies(_cookie);
foreach ( Cookie c in listCookie)
{
if (c.Name == "skey")
{
skey = c.Value;
break;
}
}
return skey;
}
private void GetCookie()
{
if (webBrowser1.Document.Cookie != null)
{
string cookieStr = webBrowser1.Document.Cookie;
string[] cookstr = cookieStr.Split( ';');
foreach ( string str in cookstr)
{
string[] cookieNameValue = str.Split( '=');
Cookie ck = new Cookie(cookieNameValue[0].Trim().ToString(), cookieNameValue[1].Trim().ToString());
ck.Domain = ".qq.com";
_cookie.Add(ck);
}
}
}
/// <summary>
/// 把CookieContainer所有的Cookie读出来
/// </summary>
/// <param name="cc"></param>
/// <returns></returns>
private List<Cookie> GetAllCookies( CookieContainer cc)
{
List< Cookie> lstCookies = new List< Cookie>();
Hashtable table = ( Hashtable)cc.GetType().InvokeMember( "m_domainTable",
System.Reflection. BindingFlags.NonPublic | System.Reflection.BindingFlags .GetField |
System.Reflection. BindingFlags.Instance, null , cc, new object [] { });
foreach ( object pathList in table.Values)
{
SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list" ,
System.Reflection. BindingFlags.NonPublic | System.Reflection.BindingFlags .GetField
| System.Reflection. BindingFlags.Instance, null , pathList, new object[] { });
foreach ( CookieCollection colCookies in lstCookieCol.Values)
foreach ( Cookie c in colCookies)
lstCookies.Add(c);
}
return lstCookies;
}
}