VATSIM的新连线客户端vPilot出来挺久了,我一直都没去看,Hans倒是当天就开始研究了。vPilot有一个问题,就是它是VATSIM-Only的设定,除了VATSIM的那一票服务器外其他的都不能连。在它的配置文件中,有一项是这样的:pZ9u441bE4a2NCGgqMxKNvwAIy0qEA+AwXB8c3sV90c=
。它看起来是用Base64编码的字符串,但是使用Base64去解码没有效果。紧随其后的,是名为CachedServer
的标签,但是它的值也和NetworkStatusURL
是一样无法解码的。
我今天怀着必胜的信念尝试解决这个问题。因为没有什么顾虑,此处我将披露所有技术细节。在开始前,我可以先说明最初的思路是错误的,但是这不要紧,这些分析方法不一定不适用于所有情况。当然,也算一次有意义的尝试。
刚开始我的方案和Hans的方案是基本一致的:想办法去解开这个加密的字符串。之前我做过一个小范围使用的Bob89加解密算法(此处不透露细节),于是我在这里编写了几个小程序对其进行了如下处理:①将每个字符的ASCII加上/减去若干整数;②翻转字符串;③小范围解码测试。不幸的是,以上尝试均以失败告终。
我在想,是不是考虑的方向错了,我不应该从解密这个字符串入手,而是从已知的字符串入手进行加密还原。考虑这样的一个事实:服务器地址是通过网络获取的,否则不存在cache
的问题。那么首先想到的应该是删掉CachedServer
信息然后开上抓包程序启动vPilot进行信息的抓取。抓包过程还是很顺利的,有不少加密的信息无法获取,但是明文都能抓全。一条条分析,我找出了vPilot的API根:vpilotapi.metacraft.com
。看上去是一个激动人心的成就,但是事实告诉我这里的API并不负责服务器地址的获取。茫忙数据包大海中苦苦搜寻,得来了一个有意义的包:正文部分包含了服务器信息。没错这就是我所需要的,我根据IP一层一层回溯上去,找到了本机与对方IP的第一次请求:域名是status.vatsim.net
,资源是status.txt
。接着往下面找,服务器信息来源于info.vroute.net/vatsim-servers.txt
。而status.txt
中是有vatsim-servers.txt
的,显然status.txt
是列表的来源。这样的分析是没错的,我想。但是再怎么尝试也不知道如何得到一个像那样加密了的字符串。
我不情愿地打开了ILSpy。我不想再次反编译vPilot,它被混淆了,分析它不仅痛苦,而且没什么意义。这次的反编译还是带来了一些好消息:在Metacraft.Vatsim.vPilot.Core
命名空间中有一个vPilotConfig
类,它有一个属性,名叫NetworkStatusURL
。再往下看,有一些被混淆了的方法,但是值得庆幸的是属性名称没有被混淆,这真是令人高兴。有一个方法进入了我的视线:
// Metacraft.Vatsim.vPilot.Core.vPilotConfig
private void a()
{
string a_ = this.c().ToString();
string[] array = this.CachedServers.ToArray();
this.CachedServers.Clear();
string[] array2 = array;
for (int i = 0; i < array2.Length; i++)
{
string a_2 = array2[i];
this.CachedServers.Add(vPilotConfig.a(a_2, a_));
}
this.NetworkStatusURL = vPilotConfig.a(this.NetworkStatusURL, a_);
try
{
this.NetworkPassword = vPilotConfig.a(this.NetworkPassword, a_);
}
catch (CryptographicException)
{
}
catch (FormatException)
{
}
}
NetworkStatusUrl出现了!我们再来看看a方法的另一个重载:
// Metacraft.Vatsim.vPilot.Core.vPilotConfig
private static string a(string A_0, string A_1)
{
UTF8Encoding uTF8Encoding = new UTF8Encoding();
MD5CryptoServiceProvider mD5CryptoServiceProvider = new MD5CryptoServiceProvider();
byte[] key = mD5CryptoServiceProvider.ComputeHash(uTF8Encoding.GetBytes(A_1));
TripleDESCryptoServiceProvider tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider();
tripleDESCryptoServiceProvider.Key = key;
tripleDESCryptoServiceProvider.Mode = CipherMode.ECB;
tripleDESCryptoServiceProvider.Padding = PaddingMode.PKCS7;
byte[] array = Convert.FromBase64String(A_0);
byte[] bytes;
try
{
ICryptoTransform cryptoTransform = tripleDESCryptoServiceProvider.CreateDecryptor();
bytes = cryptoTransform.TransformFinalBlock(array, 0, array.Length);
}
finally
{
tripleDESCryptoServiceProvider.Clear();
mD5CryptoServiceProvider.Clear();
}
return uTF8Encoding.GetString(bytes);
}
其中,a(void)
里面的a_
变量调用了c
方法。c
方法只有一条语句:return new Guid(1433775113u, 62174, 18974, 128, 139, 227, 57, 142, 23, 248, 191);
。这样一来就好办了,这些部分完全可以拼在一起用以证实我的猜想。没错,http://status.vatsim.net/
加密出来结果就是配置文件中所看到的pZ9u441bE4a2NCGgqMxKNvwAIy0qEA+AwXB8c3sV90c=
了。
接下来的任务是什么,已经是十分明朗的:仅需自己做一个URL替换掉原来的,便可以自己定义服务器列表了。所以第一个任务是写个程序来加密URL。简要分析一下这里的加解密方法:基础算法是Triple DES,密钥是通过特定参数生成的Guid的MD5散列值。事实上之前的分析并没有出错,这个串的确是Base64编码的产物,只不过它的明文不是一个普通的字符串罢了。写个加密程序不费事,不用多久就能完成。
改完了NetworkStatusURL
,要做的就是把对应的URL资源做好了。先在修改的URL目录里放一个status.txt
文件,里面需要有一个行:url1={xxx.txt}
。再建立一个对应的xxx.txt
,其中按诸如ASIA:106.186.24.200:Tokyo, JAPAN:ASIA:1:
的格式组织好服务器列表,然后启动vPilot即可。
如果你想连接大陆三大平台(A/F/S),请直接修改NetworkStatusURL
为6FXSmoBv/MERbMqqCvbTYeIgUd9gK+Aw
,我已经制作好了。这样的服务器列表没有删减VATSIM服务器,仅是添加了三平台的服务器。此外,我写了一个小工具,它可以生成NetworkStatusURL
,其中已打上了必要的提示。你可以通过它来创造自己需要的服务器列表。我没有对其混淆处理,想看看怎么实现的,直接反编译就好了。这里可以下载。