360免费wifi刷金币50金币抢购什么时候更新

阅读 97 views
阅读 93 views
阅读 222 views
阅读 12 views
阅读 1,008 views
阅读 1,808 views
您还未添加分享代码,请到主题选项中,添加百度分享代码!薅羊毛,助你踏出理财第一步!交流群-联系人Q:小鱼- ;naopa-
活动名称:360wifi免费抽奖活动,10秒完成,50名额
截止日期:日
活动方:奇虎360
打开地址后拉到最下面的猜售价赢大礼,填写价格,勾选功能,填写手机号码 就有机会得到360WIFI-U盘版,只要10秒就可以完成, 但名额只有50个,试试人品。
申明:文章允许复制转载,切忌直接使用本站图片&&|&薅羊毛您的位置:
更多频道:
360免费wifi可以用多久?有时间限制吗
  可以用多久?有时间限制吗&有朋友问360免费wifi要钱吗?下文将会告诉大家360免费wifi收费吗?如果想要用电脑开wifi,我们需要用到路由器,但是现在使用“360免费wifi”也能达到一样的效果哦~但是要不要收费呢?  功能大全中的免费WIFI是不需要费用的,这里提示的费用,是告诉你360免费WIFI帮助你节省的流量费用,只是比喻,并不是实际产生的费用。  就相当于把电脑当成了无线路由器,其他人可以通过你的电脑作为接入点上网。不会另收费,笔记本理论上是可以连接100台的。  360免费WiFi是免费的,你大可放心使用,这个其实就是把你的电脑有线网络共享为无线
决定于你的有线宽带,意思就是你本来是只能使用一个有线网络来上网,使用360wifi后你可以在半径80m(理论值)使用任何能够连接wifi的设备来上网。  目前免费WIFI上网软件不少,常见的有“360免费WiFi”,“猎豹免费WiFi”,“WIFI共享精灵”等软件,大家可以根据自己的喜好来选择其中一款,此处以360免费WiFi为例详细介绍相关操作与设置。360免费WiFi可以帮助你用无线网卡创建出一个虚拟无线接入设备,能将电脑瞬间变成免费的WiFi路由器,从而让手机、电脑、平板、PAD等具备无线功能的硬件设备上网,具有体积小巧,永久免费,零流量,防蹭网,手机遥控电脑,摇摇传图等特点。并可免去购买360随身WIFI硬件设备,节省了费用。
相关文章:360免费WIFI加密签名破解获取他人无线明文密码(还可刷金币换运营商流量) - 推酷
360免费WIFI加密签名破解获取他人无线明文密码(还可刷金币换运营商流量)
第一回合:加解密破除
根据特征定位功能点代码
根据 http 请求中method=Wifi.password 为特征,定位请求封装代码存在 qE 类中
接下来对函数进行hook 分析
追踪到其加密方式为DESede (DESede 是由DES对称加密算法改进后的一种对称加密算法。使用 168 位的密钥对资料进行三次加密的一种机制 ),实现类为 vA
接下要做的就是定位DESede key 就可以破解完成 http 请求加解密的整个过程并且自己用代码实现.
现在开始跟踪 key 的生成算法.从以下代码可以得知 init 中的 key 是由 public static String a(String arg2) 方法获取的. 从代码中得知 key 的生成实际是由com.qihoo.freewifi.utils.SecurityUtils完成的
其中 getkey 是一个 native 方法 (可以看出 app 的保护工作主要放在保护 key 上)
public static native String getKey(String paramString1, String paramString2);
接下来就要分析 so 咯.
& strings libsecurity.so |grep -i getkey
Java_com_qihoo_freewifi_utils_SecurityUtils_getKey
然后再对 IDA F5中参数类型进行修复就得到了如下
一个 hash 过程,这个函数在so 没有啥包含可以直接引用
主导 key 生成因子2的就是 getKey(String paramString1, String paramString2) 第二个参数了. (因子1就是一些固定 method 字符串)
SecurityUtils#b(Context arg1, String arg2, String arg3)的 arg3引入
回看vA#a代码
public static String a(String arg2) {
return SecurityUtils.b(Application.a(), arg2, vB.a(Application.a()));
vB#a 得到类似 UUID 的东西传入 SecurityUtils#getKey 得到 key. (这里在可以否定前面的推断 类UUID 的字符串比和服务端有关.不然服务端无法得到 key 解密,客户端会把生成 key 的因子2传到服务端,在 http 请求中是 m2 参数. 这样服务端就有了生成 key 的两个因子来生成 key 进行解密了)
设备关联 id 生成函数vB#a 分析 ,主要逻辑如下:将 imei,deviceid,android_id拼接后进行 md5
v0 = vB.b(arg6);
String v1 = Settings$System.getString(arg6.getContentResolver(), &android_id&);
String v2 = vB.a();
vB.a = vP.a(&& + v0 + v1 + v2);
其中 v0是由vB#b(Context arg2)生成 ,一种情况是返回vB.b = arg2.getSystemService(&phone&).getDeviceId() ,如果若空则返回&360_DEFAULT_IMEI&
public static String b(Context arg2) {
vB.b = wa.a(arg2, &APP_STORE_IMEI0&, &&);
if(!TextUtils.isEmpty(vB.b)) {
String v0_1 = vB.b;
return v0_1;
vB.b = arg2.getSystemService(&phone&).getDeviceId();
if(TextUtils.isEmpty(vB.b)) {
return &360_DEFAULT_IMEI&;
wa.b(arg2, &APP_STORE_IMEI0&, vB.b);
return vB.b;
catch(Exception v0) {
return &360_DEFAULT_IMEI&;
v1是由 Settings$System.getString(arg6.getContentResolver(), &android_id&) 生成
v2是由 vB#a() 生成,连接之后传入vP#a(String arg1) 算出 md5 值.即得到生成的 key 因子2.
public static String a() {
String v0_3;
String v1 = &&;
Class v0_1 = Class.forName(&android.os.SystemProperties&);
Object v0_2 = v0_1.getMethod(&get&, String.class).invoke(v0_1, &ro.serialno&);
catch(Exception v0) {
v0_3 = v1;
return v0_3;
响应包的加密方法和请求包的加密方法一致.直接解密响应包
其中 pwd 参数就是 wifi 的密码了,若未查询到则为空.
梳理一下整个流程:
1.通过拼接imie/android_id/deviceid 再进行 md5得 m2
2.将 m2 和 method 传入 native 函数getkey 得到对称密钥 key
3.通过 key 对请求相应包内的 data 进行 DESede 加解密
自此数据的加解密工作已经基本完成.进入第二个环节:签名
第二回合:签名破除
其中 sign 参数由
v0_1.add(new BasicNameValuePair(&sign&, tM.b(v0_1, v1)));
函数生成,v0_1为 url 中参数的 list 集合,而 v1则由tM.b()方法生成的一个32位字符串
tm#b生成字符串的的过程又和tM.c(); 以及 vA.b(v1, &User.getConfig&);有关联
private static String b() {
String v0 = &&;
String v1 = tM.c();
if(!TextUtils.isEmpty(((CharSequence)v1))) {
v0 = vA.b(v1, &User.getConfig&); // DESede 解密函数
catch(Exception v1_1) {
v1_1.printStackTrace();
return v0;
而在 tM.c()方法中主要是调用了wa.a(Application.a().getBaseContext(), &qlink_secret_key&, &&)
private static String c() {
String v0;
if(!TextUtils.isEmpty(tM.a)) {
v0 = tM.a;
tM.a = wa.a(Application.a().getBaseContext(), &qlink_secret_key&, &&);
v0 = tM.a;
return v0;
wa#a(Context arg1, String arg2, String arg3)方法调用了sV#b(Context arg2, String arg3, String arg4)
public static String a(Context arg1, String arg2, String arg3) {
return sV.b(arg1, arg2, arg3);
hook sV#b(Context arg2, String arg3, String arg4) 输入输出如下
09-15 11:02:27.749
/? I/QihooWifi﹕ in sV#b(C|s|s) = last_update_date| para2 =
09-15 11:02:27.749
/? I/QihooWifi﹕ out sV#b(C|s|s) =
09-15 11:56:55.622
/? I/QihooWifi﹕ in sV#b(C|s|s) = qlink_secret_key| para2 =
09-15 11:56:55.632
/? I/QihooWifi﹕ out sV#b(C|s|s) = Rd36RTbNXij5tjaqHZiEQY7ulZdvnrjbRWFtcIUBivz6wPxjdAMfYw==
//DESede 加密后的32位字符串
09-15 11:57:00.032
/? I/QihooWifi﹕ in sV#b(C|s|s) = APP_STORE_IMEI| para2 =
09-15 11:57:00.032
/? I/QihooWifi﹕ out sV#b(C|s|s) = 9f2de7ceb7dc3e4a0e9
其中qlink_secret_key字符串将传入sV#b(Context arg7, String arg8)
private static Cursor b(Context arg7, String arg8) {
Cursor v0_2;
Cursor v6 =
if(arg7 != null && !TextUtils.isEmpty(((CharSequence)arg8))) {
ContentResolver v0 = arg7.getContentResolver();
v0_2 = v0.query(SharedPrefProvider.a, null, &key=\'& + arg8 + &\'&, null, null);
catch(Throwable v0_1) {
v0_2 = v6;
if(v0_2 == null) {
String v0_3 = &select value from sharedpref where key=?&;
if(sV.b == null || !sV.b.isOpen()) {
sV.b = new SPDBHelper(arg7).getReadableDatabase();
v0_2 = sV.b.rawQuery(v0_3, new String[]{arg8});
catch(Throwable v0_1) {
v0_2 = v6;
v0_2 = v6;
return v0_2;
从代码中可以看出qlink_secret_key的值是从表 sharepref 中取出
那这个值又是如何生成并存储到 sqlite 中的了?
会看tM#c()方法,当成员变量 tM.a 为空的时候是通过 tM#a(String paramString) 来赋值的.
public static void a(String paramString)
a = paramS
wa.b(Application.a().getBaseContext(), &qlink_secret_key&, paramString);
追踪到 wa#b(Context paramContext, String paramString1, String paramString2)
public static void b(Context paramContext, String paramString1, String paramString2)
sV.a(paramContext, paramString1, paramString2);
继续跟踪sV#a(Context paramContext, String paramString1, String paramString2)
public static void a(Context paramContext, String paramString1, String paramString2)
if (paramContext == null) {}
paramContext = paramContext.getContentResolver();
ContentValues localContentValues = new ContentValues();
localContentValues.put(&key&, paramString1);
localContentValues.put(&value&, paramString2);
if (paramContext.update(SharedPrefProvider.a, localContentValues, &key=?&, new String[] { paramString1 }) == 0)
paramContext.insert(SharedPrefProvider.a, localContentValues);
catch (Throwable paramContext) {}
可以确定是通过tM#c()方法写入qlink_secret_key这个键值的,现在又要用xref 来查看改方法的调用了. (猜测一:这个值是服务端返回的,恰巧返回包就是用 DESede 加密的,此处也是加密的. 猜测二:之前提到的 update_key可能是更新此处的 key)
有两处引用,其中一处是rn#a(rp arg3) ,其中 arg3.c 是通过取 json 中的 data 下 url 键值.(可以佐证猜测一)
public void a(rp arg3) {
if(arg3 != null && arg3.c != null) {
String v0_1 = arg3.c.optString(&url&);
if(TextUtils.isEmpty(((CharSequence)v0_1))) {
goto label_9;
tM.a(v0_1);
catch(Exception v0) {
rh.a(this.a, arg3);
第二处应用在tk#a(tz arg7) , 其中 tk.a = &http://api.free./intf.php&; method 阐述为User.getConfig(继续佐证猜测一这个返回值是通过此处 url 请求到的)
public static void a(tz arg7) {
vO.a(&ApiHelper&, &getUserConfig&);
tL v0 = tK.a(tk.a, &User.getConfig&, null, null, null, null);
//请求 api
vO.a(&ApiHelper&, &getUserConfig end:& + v0.h);
JSONObject v1 = tk.a(v0);
//从返回值中取出 data 字段 既为 qlink_secret_key
if(v1 == null) {
tk.a(v0, arg7, new Object[0]);
String v1_1 = v1.optString(&url&);
if(!TextUtils.isEmpty(((CharSequence)v1_1))) {
tM.a(v1_1);
tk.a(v0, arg7, new Object[0]);
接下来清除 app 数据后抓包来捕获此请求,东静态结合提高效率.
重置应用后第一个请求就是获取此参数,那么问题来了.知道那是用来计算 sign 的,那么第一请求包的sign是如何来的了? (猜测:和另外两个 native 函数有关)
回看tM#a(String arg9, String arg10, List arg11, String arg12, boolean arg13) 方法,若 method 为User.getConfig那么 v1 便为空来计算 sign....
v1 = &User.getConfig&.equals(arg10) ? && : tM.b();
v0_1.add(new BasicNameValuePair(&sign&, tM.b(v0_1, v1)));
回看tM#a(Context paramContext, String paramString1, String paramString2) 方法,若 para2为空则调用的是SecurityUtils.b(paramContext, paramString1)函数
private static String a(Context paramContext, String paramString1, String paramString2)
if (TextUtils.isEmpty(paramString1)) {
return &&;
synchronized (rz.a)
if (TextUtils.isEmpty(paramString2))
paramContext = SecurityUtils.b(paramContext, paramString1);
paramContext = paramContext.toLowerCase();
return paramC
paramContext = SecurityUtils.a(paramContext, paramString1, paramString2);
而 tM#b(Context paramContext, String paramString)
public static String b(Context paramContext, String paramString)
if ((paramContext == null) || (paramString == null) || (paramString.equals(&&)))
if (paramContext == null) {
return &contextisnull&;
if ((paramString == null) || (paramString.length() == 0)) {
return &signstrisnull&;
a(paramContext);
return paramString + &&loadsoerror=true&;
paramContext = initnew(paramContext.getApplicationContext(), paramString, &&, false);
return paramC
catch (Throwable paramContext) {}
return &&;
又要到查看 so 的时候啦
这里显然做了个包判断,若像getkey 一样直接调用肯定会返回 none,所以得分析下isVaild函数来尝试绕过这个限制.
这时有两个选择 1.path so 在判断处将 BEQ 改成 BNE 2.最后一个布尔型变量传 true..
这里选择第二种简单的方法.算出如下结果
09-15 18:29:20.060
/org.wooyun.qihoowifi I/Hi360﹕ MySign = 5c1c5d32ebd2ee7f8beea1b
对比之前 hook 的结果,证明猜测是正确的
09-15 15:09:14.610
/? I/QihooWifi﹕ in tM#a(c|s|s) = channel=100001&devtype=android&inviter_qid=0&m2=9f2de7ceb7dc3e4a0e94&manufacturer=LGE&method=User.getConfig&model=Nexus%205&nance=9&nettype=WIFI&os=4.4.4&qid=0&v=237 | para3 =
09-15 15:09:14.610
/? I/QihooWifi﹕ out tM#a(c|s|s) = 5c1c5d32ebd2ee7f8beea1b
nance 为时间戳生成方式如下:
v3[18] = &nance&;
v3[19] = String.valueOf(System.currentTimeMillis());
至此 sign 的破解基本完成.简单梳理下整个流程
1.先将 url 中参数按序拼接成字符串
2.若 method为User.getConfig将拼接字符串传入native 函数 initnew 计算出 sign 值,并且得到 sign 的加密盐值 data:url
3.若 method 不等于 User.getConfig 则将拼接字符串传入 native 函数 sign 中, 并且对2得到的加密盐进行 DESede 解密后一同传入. (注意大小写敏感)
已发表评论数()
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
排版有问题
没有分页内容
视频无法显示
图片无法显示}

我要回帖

更多关于 淘金币抢购 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信