几个月没登过csdn 期间对于安卓逆向自然是多学习了一些
本次研究学习运动世界校园的程度应该会比以前深一点
(以前发的那篇算个什么东西 简直是羞耻 留着就当激励自己了)
这次对360加固进行脱壳 拿到真实DEX以后就没什么难度了 只是练一个阅读代码的学习能力而已 脱壳方法多种多样 与主题无关暂不详述
前文提到的检测模拟器特征文件的函数仍然存在 只是没有用File.exists()的方法了 先放出反编译后的代码
private static List首先不看内部代码 直接hook 在模拟器内运行的返回值为m(Context object) { Object object2; try { object2 = (String)aj.b((Context)object, b.ac, "[]"); object = a.a().b((String)object2, object.getString(2131296410));//这个String为SWCampus2017DDY_ 用于解密加密后的Json Json内容为检测文件列表 我是根据这个字符串在strings.xml里的名字为emulator_key跟进来的 object = (List)w.a().fromJson((String)object, new TypeToken >(){}.getType()); if (object == null) return Arrays.asList((Object[])com.zjwh.android_wh_physicalfitness.b.a.u); object2 = object; } catch (Exception exception) { object = null; object2.printStackTrace(); if (object == null) return Arrays.asList((Object[])com.zjwh.android_wh_physicalfitness.b.a.u); object2 = object; if (!object.isEmpty()) return object2; return Arrays.asList((Object[])com.zjwh.android_wh_physicalfitness.b.a.u); } if (!object.isEmpty()) return object2; return Arrays.asList((Object[])com.zjwh.android_wh_physicalfitness.b.a.u); { catch (Exception exception) {} } }
一看便知 只要将返回值设为空列表就可以了
param.setResult(new ArrayList());
检测模拟器文件这关就算是过了
public static boolean a(Context var0) { block26 : { block19 : { var14_6 = (String)aj.b("emulator_switch", "");//明文硬编码 大忌 一看就知道是干什么的了 if (!TextUtils.isEmpty((CharSequence)var14_6)) { var14_6 = com.zjwh.android_wh_physicalfitness.utils.a.a().b((String)var14_6, var0.getString(2131296410)); d.f((String)"emulatorSwitch", (String)var14_6); var14_6 = (EmulatorSwitchBean)new Gson().fromJson((String)var14_6, EmulatorSwitchBean.class); if (var14_6 != null) { var5_7 = var14_6.isCpu();//这些我不知道是不能混淆掉吗 一看就知道是检测硬件信息 var6_8 = var14_6.isCpuFreq(); var11_9 = var14_6.isKernel(); var10_10 = var14_6.isGravity(); var9_11 = var14_6.isTemp(); var8_12 = var14_6.isVolt(); var7_13 = var14_6.isFile(); var12_14 = var14_6.isGps(); var2_15 = var14_6.getPassCount(); var13_16 = var5_7; var5_7 = var12_14; break block19; } } var5_7 = false; var7_13 = false; var8_12 = false; var9_11 = false; var10_10 = false; var11_9 = false; var6_8 = false; var13_16 = false; var2_15 = 0; } if (!var13_16) ** GOTO lbl44 var14_6 = JniAnti.getCpuinfo();//检测CPU信息 包含桌面平台就是模拟器 if (!var14_6.contains((CharSequence)"Genuine Intel(R)") && !var14_6.contains((CharSequence)"Intel(R) Core(TM)") && !var14_6.contains((CharSequence)"Intel(R) Pentium(R)") && !var14_6.contains((CharSequence)"Intel(R) Xeon(R)") && !(var12_14 = var14_6.contains((CharSequence)"AMD"))) ** GOTO lbl44 var4_17 = 1; ** GOTO lbl45 { catch (Exception var0_3) { var1_19 = var2_15; var2_15 = 0; break block20; } } catch (Exception var0_1) { block20 : { block25 : { block24 : { block23 : { block22 : { block21 : { var1_19 = 0; var2_15 = 0; ** GOTO lbl118 lbl44: // 2 sources: var4_17 = 0; lbl45: // 2 sources: var3_18 = var4_17; if (!var11_9) ** GOTO lbl58 var1_19 = var4_17; var14_6 = JniAnti.getKernelVersion(); var1_19 = var4_17; //下面的应该是检测服务 if (var14_6.contains((CharSequence)"qemu+")) ** GOTO lbl-1000 var1_19 = var4_17; if (var14_6.contains((CharSequence)"tencent")) ** GOTO lbl-1000 var3_18 = var4_17; var1_19 = var4_17; if (var14_6.contains((CharSequence)"virtualbox")) lbl-1000: // 3 sources: { var3_18 = var4_17 + 1; } lbl58: // 4 sources: var4_17 = var3_18; if (!var10_10) break block21; var4_17 = var3_18; var1_19 = var3_18; if (a.a((Context)var0)) break block21; var4_17 = var3_18 + 1; } var3_18 = var4_17; if (var9_11) { var3_18 = var4_17; var1_19 = var4_17; if (!TextUtils.isEmpty((CharSequence)a.d((Context)var0))) break block22; var3_18 = var4_17 + 1; } } var4_17 = var3_18; if (var8_12) { var4_17 = var3_18; var1_19 = var3_18; if (!TextUtils.isEmpty((CharSequence)a.e((Context)var0))) break block23; var4_17 = var3_18 + 1; } } var3_18 = var4_17; if (var7_13) { var3_18 = var4_17; var1_19 = var4_17; if (JniAnti.checkAntiFile() <= 0) break block24;//JNI层的文件检测 检测列表也可以逆向SO看出来 var3_18 = var4_17 + 1; } } if (!var5_7) ** GOTO lbl101 var1_19 = var3_18; try { var5_7 = a.c((Context)var0); if (var5_7) break block25; } catch (Exception var0_4) { var3_18 = var1_19; var1_19 = var2_15; var2_15 = var3_18; } var1_19 = var3_18 + 1; ** GOTO lbl103 ** GOTO lbl118 } var1_19 = var3_18; lbl103: // 2 sources: var3_18 = var1_19; var4_17 = var2_15; if (!var6_8) break block26; try { var5_7 = c.a(a.a()).equals((Object)"0M");//不知道是什么 期待大牛点拨 var3_18 = var1_19; var4_17 = var2_15; ** if (!var5_7) goto lbl-1000 } catch (Exception var0_5) { var3_18 = var1_19; var1_19 = var2_15; var2_15 = var3_18; } lbl-1000: // 1 sources: { var3_18 = var1_19 + 1; var4_17 = var2_15; } lbl-1000: // 2 sources: { } } var0_2.printStackTrace(); var3_18 = var2_15; var4_17 = var1_19; } } if (var3_18 <= 0) return false; if (var3_18 < var4_17) return false; return true; }
private static boolean b() { String string2; HashSet hashSet = new HashSet(); String string3 = "/proc/" + Process.myPid() + "/maps";//读取映射 try { string3 = new BufferedReader((Reader)new FileReader(string3)); while ((string2 = string3.readLine()) != null) { if (!string2.endsWith(".so") && !string2.endsWith(".jar")) continue;//过滤so和jar hashSet.add((Object)string2.substring(string2.lastIndexOf(" ") + 1)); } hashSet = hashSet.iterator(); } catch (Exception exception) { exception.printStackTrace(); return false; } do { if (!hashSet.hasNext()) { string3.close(); return false; } string2 = (String)hashSet.next(); if (!string2.contains((CharSequence)"com.saurik.substrate")) continue;//cydia return true; } while (!string2.contains((CharSequence)"XposedBridge.jar"));//xposed return true; }
private static boolean d(Context context) { for (ApplicationInfo applicationInfo : context.getPackageManager().getInstalledApplications(128)) { if (applicationInfo.packageName.equals((Object)"de.robv.android.xposed.installer")) { return true; } if (!applicationInfo.packageName.equals((Object)"com.saurik.substrate")) continue; return true; } return false; }第三个 我最喜欢的一个窝里龌龊的玩法 栈回溯 是很多调用者检测的常用手法 虽然这个样本不需要检测调用者
private static boolean a() { try { throw new Exception("blah");//blah有点可爱 } catch (Exception exception) { StackTraceElement[] arrstackTraceElement = exception.getStackTrace(); int n2 = arrstackTraceElement.length; int n3 = 0; for (int i2 = 0; i2 < n2; ++i2) { StackTraceElement stackTraceElement = arrstackTraceElement[i2]; int n4 = n3++; if (stackTraceElement.getClassName().equals((Object)"com.android.internal.os.ZygoteInit")) { n4 = n3; if (n3 == 2) { return true; } } if (stackTraceElement.getClassName().equals((Object)"com.saurik.substrate.MS$2") && stackTraceElement.getMethodName().equals((Object)"invoked")) { return true; } if (stackTraceElement.getClassName().equals((Object)"de.robv.android.xposed.XposedBridge") && stackTraceElement.getMethodName().equals((Object)"handleHookedMethod")) { return true; } n3 = n4; } return false; } }