在测试移动端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的测试实践,有不对之处还希望能够指点,感谢