0


实战 逆向最新黄鸟抓包软件

前言

观众器者为良匠,观众病者为良医。这篇文章分析了知名抓包软件HttpCanary高级功能的使用限制,使用了许多实用的工具,过程写的尽可能的详细,希望对大家有所帮助。

笔者实践环境:

  1. pixel 6
  2. Android 12
  3. frida 15.1.27
  4. HttpCanary v3.3.5

脱壳

在jadx中查看原包,检查软件是否加固

在这里插入图片描述

由于包下的类比较少且看见了stub,因此可以确定是360加固了,直接用工具脱壳,我用的是hluwa巨佬的frida-dexdump,具体用法可以看官网,这里直接进行尝试脱壳

在这里插入图片描述

在众多dex文件中通过入口类进行筛选

在这里插入图片描述

脱壳完毕~~

核心代码定位与分析

两种思路:

  1. 从激活功能下手,修改成功逻辑

在这里插入图片描述

  1. 从vip功能下手,定位身份判断关键点

在这里插入图片描述

对比两种思路,第二种思路感觉更加的简单和直接,当然第一种也是可以做的,只不过会比想想中的更加复杂,我这里直接给出第一种思路的frida版本,但它是不完善的,重启软件会失效,有兴趣的可以研究一下

functionpojie(){// remove app detect expression
    Java.choose("com.guoshi.httpcanary.ui.premium.PremiumActivateActivity",{onMatch:function(instance){
            console.log("f7834 before value is "+ instance.\uFC82.value)
            instance.\uFC82.value =1},onComplete:function(){}})// break vip step1letC2217= Java.use("com.guoshi.\uFC70.\uFC71.\uFC72");C2217["\uFC70"].implementation=function(){let ret =this.\uFC70.apply(this, arguments);var CodeActivateResBody = Java.use("com.guoshi.httpcanary.model.CodeActivateResBody")var obj = CodeActivateResBody.$new()
        obj.status.value =1;
        obj.encryptToken.value ="mdcg";
        obj.token.value ="mdcg";
        console.log("Create obj --> "+ obj)
        console.log("status --> "+ obj.status.value)
        console.log("encryptToken --> "+ obj.encryptToken.value)
        console.log("token --> "+ obj.token.value)return obj;};// break vip step2let PremiumActivateActivity = Java.use("com.guoshi.httpcanary.ui.premium.PremiumActivateActivity");
    PremiumActivateActivity["\uFC71"].overload('java.lang.String','java.lang.String').implementation=function(arg1, arg2){let ret =this.\uFC71(arg1, arg2);
        console.log('\uFC71 ret before value is '+ ret);
        ret =true
        console.log('\uFC71 ret after value is '+ ret);return ret;};}functionmain(){
    Java.perform(function(){pojie()})}setImmediate(main)

在这里插入图片描述

下面主要对第二种思路进行分析,极速模式属于高级功能,由一个按钮进行控制,最迅速的定位方式为hook点击事件,并反推出核心判断。我使用r0ysue巨佬的hookEvent.js快速定位点击事件,代码不复杂,建议研究一下

var jclazz =null;var jobj =null;functiongetObjClassName(obj){if(!jclazz){var jclazz = Java.use("java.lang.Class");}if(!jobj){var jobj = Java.use("java.lang.Object");}return jclazz.getName.call(jobj.getClass.call(obj));}functionwatch(obj, mtdName){var listener_name =getObjClassName(obj);var target = Java.use(listener_name);if(!target ||!mtdName in target){return;}
    target[mtdName].overloads.forEach(function(overload){
        overload.implementation=function(){
            console.log("[WatchEvent] "+ mtdName +": "+getObjClassName(this))returnthis[mtdName].apply(this, arguments);};})}functionOnClickListener(){
    Java.perform(function(){
        Java.use("android.view.View").setOnClickListener.implementation=function(listener){if(listener !=null){watch(listener,'onClick');}returnthis.setOnClickListener(listener);};
        
        Java.choose("android.view.View$ListenerInfo",{onMatch:function(instance){
                instance = instance.mOnClickListener.value;if(instance){
                    console.log("mOnClickListener name is :"+getObjClassName(instance));watch(instance,'onClick');}},onComplete:function(){}})})}setImmediate(OnClickListener);

在这里插入图片描述

注册点击事件的类是com.guoshi.httpcanary.ui.-$

     L 
    
   
     a 
    
   
     m 
    
   
     b 
    
   
     d 
    
   
     a 
    
   
  
    Lambda 
   
  
LambdaHomeActivity$L0WEKAV1lAcNYjl4nGyTdnm61r8,在jadx中查看

在这里插入图片描述

在这里插入图片描述

后面的注释是我加上去的,下面从第一处判断开始分析

m6185函数传入了一串加密字符串,我们需要知道它代表了什么意思,可以看一下这个函数

在这里插入图片描述

在这里插入图片描述

可以确定是一个解密函数,但我们不需要逆向出解密的逻辑,因为可以直接hook获取返回值

functionhook_1(){letC2146= Java.use("com.guoshi.httpcanary.\uFC72");C2146["\uFC70"].implementation=function(str){
        console.log('input str: '+ str);let ret =this.\uFC70(str);
        console.log('ret value is '+ ret);return ret;};}functionmain(){
    Java.perform(function(){hook_1()})}setImmediate(main)

在这里插入图片描述

解密的字符串是settings_turbo_mode,翻译成汉语就是设置极速模式,那m6317函数是什么呢?点进去看看

在这里插入图片描述

懂了,m6317是从sharedPreferences中取出相应key的value,而settings_turbo_mode保存的是当前极速模式是打开还是关闭,如果返回值为true,那么表明当前属于开启的状态,这样就要进入判断成功的逻辑,把开启状态变成关闭状态。

下面分析第二处判断,该处判断取决于a函数和z函数的返回值,点开看一下

在这里插入图片描述

有native关键字就意味着我们要分析so层了,那么第一步就是要确定这些函数在哪个so文件中,首先我们假设这些函数都是动态注册的,那么就可以使用yang神的hook_RegistNatives.js脚本迅速判断,注意要以spawn模式启动,脚本如下:

functionfind_RegisterNatives(params){var symbols = Module.enumerateSymbolsSync("libart.so");var addrRegisterNatives =null;for(var i =0; i < symbols.length; i++){var symbol = symbols[i];//_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodiif(symbol.name.indexOf("art")>=0&&
                symbol.name.indexOf("JNI")>=0&& 
                symbol.name.indexOf("RegisterNatives")>=0&& 
                symbol.name.indexOf("CheckJNI")<0){
            addrRegisterNatives = symbol.address;
            console.log("RegisterNatives is at ", symbol.address, symbol.name);hook_RegisterNatives(addrRegisterNatives)}}}functionhook_RegisterNatives(addrRegisterNatives){if(addrRegisterNatives !=null){
        Interceptor.attach(addrRegisterNatives,{onEnter:function(args){
                console.log("[RegisterNatives] method_count:", args[3]);var env = args[0];var java_class = args[1];var class_name = Java.vm.tryGetEnv().getClassName(java_class);var methods_ptr =ptr(args[2]);var method_count =parseInt(args[3]);for(var i =0; i < method_count; i++){var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize *3));var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize *3+ Process.pointerSize));var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize *3+ Process.pointerSize *2));var name = Memory.readCString(name_ptr);var sig = Memory.readCString(sig_ptr);var find_module = Process.findModuleByAddress(fnPtr_ptr);
                    console.log("[RegisterNatives] java_class:", class_name,"name:", name,"sig:", sig,"fnPtr:", fnPtr_ptr," fnOffset:",ptr(fnPtr_ptr).sub(find_module.base)," callee:", DebugSymbol.fromAddress(this.returnAddress));}}});}}setImmediate(find_RegisterNatives);

在这里插入图片描述

确定了我们要分析的是libHttpCanary.so文件,并且函数的偏移地址也拿到了,把文件拖进ida中看一下,重新命名的过程就不展示了

在这里插入图片描述

a方法调用了z方法和l方法,点进z方法看一下

在这里插入图片描述

由上面的伪代码可以推出,z方法就是判断当前是否是高级模式,如果是高级模式则返回true,下面看看l方法是什么

在这里插入图片描述

由伪代码可以看出l方法返回用户试用的剩余天数,如果为正数则表明用户的试用还没有到期,如果为负数则表明用户的试用到期了,现在重新看a方法应该清晰了很多

在这里插入图片描述

这个逻辑表达式表示的是如果用户不是vip且试用还没有到期,那么结果为true。

那么两个核心函数就找到了,一个是a方法,一个是z方法,a方法判断是否是试用模式,z方法判断是否是vip模式,那么这两个方法只要有一个为真就能使用软件的高级功能了,下面使用frida简单测试一下

functionhook_2(){let Cont = Java.use("com.guoshi.httpcanary.jni.Cont");
    Cont["a"].implementation=function(context){let ret =this.a(context);
        ret =true
        console.log('a ret value is '+ ret);return ret;};

    Cont["z"].implementation=function(context){let ret =this.z(context);
        ret =false
        console.log('z ret value is '+ ret);return ret;};}functionmain(){
    Java.perform(function(){// hook_1()hook_2()})}setImmediate(main)

使用脚本之前

在这里插入图片描述

使用脚本之后

在这里插入图片描述

结尾

这个软件整体的防护还是很到位的,java层的混淆也是很给力,但如果加一些frida的反调试并且在so层多加一点防护那么就更安全了。上面只是使用了frida脚本进行了功能的分析,我也把它写成了xposed模块,方便大家的使用,原包与模块都放在了下面的链接中,当然有能力的还是要支持下正版。因为新人创作不易,希望大家点个赞鼓励一下((′▽`〃))

HttpCanary_v3.3.5.apk

httpCanaryBreaker.apk

标签: android 安全

本文转载自: https://blog.csdn.net/weixin_56039202/article/details/125894813
版权归原作者 马到成功~ 所有, 如有侵权,请联系我们删除。

“实战 逆向最新黄鸟抓包软件”的评论:

还没有评论