zoukankan      html  css  js  c++  java
  • xposed的使用实践

    在测试移动端app的时候,抓包过程中可能都会遇到app客户端做了sign,导致无法修改数据包的情况,这个时候一般我们就需要反编译客户端,查找到sign的生成算法,破解算法后,再模拟请求。但这样成本老高了,客户端再做了代码混淆,很难分析。这个时候,可以使用xposed,hook劫持一些关键函数的返回值,让客户端生成我们期待的请求包。

    xposed 可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。

    实践测试。

    我们以想看app测试。

    https://app.mi.com/details?id=com.xiangkan.android&ref=search

    首先反编译客户端,下载后的apk进行解压。

     提取其中dex文件

    放到dex2jar.20目录下,记得去下载官方最新版的dex2jar,低版本啥也还原不出来

    命令:

    D:downloadsdex2jar-2.0>d2j-dex2jar classes.dex
    

      还原成jar包

    然后使用jd-gui打开,4个dex全部还原成jar包

    通过app抓包

    查看个人信息的请求为:

    https://feed.browser.miui.com/api/oauth/bindinfo

    其返回结果为

    由于有requestsign,修改分包会报错,分析请求中userId参数,那么这里可能存在越权遍历信息的问题。

    通过jd-gui中搜索*bindinfo(注意有个*)

    找到定义的抽象接口,其中有个抽象 getBindInfo函数,定义了请求地址。查询这个函数发现它在UserInfoEditActivity.class中被调用。

     其中有个getUserId函数,在实体类User中定义

    那么我只要hook这个功函数,劫持它的返回结果为我们测试的userid,即可验证是否存在越权。

    接下来才是正题

     xposed 下载地址:

    https://forum.xda-developers.com/t/official-xposed-for-lollipop-marshmallow-nougat-oreo-v90-beta3-2018-01-29.3034811/

    授权root权限后激活即可。顺便提一下我的环境是小米4,android6.0,miui10开发版

    idea新建项目,选择empty activity,创建成功后,

    1.在AndroidManifest.xml中添加如下代码

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.xkxposeddemo">

    <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
    <intent-filter>
    <action android:name="android.intent.action.MAIN"/>

    <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
    </activity>
    <meta-data
    android:name="xposedmodule"
    android:value="true" /> <!--告诉xposed框架这是一个xposed模块-->
    <meta-data
    android:name="xposeddescription"
    android:value="这是一个Xposed例程" /> <!--模块描述-->
    <meta-data
    android:name="xposedminversion" android:value="54" /><!--模块支持的最低版本-->
    </application>


    </manifest>

      

    2.下载XposedBridgeApi-54.jar,app目录下创建一个lib目录,注意是lib目录,不是放到libs目录去,把jar复制进去

    链接:https://pan.baidu.com/s/1WNSr4iJSZxXXvWe87vOGjg
    提取码:61uw

    bulid.gradle加入

    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
        implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
        compileOnly files('lib/XposedBridgeApi-54.jar')
    }
    

      

    gradle刷新一下

    4.创建HookTest.class

    测试内容为:

    package com.example.xkxposeddemo;
    
    import java.lang.reflect.Array;
    import java.security.PublicKey;
    import java.util.Arrays;
    import java.util.Map;
    
    import android.util.Log;
    import android.widget.Toast;
    import de.robv.android.xposed.IXposedHookLoadPackage;
    import de.robv.android.xposed.XC_MethodHook;
    import de.robv.android.xposed.XposedBridge;
    import de.robv.android.xposed.XposedHelpers;
    import de.robv.android.xposed.callbacks.XC_LoadPackage;
    
    public class HookTest implements IXposedHookLoadPackage {
        private static final String HOOK_APP_NAME = "com.example.xkxposeddemo";
    
        public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
            XposedBridge.log("Hook初体验:" + lpparam.processName + ":" + lpparam.packageName);
        }
    }
    

      

    5.main目录下创建assets文件夹,放入文件xposed_init内容为 包名.HookTest

    6.运行安装app,xposed模块中出现你写的app说明xposed已经识别出这是个xopsed模块,如果没有,自己去看看xposed有没有激活成功,或者配置错误。选中后,重启设备

    7.勾选掉Instan Run中的所有选项

    8.运行app如果出现

     说明hook成功,如果没有出现,仔细检查以上步骤是否正确,比如包名是不是写错了?比如jar文件是不是放到libs文件夹去了?还是找不到错误的话,xposed日志模块里有日志信息,自行审计一下。

    好,以上只是验证xposed hook测试成功,接下里,是实战测试。前面已经分析过了,我们要hook的函数是getUserId,那么重新编写HookTest

    package com.example.xkxposeddemo;
    
    import java.lang.reflect.Array;
    import java.security.PublicKey;
    import java.util.Arrays;
    import java.util.Map;
    
    import android.os.SystemClock;
    import android.util.Log;
    import android.widget.Toast;
    import de.robv.android.xposed.IXposedHookLoadPackage;
    import de.robv.android.xposed.XC_MethodHook;
    import de.robv.android.xposed.XposedBridge;
    import de.robv.android.xposed.XposedHelpers;
    import de.robv.android.xposed.callbacks.XC_LoadPackage;
    
    import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
    
    public class HookTest implements IXposedHookLoadPackage {
        private static final String HOOK_APP_NAME = "com.xiangkan.android";
        Class class_hook;
    
        public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
            //我们要hook的包名
            if(!lpparam.packageName.equals(HOOK_APP_NAME))
                return;
            XposedBridge.log("Xposed 加载的 app: " + lpparam.packageName);
            //创建一个线程,用于实时的动态发现要hook的类
            new Thread(new Runnable(){
                @Override
                public void run() {
                    String className = "com.bikan.coordinator.router.account.entity.User";
                    //监听是否触发到了需要的hook类名
                    while(true) {
                        SystemClock.sleep(50);
                        try {
                            class_hook = lpparam.classLoader.loadClass(className);
                            XposedBridge.log("Find Class: " + className);
                            break;
                        } catch (Exception e) {
                            Log.e("Find Class error", "ERROR: run: " + e.getMessage());
                        }
                    }
                    //发现指定的类名后,第三个参数写你要hook函数名,后边的跟对应的函数参数类别,比如String.class,如果没有参数不要即可。
                    findAndHookMethod(className, lpparam.classLoader, "getUserId", new XC_MethodHook(){
    
                        //hook函数,劫持函数返回结果
                        protected void afterHookedMethod(MethodHookParam param)
                                throws Throwable {
                            //真实的id
                            String trueResult=(String) param.getResult();
                            XposedBridge.log("trueUserID:"+trueResult);
                            String result = "1496838";
                            param.setResult(result );
                            XposedBridge.log("hook ----ok,nowUserId:"+result);
                        }
    
                    });
    
                }
            }).start();
        }
    }
    

      

     注意以上代码中的红色部分,你需要填写你hook的包名,类名,函数名,以及hook的结果。

    安装app后,重启设备,打开想看app,再次抓包,发现userId已经变成了我们hook的值,而请求也正确的返回了结果,可惜的是,此处验证并不存在越权问题。

     logcat中的日志

     

    测试时发现,只hook了com.bikan.coordinator.router.account.entity.User中的getUserId只修改了bindInfo接口中的userId,如果想修改所有接口中的userId可以修改com.bikan.reading.model.User中的,这样能更快捷的测试其他接口是否存在越权。

     以上是对afterHookedMethod的使用介绍,这是劫持返回结果,但很多时候我们还要劫持的是函数输入内容接下来介绍的就是beforeHookedMethod

    //第三个参数是要hook的函数名,byte[].class是要hook的函数参数类型
    findAndHookMethod(className, lpparam.classLoader, "a",byte[].class, new XC_MethodHook(){
    
                        //hook函数之前劫持输入参数内容
                        protected void beforeHookedMethod(MethodHookParam param)
                                throws Throwable {
    //param.args[0]对应的参数位置 param.args[0]=strToByteArray("<script>alert(1)</script>"); } });

     也是一样的,需要的关键内容,hook需要的类、函数、参数。

    以上就是xposed的测试实践,有不对之处还希望能够指点,感谢

  • 相关阅读:
    正方形_自适应_移动端
    meta name="viewport" content="width=device-width,initial-scale=1.0"
    :before/:after与::before/::after的区别 和属性content:值
    布局:flex弹性布局_兼容性写法
    布局:文本多列布局 column-* :
    布局:网格布局
    clear
    布局:盒模型 box-sizing : border-box ;
    object-fit : cover; 对象(图片和视频对象)
    布局:flex弹性布局_实践02
  • 原文地址:https://www.cnblogs.com/fczlm/p/14366702.html
Copyright © 2011-2022 走看看