一、APP常用抓包技术
- 工具
Charles,fiddler,burpsuite,Packet Capture等,具体操作可以查找百度 - 抓包方法
a.常规操作直接抓
b.使用Xposed+JustTrustMe关闭SSL证书验证抓包
关闭SSL证书校验之前抓包
关闭SSL证书校验之后抓包
c.使用Packet Capture抓取TCP数据包
d.通过写xposed hook插件打印请求url和请求参数(示例可参照下面的案例)
二、APP脱壳
- .加壳的原理
给dex文件加层壳,反编译后的代码就是加壳的代码,看不到原dex代码,在一定程度上来说,还是可以起到防破解的,也可以防止二次打包 - .常用的APP加固壳
360 腾讯乐固、百度、网易、阿里、爱加密、梆梆、娜迦、顶象等 - 手写脱壳工具:
脱壳方式有好多种,企业壳最难搞,这里分享一种使用xposed插件脱免费壳,主要的代码如下:
public class PackageHook {Class Dex;Method Dex_getBytes;Method getDex;String packagename;public PackageHook(XC_LoadPackage.LoadPackageParam sharePkgParam) {packageHook(sharePkgParam);}private void packageHook(final XC_LoadPackage.LoadPackageParam lpparam) {Log.i("jyy", lpparam.packageName);final String packagename = "你要脱壳的app包名";//添加程序包名initRefect();XposedBridge.log("目标包名:" + lpparam.packageName);String str = "java.lang.ClassLoader";String str2 = "loadClass";XposedHelpers.findAndHookMethod(str, lpparam.classLoader, str2, String.class, Boolean.TYPE, new XC_MethodHook() {protected void afterHookedMethod(MethodHookParam param) throws Throwable {super.afterHookedMethod(param);Class cls = (Class) param.getResult();if (cls == null) {//XposedBridge.log("cls == null");return;}String name = cls.getName();XposedBridge.log("当前类名:" + name);byte[] bArr = (byte[]) Dex_getBytes.invoke(getDex.invoke(cls, new Object[0]), new Object[0]);if (bArr == null) {XposedBridge.log("数据为空:返回");return;}XposedBridge.log("开始写数据");String dex_path = "/data/data/" + packagename + "/" + packagename + "_" + bArr.length + ".dex";XposedBridge.log(dex_path);File file = new File(dex_path);if (file.exists()) return;writeByte(bArr, file.getAbsolutePath());}} );}public void initRefect() {try {Dex = Class.forName("com.android.dex.Dex");Dex_getBytes = Dex.getDeclaredMethod("getBytes", new Class[0]);getDex = Class.forName("java.lang.Class").getDeclaredMethod("getDex", new Class[0]);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}}public void writeByte(byte[] bArr, String str) {try {OutputStream outputStream = new FileOutputStream(str);outputStream.write(bArr);outputStream.close();} catch (Exception e) {e.printStackTrace();XposedBridge.log("文件写出失败");}}
通过代码可以发现就是反射拿到Android中com.android.dex.Dex对象然后调用getDex方法然后把字节写到文件,其实就是脱壳后dex文件。Fdex2脱壳工具的核心原理就是上述代码。
三、App逆向分析
- 目标:xxx.apk 用户注册短信校验接口分析(仅仅用于学习,违法使用后果自负)
- 工具:jadx,jeb, Android studio等
- 抓包:注册短信校验包
如果没有逆向分析APP的看到请求参数是不是有点傻眼了,下面来探探究竟,先脱壳然后使用jadx打开脱壳后的dex,然后搜索关键词
继续跟踪代码,发现CLIENT_KEY是通过一个算法得到这个值
继续跟进代码(选中该方法按ctrl+鼠标左键)
先看h方法其实就是一个MD5算法
继续跟进上述a方法中的a方法:
其实f方法就是做了一些字符串拼接操作,g方法就是做了数组排序,可以自行继续追踪下去,如果是Java开发则只需要拷贝就行,其他语言改写就可以。到这里算法基本已经明确,现在最主要的问题就是a方法的参数:
常规操作是去找这个方法在哪里调用,这里先介绍一个技巧可以使用xposed 写一个hook插件把参数打印出来,如果打出来的参数还有加密,还是得去找它被调用的地方。不熟悉xposed框架可以去百度,一个神器的框架,hook插件代码:
private void cgvHook(final XC_LoadPackage.LoadPackageParam lpp) {Log.i("jyy", lpp.packageName);if (!lpp.packageName.contains("com.cgv.cn.movie")) {return;}XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {ClassLoader cl = ((Context) param.args[0]).getClassLoader();Class<?> hookclass = null;try {hookclass = cl.loadClass("com.cgv.cn.movie.b.ar");} catch (Exception e) {Log.e("jyy", "寻找xxx.xxx.xxx报错", e);return;}//cn.ikicker.moviefans.ui.activity.b//a(String str, String str2, String str3)Log.e("jyy", "寻找xxx.xxx.xxx成功");//com.loopj.android.httpClass hookclasss = cl.loadClass("com.loopj.android.http.RequestParams");XposedHelpers.findAndHookMethod(hookclass, "a",hookclasss,String.class, new XC_MethodHook() {@Overrideprotected void beforeHookedMethod(MethodHookParam param) throws Throwable {Object params = param.args[0];String param1 = (String) param.args[1];XposedBridge.log("a params:"+params.toString());XposedBridge.log("a param1:"+param1);super.beforeHookedMethod(param);}@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {String result = (String) param.getResult();XposedBridge.log("a result:"+result);super.afterHookedMethod(param);}});XposedHelpers.findAndHookMethod(hookclass, "a",hookclasss,String.class, String.class,new XC_MethodHook() {@Overrideprotected void beforeHookedMethod(MethodHookParam param) throws Throwable {Object params = param.args[0];String param1 = (String) param.args[1];String param2 = (String) param.args[2];XposedBridge.log("aa params:"+params.toString());XposedBridge.log("aa param1:"+param1);XposedBridge.log("aa param2:"+param2);super.beforeHookedMethod(param);}@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {String result = (String) param.getResult();XposedBridge.log("aa result:"+result);super.afterHookedMethod(param);}});XposedHelpers.findAndHookMethod(hookclass, "g",String.class, new XC_MethodHook() {@Overrideprotected void beforeHookedMethod(MethodHookParam param) throws Throwable {String params = (String) param.args[0];XposedBridge.log("g param1:"+params);super.beforeHookedMethod(param);}@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {String result = (String) param.getResult();XposedBridge.log("g result:"+result);super.afterHookedMethod(param);}});XposedHelpers.findAndHookMethod(hookclass, "h",String.class, new XC_MethodHook() {@Overrideprotected void beforeHookedMethod(MethodHookParam param) throws Throwable {String params = (String) param.args[0];XposedBridge.log("h param1:"+params);super.beforeHookedMethod(param);}@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {String result = (String) param.getResult();XposedBridge.log("h result:"+result);super.afterHookedMethod(param);}});}});}
打开ddms就可以查看aa params打印出来的就是我们a方法的第一个参数,aa param1打印出的就是第二参数,其实就是请求URL,换句话如果抓不到包也就可以使用这种办法把请求URL打出,也就是上面描述抓包方法中的第四种。aa result打印出的就是a方法的返回值,发现和抓包的的值是完全一样的,h方法的参数和返回值也打印出来了。其他的参数都可以按照这种思路去操作,图片中打码部分为手机号,你换成你们注册发送短信的手机号码即可。
加密算法和加密参数已经知道了,CLIENT_KEY基本搞定了,这些都是一些初级的操作,还有很多app算法套路更深需要不断提升自己的实力才能击破他。其实这种Java基础加密完全可以写一套常用算法hook也就是可以直接打印出加密参数和加密结果