APP常用抓包技術

古時明月2333發表於2020-11-20

此文轉載於:https://blog.csdn.net/xiaoxsen/article/details/89855420

一、APP常用抓包技術

  • 工具
    Charles,fiddler,burpsuite,Packet Capture等,具體操作可以查詢百度
  • 抓包方法
    a.常規操作直接抓
    b.使用Xposed+JustTrustMe關閉SSL證照驗證抓包
    關閉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() {
            @Override
            protected 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.http

                Class hookclasss = cl.loadClass("com.loopj.android.http.RequestParams");
                XposedHelpers.findAndHookMethod(hookclass, "a",hookclasss,String.class, new XC_MethodHook() {

                    @Override
                    protected 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);
                    }
                    @Override
                    protected 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() {

                    @Override
                    protected 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);
                    }
                    @Override
                    protected 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() {

                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        String params = (String) param.args[0];
                        XposedBridge.log("g param1:"+params);
                        super.beforeHookedMethod(param);
                    }
                    @Override
                    protected 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() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        String params = (String) param.args[0];
                        XposedBridge.log("h param1:"+params);
                        super.beforeHookedMethod(param);
                    }
                    @Override
                    protected 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也就是可以直接列印出加密引數和加密結果,本人寫了一個Java基本演算法自吐外掛,常規演算法可以不需要脫殼和逆向app,直接列印加密演算法和加密引數,但也有缺陷僅僅是Java層的演算法而且是常規演算法,如果演算法有做修改則還是需要逆向程式碼,但是可以給我做一些前期的準備,過濾掉一些引數演算法逆向操作。

 

轉載於:https://blog.csdn.net/xiaoxsen/article/details/89855420

相關文章