篇幅有限 完整内容及源码关注公众号:ReverseCode,发送 冲
pixel刷安卓7 proxychains wget https://dl.google.com/dl/android/aosp/sailfish-n2g47o-factory-f2bc8024.zip
proxychains wget https://forum.xda-developers.com/attachments/xposedinstaller_3-1-5-apk.4393082/
proxychains wget https://supersuroot.org/downloads/supersu-pro.apk
proxychains wget https://dl.twrp.me/sailfish/twrp-3.3.0-0-sailfish.img
1 2 3 4 5 6 cd sailfish-opm4.171019.021.p1 && adb reboot bootloader && ./flash-all.sh adb push SR5-SuperSU-v2.82-SR5-20171001224502.zip /data/local/tmp adb reboot bootloader && fastboot boot twrp-3.3.0-0-sailfish.img 刷入twrp后安装supersu adb install XposedInstaller_3.1.5.apk 常见模块https://github.com/WrBug/GravityBox.git adb push timeadjust.sh /data/local/tmp && sh timeadjust.sh 时间修改正确 adb install com.ttxapps.wifiadb_2.1.3-810031745_minAPI15.apk
pixel刷安卓10 1 2 3 4 5 6 7 8 9 10 11 12 13 14 adb reboot bootloader 安卓10,marlin-qp1a.191005.007.a3解压缩拿到boot.img flash-all.sh adb install magisk-25.2.apk 开发者模式开启后安装magisk adb push boot.img /sdcard/Download 在magisk安装选择一个修补文件,生成同目录magisk_patched-25200_5K3cq.img adb pull /storage/emulated/0/Download/magisk_patched-25200_5K3cq.img adb reboot bootloader fastboot flash boot magisk_patched-25200_5K3cq.img settings put global captive_portal_http_url https://www.google.cn/generate_204 去除wifi上的× settings put global captive_portal_https_url https://www.google.cn/generate_204 settings put global ntp_server 1.hk.pool.ntp.org 修改时区 adb push Shamiko-v0.5.2-120-release.zip /sdcard/Download adb push LSPosed-v1.8.4-6609-zygisk-release.zip /sdcard/Download adb install com.ttxapps.wifiadb_2.1.3-810031745_minAPI15.apk adb push MagiskHidePropsConf-v5.3.4.zip /sdcard/Download 通过magisk安装后adb shell-props-413yy,getprop ro.debuggable 即可查看1,开启全局可调式
如何卸载Magisk: 方法一:在Magisk首页点击“卸载Magisk”并按提示操作; 方法二:下载官方Magisk.apk,复制并改名为uninstall.zip,再使用Recovery刷入; 从Magisk v22.0开始,Magisk和Magisk Manager就合并为一个文件了,将文件名为Magisk.apk时它是Magisk应用程序,用于管理Magisk模块及功能;当文件名为Magisk.zip时它是刷入Magisk的卡刷包;当文件名为uninstall.zip时它是用于卸载Magisk的卡刷包。 如果安装Magisk导致无法正常开机,可在Recovery中刷入uninstall.zip即可卸载Magisk。 magisk在v24之后取消了magisk hide和在线仓库,可以通过Zygisk来实现root隐藏,刷入Shamiko模块,关闭遵守排除列表。
为什么要用Shamiko做root隐藏,而不是使用zygisk magisk自带的遵守排除列表? 不适用Shamiko也是可以的,zygisk magisk自带排除列表功能,但是这种情况下排除列表中的应用是无法使用magisk和xposed模块的,如果我想对某个排除列表中的应用使用虚拟框架和模块,就需要使用到Shamiko模块
zygisk是什么?和riru有什么关系 在Zygisk出现之前,Xposed是通过riru实现的,riru注入zygote以允许模块在应用程序中运行。在magisk v24+中,推出zygisk,可以理解成Zygisk = Zygote + Magisk,和riru的功能类似。使用了Zygisk后,就不需要安装riru模块了,同时依赖于riru的xposed框架也无法使用,但是可以使用支持zygisk的LSPosed。目前riru已经停止更新。
xposed xposed api
demo 过滤子进程:loadPackageParam.processName,可以通过hook参数、调用栈、返回值 ,打印和修改,Xposed的开发,本质上就是Java的开发。
创建安卓项目xposed1
build.gradle引入xposed api依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 apply plugin: 'com.android.application' android { compileSdkVersion 30 buildToolsVersion "30.0.2" defaultConfig { applicationId "com.roysue.xposed1" minSdkVersion 16 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } } dependencies { compileOnly 'de.robv.android.xposed:api:82' compileOnly 'de.robv.android.xposed:api:82:sources' implementation fileTree(dir: "libs", include: ["*.jar"]) implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.2' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' }
AndroidManifest.xml添加xposed项目基本配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.roysue.xposed1"> <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"> <meta-data android:name="xposedmodule" android:value="true" /> <meta-data android:name="xposeddescription" android:value="这是一个Xposed例程" /> <meta-data android:name="xposedminversion" android:value="53" /> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
activity_main.xml添加按钮组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" tools:layout_editor_absoluteX="158dp" tools:layout_editor_absoluteY="238dp" /> </androidx.constraintlayout.widget.ConstraintLayout>
MainActivity调用Button组件,实现被hook方法toastMessage 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class MainActivity extends AppCompatActivity { private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Toast.makeText(MainActivity.this, toastMessage("我未被劫持"), Toast.LENGTH_SHORT).show(); } }); } public String toastMessage(String message) { return message; } }
继承IXposedHookLoadPackage实现hook 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class HookTest implements IXposedHookLoadPackage { // 堆栈打印 public void PrintStack(){ XposedBridge.log("Dump Stack: "+ "---------------start----------------"); Throwable ex = new Throwable(); StackTraceElement[] stackElements = ex.getStackTrace(); if (stackElements != null) { for (int i = 0; i < stackElements.length; i++) { XposedBridge.log("Dump Stack"+i+": "+ stackElements[i].getClassName() +"----"+stackElements[i].getFileName() +"----" + stackElements[i].getLineNumber() +"----" +stackElements[i].getMethodName()); } } XposedBridge.log("Dump Stack: "+ "---------------over----------------"); RuntimeException e = new RuntimeException("<Start dump Stack !>"); e.fillInStackTrace(); Log.i("<Dump Stack>:", "++++++++++++", e); } public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable { //XposedBridge.log(loadPackageParam.processName); if (loadPackageParam.packageName.equals("com.roysue.xposed1")) { XposedBridge.log(" has Hooked!"); XposedBridge.log("inner"+loadPackageParam.processName); Class clazz = loadPackageParam.classLoader.loadClass("com.roysue.xposed1.MainActivity"); XposedHelpers.findAndHookMethod(clazz, "toastMessage", String.class,new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam param) throws Throwable { // 原始参数 String oldText = (String) param.args[0]; Log.d("din not hijacked=>", oldText); //param.args[0] = "test"; // 修改新参数 param.args[0] = "你已被劫持"; PrintStack(); //super.beforeHookedMethod(param); //XposedBridge.log(" has Hooked!"); } protected void afterHookedMethod(MethodHookParam param) throws Throwable { Log.d("getResult is => ",(String) param.getResult()); param.setResult("你已被劫持2"); } }); } } }
xposed_init配置hook方法 com.roysue.xposed1.HookTest
编译启动该app,注入Xposed
点击按钮查看log及调用栈
1 2 3 objection -g com.roysue.xposed1 explore android hooking search classes HookTest android hooking list class_methods com.roysue.xposed1.HookTest 找不到该类,原因是实现了接口IXposedHookLoadPackage,HookTest不在接口包中,需要在xposed_init里指定路径
hook Hook HookTest objection无法找到,通过frida进行hook拿到HookTest,frida -UF -l hookXposed.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 function hook() { Java.perform(function () { console.log("start") Java.enumerateClassLoaders({ onMatch: function (loader) { try { if(loader.findClass("com.roysue.xposed1.HookTest")){ console.log("Successfully found loader") console.log(loader); Java.classFactory.loader = loader ; } } catch(error){ console.log("find error:" + error) } }, onComplete: function () { console.log("end1") } }) }) Java.use("com.roysue.xposed1.HookTest").PrintStack.implementation = function (param){ console.log("entering PrintStack"); return true; } console.log("end2") } function main(){ hook() } setImmediate(main)
Hook XposedBridge 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 function hook() { Java.perform(function () { console.log("start") Java.enumerateClassLoaders({ onMatch: function (loader) { try { // if (loader.findClass("com.roysue.xposed1.HookTest")) { if(loader.findClass("de.robv.android.xposed.XposedBridge")){ console.log("Successfully found loader") console.log(loader); Java.classFactory.loader = loader; } } catch (error) { console.log("find error:" + error) } }, onComplete: function () { console.log("end1") } }) Java.use("de.robv.android.xposed.XposedBridge").log.overload('java.lang.String').implementation = function (str) { console.log("entering XposedBridge.log",str.toString()); return true; } console.log("end2") }) }
Hook All Methods 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 function uniqBy(array, key) { var seen = {}; return array.filter(function (item) { var k = key(item); return seen.hasOwnProperty(k) ? false : (seen[k] = true); }); } // trace a specific Java Method function traceMethod(targetClassMethod) { var delim = targetClassMethod.lastIndexOf("."); if (delim === -1) return; var targetClass = targetClassMethod.slice(0, delim) var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length) var hook = Java.use(targetClass); var overloadCount = hook[targetMethod].overloads.length; console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]"); /* // hook all class_method for (var i = 0; i < overloadCount; i++) { hook[targetMethod].overloads[i].implementation = function () { console.warn("\n*** entered " + targetClassMethod); // print backtrace // Java.perform(function() { // var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()); // console.log("\nBacktrace:\n" + bt); // }); // print args if (arguments.length) console.log(); for (var j = 0; j < arguments.length; j++) { console.log("arg[" + j + "]: " + arguments[j]); } // print retval var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?) console.log("\nretval: " + retval); console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); console.warn("\n*** exiting " + targetClassMethod); return retval; } } */ } function traceClass(targetClass) { //Java.use是新建一个对象哈,大家还记得么? var hook = Java.use(targetClass); //利用反射的方式,拿到当前类的所有方法 var methods = hook.class.getDeclaredMethods(); // var methods = hook.class.getMethods(); //建完对象之后记得将对象释放掉哈 hook.$dispose; //将方法名保存到数组中 var parsedMethods = []; methods.forEach(function (method) { parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]); }); //去掉一些重复的值 var targets = uniqBy(parsedMethods, JSON.stringify); //对数组中所有的方法进行hook,traceMethod也就是第一小节的内容 targets.forEach(function (targetMethod) { traceMethod(targetClass + "." + targetMethod); }); }
traceClass(“de.robv.android.xposed.XposedBridge”);
1 2 if (loader.findClass("com.roysue.xposed1.HookTest$1")) { traceClass("com.roysue.xposed1.HookTest$1");
说明com.roysue.xposed1.HookTest$1
就是XposedHelpers.findAndHookMethod(clazz, "toastMessage", String.class,new XC_MethodHook() {
中的XC_MethodHook内部类
hook afterHookedMethod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 function hook() { Java.perform(function () { console.log("start") Java.enumerateClassLoaders({ onMatch: function (loader) { try { // if (loader.findClass("com.roysue.xposed1.HookTest")) { if(loader.findClass("com.roysue.xposed1.HookTest$1")){ console.log("Successfully found loader") console.log(loader); Java.classFactory.loader = loader; } } catch (error) { console.log("find error:" + error) } }, onComplete: function () { console.log("end1") } }) Java.use("com.roysue.xposed1.HookTest$1").afterHookedMethod.implementation = function (param) { console.log("entering afterHookedMethod param is ",param); return this.afterHookedMethod(param); } console.log("end2") }) }
通过traceClass("de.robv.android.xposed.XC_MethodHook$MethodHookParam")
拿到所有的类方法,在classloader中而不是在app中
1 2 3 4 5 6 Java.use("de.robv.android.xposed.XC_MethodHook$MethodHookParam").setResult.implementation = function (param) { console.log("entering XC_MethodHook$MethodHookParam setResult param is ",param); // 打印调用栈 console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); return this.setResult(param); }
XC_MethodHook是抽象类不能直接hook,需要hook实现。
traceClass(“com.roysue.xposed1.HookTest$1”)
GravityBox git clone https://github.com/GravityBox/GravityBox.git
修改app/build.gradle
1 2 3 4 5 6 7 8 9 compileSdkVersion 23 targetSdkVersion 23 debug { 避免打包需要秘钥 // versionNameSuffix "-Dev" // if (signingConfigs.releaseConfig != null) { // signingConfig signingConfigs.releaseConfig // } } compile 'com.android.support:appcompat-v7:26.0.2' 指定版本
build.gradle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 buildscript { repositories { jcenter() google() 添加google镜像源 } dependencies { classpath 'com.android.tools.build:gradle:2.3.3' } } allprojects { repositories { jcenter() google() maven { url 'https://jitpack.io' } } }
源码分析 src/assets/xposed_init 文件中提供了入口类com.wrbug.gravitybox.nougat.GravityBox
1 public class GravityBox implements IXposedHookZygoteInit, IXposedHookInitPackageResources, IXposedHookLoadPackage
入口类中实现了三个接口IXposedHookInitPackageResources ,IXposedHookLoadPackage ,IXposedHookZygoteInit
IXposedHookZygoteInit 所有的进程
Hook the initialization of ** (es), from which **all the apps are forked.
Implement this interface in your module’s main class in order to be notified when Android is starting up . In IXposedHookZygoteInit
, you can modify objects and place hooks that should be applied for every app . Only the Android framework/system classes are available at that point in time. Use null
as class loader for XposedHelpers.findAndHookMethod(String, ClassLoader, String, Object...)
and its variants.
If you want to hook one/multiple specific apps, use IXposedHookLoadPackage
instead.
说明initZygote只有在系统启动的时候执行一遍,只有系统框架库可以使用。
XposedBridge.log(“GB:Hardware: “ + Build.HARDWARE); 代码中调用了Build.HARDWARE
1 2 3 frida-ps -U|grep gravity objection -g com.ceco.nougat.gravitybox explore -P ~/.objection/plugins plugin wallbreaker classdump --fullname android.os.Build
**IXposedHookInitPackageResources ** 所有的资源
Get notified when the resources for an app are initialized. In handleInitPackageResources(XC_InitPackageResources.InitPackageResourcesParam)
, resource replacements can be created.
This interface should be implemented by the module’s main class. Xposed will take care of registering it as a callback automatically.
说明handleInitPackageResources实现的回调在创建之后就会得到通知
**IXposedHookLoadPackage ** 所有的包
Get notified when an app (“Android package”) is loaded. This is especially useful to hook some app-specific methods.
This interface should be implemented by the module’s main class. Xposed will take care of registering it as a callback automatically.
xposed会将handleLoadPackage注册成为回调,app在加载时都会经过该回调,主要用来实现具体的hook逻辑。
在handleLoadPackage中调用了ModStatusbarColor.init
1 2 3 if (lpparam.packageName.equals(ModStatusbarColor.PACKAGE_NAME)) { ModStatusbarColor.init(prefs, lpparam.classLoader); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public static final String PACKAGE_NAME = "com.android.systemui"; private static final String CLASS_PHONE_STATUSBAR = "com.android.systemui.statusbar.phone.PhoneStatusBar"; public static void init(final XSharedPreferences prefs, final ClassLoader classLoader) { try { // findClass底层通过反射获取CLASS_PHONE_STATUSBAR类 final Class<?> phoneStatusbarClass = XposedHelpers.findClass(CLASS_PHONE_STATUSBAR, classLoader); final Class<?> statusbarIconViewClass = XposedHelpers.findClass(CLASS_STATUSBAR_ICON_VIEW, classLoader); final Class<?> sbTransitionsClass = XposedHelpers.findClass(CLASS_SB_TRANSITIONS, classLoader); XposedHelpers.findAndHookMethod(phoneStatusbarClass, // hook相同的类时XCallback.PRIORITY_LOWEST最低,优先级最高 // https://api.xposed.info/reference/de/robv/android/xposed/XC_MethodHook.html "makeStatusBarView", new XC_MethodHook(XCallback.PRIORITY_LOWEST) { @Override protected void afterHookedMethod(final MethodHookParam param) throws Throwable { mPhoneStatusBar = param.thisObject; // getObjectField获取对象的属性值 // https://api.xposed.info/reference/de/robv/android/xposed/XposedHelpers.html Context context = (Context) XposedHelpers.getObjectField(param.thisObject, "mContext"); if (SysUiManagers.IconManager != null) { SysUiManagers.IconManager.registerListener(mIconManagerListener); } Intent i = new Intent(ACTION_PHONE_STATUSBAR_VIEW_MADE); context.sendBroadcast(i); } }); } catch (Throwable t) { GravityBox.log(TAG, t); } }
由于com.android.systemui
和当前hook的包在不同进程中
1 2 3 objection -g com.android.systemui explore android hooking search classes com.android.systemui ~/.objection/plugins plugin wallbreaker classdump --fullname com.android.systemui.statusbar.phone.PhoneStatusBar
静态域
https://api.xposed.info/reference/de/robv/android/xposed/XposedHelpers.html
1 2 3 4 5 BRIGHTNESS_ON = XposedHelpers.getStaticIntField(powerManagerClass, "BRIGHTNESS_ON"); plugin wallbreaker classdump --fullname android.os.PowerManager 查看静态域 (int[])XposedHelpers.getStaticObjectField(classAudioService, "MAX_STREAM_VOLUME"); XposedHelpers.getStaticLongField(param.thisObject.getClass(),"SWIPE_TIMEOUT_MS") (boolean) XposedHelpers.getStaticBooleanField(mDisplayPowerController.getClass(), "MTK_ULTRA_DIMMING_SUPPORT");
动态域
https://api.xposed.info/reference/de/robv/android/xposed/XposedHelpers.html
1 2 3 4 5 XposedHelpers.getObjectField(param.thisObject, "mNotification") == null objection -g com.ceco.nougat.gravitybox explore -P ~/.objection/plugins android heap search instances com.android.systemui.statusbar.phone.PhoneStatusBar 内存搜索PhoneStatusBar类实例 plugin wallbreaker objectsearch com.android.systemui.statusbar.phone.PhoneStatusBar 内存搜索对象 plugin wallbreaker objectiondump --fullname 0x100e6e 查看类内容中的动态域mNotification
主动调用
https://api.xposed.info/reference/de/robv/android/xposed/XposedHelpers.html
1 2 3 4 5 6 (Float) XposedHelpers.callMethod(param.thisObject, "getNonBatteryClockAlphaFor", (Integer) param.args[0]); XposedHelpers.callStaticMethod(mClsPhoneFactory, "getPhone", mSimSlot); plugin wallbreaker objectsearch com.android.systemui.statusbar.phone.PhoneStatusBarTransitions plugin wallbreaker objectdump --fullname 0x10141e 查找getNonBatteryClockAlphaFor方法 int phoneId = XposedHelpers.getIntField(param.thisObject, "mPhoneId"); Context context = (Context) XposedHelpers.getObjectField(param.thisObject, "mContext");
构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 XposedHelpers.findAndHookConstructor("android.media.AudioManager", classLoader, Context.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { Object objService = XposedHelpers.callMethod(param.thisObject, "getService"); Context mApplicationContext = (Context) XposedHelpers.getObjectField(param.thisObject, "mApplicationContext"); if (objService != null && mApplicationContext != null) { XposedHelpers.callMethod(param.thisObject, "disableSafeMediaVolume"); } } }); android hooking search classes android.media.AudioManger plugin wallbreaker objectsearch android.media.AudioManager plugin wallbreaker objectdump --fullname 0x186e 查看getService和disableSafeMediaVolume和mApplicationContext
Not In Frida 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 setAdditionalInstanceField(param.thisObject, "mVolumeUpLongPress", mVolumeUpLongPress); 给对象加静态域 Object ls = XposedHelpers.getSurroundingThis(mLight); 内部类对象返回给外部类 Class[] params = method.getParameterTypes(); 获取参数列表 UserHandle uh = (UserHandle) uhConst.newInstance(-2); 创建新实例对象 Constructor<?> uhConst = XposedHelpers.findConstructorExact(UserHandle.class, int.class); 查找一个构造函数让其可用 XposedBridge.hookAllConstructors(XposedHelpers.findClass( hook所有构造函数 CLASS_TRUST_MANAGER_SERVICE, classLoader), new XC_MethodHook() { @Override protected void afterHookedMethod(final MethodHookParam param) throws Throwable { mTrustManager = param.thisObject; Context context = (Context) XposedHelpers.getObjectField(param.thisObject, "mContext"); mWifiManager = new WifiManagerWrapper(context, null); mConnectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(WifiPriorityActivity.ACTION_WIFI_TRUSTED_CHANGED); intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); context.registerReceiver(mBroadcastReceiver, intentFilter); if (DEBUG) log("Trust manager constructed"); } }); XposedBridge.hookMethod(mtdHandlePlay, new XC_MethodHook() { hook所有方法并创建回调 @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { qhPrefs.reload(); QuietHours qh = new QuietHours(qhPrefs); if (qh.isSystemSoundMuted(QuietHours.SystemSound.RINGER)) { param.setResult(null); } } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { if (!mRingerConfig.enabled) return; mRingtone = (Ringtone) XposedHelpers.getObjectField(mAsyncRinger, "mRingtone"); if (mRingtone == null) { if (DEBUG) log("handlePlay called but ringtone is null"); return; } setVolume(mRingerConfig.minVolume); mIncrementAmount = (1f - mRingerConfig.minVolume) / (float) mRingerConfig.rampUpDuration; mCurrentIncrementVolume = mRingerConfig.minVolume; mHandler = (Handler) XposedHelpers.getObjectField(mAsyncRinger, "mHandler"); mHandler.postDelayed(mRunnable, 1000); if (DEBUG) log("Starting increasing ring"); } });
set(get)AdditionalInstanceField getMD5Sum getMethodDepth getParameterTypes getSurroundingThis hookMethod 系统级别的,过滤所有的进程 只要Xposed生效了,可以把Xposed理解为系统框架,作为系统的本身来考虑没有关系。 Not In Xposed Java.choose rpc 热重载/加载 单进程级别的,只能在hook的进程内生效 hook 本项目中 xposed 系统级别的,过滤所有的进程,入口类中实现了三个接口,hook了所有的资源,进程,包。只会hook进程中的包等于ModStatusbarColor.PACKAGE_NAME即com.android.systemui
时,才启动hook。所有逻辑不在GravityBox中,也不在xposed.jar中,而是在com.android.systemui
if (lpparam.packageName.equals(ModStatusbarColor.PACKAGE_NAME)) {
ModStatusbarColor.init(prefs, lpparam.classLoader);
}
frida-ps -U |grep com.android.systemui
在app逆向中遇到interface搜索其实现还是一顿乱搜,可以使用反射getInterfaces得到实现的接口数组,然后打印出来即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 function hook() { Java.perform(function () { console.log("start") Java.enumerateClassLoaders({ onMatch: function (loader) { try { if (loader.findClass("com.ceco.nougat.gravitybox.ModStatusbarColor$1")) { // if(loader.findClass("de.robv.android.xposed.XC_MethodHook")){ // if(loader.findClass("com.roysue.xposed1.HookTest")){ // if(loader.findClass("de.robv.android.xposed.XposedBridge")){ //if(loader.findClass("com.android.internal.statusbar.StatusBarIcon")){ console.log("Successfully found loader") console.log(loader); Java.classFactory.loader = loader; } } catch (error) { console.log("find error:" + error) } }, onComplete: function () { console.log("end1") } }) // Java.use("de.robv.android.xposed.XposedBridge").log.overload('java.lang.String').implementation = function (str) { // console.log("entering Xposedbridge.log ",str.toString()) // return true // } //traceClass("com.ceco.nougat.gravitybox.ModStatusbarColor") // Java.use("com.roysue.xposed1.HookTest$1").afterHookedMethod.implementation = function (param){ // console.log("entering afterHookedMethod param is => ",param); // return this.afterHookedMethod(param); // } // traceClass("de.robv.android.xposed.XC_MethodHook") // Java.use("de.robv.android.xposed.XC_MethodHook$MethodHookParam").setResult.implementation = function(str){ // console.log("entersing de.robv.android.xposed.XC_MethodHook$MethodHookParam setResult => ",str) // console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); // return this.setResult(str); // } Java.enumerateLoadedClasses({ onMatch: function (className) { if (className.toString().indexOf("gravitybox") > 0 && className.toString().indexOf("$") > 0 ) { console.log("found => ", className) // var interFaces = Java.use(className).class.getInterfaces(); // if(interFaces.length>0){ // console.log("interface is => "); // for(var i in interFaces){ // console.log("\t",interFaces[i].toString()) // } // } if (Java.use(className).class.getSuperclass()) { var superClass = Java.use(className).class.getSuperclass().getName(); // console.log("superClass is => ",superClass); if (superClass.indexOf("XC_MethodHook") > 0) { console.log("found class is => ", className.toString()) traceClass(className); } } } }, onComplete: function () { console.log("search completed!") } }) console.log("end2") }) }