首页
社区
课程
招聘
[原创]圣诞礼物——突破Netkeeper开wifi限制
发表于: 2013-12-25 01:36 25799

[原创]圣诞礼物——突破Netkeeper开wifi限制

2013-12-25 01:36
25799
        原文来自Tracy'Blog——【圣诞礼物——突破Netkeeper开wifi限制

        在用SF飘逸的赢下一局后,果断退出游戏,选定11+war3,然后shift+delete。从此似乎世界清静了好多,效率也高多了,于是,就有了这篇文章。今天12/24平安夜,明天就是圣诞节了,顿时感觉自己像是经历了各种沧桑后对这些节日压根就提不起任何兴趣了。还记得大一大二还在满校园跑着送苹果来着,可现在却感觉将这一切都看淡了一般,节日,似乎并没什么特别。写着文章时,习惯性点开douban.fm结果第一首歌就是MerryChristmas。好吧,虽然已没有那般冲动为各位送上苹果。那,写下这篇文章,就当送给所有用Netkeeper客户端却想开wifi的孩子吧。嗯,这是送给你的圣诞礼物!还记得去年的圣诞节,还坐在图书馆平平安安的看了一平安夜的计算机网络呢~~额,不扯远了。
        回归正文来聊聊Netkeeper吧,想要解除限制,我们首先得知道它做了些什么,也即是分析这个客户端是干嘛的。我们来推断一下吧:
       
1、拨号上网(这也是它对我们来说的主要功能了,我们装这个软件不就是为了上网么?)
2、为什么win自带拨号功能,还要个客户端呢?(限制一:防止我们用win自带的拨号功能)
3、为什么要限制呢?(因为win提供的拨号程序,可以实现共享,那就不能限制每人只用一个账号了,这样的话,每个人就要去开账号,他赚的就多了,而且,附加一些其他的功能,比如广告推送可以赚宣传费、比如流量控制、比如方便网络管理、比如消息控制、比如……)
4、怎么限制呢?
a、win自带客户端,程序界面中不能输入特殊符号,可用特殊字符来限制。(安郎客户端就是这么做的)
b、用户从ISP手中得到的账号密码,并不是真实的拨号用的账号密码,真实的账号密码可能是这个账号或者密码,通过一种特定的加密算法加密后所生成的。(绝大多数拨号客户端的做法)
c、用户得到的账号密码是真实的,不过,在于pppoe服务器验证时,却附带了其他条件,如netkeeper的动态用户名。
d、我还没遇到其他的,暂且不分析……

        从上面的分析来看,整个客户端,我们想要的,也就只有第一项了,其余的都是附加的~。那,我们要做的事,无非就是还原回去,去掉这些其他的限制,直接使用win拨号,如此一来我们也就可以破除其所谓的限制了。我们可以开wifi、用路由,可以毫无限制了。(当然,心跳包的事待会儿会提到)
        那,我们要做的事就是分析一下我们的客户端是怎么实现限制的吧。记得来重邮知道netkeeper这个玩意之后就做过一件事,用以前的hook工具,看真实密码,结果发现程序在我们的用户名前加了一些字符,然后多试了几次,发现,居然每次添加的字符都是不同的。顿时在想,这玩意儿莫不是用的动态用户名?那,原理呢?时间?还是传说中的伪随机数生成算法?
        实践告诉我们,不懂得问问度娘、问问谷歌。一搜索,发现是用的动态用户名,那他是怎么生成的呢?在分析完本地密码保存后,一直有个想法,去自己分析心跳包、和这个动态用户名生成算法。可,想法终归还只是想法,到现在都没去真正分析过。之后,因为怕大家用工具共享wifi,于是,netkeeper在每次拨号的时候建立一个属于自己的拨号实体ChainNetSNWide,并且在每次断开连接的时候,删除掉这个实体。目的是什么呢?就是不让你设置让它共享。因为你的设置必须在非连接状态。而这个ChainNetSNWide也只在建立连接后才能操作的。
        之后,搜索找到了动态用户名的生成算法js脚本,和linux下的openkeeper,既然有linux下的东西,那就说明可能能找到源码,再就是有js脚本,和后来搜索得到的win下的用户名生成器源码。就开始了这次写自己的拨号工具的过程了。
        首先了解下这个动态用户名生成算法,核心就是:
       
realusername = "\r\n" & 算法b(格式符计算) & (MD5(算法a(时间) + m_username.Left(m_username.FindOneOf("@")) + RADIUS)).Left(2) & username;
        也就是,在生成的用户名中,前两个字符时固定的\r\n,之后通过算法b得到四位格式符,然后再把通过算法a作用于时间得到的结果与用户名中“@”符号前的字符与拨号因子RADIUS连接起来,之后用MD5对其散列,并取其左两位字符,之后把前面得到的这8个字符连接我们输入的用户名,便得到了真实的用户名。
        好吧,分析阶段到这里了。下面开始看代码吧,由于不是我写的,我只是改了改,让他能够为我所用而已,所以,我只是简短的用他的代码,阐述一下这个动态用户名的生成过程。(由于没学过C++、linux下的C编程等等,移植程序还是花了点时间)
        移植到win下的,用VC++ 6.0能编译的主要用户名生成代码如下:
CString CXKUsername::Realusername()
{
	time_t m_time;						//得到系统时间,从1970.01.01.00:00:00 开始的秒数
	long m_time1c;						//时间初处理m_time1c为结果,经过时间计算出的第一次加密
	long m_time1convert;				//对时间操作后的结果,此为格式字串的原始数据
	unsigned char ss[4] =
	{
		0,0,0,0
	};		//源数据1,对m_time1convert进行计算得到格式符源数据
	unsigned char ss2[4] =
	{
		0,0,0,0
	};		//md5加密参数的一部分,m_time1c的字符形式
	CString strS1;						//md5加密参数的一部分,ss2的整体形式
	CString m_formatsring;				//由m_timece算出的字符串,一般为可视字符
	CString m_md5;						//对初加密(m_timec字符串表示+m_username+radius)的MD5加密
	CString m_md5use;					//md5 Lower模式的前两位



	//取得系统时间m_time
	time(&m_time);
	//时间初处理m_time1c为结果,经过时间计算出的第一次加密
	//子函数////////////////////////////
	{
		LONG64 t;
		t = m_time;
		t *= 0x66666667;
		t >>= 0x20;
		t >>= 0x01;
		m_time1c = (long) t;
	}
	//5秒内动态用户名一致处理
	if (m_time1c <= m_lasttimec)
	{
		m_time1c = m_lasttimec + 1;
	}
	m_lasttimec = m_time1c;
	{
		long t;
		t = m_time1c;
		ss2[3] = (t & 0xFF);
		ss2[2] = (t & 0xFF00) / 0x100  ;
		ss2[1] = (t & 0xFF0000) / 0x10000;
		ss2[0] = (t & 0xFF000000) / 0x1000000;
		{
			//strS1必须用自加得到,直接加出问题
			for (int i = 0; i < 4; i++)
			{
				strS1 += ss2[i];
			}
		}
	}

	/////////////////////////////////////
	//倒置过程m_time1convert为结果
	//子函数////////////////////////////
	{
		int t, t1, t2, t3;
		t = m_time1c;
		t1 = t;
		t2 = t;
		t3 = t;
		t3 = t3 << 0x10;
		t1 = t1 & 0x0FF00;
		t1 = t1 | t3;
		t3 = t;
		t3 = t3 & 0x0FF0000;
		t2 = t2 >> 0x10;
		t3 = t3 | t2;
		t1 = t1 << 0x08;
		t3 = t3 >> 0x08;
		t1 = t1 | t3;
		m_time1convert = t1;
	}
	/////////////////////////////////////

	//源数据1,对m_time1convert进行计算得到格式符源数据
	//子函数////////////////////////////
	{
		long t;
		t = m_time1convert;
		ss[3] = (t & 0xFF);
		ss[2] = (t & 0xFF00) / 0x100  ;
		ss[1] = (t & 0xFF0000) / 0x10000;
		ss[0] = (t & 0xFF000000) / 0x1000000;
	}
	/////////////////////////////////////

	//格式符初加密
	unsigned char pp[4] =
	{
		0,0,0,0
	};
	//子函数////////////////////////////
	{
		int i = 0, j = 0, k = 0;
		for (i = 0; i < 0x20; i++)
		{
			j = i / 0x8;
			k = 3 - (i % 0x4);
			pp[k] *= 0x2;
			if (ss[j] % 2 == 1)
			{
				pp[k]++;
			}
			ss[j] /= 2;
		}
	}
	/////////////////////////////////////
	//格式符计算,m_formatsring为结果
	unsigned char pf[6] =
	{
		0,0,0,0,0,0
	};
	//子函数////////////////////////////
	{
	if(sizeof(int)==2){
		int t1, t2;
		t1 = pp[3];
		t1 /= 0x4;
		pf[0] = t1;
		t1 = pp[3];
		t1 = t1 & 0x3;
		t1 *= 0x10;
		pf[1] = t1;
		t2 = pp[2];
		t2 /= 0x10;
		t2 = t2 | t1;
		pf[1] = t2;
		t1 = pp[2];
		t1 = t1 & 0x0F;
		t1 *= 0x04;
		pf[2] = t1;
		t2 = pp[1];
		t2 /= 0x40;
		t2 = t2 | t1;
		pf[2] = t2;
		t1 = pp[1];
		t1 = t1 & 0x3F;
		pf[3] = t1;
		t2 = pp[0];
		t2 /= 0x04;
		pf[4] = t2;
		t1 = pp[0];
		t1 = t1 & 0x03;
		t1 *= 0x10;
		pf[5] = t1;
		}
	else{
	        short t1,t2 ;
		t1 = pp[3];
		t1 /= 0x4;
		pf[0] = t1;
		t1 = pp[3];
		t1 = t1 & 0x3;
		t1 *= 0x10;
		pf[1] = t1;
		t2 = pp[2];
		t2 /= 0x10;
		t2 = t2 | t1;
		pf[1] = t2;
		t1 = pp[2];
		t1 = t1 & 0x0F;
		t1 *= 0x04;
		pf[2] = t1;
		t2 = pp[1];
		t2 /= 0x40;
		t2 = t2 | t1;
		pf[2] = t2;
		t1 = pp[1];
		t1 = t1 & 0x3F;
		pf[3] = t1;
		t2 = pp[0];
		t2 /= 0x04;
		pf[4] = t2;
		t1 = pp[0];
		t1 = t1 & 0x03;
		t1 *= 0x10;
		pf[5] = t1;
		}
	}
	/////////////////////////////////////
	{
		int i;
		for (i = 0; i < 6; i++)
		{
			pf[i] += 0x20;
			if ((pf[i]) >= 0x40)
			{
				pf[i]++;
			}
		}
	}
	{
		for (int i = 0; i < 6; i++)
		{
			m_formatsring += pf[i];
		}
	}
	/////////////////////////////////////
	CString strInput;
	char temp[100];
	strInput = strS1 + m_username.Left(m_username.FindOneOf("@")) + RADIUS;
	strcpy(temp,strInput.GetBuffer(100));
	m_md5 = MD5String(temp);
	m_md5use = m_md5.Left(2);
	m_realusername = m_formatsring + m_md5use + m_username;
	m_realusername = LR + m_realusername;//前面两位为回车换行0D0A,接着再是后续的
//#define _debug	
#ifdef _debug
cout<<"m_username.FindOneOf(\"@\"):"<<m_username.FindOneOf("@")<<endl;	
cout<<"sizeof(int):"<<sizeof(int)<<",m_formatsring:"<<m_formatsring<<endl<<"temp:"<<temp<<",m_md5:"<<m_md5<<endl<<"m_realusername:"<<m_realusername<<", m_md5use:"<< m_md5use<<endl;
#endif
	return m_realusername;
}
        本来还想善始善终的解释下这些代码的,看着看着就不想解释了,甚至连自己改了哪些都不想说了,自己看看吧。
        这样子就可以得到我们的用户名了,于是,瞬间想到直接脱离客户端,自己使用用户名和密码拨号吧。
        就写了个main函数,其作用是接受输入用户名返回真实用户名,形如:
char main (int argc,char **argv)
{
	CXKUsername real(argv[1]);
	return (LPSTR)(LPCTSTR)real.Realusername();
}
        后来想了想,里面有特殊字符不能输入怎么办?很简单啊,用rasdial命令,可是,如何用bat得到这个程序的返回值将是一个头痛的问题。
        于是,想了想,直接把拨号也整合到程序里去吧,又有了下面这个main,怕服务器端对拨号连接的实体有判定,就先复制了个ChainNetSNWide为ChainNetSNWide1,main函数形如:
int main (int argc,char **argv)
{
	CXKUsername real(argv[1]);
	char *temp = (LPSTR)(LPCTSTR)real.Realusername();
	char cmd1[]="rasdial ChainNetSNWide1 ";//构造cmd命令
	strcat(cmd1,temp);
	strcat(cmd1," ");//命令中需要空格
	strcat(cmd1,argv[2]);
	system (cmd1);
}
        可,这样做的结果是:总显示错误691,问题在哪呢?分析了半天没结果,调试了下,发现生成的动态用户名与客户端生成的一致,难不成是不能用cmd命令的?
        于是想了想,还是直接用VC调用api拨号吧,这样能保证不在某个地方出错,于是,又有了下面的main函数:
int main (int argc,char **argv)
{
	if (argc!=4)
	{
		printf("Parameter Error!\nUseage:rdial [entryname] [username] [password]\n");
		system("pause");
		exit(0);
	}
	CXKUsername real(argv[2]);
	// 同步调用方式
	RASDIALPARAMS RasDialParams;
	HRASCONN m_hRasconn;
	// 总是设置dwSize 为RASDIALPARAMS结构的大小
	RasDialParams.dwSize = sizeof(RASDIALPARAMS);
	m_hRasconn = NULL; 
	// 设置szEntryName为空字符串将允许RasDial使用缺省拨号属性
	_tcscpy(RasDialParams.szEntryName, _T(argv[1])); 
	RasDialParams.szPhoneNumber[0] =  _T('\0');
	RasDialParams.szCallbackNumber[0] = _T('\0');
	_tcscpy(RasDialParams.szUserName, _T(real.Realusername()));
	_tcscpy(RasDialParams.szPassword, _T(argv[3]));
	RasDialParams.szDomain[0] =  _T('\0');
	// 同步方式调用RasDial(第五个参数为NULL)
	DWORD Ret = RasDial(NULL, NULL, &RasDialParams, 0, NULL, &m_hRasconn);
	if (Ret != 0) 
	{ 
		TCHAR szBuff[MAX_PATH];
		_stprintf(szBuff,_T("RasDial失败: Error = %d\n"), Ret);
		OutputDebugString(szBuff);
		printf (szBuff);
		return 1;
	}
	else
	{
		printf("使用 %s 连接成功\n",argv[2]);
		return 0;
	}
}
        为了方便在dos下调用,实现循环拨号,于是在成功时返回0,失败是返回1。
        就这样,我们的可以替代Netkeeper的拨号工具就打造成功了。下面就可以验证这个拨号认证过程中,服务器会不会判定拨号实体的名字了,随意建立了一个宽带连接,放上去测试,顺利连接。也就说明,没有这个限制。那么,接下来我们就可以共享网络了。其他的不说了,只说怎么开wifi吧(win8下我各种测试都没成功,所以,我又装了个win7)。
        1. 首先确认无线网卡开关开启,驱动程序已成功安装,无线网络功能可正常使用。
        鼠标点击右下角任务栏网络图标,若出现周围其他网络信号,无线网卡即为可用状态。
         
        2. 确定网络共享相关服务是否开启。
        可右击桌面“计算机”图标,依次打开“管理”---“服务和应用程序”---“服务”(或同时按下“windows键和R键”,输入“services.msc”,点击确定打开“服务管理器”),查看“Internet Connection Sharing (ICS)”和“Remote Procedure Call (RPC)”服务是否启用。若“手动”未“正在运行”,在相应服务右击选“启动”;若“禁用”,相应服务处右击选“属性”,“启动方式”设置为“自动”,点击“应用”按钮,点击“启动”,再点击“确定”,完成设置。
         
        3. 设置承载网络。

        新建一个txt文档,记事本打开,输入netsh wlan set hostednetwork mode=allow ssid=您想建立的网络名字(英文格式) key=您想设置的密码(至少8位)按下Enter键,设置ssid和密码,换行再netsh wlan start hostednetwork。
        例如:
        netsh wlan set hostednetwork mode=allow ssid=mywlan key=12345678
        netsh wlan start hostednetwork
        之后保存,关闭记事本,改文件名“新建文本文档.txt”为“start_wifi.bat”。
        之后右键该文件,选择以管理员运行。即可开启承载网络。
         
        4. 设置网络共享

        依次打开 控制面板---查看网络状态和任务---更改适配器设置,若以上命令创建成功,会出现一个“本地连接*”后面带数字的网络连接。并且中间部分会显示所设置无线网络名称。在“以太网”右击选择“属性”,点击“共享”,按下图所示设置,点击“确定”按钮保存设置。(若使用宽带连接拨号上网,请在“宽带连接”右击选择属性,设置共享)
        5. 用我提供的rdial拨号上网。
        使用办法:新建一个txt文档,记事本打开,输入:
        rdial "你拨号的实体名" "username" "password"
        例如:rdial 宽带连接 xxxx@cqupt xxxx
        之后保存,关闭记事本,改文件名“新建文本文档.txt”为“connect.bat”并放在rdial所在的文件夹中。
        之后,双击运行即可联网。

        以上操作完成以后手机搜索创建的无线网络“mywlan”,使用密钥“12345678”连接测试。

        好吧,就敲到这了,不经意间都8000个字了。嗯,圣诞节了,祝大家节日快乐。
        这篇文章,也当是送给大家的圣诞礼物了。当然,你会说,还有心跳包的限制,的确,不过,先凑合着吧,下次我还来给大家分析分析心跳包。晚安~~

        (附件中提供rdial.exe、start_wifi.bat、connect.bat,需要cpp的联系我吧~)
——Tracy_梓朋
2013/12/25 01:00:25

[课程]Android-CTF解题方法汇总!

上传的附件:
收藏
免费 5
支持
分享
最新回复 (33)
雪    币: 230
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
真精彩.
2013-12-25 05:04
0
雪    币: 211
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
强大的楼主,不过除了闪讯,还有一个闪通的东西[VPN 高速通道],楼主有没有研究。
2013-12-25 08:51
0
雪    币: 458
活跃值: (306)
能力值: ( LV12,RANK:400 )
在线值:
发帖
回帖
粉丝
4
圣诞来顶帖了。。
2013-12-25 09:26
0
雪    币: 5855
活跃值: (438)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
5
难道楼主所在地区没有心跳机制。。
不模拟心跳会掉线
2013-12-25 10:34
0
雪    币: 8
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
圣诞就是好。
2013-12-25 12:44
0
雪    币: 3343
活跃值: (1243)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
7
圣诞快乐 来阅大神新作~ 这个貌似是视频版的 www.youtube.com/watch?v=YTTPqyKtgbA
大神貌似对一些客户端情有独钟啊~
2013-12-25 17:08
0
雪    币: 1050
活跃值: (1208)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
算法和我逆粗来的差不多……我有一段我没搞……正好在楼主这里补全了……终于不偶尔掉线了……用几天没事我就可以把E信卸载了……
2013-12-25 22:54
0
雪    币: 53
活跃值: (523)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
Netkeeper会发送心跳包。自己拨号上去过一会儿就会掉线。
2013-12-26 05:17
0
雪    币: 329
活跃值: (230)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
10
还真没见过。。。。所以没怎么研究了
2013-12-26 10:57
0
雪    币: 329
活跃值: (230)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
11
有心跳包。只不过最近在linux下发现不掉线了,然后就写出这么一个客户端。

心跳包也有分析过,不过没什么时间继续弄下去、、、等过一会儿再说吧。
2013-12-26 10:58
0
雪    币: 329
活跃值: (230)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
12
每五分钟发一次心跳包。连续两次等不到回复,怎会自动掉线。

如果是服务器发送过来的数据包,验证不通过,客户端直接退出~~~
2013-12-26 10:59
0
雪    币: 74
活跃值: (703)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
圣诞是看雪的节日
2013-12-26 13:31
0
雪    币: 1491
活跃值: (975)
能力值: (RANK:860 )
在线值:
发帖
回帖
粉丝
14
非常精彩,我大学的时候都是xp系统,还没有win7,也没有共享wifi上网,呵呵
2013-12-26 17:03
0
雪    币: 486
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
还是重邮代码没改啊,不对了吧
2013-12-26 19:07
0
雪    币: 329
活跃值: (230)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
16
什么改了没改?你指的是RADIUS值?

我又没贴出来,你怎么就知道没改呢?
2013-12-26 19:39
0
雪    币: 233
活跃值: (10)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
17
如果不这么搞,直接用第三方工具开热点,比如Connectify,不行吗?
2013-12-26 22:15
0
雪    币: 486
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
我是说加密部分代码没变,找了重邮,杭电代码看了,总算是搞定了,总得来说文章蛮好的,赞个
2013-12-27 00:18
0
雪    币: 6825
活跃值: (1570)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
不知道e信能能不能用,过几天试一试
2013-12-27 23:28
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
搞个e信就好,可以随时用手机上网不?
2013-12-28 00:15
0
雪    币: 329
活跃值: (230)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
21
可以,不过,我没研究过e信~~~所以,不知道那个客户端干嘛的~~~
2013-12-28 12:47
0
雪    币: 329
活跃值: (230)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
22
感谢版主支持,我觉得xp用的更加顺手些。。。所以~~~现在给自己电脑强行装上了xp(有些驱动没有)。
2013-12-28 19:16
0
雪    币: 80
活跃值: (109)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
23
楼主的文章不错,一直关注
2013-12-28 19:31
0
雪    币: 45
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
24
和原版的代码差不多 没改多少
2014-1-1 23:51
0
雪    币: 159
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
元旦都过了。
2014-1-2 00:32
0
游客
登录 | 注册 方可回帖
返回
//