对某校园网跨域软件的逆向分析和重实现
上学期校园网里突然流行起一款免费的跨域软件(威皮恩),速度非常不错,下载能达到1M/S,但是只能在校园网范围内使用。最近放假在家,想要翻墙下一款软件,苦于找不到好的威皮恩,所以就想到是不是能把校园网的跨域软件弄到家里来用用。
用DIE查看程序的编写语言和加壳情况(对于壳和混淆的分析我还是新手,只能靠工具,还得加油学习)
发现程序使用.NET服务框架写的,用.NET Reactor加的壳。考虑脱壳后反编译试试。
De4Dot对.NET Reactor的脱壳效果一向不错,考虑直接用它试试
(为了尊重程序作者的权益,程序名已打码,文章中也不会出现程序名)
发现成功了,不知道脱壳玩不完全,但是可以尝试反编译了,就是不知道反编译之后的效果会怎么样。
直接上DotPeek试试
发现反编译后的代码特别干净整齐,应该是成功了,既然反编译成功了,我也就不甘于之解决校园网外的连接问题了。
由于改程序在连接威皮恩时没有要求输入用户凭证,是一键式连接的,怀疑在程序中存有服务器信息和账号密码信息。
上面两款软件已经帮我把它的代码还原得这么干净整齐了,我当然不能浪费了这个资源。
怀疑程序作者在写程序的时候方法使用了"connect"字样,直接搜索试试,得到了下面的代码块:
发现服务器地址了:"jp" + MainWindow.fastest_server.ToString() + ".toven.info"
怀疑程序在启动的时候ping了一下威皮恩服务器,然后按延迟排序,选了延迟最小的服务器来连接。
按格式来看,不用找fastest_server变量了,它肯定是int型。那么按这个格式ping一下服务器试试:
ping到"jp9.toven.info"的时候发现ping不通了,那么怀疑服务器是"jp1"到"jp8"。
这时候服务器地址也有了,只差账服务器的连接凭证了,再在源码中找找,搜"user"和"pass"字符居然一时半会没找到账号密码。
耐下心来,从头开始找,发现了这么个东西:
看到链接中有"reg.php"和"user"的字符,怀疑是通过程序向reg.php页面发送了http请求申请了一个账号,那么打开链接试试:
打开发现是这么个页面,发现注册不用填写验证码,而且“初始预付服务”中有“免费账户”的选项。随便注册一个免费账户后发现免费用户是三十分钟的试用时间,用完之后就只能付费使用了。
这时候能得出结论了:这个校园网跨域软件用的不是用自己的服务器,而是别人威皮恩产品提供的试用服务,通过HTTP请求申请账号(申请账号不要求填写验证码,这个实现起来非常简单),三十分钟一断,断开之后再申请一个,重新连接。
得出这个结论之后,我决定利用作者的成果来写一个自己用的威皮恩(其实是用了别人的服务器)
查看网页的元素发现表单的命名也非常规则,得出了申请账号的post格式:
http://user.tosver.cn/reg.php?cont=store_user&lang=Chinese&username=用户名&password1=密码&password2=再次输入密码&mobile&email&srvid=1&textarea=%E6%8F%90%E7%A4%BA%EF%BC%9A%E8%AF%B7%E4%BB%94%E7%BB%86%E9%98%85%E8%AF%BB%E4%BB%A5%E4%B8%8B%E6%9D%A1%E6%AC%BE%EF%BC%8C%E5%86%8D%E6%B3%A8%E5%86%8C%E5%B8%90%E5%8F%B7%E3%80%82%E4%BD%BF%E7%94%A8%E6%9C%AC%E7%BD%91%E7%AB%99%E8%A1%A8%E7%A4%BA%E6%82%A8%E5%90%8C%E6%84%8F%E9%81%B5%E5%AE%88%E8%BF%99%E4%BA%9B%E6%9D%A1%E6%AC%BE%E5%92%8C%E6%9D%A1%E4%BB%B6%E3%80%82%E5%A6%82%E6%9E%9C%E6%82%A8%E4%B8%8D%E6%8E%A5%E5%8F%97%E8%BF%99%E4%BA%9B%E6%9D%A1%E6%AC%BE%EF%BC%88%E2%80%9C%E6%9D%A1%E6%AC%BE%E2%80%9D%EF%BC%89%EF%BC%8C%E8%AF%B7%E5%8B%BF%E6%B3%A8%E5%86%8C%E3%80%82&acceptterms=1&adduser=%E5%88%9B%E5%BB%BA%E8%B4%A6%E6%88%B7
username参数是用户名,password1是密码,password2是确认密码输入,srvid是用户类型,1是免费用户,然后是一大串用户协议之类的内容(不知道这个参数有没有必要,总是先弄上去),acceptterms是接受用户协议,给它传递个1应该就是接受了吧。
随便弄一个用户名和密码用postman来post这个页面发现返回了注册成功的页面
那么现在就能写一个程序来方便以后使用了。
界面就这样吧,毕竟是自己用的简易威皮恩
接下来实现账号密码申请功能:
先是post方法:
public static string PostWebRequest(string postUrl, string paramData, Encoding dataEncode)
{
string ret = string.Empty;
try
{
byte[] byteArray = dataEncode.GetBytes(paramData);
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(new Uri(postUrl));
webReq.Method = "POST";
webReq.ContentType = "application/x-www-form-urlencoded";
webReq.ContentLength = byteArray.Length;
Stream newStream = webReq.GetRequestStream();
newStream.Write(byteArray, 0, byteArray.Length);
newStream.Close();
HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.Default);
ret = sr.ReadToEnd();
sr.Close();
response.Close();
newStream.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return "Error";
}
return ret;
}
然后是账号密码部分:
用一串10位的随机数来填充账号部分,短时间内应该不会有重复的用户名:
private string CreateUsername()
{
string username = "crac";
Random random = new Random();
for (int i = 0; i < 10; ++i)
{
username += random.Next(0, 9).ToString();
}
return username;
}
密码就随便在键盘上敲一下吧,就用dsDW4er2342
然后是账号密码申请方法:
public bool Register()
{
string password = "dsDW4er2342";
string username = CreateUsername();
string postUrl = "http://user.tosver.cn/reg.php";
string usernamePart = "cont=store_user&lang=Chinese&username=" + username + "&";
string passwordPart = "password1=" + password + "&password2=" + password + "&";
string otherPart = "mobile&email&srvid=1&textarea=%E6%8F%90%E7%A4%BA%EF%BC%9A%E8%AF%B7%E4%BB%94%E7%BB%86%E9%98%85%E8%AF%BB%E4%BB%A5%E4%B8%8B%E6%9D%A1%E6%AC%BE%EF%BC%8C%E5%86%8D%E6%B3%A8%E5%86%8C%E5%B8%90%E5%8F%B7%E3%80%82%E4%BD%BF%E7%94%A8%E6%9C%AC%E7%BD%91%E7%AB%99%E8%A1%A8%E7%A4%BA%E6%82%A8%E5%90%8C%E6%84%8F%E9%81%B5%E5%AE%88%E8%BF%99%E4%BA%9B%E6%9D%A1%E6%AC%BE%E5%92%8C%E6%9D%A1%E4%BB%B6%E3%80%82%E5%A6%82%E6%9E%9C%E6%82%A8%E4%B8%8D%E6%8E%A5%E5%8F%97%E8%BF%99%E4%BA%9B%E6%9D%A1%E6%AC%BE%EF%BC%88%E2%80%9C%E6%9D%A1%E6%AC%BE%E2%80%9D%EF%BC%89%EF%BC%8C%E8%AF%B7%E5%8B%BF%E6%B3%A8%E5%86%8C%E3%80%82&acceptterms=1&adduser=%E5%88%9B%E5%BB%BA%E8%B4%A6%E6%88%B7";
if (PostWebRequest(postUrl, usernamePart + passwordPart + otherPart, Encoding.UTF8).IndexOf("账户已经创建") != -1)
{
this.username = username;
this.password = password;
return true;
}
else
{
postUrl = "http://user.tovens.com/reg.php";
if (PostWebRequest(postUrl, usernamePart + passwordPart + otherPart, Encoding.UTF8).IndexOf("账户已经创建") != -1)
return true;
else
return false;
}
}
我将它们写在了一个类中,类中有public string型的username和password属性,构造方法中调用Register()方法,
若Register方法返回True则该类对象可用,若返回False则username和password属性为null,该对象不可用。
接下来用DotRas库来实现威皮恩连接功能,这里用到了别人写的VPNHelper类,用来辅助调用DotRas库的方法来创建和链接威皮恩。我重载了一个构造方法,使它接受一个UsernameKeeper类对象(就是上面写的用来申请账号的类)来初始化vpnHelper类对象的账号密码以连接威皮恩。
这个类就不贴出来了,代码太长。
直接到创建和链接威皮恩部分:
private void buttonConnect_Click(object sender, EventArgs e)
{
UsernameKeeper usk = new UsernameKeeper();
vpnHelper = new VPNHelper("jp1.toven.info", "EasyVPN", usk);
vpnHelper.CreateOrUpdateVPN();
vpnHelper.TryConnectVPN();
}
然后就搞定了,以后就能在任何地方一键连接威皮恩了。至于半小时断一次的解决方案,我认为每20s ping一次twitter.com是可行的,如果Ping不通的话就断开重连。
为了使文章不过于冗长,就先不实现更多功能了。
至此,整个过程结束。
(由于规定,我就不放出原校园网跨域软件和编译后的威皮恩及完整源码了,只分享思路和一小部分关键部分的C#语言实现,有兴趣的朋友可以自己用任何其他的语言将其完整实现写出来)
然而网址还是没打码。。。。{:1_925:}
楼主,经我测试,那个postdata里的很多参数都可以不带,进行注册。
只需要一下参数:
username=&password1=&password2=&srvid=1&acceptterms=1
///依次是:用户名密码 重复密码 服务id(1为免费) 是否接受条款(1为接受) blueshell1949 发表于 2015-9-9 16:28
请问楼主,怎么样才可以反编译得到源码呀?新手求问。谢谢您
.net程序可以用DOTPEEK或.net reflector等工具实现,C++没有一个好的办法,逆向一般通过OD等调试工具实现 原创作品啊。。。。学习支持了
好东西, 看完了,期待发出来 太厉害了啊佩服的五体投地啊 XhyEax 发表于 2015-8-28 16:52
然而网址还是没打码。。。。
楼主,经我测试,那个postdata里的很多参数都可以不带,进行注册 ...
哦哦,好的,感谢测试 (^_^) 720830 发表于 2015-8-29 00:49
看完了,期待发出来
不能发,是违规的。
实现的思路和原理应该不难,照上面的自己实现一下就能用了 学习了!!