GithubHelp home page GithubHelp logo

highcapable / yukihookapi Goto Github PK

View Code? Open in Web Editor NEW
1.2K 10.0 83.0 28.93 MB

⛱️ An efficient Hook API and Xposed Module solution built in Kotlin.

Home Page: https://highcapable.github.io/YukiHookAPI/

License: Apache License 2.0

Kotlin 97.56% TypeScript 1.98% SCSS 0.46%
android hook-api xposed kotlin kotlin-android kotlin-library library xposedmodule xposed-framework

yukihookapi's Introduction

Yuki Hook API

GitHub license GitHub release Telegram Telegram QQ

LOGO

⛱️ An efficient Hook API and Xposed Module solution built in Kotlin.

English | 简体中文

LOGO HighCapable

This project belongs to the above-mentioned organization, click the link above to follow this organization and discover more good projects.

What's this

This is an efficient Hook API rebuilt based on the Xposed API using Kotlin, and creates rich function extensions for the development of Xposed Modules.

The name is taken from "ももくり" heroine Yuki Kurihara.

Formerly the Innocent Xposed API used in Development Learning Project, now renamed and open sourced.

Get Started

Click here go to the documentation page for more detailed tutorials and content.

For supportive related information, you can check it directly click here.

Cooperations

The following are projects that have collaborated and are using YukiHookAPI.

Repository Developer
TSBattery fankesyooni
MIUI 原生通知图标 fankesyooni
ColorOS 通知图标增强 fankesyooni
自由屏幕旋转 fankesyooni
拒绝强制亮度 fankesyooni
AppErrorsTracking fankesyooni
Enable WebView Debugging WankkoRee
Fuck MIUI Gesture mahoshojoHCG
MIUI遮罩进化 GSWXXN
Color OS Installer Plus NextAlone
Auto NFC GSWXXN
不要竖屏 WankkoRee
QDReadHook xihan123
HXReadHook xihan123
WxRecordRead Coderpwh
FuckShake Coderpwh
MIUI更新进化 ZQDesigned
MIUI录屏进化 ZQDesigned
Fuck AD hujiayucc
Zuiyou ADFree kazutoiris

Are you also using YukiHookAPI? Come and PR to add your repository to the list above (private repositories do not need to indicate web links).

Promotion

Hey, please stay! 👋

Here are related projects such as Android development tools, UI design, Gradle plugins, Xposed Modules and practical software.

If the project below can help you, please give me a star!

All projects are free, open source, and follow the corresponding open source license agreement.

Star History

Star History Chart

Third-Party Open Source Usage Statement

License

Apache License Version 2.0

Copyright (C) 2019-2024 HighCapable

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Copyright © 2019-2024 HighCapable

yukihookapi's People

Contributors

bluecat300 avatar buffcow avatar chachako avatar fankes avatar gswxxn avatar kazutoiris avatar lightsummer233 avatar pwh-pwh avatar wankkoree avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yukihookapi's Issues

hook方法请教

刚学XP没多久,好多不是很懂233,findclass一个类,hook了A方法,替换A方法内容为 调用这个类的B方法,该如何操作,XP里大概是XposedHelpers.callMethod

[BUG] YukiHookDataChannel. Supporting Android 14

It looks like DataChannel does not support Android 14. Crashes when trying to register receivers on YukiHookDataChannel class line 211.
Possible fix - TheranicaRD-SW/Fetch@f82b752

targetSdk = 34
YukiHookAPI 1.1.11

Stacktrace:
FATAL EXCEPTION: main
Process: ru.bluecat.alfabankpatcher, PID: 6272
java.lang.RuntimeException: Unable to create application ru.bluecat.alfabankpatcher.ui.App: java.lang.SecurityException: ru.bluecat.alfabankpatcher: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7003)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2236)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: java.lang.SecurityException: ru.bluecat.alfabankpatcher: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
at android.os.Parcel.createExceptionOrNull(Parcel.java:3057)
at android.os.Parcel.createException(Parcel.java:3041)
at android.os.Parcel.readException(Parcel.java:3024)
at android.os.Parcel.readException(Parcel.java:2966)
at android.app.IActivityManager$Stub$Proxy.registerReceiverWithFeature(IActivityManager.java:5684)
at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1852)
at android.app.ContextImpl.registerReceiver(ContextImpl.java:1792)
at android.app.ContextImpl.registerReceiver(ContextImpl.java:1780)
at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:755)
at com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel.register$yukihookapi_release(YukiHookDataChannel.kt:211)
at com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel.register$yukihookapi_release$default(YukiHookDataChannel.kt:208)
at com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.onCreate(ModuleApplication.kt:86)
at ru.bluecat.alfabankpatcher.ui.App.onCreate(App.kt:16)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1316)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6998)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2236) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loopOnce(Looper.java:205) 
at android.os.Looper.loop(Looper.java:294) 
at android.app.ActivityThread.main(ActivityThread.java:8177) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.server.am.ActivityManagerService.registerReceiverWithFeature(ActivityManagerService.java:13908)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2570)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2720)
at android.os.Binder.execTransactInternal(Binder.java:1339)
at android.os.Binder.execTransact(Binder.java:1275)

Some problems about logger

I manually use method loggerI in beforehook, but it seems that it does not work properly and I can’t find log in LSPosed. Could I use it in beforehook?

The new LSP Api

现在 LSP 团队出新的 api 和 模块配置方法了,这是示例

可以适配一下吗,不然 LSP 的日志每次都提示
[ LSPosed-Bridge ] Loading legacy module xxx

在hook ClassLoader时,有一定概率会有原因不明的app卡死现象或代码执行中断

为了hook动态加载的class,我使用了hook ClassLoader.loadClass(String)的方法,此方法在原生Xposed API上生效,但在Yuki上会有app卡死或代码执行中断的问题。
以下是原生Xposed API正常使用的代码:

public class ZuoyebangHook implements IXposedHookLoadPackage {
    public String LOG_TAG = "ZuoyebangHook: ";
    @Override
    public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        XposedBridge.log("Loaded app: " + lpparam.packageName);
        if (lpparam.packageName.equals("com.baidu.homework")){
            XposedBridge.log(LOG_TAG + "作业帮已启动");
            findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    if (param.hasThrowable()) return;
                    super.afterHookedMethod(param);
                    //下面一行代码可以查看动态加载的类
                    XposedBridge.log(LOG_TAG + "已加载类:" + param.args[0]);
                    hook(lpparam, (String)param.args[0]);
                }
            });
        }
    }

    public void hook(XC_LoadPackage.LoadPackageParam lpparam, String className) {
        switch (className){
            case "com.baidu.homework.activity.search.whole.PicManySearchActivity":
                XposedBridge.log(LOG_TAG + "已加载" + className + ",并捕捉");
                findAndHookMethod(
                        "com.baidu.homework.activity.search.whole.PicManySearchActivity",
                        lpparam.classLoader,
                        "onCreate",
                        Bundle.class,
                        new XC_MethodHook() {
                            @Override
                            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                super.beforeHookedMethod(param);
                                XposedBridge.log(LOG_TAG + "PicManySearchActivity.onCreate已调用");
                            }
                            @Override
                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                super.afterHookedMethod(param);
                            }
                        });
    }
}

以下是使用Yuki不能正常工作的代码:

@InjectYukiHookWithXposed
class HookEntry : IYukiHookXposedInit {

    override fun onInit() {
        // 配置 YuKiHookAPI
        // 可简写为 configs {}
        YukiHookAPI.configs {
            // 全局调试用的 TAG
            // 在 Logcat 控制台过滤此 TAG 可找到详细日志
            debugTag = "HomeworkKiller"
            // 是否开启调试模式
            // 请注意 - 若作为发布版本请务必关闭调试功能防止对用户设备造成大量日志填充
            isDebug = true
            // 是否启用调试日志的输出功能
            // 一旦关闭后除手动日志外 API 将停止全部日志的输出 - 建议不要随意关掉这个选项
            // 虽然说对用户的设备写入大量日志是不正确的 - 但是没有日志你将无法调试
            // 关于日志是否会影响设备的流畅度一直是一个伪命题
            // 但是不设置这个选项可能会引起一些非议 - 建议不要关闭就是了
            isAllowPrintingLogs = true
            // 是否启用 [YukiHookModulePrefs] 的键值缓存功能
            // 若无和模块频繁交互数据在宿主重新启动之前建议开启
            // 若需要实时交互数据建议关闭或从 [YukiHookModulePrefs] 中进行动态配置
            isEnableModulePrefsCache = true
            // 是否启用当前 Xposed 模块自身 [Resources] 缓存功能
            // 一般情况下模块的 Resources 是不会改变的 - 但是在语言区域更改、分辨率更改等情况下 - 就需要刷新缓存
            // 若无上述需求 - 在宿主重新启动之前建议开启
            // 你可以手动调用 [PackageParam.refreshModuleAppResources] 来刷新缓存
            isEnableModuleAppResourcesCache = true
            // 是否启用 Hook Xposed 模块激活等状态功能
            // 为原生支持 Xposed 模块激活状态检测 - 此功能默认启用
            // 关闭后你将不能再在模块环境中使用 [YukiHookAPI.Status] 中的功能
            // 功能启用后 - 将会在宿主启动时自动 Hook [YukiHookModuleStatus]
            isEnableHookModuleStatus = true
            // 是否启用当前 Xposed 模块与宿主交互的 [YukiHookDataChannel] 功能
            // 请确保 Xposed 模块的 [Application] 继承于 [ModuleApplication] 才能有效
            // 此功能默认启用 - 关闭后将不会在功能初始化的时候装载 [YukiHookDataChannel]
            // 功能启用后 - 将会在宿主启动时自动 Hook [Application] 的生命周期方法进行注册
            isEnableDataChannel = true
            // 是否启用 [Member] 缓存功能
            // 为防止 [Member] 复用过高造成的系统 GC 问题 - 此功能默认启用
            // 除非缓存的 [Member] 发生了混淆的问题 - 否则建议启用
            isEnableMemberCache = true
        }
    }
    override fun onHook(){
        YukiHookAPI.encase {
            loadApp( APP_NAME ){

                ClassLoader::class.java.hook {
                    injectMember {
                        method {
                            name = "loadClass"
                            //param(String::class.java)
                        }
                        afterHook {
                            val className = args[0] as String
                            //loggerI(msg = "loaded class:${className}")
                            loggerI(msg = "result:${hook_classes.contains(className)}")//正常打印,后面的代码不会运行
                            loggerI(msg = "现在要加载hooker")//不能打印
                            loadHooker(MethodHooks(className))
                        }


                    }
                }
                "com.baidu.homework.activity.search.whole.PicManySearchActivity".hook {
                    injectMember {
                        method {
                            name = "onCreate"
                            param(BundleClass)
                        }
                        beforeHook {
                            loggerI(msg = "Has hooked method:PicManySearchActivity.onCreate")
                        }
                    }
                }
            }
        }
    }
}
val hook_classes  = listOf(
    "com.baidu.homework.activity.search.whole.PicManySearchActivity",
)

class MethodHooks(className : String) : MyBaseHooker(className){
    override fun onHook() {

        loadApp(APP_NAME){
            loggerI(msg = "loaded class:${className}")
            //若执行以下代码,则app直接卡死
            //loggerI(msg = hook_classes.contains(className) as String)

        }
    }
}
abstract class MyBaseHooker(class_name : String) : YukiBaseHooker() {
    var className : String = "";
    init {
        className = class_name
    }
    abstract override fun onHook()
}

how to change hook behavior without relaunch?

Already used xsharedpreference to implement configuration read/write and reread configuration on each hook, but without restarting the hook behaviour doesn't change, would like to know if the api might support this functionality or if the author understands how this can be implemented, respect

模块无法收到从宿主传来的消息

项目地址 https://github.com/cledwynl/mbga/tree/34c32c470ba26153242064f5ba765eddf9611de3

模块的流程是这样的:

  1. 打开宿主
  2. 在宿主内点击某个区域打开模块的Activity
  3. 模块向宿主发送请求
  4. 宿主收到后向模块发送数据,这一步模块没收到

初步排查下来发现是模块的BroadcastReceiver在收到广播后调用的YukiHookDataChannel.isCurrentBroadcast中获取不到task

image

接着我尝试将模块Activity加上了

<intent-filter>
  <action android:name="android.intent.action.MAIN" />
  <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

再试就成功收到消息了。有没有什么方式可以让不展示在启动器的Activity接收消息

cannot be cast to 类型转换异常

关键代码
context.injectModuleAppResources()
ModuleClassLoader.excludeModuleClasses("androidx.appcompat.widget.AppCompatImageView")
ModuleClassLoader.excludeHostClasses("androidx.appcompat.widget.AppCompatImageView")
val moduleContext = context.applyModuleTheme(androidx.appcompat.R.style.Base_Theme_AppCompat, null)
rootView = LayoutInflater.from(moduleContext).inflate(R.layout.test, null)
布局代码

                <com.xiaolang.wechathelper.widget.BlurView
                    android:id="@+id/blur"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_alignTop="@id/bottom_bar"
                    android:layout_alignBottom="@id/bottom_bar" />
              
                <androidx.appcompat.widget.AppCompatImageView
                    android:id="@+id/bottom_bar"
                    android:tag="bottom_bar"
                    app:abb_tabs="@menu/tabs"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />
            </RelativeLayout>`

异常
java.lang.ClassCastException: androidx.appcompat.widget.AppCompatImageView cannot be cast to androidx.appcompat.widget.AppCompatImageView at com.xiaolang.wechathelper.plugins.Test2BottomBar.getBottomBar(Test2BottomBar.kt:48) at com.xiaolang.wechathelper.plugins.BaseBottomBar.addBottomBar(BaseBottomBar.kt:26) at com.xiaolang.wechathelper.hooker.HomeHooker$onHook$2$1.invoke(HomeHooker.kt:52) at com.xiaolang.wechathelper.hooker.HomeHooker$onHook$2$1.invoke(HomeHooker.kt:46) at com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator$MemberHookCreator$hook$beforeAfterHook$1.afterHookedMember$yukihookapi_core_release( at com.highcapable.yukihookapi.hook.core.api.factory.YukiHookDelegateFactoryKt.callAfterHookedMember(YukiHookDelegateFactory.kt:102) at com.highcapable.yukihookapi.hook.core.api.compat.HookCompatHelper$compat$9.afterHookedMethod(HookCompatHelper.kt:86) at A.BhBfpdEl.eyyOj.qImQN.XposedBridge$LegacyApiSupport.handleAfter(Unknown Source:33) at J.callback(Unknown Source:292) at LSPHooker_.d(Unknown Source:8) at com.tencent.mm.ui.HomeUI.h(Unknown Source:457) at com.tencent.mm.ui.LauncherUI.onResume(Unknown Source:228) at android.app.Instrumentation.callActivityOnResume(Unknown Source:3) at com.highcapable.yukihookapi.hook.xposed.parasitic.activity.delegate.InstrumentationDelegate.callActivityOnResume(InstrumentationDelegate.kt:284) at android.app.Activity.performResume(Unknown Source:68) at android.app.ActivityThread.performResumeActivity(Unknown Source:167) at android.app.ActivityThread.handleResumeActivity(Unknown Source:6) at android.app.servertransaction.ResumeActivityItem.execute(Unknown Source:12) at android.app.servertransaction.ActivityTransactionItem.execute(Unknown Source:4) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(Unknown Source:32) at android.app.servertransaction.TransactionExecutor.execute(Unknown Source:79) at android.app.ActivityThread$H.handleMessage(Unknown Source:172) at android.os.Handler.dispatchMessage(Unknown Source:19) at android.os.Looper.loopOnce(Unknown Source:182) at android.os.Looper.loop(Unknown Source:82) at android.app.ActivityThread.main(Unknown Source:123) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(Unknown Source:11) at com.android.internal.os.ZygoteInit.main(Unknown Source:312)

New Xposed Module Config Plan

New Xposed Module Config Plan

The API currently uses annotations and KSP to complete the automatic generation of entry class code.

Some codes still need to be manually configured, such as meta-data of the Xposed Module.

Currently, Android projects are managed uniformly using the Gradle build system, so we decided to remove KSP, launch a Gradle plugin to fully automate the entire Xposed Module configuration, and use YAML as a new configuration file language for management.

The following example

generator:
  target-type: COMPAT
  use-activity-proxy: true
  use-data-channel: true

xposed-module:
  package-name: com.mydemo
  java-entry: com.mydemo.hook.MyModule
  native-entry: mymodule # libmymodule.so
  description: My new Xposed Module.
  api-level: 100
  host-scopes:
    com.android.systemui
    com.android.phone

The Gradle plugin will automatically generate various types of Xposed Modules based on the configuration file content, and automatically generate corresponding types of configuration files, such as traditional Rovo89 and modern libxposed as well as more compatible Xposed Module types.

The style of the configuration file is only a first draft and will be modified later for actual functionality.

新的 Xposed 模块配置方案

API 目前使用注解配合 KSP 来完成入口类代码的自动生成,部分代码依然需要手动进行配置,例如 Xposed 模块的 meta-data

目前 Android 项目统一使用 Gradle 构建系统进行管理,所以我们决定去掉 KSP,推出一个 Gradle 插件来实现整个 Xposed 模块配置的完全自动化,并采用 YAML 作为新的配置文件语言进行管理。

示例如下

generator:
  target-type: COMPAT
  use-activity-proxy: true
  use-data-channel: true

xposed-module:
  package-name: com.mydemo
  java-entry: com.mydemo.hook.MyModule
  native-entry: mymodule # libmymodule.so
  description: My new Xposed Module.
  api-level: 100
  host-scopes:
    com.android.systemui
    com.android.phone

Gradle 插件会根据配置文件内容自动生成各种类型的 Xposed 模块,自动生成对应类型的配置文件,例如传统的 Rovo89 和现代的 libxposed 以及更多兼容的 Xposed 模块类型。

配置文件的样式只是一个初稿,后期会针对实际功能进行修改。

Need help, prefs doesn`t work

Could you please help? In the module app, I set prefs. But it doesn't work in the host app. The hook is working, but prefs.getString(Constants.KEY_ID) always returns an empty string.

Module App

class MainActivity : BaseActivity<ActivityMainBinding>() {

    override fun onCreate() {
       ...
        val button = findViewById<Button>(R.id.setup)

        button.setOnClickListener {
            prefs().edit {
                putString(KEY_ID, androidIdText.text.toString()).apply()
            }
        }
    }
...

Host App

override fun onHook() = encase {

        classOf<Settings.Secure>().hook {
            injectMember {
                method {
                    name = "getString"
                }.all()

                beforeHook {
                    result = prefs.getString(Constants.KEY_ID)
                }
            }
        }

Manifest

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

    <application
        android:name=".application.DefaultApplication"
        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/Theme.AppDefault"
        tools:targetApi="31">

        <meta-data
            android:name="xposedsharedprefs"
            android:value="true" />
        <meta-data
            android:name="xposedscope"
            android:resource="@array/module_scope" />
        <meta-data
            android:name="xposeddescription"
            android:value="@string/xposed_desc" />
        <meta-data
            android:name="xposedminversion"
            android:value="93" />

        <activity
            android:name=".ui.activity.MainActivity"
            android:exported="true"
            android:screenOrientation="behind">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="de.robv.android.xposed.category.MODULE_SETTINGS" />
            </intent-filter>
        </activity>

        <activity-alias
            android:name=".Home"
            android:exported="true"
            android:label="@string/app_name"
            android:screenOrientation="behind"
            android:targetActivity=".ui.activity.MainActivity">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
    </application>
</manifest>

[bug]在windows下无法识别路径,无法正常编译

在win下无法识别路径,编译失败。在linux下可正常编译。

test项目 MIUINativeNotifyIcon

> Task :app:kspDebugKotlin FAILED
e: [ksp] [YukiHookAPI] Project Source Path "src\main" not matched
Looking for help? see https://github.com/fankes/YukiHookAPI/wiki/%E4%BD%9C%E4%B8%BA-Xposed-%E6%A8%A1%E5%9D%97%E4%BD%BF%E7%94%A8%E7%9A%84%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE
e: [ksp] java.lang.RuntimeException: [YukiHookAPI] Project Source Path "src\main" not matched
Looking for help? see https://github.com/fankes/YukiHookAPI/wiki/%E4%BD%9C%E4%B8%BA-Xposed-%E6%A8%A1%E5%9D%97%E4%BD%BF%E7%94%A8%E7%9A%84%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.error(YukiHookXposedProcessor.kt:89)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.access$error(YukiHookXposedProcessor.kt:49)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1$injectAssets$1.invoke(YukiHookXposedProcessor.kt:172)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1$injectAssets$1.invoke(YukiHookXposedProcessor.kt:162)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.environment(YukiHookXposedProcessor.kt:78)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.environment$default(YukiHookXposedProcessor.kt:76)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.injectAssets(YukiHookXposedProcessor.kt:162)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.access$injectAssets(YukiHookXposedProcessor.kt:49)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1$injectProcess$1.invoke$lambda-4$fetchKSClassDeclaration(YukiHookXposedProcessor.kt:119)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1$injectProcess$1.invoke(YukiHookXposedProcessor.kt:148)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1$injectProcess$1.invoke(YukiHookXposedProcessor.kt:107)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.environment(YukiHookXposedProcessor.kt:78)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.environment$default(YukiHookXposedProcessor.kt:76)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.injectProcess(YukiHookXposedProcessor.kt:107)
        at com.highcapable.yukihookapi_ksp_xposed.YukiHookXposedProcessor$create$1.process(YukiHookXposedProcessor.kt:99)
        at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$4$1.invoke(KotlinSymbolProcessingExtension.kt:195)
        at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$4$1.invoke(KotlinSymbolProcessingExtension.kt:193)
        at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.handleException(KotlinSymbolProcessingExtension.kt:287)
        at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.doAnalysis(KotlinSymbolProcessingExtension.kt:193)
        at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:120)
        at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:96)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:262)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:53)
        at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:113)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:253)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:100)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli$default(KotlinToJVMBytecodeCompiler.kt:58)
        at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:170)
        at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:52)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:92)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:44)
        at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:98)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1618)
        at jdk.internal.reflect.GeneratedMethodAccessor97.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
        at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
        at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:691)
        at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
        at java.base/java.lang.Thread.run(Thread.java:832)

e: Error occurred in KSP, check log for detail

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:kspDebugKotlin'.
> Compilation error. See log for more details

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
14 actionable tasks: 1 executed, 13 up-to-date

Prefs相关问题

在Activity中,使用以下代码保存配置。

val strongMode = sharedPreferences.getBoolean("strong_mode", false)
modulePrefs.putBoolean("strong_mode", strongMode)

保存后,在Activity中再使用modulePrefsgetBoolean方法进行检查,发现设置已经保存。

但是在hook中,prefs.getBoolean始终返回默认值false,perfs.all返回为空。

Target API 32,运行系统API 31,已经按照文档中说明进行配置,也参考了demo中的代码,使用PrefsData问题依然出现,使用String进行数据保存问题依旧。

请问是我用法不对,还是这是一个bug。

[BUG] 无法保存键值

部分用户反馈YukiHookPrefsBridge.Editor无法保存键值

//Kotlin
val global: PrefsData<Boolean> = PrefsData("global", true)
prefs().edit {
    putLong("id",  0)
    put(global, item.isChecked)
}
//Java
prefs.edit().putLong("id", 0).apply();

Hook美团众包没效果

美团众包的版本号:9.6.5.3347 (没加固)

@KyuubiRan 的 EzXHelper 去 Hook 有效果

具体代码:

object TestHooker : YukiBaseHooker() {
    override fun onHook() {

        "com.meituan.banma.main.activity.MainActivity".hook {
            injectMember {
                method { name("onCreate") }
                afterHook {
                    loggerD(msg = "YukiHook:执行后")
                }
            }
        }

        "com.meituan.banma.main.activity.MainActivity".toClass()
            .method { name("onCreate") }
            .give()!!.createHook {
                after {
                    loggerD(msg = "EzXHelper:执行后")
                }
            }
    }
}

log输出:
YukiHook:Find Method [public void com.meituan.banma.main.activity.MainActivity.onCreate(android.os.Bundle)] takes 0ms [Default] 但没执行后
EzXHelper: 有执行后

试过只用其中一个Hook,效果一样
EzXHelper 底层也是用 XposedBridge#hookMethod 的方法实现的
框架是Lsposed 1.8.5 Zygisk

实在搞不清楚是哪里出了问题

关于XposedHelpers.set...Field

你好,我正在浏览并尝试使用Yukihook,但是我在api中没有发现类似于XposedHelper.set...Field的实现,所以想请问使用Yukihook的api我该如何实现。是否应该使用原生的Xposed api

[BUG] HookParam call timing problem

复现步骤:

  1. 创建模块,代码如下,启用模块
loadApp(name = "com.wibo.bigbang.ocr") {
  findClass(name = "okhttp3.Request\$Builder").hook {
      injectMember {
          method {
              name = "addHeader"
              param(StringClass,StringClass)
              returnType = "okhttp3.Request\$Builder"
          }
          beforeHook {
              val a1 = args().first().string();
              loggerD("checkEqual", "", LoggerType.LOGD)
              val a2 = args().first().string();
              loggerD(
                  tag = "checkEqual",
                  msg = "${a1 == a2} $a1 $a2"
              )
          }
      }
  }
}
  1. 安装宿主app:布丁扫描,启动宿主APP

  2. 观察Logcat,发现有好几次输出了false,按理来说应该始终是true才对
    image

  3. 把a1后面的loggerD("checkEqual", "", LoggerType.LOGD)删掉后,程序运行正常(始终输出true
    image

Migrating to 1.2.0

Hello, I have a few questions about the new code style and I don't know where else to ask if not here. I managed to migrate my module's syntax to 1.2.0 (Mesa-Labs-Archive/KnoxPatch@ae4caaa), but I currently have two doubts:

  • What's the new replacement for onHookClassNotFoundFailure?

I'm currently handling this exception to show a prettier error message in logs when the class to hook is not found:

findClass("com.samsung.android.security.keystore.AttestParameterSpec").hook {
    injectMember {
        method {
            name = "isVerifiableIntegrity"
            emptyParam()
            returnType = BooleanType
        }
            replaceToTrue()
        }
}.onHookClassNotFoundFailure {
    loggerE(msg = "$TAG: couldn't access class " +
        "com.samsung.android.security.keystore.AttestParameterSpec " +
        "(${it.javaClass.simpleName})")
}

This is because the class I'm trying to hook isn't part of android frameworks (framework.jar) but rather of a separate library (samsungkeystoreutils.jar), that if not declared in the manifest of the app:

<uses-library android:name="samsungkeystoreutils" android:required="false" />

will make hooking the class to fail. This is what I'm currently using, but I'm not sure if it's correct:

"com.samsung.android.security.keystore.AttestParameterSpec".toClass()
    .method {
        name = "isVerifiableIntegrity"
        emptyParam()
        returnType = BooleanType
    }.hook {
        replaceToTrue()
    }.onAllFailure {
        YLog.error(msg = "$TAG: couldn't access class " +
            "com.samsung.android.security.keystore.AttestParameterSpec " +
            "(${it.javaClass.simpleName})")
    }
  • How can I hook multiple methods of the same class without having to call .toClass() twice?

With the old syntax, I could hook multiple methods of the same class like this:

findClass("android.os.SemSystemProperties").hook {
    injectMember {
        method {
            name = "get"
            param(String::class.java)
            returnType = StringClass
        }
        beforeHook {
            val key: String = args(0).string()

            // Fixes:
            // - Legacy Secure Wi-Fi (ICD)
            // - SPCMAgent (SAK)
            when (key) {
                "ro.build.type" -> result = "eng"
                "ro.security.keystore.keytype" -> result = ""
            }
        }
    }

    injectMember {
        method {
            name = "get"
            param(String::class.java, String::class.java)
            returnType = StringClass
        }
        beforeHook {
            val key: String = args(0).string()
            val def: String = args(1).string()

            if (key == "ro.boot.flash.locked"
                || key == "ro.boot.verifiedbootstate"
                || key == "ro.boot.warranty_bit"
                || key == "ro.config.iccc_version") {
                result = def
            }
        }
    }
}

With the new syntax I ended up with something like this:

"android.os.SemSystemProperties".toClass()
    .method {
        name = "get"
        param(String::class.java)
        returnType = StringClass
    }.hook {
        before {
            val key: String = args(0).string()

            // Fixes:
            // - Legacy Secure Wi-Fi (ICD)
            // - SPCMAgent (SAK)
            when (key) {
                "ro.build.type" -> result = "eng"
                "ro.security.keystore.keytype" -> result = ""
            }
        }
    }

"android.os.SemSystemProperties".toClass()
    .method {
        name = "get"
        param(String::class.java, String::class.java)
        returnType = StringClass
    }.hook {
        before {
            val key: String = args(0).string()
            val def: String = args(1).string()

            if (key == "ro.boot.flash.locked"
                || key == "ro.boot.verifiedbootstate"
                || key == "ro.boot.warranty_bit"
                || key == "ro.config.iccc_version") {
                result = def
            }
        }
    }

JNI DETECTED ERROR IN APPLICATION: java_object == null

用如下代码Hook 腾讯的广告会概率出现如题的闪退(点击桌面图标直接闪退,这个时候hook貌似都没加载到这,关掉这个就不会),特别是Android 9 以上并且在MIUI系统最为严重,我实在是找不到原因,想来问问您

/**
 * 免广告领取奖励
 */
fun PackageParam.freeAdReward(versionCode: Int) {
    when (versionCode) {
        in 854..878 -> {
            findClass("com.qq.e.comm.managers.plugin.PM").hook {
                injectMember {
                    method {
                        name = "getPluginClassLoader"
                        emptyParam()
                        returnType = "java.lang.ClassLoader".toClass()
                    }
                    afterHook {
                        val classLoader = result as? ClassLoader
                        classLoader?.let {
                            /**
                             * com.qq.e.comm.plugin.tangramrewardvideo.g.K() : void
                             *  int v = this.p.aQ()
                             */
                            findClass(
                                "com.qq.e.comm.plugin.tangramrewardvideo.c.b", it
                            ).hook {
                                injectMember {
                                    method {
                                        name = "p"
                                        emptyParam()
                                        returnType = IntType
                                    }
                                    replaceTo(0)
                                }
                            }

                            /**
                             * com.qq.e.comm.plugin.tangramrewardvideo.f.onAfterCreate
                             */
                            findClass("com.qq.e.comm.plugin.tangramrewardvideo.f", it).hook {
                                injectMember {
                                    method {
                                        name = "ao"
                                        emptyParam()
                                        returnType = UnitType
                                    }
                                    afterHook {

                                        val r = instance.getParam<Any>("R")
                                        val g = r?.getParam<Any>("g")
                                        val d = g?.getView<ImageView>("d")

                                        d?.postDelayed(
                                            {
                                                instance.current {
                                                    method {
                                                        name = "s"
                                                        emptyParam()
                                                    }.call()

                                                    method {
                                                        name = "onBackPressed"
                                                        emptyParam()
                                                    }.call()
                                                }
                                            },
                                            (optionEntity.mainOption.freeAdRewardAutoExitTime * 1000).toLong()
                                        )
                                    }
                                }
                            }

                            findClass(
                                "com.qq.e.comm.plugin.tangramrewardvideo.widget.j", it
                            ).hook {
                                injectMember {
                                    method {
                                        name = "b"
                                        paramCount(1)
                                        returnType = UnitType
                                    }
                                    afterHook {
                                        val h = instance.getParam<TextView>("h")
                                        h?.let { tvh ->
                                            if (tvh.text == "跳过视频") {
                                                tvh.performClick()
                                            }
                                        }
                                    }
                                }
                            }

                            findClass(
                                "com.qq.e.comm.plugin.tangramrewardvideo.c.a", it
                            ).hook {
                                injectMember {
                                    method {
                                        name = "aQ"
                                        emptyParam()
                                        returnType = IntType
                                    }
                                    replaceTo(-0x64)
                                }
                            }

                            findClass(
                                "com.qq.e.comm.plugin.tangramrewardvideo.g", it
                            ).hook {
                                injectMember {
                                    method {
                                        name = "L"
                                        emptyParam()
                                        returnType = IntType
                                    }
                                    replaceTo(0)
                                }
                            }


                        }
                    }
                }
            }

            findClass("com.qq.e.comm.managers.setting.SM").hook {
                injectMember {
                    method {
                        name = "getInteger"
                        param(StringClass, IntType)
                        returnType = IntType
                    }
                    afterHook {
                        args(1).set(0)
                    }
                }
            }
        }

        else -> "免广告领取奖励".printlnNotSupportVersion(versionCode)
    }
}
展开查看

[ 2023-03-04T12:28:18.571        0:   857:  1336 I/LSPosedLogcat   ] New log file: /data/adb/lspd/log/verbose_2023-03-04T12:28:18.570797.log
[ 2023-03-04T12:28:22.897    10263: 22360: 22360 I/LSPosed         ] Loading xposed for com.qidian.QDReader/10263
[ 2023-03-04T12:28:22.900    10263: 22360: 22360 I/LSPosed-Bridge  ] Loading module cn.xihan.qdds from /data/app/~~U4MIEf5JRh2Q2uwjeh9XVw==/cn.xihan.qdds-rvGW3iNliX6mnvQni3zWeg==/base.apk
[ 2023-03-04T12:28:22.911    10263: 22360: 22360 I/LSPosed-Bridge  ]   Loading class cn.xihan.qdds.HookEntry_YukiHookXposedInit
[ 2023-03-04T12:28:23.389    10263: 22360:  9897 F/libc            ] Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 9897 (pool-68-thread-), pid 22360 (qidian.QDReader)
[ 2023-03-04T12:28:23.705    10263: 10153: 10153 I/LSPosed         ] Loading xposed for com.qidian.QDReader:pushcore/10263
[ 2023-03-04T12:28:23.710    10263: 10153: 10153 I/LSPosed-Bridge  ] Loading module cn.xihan.qdds from /data/app/~~U4MIEf5JRh2Q2uwjeh9XVw==/cn.xihan.qdds-rvGW3iNliX6mnvQni3zWeg==/base.apk
[ 2023-03-04T12:28:23.731    10263: 10153: 10153 I/LSPosed-Bridge  ]   Loading class cn.xihan.qdds.HookEntry_YukiHookXposedInit
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] Build fingerprint: 'Xiaomi/venus/venus:13/TKQ1.220829.002/V14.0.23.2.23.DEV:user/release-keys'
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] Revision: '0'
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] ABI: 'arm64'
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] Timestamp: 2023-03-04 12:28:23.454317380+0800
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] Process uptime: 318s
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] Cmdline: com.qidian.QDReader
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] pid: 22360, tid: 9897, name: pool-68-thread-  >>> com.qidian.QDReader <<<
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] uid: 10263
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] Abort message: 'JNI DETECTED ERROR IN APPLICATION: java_object == null
    in call to MonitorEnter
    from boolean org.lsposed.lspd.nativebridge.HookBridge.hookMethod(java.lang.reflect.Executable, java.lang.Class, int, java.lang.Object)'
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]     x0  0000000000000000  x1  00000000000026a9  x2  0000000000000006  x3  0000007074bf0df0
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]     x4  5151441f43445342  x5  5151441f43445342  x6  5151441f43445342  x7  7f7f7f7f7f7f7f7f
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]     x8  00000000000000f0  x9  00000071a94fecb0  x10 0000000000000001  x11 00000071a9573748
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]     x12 0000007082347030  x13 0000000000deb4c8  x14 0000000000deb388  x15 0000000034155555
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]     x16 00000071a95dea70  x17 00000071a95b73d0  x18 0000007072de0000  x19 0000000000005758
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]     x20 00000000000026a9  x21 00000000ffffffff  x22 000000000000006e  x23 0000007074bf1008
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]     x24 000000710c616000  x25 0000007074bf1000  x26 0000007074bf2000  x27 000000710c40b038
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]     x28 000000710c40b268  x29 0000007074bf0e70
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]     lr  00000071a95646c8  sp  0000007074bf0dd0  pc  00000071a95646f4  pst 0000000000001000
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ] backtrace:
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]       #00 pc 000000000008d6f4  /apex/com.android.runtime/lib64/bionic/libc.so (abort+168) (BuildId: 2bb0d7188c0db2e8beecb24658ba9d71)
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]       #01 pc 000000000061f104  /apex/com.android.art/lib64/libart.so (art::Runtime::Abort(char const*)+1204) (BuildId: 4ecc70344e180e7eb5404cd12fba6904)
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]       #02 pc 0000000000017114  /apex/com.android.art/lib64/libbase.so (android::base::SetAborter(std::__1::function&&)::$_3::__invoke(char const*)+84) (BuildId: ef369bfbad96b532c6d8e0b144a68b96)
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]       #03 pc 0000000000016648  /apex/com.android.art/lib64/libbase.so (android::base::LogMessage::~LogMessage()+356) (BuildId: ef369bfbad96b532c6d8e0b144a68b96)
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]       #04 pc 0000000000459d44  /apex/com.android.art/lib64/libart.so (art::JavaVMExt::JniAbort(char const*, char const*)+2368) (BuildId: 4ecc70344e180e7eb5404cd12fba6904)
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]       #05 pc 00000000004bfe50  /apex/com.android.art/lib64/libart.so (art::JNI::MonitorEnter(_JNIEnv*, _jobject*)+1380) (BuildId: 4ecc70344e180e7eb5404cd12fba6904)
[ 2023-03-04T12:28:24.261    10263:  9996:  9996 F/DEBUG           ]       #06 pc 0000000000013c18  /memfd:jit-cache (deleted)
[ 2023-03-04T12:28:26.640    10263: 22361: 22361 I/LSPosed         ] Loading xposed for com.qidian.QDReader/10263
[ 2023-03-04T12:28:26.642    10263: 22361: 22361 I/LSPosed-Bridge  ] Loading module cn.xihan.qdds from /data/app/~~U4MIEf5JRh2Q2uwjeh9XVw==/cn.xihan.qdds-rvGW3iNliX6mnvQni3zWeg==/base.apk
[ 2023-03-04T12:28:26.654    10263: 22361: 22361 I/LSPosed-Bridge  ]   Loading class cn.xihan.qdds.HookEntry_YukiHookXposedInit
[ 2023-03-04T12:28:27.289    10263: 11141: 11141 I/LSPosed         ] Loading xposed for com.qidian.QDReader:pushcore/10263
[ 2023-03-04T12:28:27.294    10263: 11141: 11141 I/LSPosed-Bridge  ] Loading module cn.xihan.qdds from /data/app/~~U4MIEf5JRh2Q2uwjeh9XVw==/cn.xihan.qdds-rvGW3iNliX6mnvQni3zWeg==/base.apk
[ 2023-03-04T12:28:27.311    10263: 11141: 11141 I/LSPosed-Bridge  ]   Loading class cn.xihan.qdds.HookEntry_YukiHookXposedInit
[ 2023-03-04T12:28:32.698        0:   857: 23105 I/LSPosedLogcat   ] !!refresh_verbose!!

[BUG] When set param.result after get it value was still original

For Example:

// getSystemProperty is a method read var from android.os.SystemProperties
val x: String? = getSystemProperty("debug.xxx")
if (x != null && x != "") {
    result = x.split(",")
}
// logger.debug is some wrap of YukiHookLogger
logger.debug(
    "Invoke X", "${appInfo.packageName}, $x, $result"
)

When debug.xxx is set to 1,2 the log out pkg_name, 1,2, [1, 2], but upgrade to 1.1.6 it became pkg_name, 1,2, [x, y], the x and y is it's original value.

Using System.out.println has same phenomenon.

[无法复现] before 和 after 替换 result 无效的问题

突然又发现了一个bug,before 和 after 的回调里替换 result 无效。

  • 例子:实现功能:
    将状态栏的 NFC 磁贴 替换成 蓝牙
  1. 我用yuki写的:
"com.android.systemui.qs.QSTileHost".hook {
            injectMember {
                method { name = "createTile"; param(StringClass) }
                beforeHook {
                    if (args(0).string() == "nfc") {
                        val tile = XposedHelpers.callMethod(instance, "createTile", "bt")
                        result = tile
                    }
                }
            }
        }
}

效果:
86b5b1440dcbe68015b62465ed55797

无效


  1. 我用原生 xp 写的
        XposedHelpers.findAndHookMethod("com.android.systemui.qs.QSTileHost".toClass(), "createTile", String::class.java, object : XC_MethodHook() {
            override fun beforeHookedMethod(param: MethodHookParam) {
                    super.beforeHookedMethod(param)
                    if (param.args[0] == "nfc") {
                        val tile = XposedHelpers.callMethod(param.thisObject, "createTile", "bt")
                        param.result = tile
                    }
                }
        })

效果:
a7ed2e1678e59e26f5153927e257736

有效

New Hook Entry Class

New Hook Entry Class

The entry class currently used by the API is designed with reference to the working mode and principle of the native Xposed API.

The biggest problem encountered so far is the logical confusion of the entry class.

For example, we cannot clearly get a Host App's lifecycle from the beginning.

The current API solution is to use onAppLifecycle to monitor the Host App's lifecycle method.

So we may adopt a new entry class design pattern in later versions to bring better experience to Xposed Module developers.

The following example

@YukiXposedModule
class YourModule(hookContext: HookContext) : YukiBaseModule(hookContext: HookContext) {

    init {
        YukiHookAPI.configs {
            isDebug = false
        }
        // HookContext means the global system context
        hookContext.packageName // "android"
        // Listen to the loading events of the native Xposed API
        YukiXposedEvent.events {
            onInitZygote {
                // The it object is [StartupParam]
            }
            onHandleLoadPackage {
                // The it object is [LoadPackageParam]
            }
            onHandleInitPackageResources {
                // The it object is [InitPackageResourcesParam]
            }
        }
    }

    override fun onHook() {
        loadApp(name = "com.example.demo") {
            // Do something...
        }
    }
}

Below are the current entry class schemes.

The following example

@InjectYukiHookWithXposed
object HookEntry : IYukiHookXposedInit {

    override fun onInit() = configs {
        isDebug = false
    }

    override fun onHook() = encase {
        loadApp(name = "com.example.demo") {
            // Do something...
        }
    }

    override fun onXposedEvent() {
        // Listen to the loading events of the native Xposed API
        YukiXposedEvent.events {
            onInitZygote {
                // The it object is [StartupParam]
            }
            onHandleLoadPackage {
                // The it object is [LoadPackageParam]
            }
            onHandleInitPackageResources {
                // The it object is [InitPackageResourcesParam]
            }
        }
    }
}

新的入口类方案

API 目前采用的入口类参考了原生 Xposed API 的工作模式与原理而设计,目前遇到的最大的问题就是入口类逻辑上的混乱问题。

例如我们无法从开始就明确地得到一个宿主的生命周期,目前 API 给出的解决方案是使用 onAppLifecycle 来监听宿主的生命周期方法。

所以我们可能会在后期的版本采用一种新的入口类设计模式来给 Xposed 模块开发者带来更好的体验。

示例如下

@YukiXposedModule
class YourModule(hookContext: HookContext) : YukiBaseModule(hookContext: HookContext) {

    init {
        YukiHookAPI.configs {
            isDebug = false
        }
        // HookContext 即全局系统上下文
        hookContext.packageName // "android"
        // 监听原生 Xposed API 的装载事件
        YukiXposedEvent.events {
            onInitZygote {
                // it 对象即 [StartupParam]
            }
            onHandleLoadPackage {
                // it 对象即 [LoadPackageParam]
            }
            onHandleInitPackageResources {
                // it 对象即 [InitPackageResourcesParam]
            }
        }
    }

    override fun onHook() {
        loadApp(name = "com.example.demo") {
            // Do something...
        }
    }
}

以下是目前采取的入口类方案。

示例如下

@InjectYukiHookWithXposed
object HookEntry : IYukiHookXposedInit {

    override fun onInit() = configs {
        isDebug = false
    }

    override fun onHook() = encase {
        loadApp(name = "com.example.demo") {
            // Do something...
        }
    }

    override fun onXposedEvent() {
        // 监听原生 Xposed API 的装载事件
        YukiXposedEvent.events {
            onInitZygote {
                // it 对象即 [StartupParam]
            }
            onHandleLoadPackage {
                // it 对象即 [LoadPackageParam]
            }
            onHandleInitPackageResources {
                // it 对象即 [InitPackageResourcesParam]
            }
        }
    }
}

demo error

项目很感兴趣,尝试demo使用报错

环境 LSP 1.8.5 系统版本8.1.0 arm64-v8a

Snipaste_2022-11-15_17-01-28

Debug环境下的log是否考虑优化一下,并且可以提供一个Hook环境判断吗?

log优化

目前在debug环境中,每一个回调函数的执行都会在日志上输出记录,比如

After Hook Member [public com.android.systemui.qs.QSTileHost(android.content.Context,com.android.systemui.statusbar.phone.StatusBarIconController,com.android.systemui.plugins.qs.QSFactory,java.util.concurrent.Executor,com.android.systemui.shared.plugins.PluginManager,com.android.systemui.tuner.TunerService,javax.inject.Provider,com.android.systemui.dump.DumpManager,com.android.systemui.broadcast.BroadcastDispatcher,java.util.Optional,com.android.systemui.qs.logging.QSLogger,com.android.internal.logging.UiEventLogger,com.android.systemui.settings.UserTracker,com.android.systemui.util.settings.SecureSettings,com.android.systemui.qs.external.CustomTileStatePersister,com.android.systemui.qs.external.TileServiceRequestController$Builder,com.android.systemui.qs.external.TileLifecycleManager$Factory,com.android.systemui.plugins.statusbar.StatusBarStateController,com.android.systemui.qs.MiuiQSTileHostInjector,com.android.systemui.controlcenter.policy.ControlCenterControllerImpl)] done [Default]

但是有一些目标函数仅是简单的替换返回值为true或false之类的也会输出日志。而且io的速度是最慢的,会很影响调试的流畅性,尤其是对手势或者动画部分进行的hook


我的想法是
类似:com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator.MemberHookCreator.Result#ignoredHookingFailure
添加一个忽略log输出的方法
然后在:com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator.MemberHookCreator#onHookLogMsg 添加多一个判断

Hook环境判断

当前的环境类似:

@YukiGenerateApi
enum class HookEntryType {

    /** 装载 Zygote */
    ZYGOTE,

    /** 装载 APP */
    PACKAGE,

    /** 装载 Resources Hook */
    RESOURCES
}

我发现com.highcapable.yukihookapi.hook.entity.YukiBaseHooker#onHook被设计在PACKAGERESOURCES 中执行,所以才会导致同样的日志会输出两个,当然hook方法应该仅对PACKAGE生效。所以用作者的sdk是能正常使用。但是原因和上面的log一样,在高频调用的函数下我没办法用作者的sdk进行hook,只好根据需求用原生api设计了自己的sdk:感觉风格也挺不错的hh

"com.test.Test".hook {
    // 第一个方法
    method {
        name = "method"
    }.before {
        // doSomeThings
    }.after {
        // doSomeThings
    }
    // 第二个方法
    method {
        name = "method"
    }.before {
        // doSomeThings
    }.after {
        // doSomeThings
    }  // 链式调用 方法异常监听、设置TAG、忽略异常等
}  // 链式调用 类异常监听,如找不到类之类的

由于默认在PACKAGERESOURCES中执行的原因,上面的自定义方式hook会被执行两遍,而且在运行时也会执行两遍。。。
我希望可以在Hooker下可以提供一个能判断当前环境的api,或者让我可以在hook时使用变量设置自己的hook环境

YukiHookPrefsBridge missing Context instance

image
关于sp的使用疑问:
1.在点击事件中写入状态-代码不报错正常运行;
2.读取状态报错,YukiHookPrefsBridge missing Context instance

我想在软件设置的时候加个开关如上图,然后在hook的时候根据开关来判断是否执行,如下,不知是否可行;
image

目前图一读取的时候就报错了,想知道一般都是怎么使用的,谢谢

Originally posted by @wangyuan0217 in #35 (comment)

An unexpected situation while looking up the class to hook(The target class exists)

近期收到部分用户反馈,在模块激活状态正常的情况下,模块功能无法生效,经排查,均在其日志中发现了如下内容:
[ 2023-02-05T19:02:19.473 1000: 30319: 30339 I/LSPosed-Bridge ] [SuperMIUI][E][com.miui.screenrecorder]--> HookClass [xxx] not found
[ 2023-02-05T19:02:19.473 1000: 30319: 30339 E/LSPosed-Bridge ] java.lang.NoClassDefFoundError: Can't find this Class in [dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/~~ihnnvDp5iD3hkGxyW5_E1g==/com.miui.screenrecorder-YB5tO2wcREqzWyojhoPibg==/base.apk"],nativeLibraryDirectories=[/data/app/~~ihnnvDp5iD3hkGxyW5_E1g==/com.miui.screenrecorder-YB5tO2wcREqzWyojhoPibg==/lib/arm64, /data/app/~~ihnnvDp5iD3hkGxyW5_E1g==/com.miui.screenrecorder-YB5tO2wcREqzWyojhoPibg==/base.apk!/lib/arm64-v8a, /system/lib64, /system_ext/lib64]]]]:
-> name:[xxx]
Generated by YukiHookAPI#ReflectionTool
at ZQDesigned.江来.雨(Unknown Source:184)
at ZQDesigned.江来.生(Unknown Source:172)
at ZQDesigned.说死.晴(Unknown Source:59)
at ZQDesigned.长利.趋(Unknown Source:59)
at ZQDesigned.说死.生(Unknown Source:50)
at ZQDesigned.有膜.invoke(Unknown Source:32)
at ZQDesigned.来气.晴(Unknown Source:516)
at UTSSG.ZQDesigned.miuiupdater.hook.initHook.handleLoadPackage(Unknown Source:10)
at de.robv.android.xposed.IXposedHookLoadPackage$Wrapper.handleLoadPackage(Unknown Source:2)
at de.robv.android.xposed.callbacks.XC_LoadPackage.call(Unknown Source:6)
at de.robv.android.xposed.callbacks.XCallback.callAll(Unknown Source:26)
at E.afterHookedMethod(Unknown Source:207)
at de.robv.android.xposed.XposedBridge$AdditionalHookInfo.callback(Unknown Source:147)
at LSPHooker_.getClassLoader(Unknown Source:8)
at android.app.LoadedApk.getResources(LoadedApk.java:1402)
at android.app.ContextImpl.createAppContext(ContextImpl.java:3101)
at android.app.ContextImpl.createAppContext(ContextImpl.java:3093)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6871)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2228)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:210)
at android.os.Looper.loop(Looper.java:299)
at android.app.ActivityThread.main(ActivityThread.java:8136)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1028)
[ 2023-02-05T19:02:19.476 1000: 30319: 30342 I/LSPosed-Bridge ] [SuperMIUI][E][com.miui.screenrecorder]--> HookClass [xxx] not found
[ 2023-02-05T19:02:19.477 1000: 30319: 30342 E/LSPosed-Bridge ] java.lang.NoClassDefFoundError: Can't find this Class in [dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/~~ihnnvDp5iD3hkGxyW5_E1g==/com.miui.screenrecorder-YB5tO2wcREqzWyojhoPibg==/base.apk"],nativeLibraryDirectories=[/data/app/~~ihnnvDp5iD3hkGxyW5_E1g==/com.miui.screenrecorder-YB5tO2wcREqzWyojhoPibg==/lib/arm64, /data/app/~~ihnnvDp5iD3hkGxyW5_E1g==/com.miui.screenrecorder-YB5tO2wcREqzWyojhoPibg==/base.apk!/lib/arm64-v8a, /system/lib64, /system_ext/lib64]]]]:
-> name:[xxx]
Generated by YukiHookAPI#ReflectionTool
at ZQDesigned.江来.雨(Unknown Source:184)
at ZQDesigned.江来.生(Unknown Source:172)
at ZQDesigned.说死.晴(Unknown Source:59)
at ZQDesigned.长利.趋(Unknown Source:430)
at ZQDesigned.说死.生(Unknown Source:50)
at ZQDesigned.有膜.invoke(Unknown Source:32)
at ZQDesigned.来气.晴(Unknown Source:516)
at UTSSG.ZQDesigned.miuiupdater.hook.initHook.handleLoadPackage(Unknown Source:10)
at de.robv.android.xposed.IXposedHookLoadPackage$Wrapper.handleLoadPackage(Unknown Source:2)
at de.robv.android.xposed.callbacks.XC_LoadPackage.call(Unknown Source:6)
at de.robv.android.xposed.callbacks.XCallback.callAll(Unknown Source:26)
at E.afterHookedMethod(Unknown Source:207)
at de.robv.android.xposed.XposedBridge$AdditionalHookInfo.callback(Unknown Source:147)
at LSPHooker_.getClassLoader(Unknown Source:8)
at android.app.LoadedApk.getResources(LoadedApk.java:1402)
at android.app.ContextImpl.createAppContext(ContextImpl.java:3101)
at android.app.ContextImpl.createAppContext(ContextImpl.java:3093)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6871)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2228)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:210)
at android.os.Looper.loop(Looper.java:299)
at android.app.ActivityThread.main(ActivityThread.java:8136)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1028)

目前已知该问题并非100%复现,且Hooker逻辑无误,目标class和method在用户对应的版本中均存在。

registerModuleAppActivities() 注册活动,不会初始化activity

能够跳转到设定的proxyClassName值,但是ModuleAppActivity继承的类,onCreate等函数并不会被创建。

 onAppLifecycle {
                attachBaseContext { baseContext, hasCalledSuper ->
                    if (hasCalledSuper) run {
                        appClassLoader = baseContext.classLoader

                        // YLog.warn("HookEntry attachBaseContext success")
                    }
                }
                onCreate {
                    // 注入模块资源
                    injectModuleAppResources()
                    // 注册模块activity
                   registerModuleAppActivities()
}

而注册的activiy代码为:

class HOOKActivity : ModuleAppActivity(){
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        YLog.info("HOOKActivity onCreate")
}
}

intent进入活动使用的是:

val intent=Intent(context, HOOKActivity::class.java).apply {
        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    }

   context.startActivity(intent)
    YLog.info("intent:$intent")

能够打印intent的值,并且能根据设定的proxyClassName进入到宿主app的指定活动,但初始化代码并不会完成。
可能是因为使用

        YukiXposedEvent.events {
            onHandleLoadPackage {
                XposedHelpers.findAndHookMethod(className.toClass(),
                    methodName,
                    object : XC_MethodHook() {
                        override fun afterHookedMethod(param: MethodHookParam?) {

来获取context的方法,用yuki框架自带的挂载不上,少部分函数能挂载,但无法获取context和其他值。

[BUG] 仅在Android 9 版本 registerModuleAppActivities 错误

  • 启动和注册代码如下
"com.qidian.QDReader.ui.activity.MoreActivity".toClass().apply {
                method {
                    name = "initWidget"
                    emptyParam()
                    returnType = UnitType
                }.hook().after {
                    instance<Activity>().apply {
                            startActivity(Intent(this, MainActivity::class.java))
                        }
                }

                method {
                    name = "onCreate"
                    param(BundleClass)
                    returnType = UnitType
                }.hook().after {
                    instance<Activity>().registerModuleAppActivities()
                }

            }


class MainActivity : ModuleAppCompatActivity() {
}
  • 使用场景: 在Andorid 9 不管模拟器还是真机,启动Activity,不管继承ModuleAppCompatActivity 还是ModuleActivity 都无法显示布局,其他版本暂时未发现问题。

  • 其他信息:另外尝试过多个不同继承的代理,如果代理的Activity继承的是android.app.Activity则会完全透明显示上一个Activity,继承的是androidx.appcompat.app.AppCompatActivity则会显示代理Activity的基础布局,想要启动的Activity布局不显示。使用布局分析软件发现启动流程是com.qidian.QDReader.ui.activity.SplashActivity > cn.xihan.qdds.MainActivity,日志也没有任何相关内容或者报错,不知道是我对于该功能理解错误还是框架bug?

`method` 能否以多个条件查找方法呢?

大概有这么一个场景,需要 Hook 的目标 App 在旧版本和新版本中存在同名但参数列表不同的方法:

// 这是旧版本 App 的方法
public static String methodName(Context context, boolean z, boolean z2)

// 这是新版本 App 的方法
public static String methodName(Context context, View view, boolean z, boolean z2, Intent intent, int i2)

我需要在目标 App 原本的 methodName 方法执行前进行一些操作。尽管新版本增加了几个参数,但这些并不是我需要用到的。也就是说除了需要 Hook 的方法签名不同之外,我不需要对我自行实现的模块中的方法进行修改。

YukiHookAPI 的文档中指出“存在多个 BaseFinder.IndexTypeCondition 时除了 order 只会生效最后一个”,这样的话我就需要将完全相同的代码复制两遍,比较繁琐。

因此,不知道能否允许通过多个 IndexTypeCondition 来查找方法呢?或者我的这个需求有其他的实现方法吗?

YukiHookPrefsBridge read value not working in the release mode

My module implements the logic of saving some parameters to disk using YukiHookPrefsBridge. When the method hook I need is called, I read the stored value using YukiHookPrefsBridge and substitute it as the return value. The problem is that in the debug build everything works, but as soon as I switch to the release, reading the value stops working and starts returning to the default value specified in the shared preferences. I can’t figure out what the problem is, maybe I need to specify some additional rules for obfuscation (I use R8 in the release build)?

驾校一点通

驾校一点通,不进行任何Hook操作,只要勾选了作用域就会卡第一屏

添加在 Hook 资源时获取宿主原始资源的扩展功能

框架中貌似没有封装获取app资源的方法
例如我要获取app的string,要经过以下步骤:

val id = appResources!!.getIdentifier(
                    "example_name",
                    "string",
                    packageName
                )
appResources.getString(id)

这样略显麻烦,有什么优雅的方法可以代替吗

New Hook Code Style

New Hook Code Style

This is a proposal.

Since the API's original design mode of constructing a Hook only for a Class does not meet some exceptions, and there are some adaptability problems, so we make a new Hook code style is given below.

The following example

// Single Method Hook
"com.demo.Test".toClass().method {
    name = "test"
    param(StringClass)
}.hook {
    before {
        // Do something...
    }
    after {
        // Do something...
    }
}
// Multiple Methods Hook
"com.demo.Test".toClass().method {
    name = "test"
}.all().hook {
    before {
        // Do something...
    }
    after {
        // Do something...
    }
}
// A Class with multiple Methods Hook
"com.demo.Test".toClass().apply {
    method {
        name = "test"
        param(StringClass)
    }.hook {
        before {
            // Do something...
        }
        after {
            // Do something...
        }
    }
    method {
        name = "another"
        param(IntType)
    }.hook {
        before {
            // Do something...
        }
        after {
            // Do something...
        }
    }
}

Below is the current Hook code style.

The following example

// Single Method Hook
"com.demo.Test".toClass().hook {
    injectMember {
        method {
            name = "test"
            param(StringClass)
        }
        beforeHook {
            // Do something...
        }
        afterHook {
            // Do something...
        }
    }
}
// Multiple Methods Hook
"com.demo.Test".toClass().hook {
    injectMember {
        method {
            name = "test"
        }.all()
        beforeHook {
            // Do something...
        }
        afterHook {
            // Do something...
        }
    }
}
// A Class with multiple Methods Hook
"com.demo.Test".toClass().hook {
    injectMember {
        method {
            name = "test"
            param(StringClass)
        }
        beforeHook {
            // Do something...
        }
        afterHook {
            // Do something...
        }
    }
    injectMember {
        method {
            name = "another"
            param(IntType)
        }
        beforeHook {
            // Do something...
        }
        afterHook {
            // Do something...
        }
    }
}

新的 Hook 代码样式

这是一个提案。

由于 API 最初设计的仅针对一个 Class 构造一个 Hook 的模式不符合一些例外情况,也存在一些适配性问题,所以我们在下方给出了一种新的 Hook 代码样式。

示例如下

// 单一方法 Hook
"com.demo.Test".toClass().method {
    name = "test"
    param(StringClass)
}.hook {
    before {
        // Do something...
    }
    after {
        // Do something...
    }
}
// 多重方法 Hook
"com.demo.Test".toClass().method {
    name = "test"
}.all().hook {
    before {
        // Do something...
    }
    after {
        // Do something...
    }
}
// 一个 Class 多个方法 Hook
"com.demo.Test".toClass().apply {
    method {
        name = "test"
        param(StringClass)
    }.hook {
        before {
            // Do something...
        }
        after {
            // Do something...
        }
    }
    method {
        name = "another"
        param(IntType)
    }.hook {
        before {
            // Do something...
        }
        after {
            // Do something...
        }
    }
}

下方是现在采用的 Hook 代码样式。

示例如下

// 单一方法 Hook
"com.demo.Test".toClass().hook {
    injectMember {
        method {
            name = "test"
            param(StringClass)
        }
        beforeHook {
            // Do something...
        }
        afterHook {
            // Do something...
        }
    }
}
// 多重方法 Hook
"com.demo.Test".toClass().hook {
    injectMember {
        method {
            name = "test"
        }.all()
        beforeHook {
            // Do something...
        }
        afterHook {
            // Do something...
        }
    }
}
// 一个 Class 多个方法 Hook
"com.demo.Test".toClass().hook {
    injectMember {
        method {
            name = "test"
            param(StringClass)
        }
        beforeHook {
            // Do something...
        }
        afterHook {
            // Do something...
        }
    }
    injectMember {
        method {
            name = "another"
            param(IntType)
        }
        beforeHook {
            // Do something...
        }
        afterHook {
            // Do something...
        }
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.