android逆向奇技淫巧五:x音fiddler抓包分析协议字段

时间:2024-03-09 18:37:33

  android逆向奇技淫巧第二篇介绍了通过method profiling追踪找到了点赞的方法,于时就用jadx打开,找到了onclick的代码: com.ss.android.ugc.aweme.feed.quick.presenter.cb类下面的onclick方法:混淆非常严重,只能看懂java语法,至于代码的业务意义大部分是不好理解的;单从部分未混淆的方法和变量名看,点击后会先判断是否登陆,如果没登陆就弹出登陆界面;如果登陆了就show各种toast;具体是哪行代码向服务器发送数据了?静态分析完全看不出来!

public final void onClick(View view) {
            String string;
            boolean z = false;
            if (!PatchProxy.proxy(new Object[]{view}, this, f171628a, false, 251117).isSupported) {
                ClickAgent.onClick(view);
                cb.this.f172363h.a("VIDEO_CANCEL_REPORT_SKIP_BEHAVIOR", cb.this.f172358c.getAid());
                int b2 = m.b();
                if (b2 == 0) {
                    z = !AccountProxyService.userService().isLogin();
                } else if (b2 > 0 && !AccountProxyService.userService().isLogin() && !cb.this.l && cb.this.f172358c.getUserDigg() == 0 && bh.b() >= b2) {
                    z = true;
                }
                if (z) {
                    new z().a(cb.this.f172359d).a(cb.this.f172361f).b(cb.this.f172358c.getAid()).f(cb.this.f172358c).c("click_like").c(!bh.d() ? 1 : 0).d(1).e();
                    if (!bh.d()) {
                        bh.c();
                    }
                    String str = "";
                    if (TextUtils.equals(cb.this.f172359d, e.c.f229429a)) {
                        string = str;
                    } else {
                        string = cb.this.m.getString(C4212R.string.f4m);
                    }
                    if (cb.this.f172358c != null) {
                        str = cb.this.f172358c.getAid();
                    }
                    if (a.h().isTeenModeON()) {
                        AccountProxyService.showLogin((Activity) cb.this.m, cb.this.f172359d, "click_like", av.a().a("login_title", string).a("group_id", str).a("log_pb", ae.k(str)).f262690b, null);
                        return;
                    }
                    AccountProxyService.showLogin((Activity) cb.this.m, cb.this.f172359d, "click_like", av.a().a("login_title", string).a("group_id", str).a("log_pb", ae.k(str)).f262690b, new cd(this, view));
                } else if (com.ss.android.ugc.aweme.login.utils.a.a(cb.this.f172358c) && cb.this.f172358c.getUserDigg() == 0) {
                    DmtToast.makeNegativeToast(cb.this.m, com.ss.android.ugc.aweme.login.utils.a.a(cb.this.f172358c, C4212R.string.n0t)).show();
                } else if (cb.this.f172358c.isCanPlay() || cb.this.f172358c.getUserDigg() != 0) {
                    if (cb.this.f172358c.isDelete() && cb.this.f172358c.getUserDigg() == 0) {
                        DmtToast.makeNegativeToast(cb.this.m, (int) C4212R.string.n0t).show();
                    } else if (cb.this.f172358c.getVideoControl() != null && cb.this.f172358c.getVideoControl().timerStatus == 0) {
                        DmtToast.makeNeutralToast(cb.this.m, (int) C4212R.string.mza).show();
                    } else if (ac.f262626b.d(cb.this.f172358c)) {
                        DmtToast.makeNeutralToast(cb.this.m, (int) C4212R.string.h6t).show();
                    } else if (cb.this.l || !ac.f262626b.c(cb.this.f172358c) || !ac.f262626b.a(cb.this.f172358c)) {
                        ((DiggAnimationView) cb.this.G.a(C4212R.id.byb).a()).a(view);
                        if (!NetworkUtils.isNetworkAvailable(cb.this.m)) {
                            DmtToast.makeNegativeToast(cb.this.m, (int) C4212R.string.f288170d).show();
                            return;
                        }
                        cb cbVar = cb.this;
                        cbVar.a(cbVar.f172358c);
                    } else {
                        DmtToast.makeNeutralToast(cb.this.m, (int) C4212R.string.n5u).show();
                    }
                } else if (cb.this.f172358c.isImage()) {
                    DmtToast.makeNegativeToast(cb.this.m, (int) C4212R.string.evm).show();
                } else {
                    DmtToast.makeNegativeToast(cb.this.m, (int) C4212R.string.n0t).show();
                }
            }
        }

   既然静态分析看不出,要不试试动态调试?这种想法理论上是可行的,但分析这里的点赞代码还是困难:(1)jeb或as调试,只能调试smali代码,无法调试java代码  (2)java代码就是smali反编译而来的,所以smali也是混淆的;如果不理解代码的业务目的,单步执行代码有啥意义了?(3)smali代码远比java多,动态逐行调试耗时也很多;怎么办了?

   计算机网络发展到今天,已经找不到单机的app了! 客户端安装的app做的所有工作最终目的都是为了和服务器通信(就像打工人,每天干的所有活的最终目的都是为了挣钱、养家糊口);前面说过了,逆向破解一般都是从数据开始的。数据可以通过CE或其他软件搜索内存,也可以先抓网络封包,看看客户端给服务器发送了啥,然后根据数据的字段在代码里面找,看看这些字段的值都是怎么生成的!这里逆向android应用,所以先用fiddler抓封包!

   这个app会给服务器发送很多数据包,哪个才是点赞的数据包了?这里介绍一个小技巧:这个软件通过发给服务器的host是aweme.snssdk.com,可以先用fiddler过滤一下,只选这个服务器;很快,就能抓到点赞的封包(个人很好奇,为啥点赞接口取名叫digg了?好奇怪的名字):

GET https://aweme.snssdk.com/aweme/v1/commit/item/digg/?aweme_id=6956180208793718055&type=1&channel_id=-1&city=510100&activity=0&os_api=22&device_type=M973Q&ssmix=a&manifest_version_code=150501&dpi=480&uuid=865166023654745&app_name=aweme&version_name=15.5.0&ts=1620296753&cpu_support64=false&app_type=normal&appTheme=light&ac=wifi&host_abi=armeabi-v7a&update_version_code=15509900&channel=xiaomi&_rticket=1620296754623&device_platform=android&iid=2744832902828125&version_code=150500&cdid=7addad62-d097-41da-b852-e0de8b24fe75&openudid=338803367b93a120&device_id=70039083151&resolution=1080*1920&os_version=5.1.1&language=zh&device_brand=Meizu&aid=1128&minor_status=0&mcc_mnc=46000 HTTP/1.1
Accept-Encoding: gzip
x-tt-dt: AAA7NE2KX2XRH5ZIBMIIJHUGNWEXQLPT2G5U2VKAPRSBVVGBNOLZGYT36N7VMCWTDFTQBQXBW6FSC2IWBD36QSIH6MSUI2SKDMHF4T27M5MS6TL2XHUCXVFWWDJM2Y3HQZEHXQ42UCB7JUEHURQRH6Y
passport-sdk-version: 18
X-Tt-Token: 000e8f473aea647b3c44fd3b9f7482439e02da23d858b1609a77f5edbf3bcc6c774f39175ea27eed09ffb2dee02c173fcc137b53019bb3614db48a84e88879cf2cabc8a810d38b88fb1d9bc7640b02e655a186f8b1e0daf197e60067b35a68adc68ad-1.0.1
sdk-version: 2
X-SS-REQ-TICKET: 1620296754625
Cookie: passport_csrf_token_default=f4442957bc07adf1986f4df139296dd7; install_id=2744832902828125; ttreq=1$184784690dc292ea1ad4e5db65553166a5674c3e; multi_sids=95063141447%3A0e8f473aea647b3c44fd3b9f7482439e; odin_tt=fac32cc300e49d8f22a70f1cd7b92569039d7305b6fdef7f2389cb98e0f9e9493f6c8374ad33dabed24ea41c55e1834e; n_mh=B6WRe0yd-1qIuffF6ZWNO-CSGlW1Q-VhC0E79NrqYTg; sid_guard=0e8f473aea647b3c44fd3b9f7482439e%7C1620296607%7C5184000%7CMon%2C+05-Jul-2021+10%3A23%3A27+GMT; uid_tt=d06498fc7329b7187e209d0e6279e1d7; sid_tt=0e8f473aea647b3c44fd3b9f7482439e; sessionid=0e8f473aea647b3c44fd3b9f7482439e;
X-Ladon: gW1IO3ulq0eYymnbYa+7nAu2l116ADdAdmSIA1eB3Cv5BBIo
X-Khronos: 1620296754
X-Gorgon: 0404401f40051f42c987ec09aebf8038d629adf2add584933f8f
X-Tyhon: s2S+nKZ8jrepKJ2VtCulu7carp/ZLqe2gn24aHA=
X-Argus: Uictv+neuH8ZqjOjXzvEIvXCEXYEgUy3dUKWzj08JUtmGeYa4HfNfN8bp7Yga22Jbik2N2dBKezA48YN1E9A1KaBjXi2ixu5cHzAkQU9Tl4f/+a9xWuLYIZ/+PkW/YXUsmRCfszWlcMePPeyNQYEGkb5FssTkIr3EZ87TJ9NLBDJCJGA0i4PICbLnClzdfmBs+57JVi1sU2/MELCr9gO/Nka5eIJsEoGB/CIaL3gPmEbZ0sUl7sxIvKksMwj3f7tYBCriYBKmfeREuiYf1S18c7i
Host: aweme.snssdk.com
Connection: Keep-Alive
User-Agent: okhttp/3.10.0.1

 服务器返回字段:每次点赞成功后,status_code会是0;

   

 

   逆向的目的是重放,简单理解就是自己构造数据包模拟用户真实的点赞行为,所以这里也要搞清楚每个字段的含义,这些字段是怎么生成的,后续才能自己写代码实现;这里面的字段有很多,哪些字段可以直接写死复用,哪些字段需要我们重新用算法生成了?这里继续在app点赞,再抓一个digg数据包,然后把两个包对比,就知道哪些字段可以写死复用,哪些字段要动态生成了,对比如下:第一行是url,参数不同,待会单独分析;接着是X-SS-REQ-TICKET和X-Khronos,这两个明显是毫秒和秒级别的时间戳,生成很简单;还剩X-Ladon、X-GORGON、X-Tyhon、X-Argus4个字段不同。从这个4个字段的取值看,明显不是人能读懂的数据,这个就需要分析代码了

   

   回过头来再看看url的参数对比,如下:第一个不一样的地方就是aweme_id,明显是被点赞短视频的id;第二个是ts、第三个是_rticket都是时间戳,所以url这里也没啥需要额外分析代码的,比较简单!注意:url里面有个type字段,等于1表示点赞,等于0表示取消点赞!

    

   综上所述:要自己写代码模拟实现真实的点赞行为,需要生成4个关键的字段:X-Ladon、X-GORGON、X-Tyhon、X-Argus;这4个字段都是怎么生成的了? 下一步就需要分析java个so层的代码了!

 

  最后有一点疑惑:这个app为啥不学微信(在tls1.3的基础上打造mmtls协议了)自定义通信协议了? 目前用的还是https协议,很容易被fiddler抓包的!微信的mmtls协议通信,用的就不是https协议,fidder就无法解析,保障了数据安全!

 

  该APP版本:15.5.0