├── .editorconfig ├── .gitignore ├── LICENSE ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── xposed_init │ ├── ic_launcher-playstore.png │ ├── java │ └── io │ │ └── github │ │ └── uhsk │ │ └── lua │ │ ├── Xposed.kt │ │ ├── extensions │ │ └── ExtensionLua.kt │ │ ├── lib │ │ ├── XposedBridgeLib.kt │ │ └── XposedHelpersLib.kt │ │ └── utils │ │ └── UtilLuaValue.kt │ └── res │ ├── drawable │ └── ic_launcher_foreground.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── themes.xml ├── build.gradle ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── key.store ├── readme.md └── settings.gradle /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | tab_width = 4 5 | indent_size = 4 6 | max_line_length = 300 7 | trim_trailing_whitespace = true 8 | ij_any_align_multiline_binary_operation = true 9 | ij_java_align_group_field_declarations = true 10 | 11 | [{*.gradle.kts, *.kts, *.kt}] 12 | ij_continuation_indent_size = 4 13 | ij_kotlin_align_in_columns_case_branch = true 14 | ij_kotlin_align_multiline_binary_operation = true 15 | ij_kotlin_align_multiline_extends_list = false 16 | ij_kotlin_field_annotation_wrap = off 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea 42 | 43 | # Keystore files 44 | # Uncomment the following lines if you do not want to check your keystore files in. 45 | #*.jks 46 | #*.keystore 47 | 48 | # External native build folder generated in Android Studio 2.2 and later 49 | .externalNativeBuild 50 | .cxx/ 51 | 52 | # Google Services (e.g. APIs or Firebase) 53 | # google-services.json 54 | 55 | # Freeline 56 | freeline.py 57 | freeline/ 58 | freeline_project_description.json 59 | 60 | # fastlane 61 | fastlane/report.xml 62 | fastlane/Preview.html 63 | fastlane/screenshots 64 | fastlane/test_output 65 | fastlane/readme.md 66 | 67 | # Version control 68 | vcs.xml 69 | 70 | # lint 71 | lint/intermediates/ 72 | lint/generated/ 73 | lint/outputs/ 74 | lint/tmp/ 75 | # lint/reports/ 76 | 77 | # MacOs 78 | .DS_Store 79 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022. sollyu 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * 17 | */ 18 | 19 | apply plugin: 'com.android.application' 20 | apply plugin: 'kotlin-android' 21 | apply plugin: 'kotlin-kapt' 22 | 23 | android { 24 | compileSdk libs.versions.compileSdk.get().toInteger() 25 | 26 | defaultConfig { 27 | applicationId "io.github.uhsk.lua" 28 | minSdk libs.versions.minSdk.get().toInteger() 29 | targetSdk libs.versions.compileSdk.get().toInteger() 30 | versionCode 1 31 | versionName "1.0.0" 32 | multiDexEnabled false 33 | setProperty('archivesBaseName', "XposedLua-$versionName-$versionCode-" + (new Date()).format('yyyyMMdd')) 34 | } 35 | 36 | buildTypes { 37 | debug { 38 | debuggable true 39 | minifyEnabled false 40 | shrinkResources false 41 | zipAlignEnabled false 42 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 43 | } 44 | release { 45 | debuggable false 46 | minifyEnabled false 47 | shrinkResources false 48 | zipAlignEnabled false 49 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 50 | } 51 | } 52 | 53 | compileOptions { 54 | sourceCompatibility JavaVersion.VERSION_11 55 | targetCompatibility JavaVersion.VERSION_11 56 | } 57 | 58 | kotlinOptions { 59 | jvmTarget = '11' 60 | } 61 | 62 | packagingOptions { 63 | exclude 'kotlin-tooling-metadata.json' 64 | exclude 'DebugProbesKt.bin' 65 | exclude '/kotlin/**.kotlin_builtins' 66 | exclude '/org/apache/commons/codec/**/' 67 | exclude '/META-INF/**.version' 68 | } 69 | } 70 | 71 | dependencies { 72 | 73 | // androidx 74 | implementation libs.androidx.core 75 | implementation libs.androidx.appcompat 76 | 77 | // kotlin 78 | implementation libs.kotlin.coroutines 79 | implementation libs.kotlin.extension 80 | 81 | // commons 82 | implementation libs.common.gson 83 | implementation libs.common.joor 84 | compileOnly libs.common.xposed 85 | 86 | implementation 'org.luaj:luaj-jse:3.0.1' 87 | } 88 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -obfuscationdictionary proguard-dic-6.txt 23 | -renamesourcefileattribute proguard-dic-6.txt 24 | -classobfuscationdictionary proguard-dic-6.txt 25 | -packageobfuscationdictionary proguard-dic-6.txt 26 | -repackageclasses java.io 27 | -renamesourcefileattribute "lua" 28 | -dontwarn ** 29 | 30 | -keepattributes Signature 31 | -keepattributes *Annotation* 32 | -keepattributes Exceptions 33 | -keepattributes InnerClasses 34 | 35 | ########################################################################################################## 36 | -keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName ; } 37 | 38 | ########################################################################################################## 39 | -keep class androidx.fragment.app.FragmentTransaction{ *; } 40 | -keep class androidx.fragment.app.FragmentTransaction$Op{ *; } 41 | 42 | ########################################################################################################## 43 | -keep public class com.alibaba.android.arouter.routes.**{*;} 44 | -keep public class com.alibaba.android.arouter.facade.**{*;} 45 | 46 | ########################################################################################################## 47 | -keep public class org.luaj.**{*;} 48 | -keep public class org.luaj.vm2.lib.Bit32Lib$*{*;} 49 | 50 | ########################################################################################################## 51 | -keep class * implements de.robv.android.xposed.IXposedHookLoadPackage 52 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 23 | 24 | 32 | 33 | 36 | 39 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | io.github.uhsk.lua.Xposed 2 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/io/github/uhsk/lua/Xposed.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022. sollyu 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * 17 | */ 18 | 19 | package io.github.uhsk.lua 20 | 21 | import android.annotation.SuppressLint 22 | import de.robv.android.xposed.IXposedHookLoadPackage 23 | import de.robv.android.xposed.callbacks.XC_LoadPackage 24 | import io.github.uhsk.kit.toFile 25 | import io.github.uhsk.lua.lib.XposedBridgeLib 26 | import io.github.uhsk.lua.lib.XposedHelpersLib 27 | import org.luaj.vm2.lib.DebugLib 28 | import org.luaj.vm2.lib.jse.CoerceJavaToLua 29 | import org.luaj.vm2.lib.jse.JsePlatform 30 | import java.io.File 31 | 32 | /** 33 | * Xposed入口类 34 | * 35 | * @since 1.0.0 36 | * @author sollyu 37 | * @date 2022-09-13 38 | */ 39 | class Xposed : IXposedHookLoadPackage { 40 | 41 | @SuppressLint("SdCardPath") 42 | override fun handleLoadPackage(loadPackageParam: XC_LoadPackage.LoadPackageParam) { 43 | handleLoadPackageLuaScriptDir(lpparam = loadPackageParam, scriptDir = "/sdcard/Android/data/${loadPackageParam.packageName}/files/xposed/".toFile()) 44 | handleLoadPackageLuaScriptDir(lpparam = loadPackageParam, scriptDir = "/sdcard/XposedLua/".toFile()) 45 | } 46 | 47 | private fun handleLoadPackageLuaScriptDir(lpparam: XC_LoadPackage.LoadPackageParam, scriptDir: File) { 48 | if (scriptDir.exists().not() || scriptDir.isDirectory.not()) { 49 | return 50 | } 51 | 52 | val appLuaScriptFileList: List = scriptDir.listFiles()?.filter { it.extension == "lua" && it.canRead() } ?: emptyList() 53 | if (appLuaScriptFileList.isEmpty()) { 54 | return 55 | } 56 | 57 | for (luaScriptFile in appLuaScriptFileList) { 58 | val globals = JsePlatform.standardGlobals() 59 | globals.load(DebugLib()) 60 | globals.load(XposedBridgeLib()) 61 | globals.load(XposedHelpersLib()) 62 | globals.load(luaScriptFile.reader(charset = Charsets.UTF_8).readText()).call() 63 | val luaHandleLoadPackage = globals["handleLoadPackage"] 64 | if (luaHandleLoadPackage.isfunction()) { 65 | luaHandleLoadPackage.call(CoerceJavaToLua.coerce(lpparam)) 66 | } 67 | } 68 | 69 | } 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/uhsk/lua/extensions/ExtensionLua.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022. sollyu 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * 17 | */ 18 | 19 | package io.github.uhsk.lua.extensions 20 | 21 | import org.luaj.vm2.LuaValue 22 | import org.luaj.vm2.lib.jse.CoerceJavaToLua 23 | import org.luaj.vm2.lib.jse.CoerceLuaToJava 24 | 25 | /** 26 | * 将普通对象转换成Lua对象 27 | * 28 | * @since 1.0.0 29 | * @author sollyu 30 | * @date 2022-09-13 31 | */ 32 | fun Any.toLuaObject(): LuaValue = CoerceJavaToLua.coerce(this) 33 | 34 | /** 35 | * 将Lua对象转换成Java对象 36 | * 37 | * @since 1.0.0 38 | * @author sollyu 39 | * @date 2022-09-13 40 | */ 41 | inline fun LuaValue.toJavaObject(): T = CoerceLuaToJava.coerce(this, T::class.java) as T 42 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/uhsk/lua/lib/XposedBridgeLib.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022. sollyu 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * 17 | */ 18 | 19 | package io.github.uhsk.lua.lib 20 | 21 | import de.robv.android.xposed.XposedBridge 22 | import de.robv.android.xposed.XposedHelpers 23 | import io.github.uhsk.lua.extensions.toLuaObject 24 | import io.github.uhsk.lua.utils.UtilLuaValue 25 | import org.luaj.vm2.LuaTable 26 | import org.luaj.vm2.LuaValue 27 | import org.luaj.vm2.lib.OneArgFunction 28 | import org.luaj.vm2.lib.ThreeArgFunction 29 | import org.luaj.vm2.lib.TwoArgFunction 30 | import org.luaj.vm2.lib.ZeroArgFunction 31 | import java.util.* 32 | 33 | /** 34 | * XposedBridge 中转类 35 | * 36 | * @since 1.0.0 37 | * @author sollyu 38 | * @date 2022-09-13 39 | */ 40 | class XposedBridgeLib : TwoArgFunction() { 41 | 42 | 43 | override fun call(modName: LuaValue, env: LuaValue): LuaValue { 44 | val table = LuaTable() 45 | table.set("getXposedVersion", GetXposedVersion()) 46 | table.set("log", Log()) 47 | 48 | table.set("hookAllMethods", HookAllMethods()) 49 | table.set("hookAllConstructors", HookAllConstructors()) 50 | 51 | env.set("XposedBridge", table) 52 | env.get("package").get("loaded").set("XposedBridge", table) 53 | return table 54 | } 55 | 56 | private class GetXposedVersion : ZeroArgFunction() { 57 | override fun call(): LuaValue { 58 | return XposedBridge.getXposedVersion().toLuaObject() 59 | } 60 | } 61 | 62 | private class HookAllMethods : ThreeArgFunction() { 63 | override fun call(luaHookClass: LuaValue, luaMethodName: LuaValue, luaCallback: LuaValue): LuaValue { 64 | return XposedBridge.hookAllMethods(luaHookClass.checkuserdata() as Class<*>, luaMethodName.checkjstring(), UtilLuaValue.luaTableToXcMethod(luaCallback.checktable())).toLuaObject() 65 | } 66 | } 67 | 68 | private class HookAllConstructors : ThreeArgFunction() { 69 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaCallback: LuaValue): LuaValue { 70 | val clazz: Class<*> = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 71 | return XposedBridge.hookAllConstructors(clazz, UtilLuaValue.luaTableToXcMethod(luaCallback.checktable())).toLuaObject() 72 | } 73 | 74 | override fun call(luaHookClass: LuaValue, luaCallback: LuaValue): LuaValue { 75 | return XposedBridge.hookAllConstructors(luaHookClass.checkuserdata() as Class<*>, UtilLuaValue.luaTableToXcMethod(luaCallback.checktable())).toLuaObject() 76 | } 77 | } 78 | 79 | private class Log : OneArgFunction() { 80 | override fun call(arg: LuaValue): LuaValue { 81 | when { 82 | arg.isstring() -> XposedBridge.log(String.format(Locale.ENGLISH, "XposedLua: %s", arg.checkstring().tojstring())) 83 | arg.isuserdata() && arg.checkuserdata() is Throwable -> XposedBridge.log(arg.checkuserdata() as Throwable) 84 | } 85 | return NONE 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/uhsk/lua/lib/XposedHelpersLib.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022. sollyu 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * 17 | */ 18 | 19 | package io.github.uhsk.lua.lib 20 | 21 | import de.robv.android.xposed.XposedHelpers 22 | import io.github.uhsk.lua.extensions.toLuaObject 23 | import io.github.uhsk.lua.utils.UtilLuaValue 24 | import org.luaj.vm2.LuaTable 25 | import org.luaj.vm2.LuaValue 26 | import org.luaj.vm2.Varargs 27 | import org.luaj.vm2.lib.OneArgFunction 28 | import org.luaj.vm2.lib.ThreeArgFunction 29 | import org.luaj.vm2.lib.TwoArgFunction 30 | import org.luaj.vm2.lib.VarArgFunction 31 | import org.luaj.vm2.lib.jse.CoerceLuaToJava 32 | 33 | /** 34 | * XposedHelpers 中转类 35 | * 36 | * @since 1.0.0 37 | * @author sollyu 38 | * @date 2022-09-13 39 | */ 40 | class XposedHelpersLib : TwoArgFunction() { 41 | override fun call(modName: LuaValue, env: LuaValue): LuaValue { 42 | val table = LuaTable() 43 | table.set("findClass", FindClass()) 44 | table.set("findClassIfExists", FindClassIfExists()) 45 | table.set("findField", FindField()) 46 | table.set("findFieldIfExists", FindFieldIfExists()) 47 | 48 | table.set("findAndHookMethod", FindAndHookMethod()) 49 | table.set("findAndHookConstructor", FindAndHookConstructor()) 50 | 51 | table.set("getObjectField", GetObjectField()) 52 | table.set("getSurroundingThis", GetSurroundingThis()) 53 | table.set("getBooleanField", GetBooleanField()) 54 | table.set("getByteField", GetByteField()) 55 | table.set("getCharField", GetCharField()) 56 | table.set("getDoubleField", GetDoubleField()) 57 | table.set("getFloatField", GetFloatField()) 58 | table.set("getIntField", GetIntField()) 59 | table.set("getLongField", GetLongField()) 60 | table.set("getShortField", GetShortField()) 61 | 62 | table.set("getStaticObjectField", GetStaticObjectField()) 63 | table.set("getStaticBooleanField", GetStaticBooleanField()) 64 | table.set("getStaticByteField", GetStaticByteField()) 65 | table.set("getStaticCharField", GetStaticCharField()) 66 | table.set("getStaticDoubleField", GetStaticDoubleField()) 67 | table.set("getStaticFloatField", GetStaticFloatField()) 68 | table.set("getStaticIntField", GetStaticIntField()) 69 | table.set("getStaticLongField", GetStaticLongField()) 70 | table.set("getStaticShortField", GetStaticShortField()) 71 | 72 | table.set("setObjectField", SetObjectField()) 73 | table.set("setBooleanField", SetBooleanField()) 74 | table.set("setByteField", SetByteField()) 75 | table.set("setCharField", SetCharField()) 76 | table.set("setDoubleField", SetDoubleField()) 77 | table.set("setFloatField", SetFloatField()) 78 | table.set("setIntField", SetIntField()) 79 | table.set("setLongField", SetLongField()) 80 | table.set("setShortField", SetShortField()) 81 | 82 | table.set("setStaticObjectField", SetStaticObjectField()) 83 | table.set("setStaticBooleanField", SetStaticBooleanField()) 84 | table.set("setStaticByteField", SetStaticByteField()) 85 | table.set("setStaticCharField", SetStaticCharField()) 86 | table.set("setStaticDoubleField", SetStaticDoubleField()) 87 | table.set("setStaticFloatField", SetStaticFloatField()) 88 | table.set("setStaticIntField", SetStaticIntField()) 89 | table.set("setStaticLongField", SetStaticLongField()) 90 | table.set("setStaticShortField", SetStaticShortField()) 91 | 92 | table.set("callMethod", CallMethod()) 93 | table.set("callStaticMethod", CallStaticMethod()) 94 | 95 | table.set("newInstance", NewInstance()) 96 | 97 | env.set("XposedHelpers", table) 98 | env.get("package").get("loaded").set("XposedHelpers", table) 99 | return table 100 | } 101 | 102 | private class FindAndHookMethod : VarArgFunction() { 103 | 104 | override fun invoke(args: Varargs): LuaValue { 105 | return when { 106 | args.isstring(1) -> invoke(className = args.checkjstring(1), classLoader = args.checkuserdata(2) as ClassLoader, methodName = args.checkjstring(3), args = args) 107 | args.isuserdata(1) -> invoke(className = args.checkuserdata(1) as Class<*>, methodName = args.checkjstring(2), args = args) 108 | else -> throw IllegalArgumentException() 109 | } 110 | } 111 | 112 | private fun invoke(className: String, methodName: String, classLoader: ClassLoader, args: Varargs): LuaValue { 113 | val clazz: Class<*> = XposedHelpers.findClass(className, classLoader) 114 | 115 | val patternList: ArrayList = ArrayList() 116 | for (i in 4 until args.narg()) { 117 | patternList.add(CoerceLuaToJava.coerce(args.arg(i), Any::class.java)) 118 | } 119 | patternList.add(UtilLuaValue.luaTableToXcMethod(args.checktable(args.narg()))) 120 | 121 | val patternArray: Array = patternList.toArray() 122 | return XposedHelpers.findAndHookMethod(clazz, methodName, *patternArray).toLuaObject() 123 | } 124 | 125 | private fun invoke(className: Class<*>, methodName: String, args: Varargs): LuaValue { 126 | val patternList: ArrayList = ArrayList() 127 | for (i in 3 until args.narg()) { 128 | patternList.add(CoerceLuaToJava.coerce(args.arg(i), Any::class.java)) 129 | } 130 | patternList.add(UtilLuaValue.luaTableToXcMethod(args.checktable(args.narg()))) 131 | 132 | val patternArray: Array = patternList.toArray() 133 | return XposedHelpers.findAndHookMethod(className, methodName, *patternArray).toLuaObject() 134 | } 135 | 136 | 137 | } 138 | 139 | private class FindAndHookConstructor : VarArgFunction() { 140 | override fun invoke(args: Varargs): LuaValue { 141 | return when { 142 | args.isstring(1) -> invoke(className = args.checkjstring(1), classLoader = args.checkuserdata(2) as ClassLoader, args = args) 143 | args.isuserdata(1) -> invoke(className = args.checkuserdata(1) as Class<*>, args = args) 144 | else -> throw IllegalArgumentException() 145 | } 146 | } 147 | 148 | private fun invoke(className: String, classLoader: ClassLoader, args: Varargs): LuaValue { 149 | val clazz: Class<*> = XposedHelpers.findClass(className, classLoader) 150 | 151 | val patternList: ArrayList = ArrayList() 152 | for (i in 3 until args.narg()) { 153 | patternList.add(CoerceLuaToJava.coerce(args.arg(i), Any::class.java)) 154 | } 155 | patternList.add(UtilLuaValue.luaTableToXcMethod(args.checktable(args.narg()))) 156 | 157 | val patternArray: Array = patternList.toArray() 158 | return XposedHelpers.findAndHookConstructor(clazz, *patternArray).toLuaObject() 159 | } 160 | 161 | private fun invoke(className: Class<*>, args: Varargs): LuaValue { 162 | val patternList: ArrayList = ArrayList() 163 | for (i in 2 until args.narg()) { 164 | patternList.add(CoerceLuaToJava.coerce(args.arg(i), Any::class.java)) 165 | } 166 | patternList.add(UtilLuaValue.luaTableToXcMethod(args.checktable(args.narg()))) 167 | 168 | val patternArray: Array = patternList.toArray() 169 | return XposedHelpers.findAndHookConstructor(className, *patternArray).toLuaObject() 170 | } 171 | 172 | } 173 | 174 | private class FindClass : TwoArgFunction() { 175 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue): LuaValue { 176 | return XposedHelpers.findClass(luaClassName.tojstring(), CoerceLuaToJava.coerce(luaClassLoader, ClassLoader::class.java) as ClassLoader).toLuaObject() 177 | } 178 | } 179 | 180 | private class FindClassIfExists : TwoArgFunction() { 181 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue): LuaValue { 182 | return XposedHelpers.findClassIfExists(luaClassLoader.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader).toLuaObject() 183 | } 184 | } 185 | 186 | private class FindField : TwoArgFunction() { 187 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 188 | return XposedHelpers.findField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 189 | } 190 | } 191 | 192 | private class FindFieldIfExists : TwoArgFunction() { 193 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 194 | return XposedHelpers.findFieldIfExists(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 195 | } 196 | } 197 | 198 | private class GetObjectField : TwoArgFunction() { 199 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue): LuaValue { 200 | return XposedHelpers.getObjectField(luaObject.checkuserdata(), luaFieldName.checkjstring()).toLuaObject() 201 | } 202 | } 203 | 204 | private class GetSurroundingThis : OneArgFunction() { 205 | override fun call(luaObject: LuaValue): LuaValue { 206 | return XposedHelpers.getSurroundingThis(luaObject.checkuserdata()).toLuaObject() 207 | } 208 | } 209 | 210 | private class GetBooleanField : TwoArgFunction() { 211 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue): LuaValue { 212 | return XposedHelpers.getBooleanField(luaObject.checkuserdata(), luaFieldName.checkjstring()).toLuaObject() 213 | } 214 | } 215 | 216 | private class GetByteField : TwoArgFunction() { 217 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue): LuaValue { 218 | return XposedHelpers.getByteField(luaObject.checkuserdata(), luaFieldName.checkjstring()).toLuaObject() 219 | } 220 | } 221 | 222 | private class GetCharField : TwoArgFunction() { 223 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue): LuaValue { 224 | return XposedHelpers.getCharField(luaObject.checkuserdata(), luaFieldName.checkjstring()).toLuaObject() 225 | } 226 | } 227 | 228 | private class GetDoubleField : TwoArgFunction() { 229 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue): LuaValue { 230 | return XposedHelpers.getDoubleField(luaObject.checkuserdata(), luaFieldName.checkjstring()).toLuaObject() 231 | } 232 | } 233 | 234 | private class GetFloatField : TwoArgFunction() { 235 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue): LuaValue { 236 | return XposedHelpers.getFloatField(luaObject.checkuserdata(), luaFieldName.checkjstring()).toLuaObject() 237 | } 238 | } 239 | 240 | private class GetIntField : TwoArgFunction() { 241 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue): LuaValue { 242 | return XposedHelpers.getIntField(luaObject.checkuserdata(), luaFieldName.checkjstring()).toLuaObject() 243 | } 244 | } 245 | 246 | private class GetLongField : TwoArgFunction() { 247 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue): LuaValue { 248 | return XposedHelpers.getLongField(luaObject.checkuserdata(), luaFieldName.checkjstring()).toLuaObject() 249 | } 250 | } 251 | 252 | private class GetShortField : TwoArgFunction() { 253 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue): LuaValue { 254 | return XposedHelpers.getShortField(luaObject.checkuserdata(), luaFieldName.checkjstring()).toLuaObject() 255 | } 256 | } 257 | 258 | private class GetStaticObjectField : ThreeArgFunction() { 259 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue): LuaValue { 260 | return XposedHelpers.getStaticObjectField(XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader), luaFieldName.checkjstring()).toLuaObject() 261 | } 262 | 263 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 264 | return XposedHelpers.getStaticObjectField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 265 | } 266 | } 267 | 268 | private class GetStaticBooleanField : VarArgFunction() { 269 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue): LuaValue { 270 | return XposedHelpers.getStaticBooleanField(XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader), luaFieldName.checkjstring()).toLuaObject() 271 | } 272 | 273 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 274 | return XposedHelpers.getStaticBooleanField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 275 | } 276 | } 277 | 278 | private class GetStaticByteField : ThreeArgFunction() { 279 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue): LuaValue { 280 | return XposedHelpers.getStaticByteField(XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader), luaFieldName.checkjstring()).toLuaObject() 281 | } 282 | 283 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 284 | return XposedHelpers.getStaticByteField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 285 | } 286 | } 287 | 288 | private class GetStaticCharField : ThreeArgFunction() { 289 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue): LuaValue { 290 | return XposedHelpers.getStaticCharField(XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader), luaFieldName.checkjstring()).toLuaObject() 291 | } 292 | 293 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 294 | return XposedHelpers.getStaticCharField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 295 | } 296 | } 297 | 298 | private class GetStaticDoubleField : ThreeArgFunction() { 299 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue): LuaValue { 300 | return XposedHelpers.getStaticDoubleField(XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader), luaFieldName.checkjstring()).toLuaObject() 301 | } 302 | 303 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 304 | return XposedHelpers.getStaticDoubleField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 305 | } 306 | } 307 | 308 | private class GetStaticFloatField : ThreeArgFunction() { 309 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue): LuaValue { 310 | return XposedHelpers.getStaticFloatField(XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader), luaFieldName.checkjstring()).toLuaObject() 311 | } 312 | 313 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 314 | return XposedHelpers.getStaticFloatField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 315 | } 316 | } 317 | 318 | private class GetStaticIntField : ThreeArgFunction() { 319 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue): LuaValue { 320 | return XposedHelpers.getStaticIntField(XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader), luaFieldName.checkjstring()).toLuaObject() 321 | } 322 | 323 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 324 | return XposedHelpers.getStaticIntField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 325 | } 326 | } 327 | 328 | private class GetStaticLongField : ThreeArgFunction() { 329 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue): LuaValue { 330 | return XposedHelpers.getStaticLongField(XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader), luaFieldName.checkjstring()).toLuaObject() 331 | } 332 | 333 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 334 | return XposedHelpers.getStaticLongField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 335 | } 336 | } 337 | 338 | private class GetStaticShortField : ThreeArgFunction() { 339 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue): LuaValue { 340 | return XposedHelpers.getStaticShortField(XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader), luaFieldName.checkjstring()).toLuaObject() 341 | } 342 | 343 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue): LuaValue { 344 | return XposedHelpers.getStaticShortField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring()).toLuaObject() 345 | } 346 | } 347 | 348 | private class SetObjectField : ThreeArgFunction() { 349 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 350 | XposedHelpers.setObjectField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checkuserdata()) 351 | return NIL 352 | } 353 | } 354 | 355 | private class SetBooleanField : ThreeArgFunction() { 356 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 357 | XposedHelpers.setBooleanField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checkboolean()) 358 | return NIL 359 | } 360 | } 361 | 362 | private class SetByteField : ThreeArgFunction() { 363 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 364 | XposedHelpers.setByteField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checknumber().tobyte()) 365 | return NIL 366 | } 367 | } 368 | 369 | private class SetCharField : ThreeArgFunction() { 370 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 371 | when { 372 | luaValue.isstring() -> XposedHelpers.setCharField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checkjstring().first()) 373 | luaValue.isnumber() -> XposedHelpers.setCharField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checknumber().tochar()) 374 | } 375 | return NIL 376 | } 377 | } 378 | 379 | private class SetDoubleField : ThreeArgFunction() { 380 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 381 | XposedHelpers.setDoubleField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checkdouble()) 382 | return NIL 383 | } 384 | } 385 | 386 | private class SetFloatField : ThreeArgFunction() { 387 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 388 | XposedHelpers.setFloatField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checkdouble().toFloat()) 389 | return NIL 390 | } 391 | } 392 | 393 | private class SetIntField : ThreeArgFunction() { 394 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 395 | XposedHelpers.setIntField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checkint()) 396 | return NIL 397 | } 398 | } 399 | 400 | private class SetLongField : ThreeArgFunction() { 401 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 402 | XposedHelpers.setLongField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checklong()) 403 | return NIL 404 | } 405 | } 406 | 407 | private class SetShortField : ThreeArgFunction() { 408 | override fun call(luaObject: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 409 | XposedHelpers.setShortField(luaObject.checkuserdata(), luaFieldName.checkjstring(), luaValue.checknumber().toshort()) 410 | return NIL 411 | } 412 | } 413 | 414 | private class SetStaticObjectField : VarArgFunction() { 415 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 416 | val clazz = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 417 | XposedHelpers.setStaticObjectField(clazz, luaFieldName.checkjstring(), luaValue.checkuserdata()) 418 | return NIL 419 | } 420 | 421 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 422 | XposedHelpers.setStaticObjectField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring(), luaValue.checkuserdata()) 423 | return NIL 424 | } 425 | } 426 | 427 | private class SetStaticBooleanField : VarArgFunction() { 428 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 429 | val clazz = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 430 | XposedHelpers.setStaticBooleanField(clazz, luaFieldName.checkjstring(), luaValue.checkboolean()) 431 | return NIL 432 | } 433 | 434 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 435 | XposedHelpers.setStaticBooleanField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring(), luaValue.checkboolean()) 436 | return NIL 437 | } 438 | } 439 | 440 | private class SetStaticByteField : VarArgFunction() { 441 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 442 | val clazz = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 443 | XposedHelpers.setStaticByteField(clazz, luaFieldName.checkjstring(), luaValue.checknumber().tobyte()) 444 | return NIL 445 | } 446 | 447 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 448 | XposedHelpers.setStaticByteField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring(), luaValue.checknumber().tobyte()) 449 | return NIL 450 | } 451 | } 452 | 453 | private class SetStaticCharField : VarArgFunction() { 454 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 455 | val clazz = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 456 | XposedHelpers.setStaticCharField(clazz, luaFieldName.checkjstring(), luaValue.checknumber().tochar()) 457 | return NIL 458 | } 459 | 460 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 461 | XposedHelpers.setStaticCharField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring(), luaValue.checknumber().tochar()) 462 | return NIL 463 | } 464 | } 465 | 466 | private class SetStaticDoubleField : VarArgFunction() { 467 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 468 | val clazz = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 469 | XposedHelpers.setStaticDoubleField(clazz, luaFieldName.checkjstring(), luaValue.checkdouble()) 470 | return NIL 471 | } 472 | 473 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 474 | XposedHelpers.setStaticDoubleField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring(), luaValue.checkdouble()) 475 | return NIL 476 | } 477 | } 478 | 479 | private class SetStaticFloatField : VarArgFunction() { 480 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 481 | val clazz = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 482 | XposedHelpers.setStaticFloatField(clazz, luaFieldName.checkjstring(), luaValue.checknumber().tofloat()) 483 | return NIL 484 | } 485 | 486 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 487 | XposedHelpers.setStaticFloatField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring(), luaValue.checknumber().tofloat()) 488 | return NIL 489 | } 490 | } 491 | 492 | private class SetStaticIntField : VarArgFunction() { 493 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 494 | val clazz = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 495 | XposedHelpers.setStaticIntField(clazz, luaFieldName.checkjstring(), luaValue.checknumber().toint()) 496 | return NIL 497 | } 498 | 499 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 500 | XposedHelpers.setStaticIntField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring(), luaValue.checknumber().toint()) 501 | return NIL 502 | } 503 | } 504 | 505 | private class SetStaticLongField : VarArgFunction() { 506 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 507 | val clazz = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 508 | XposedHelpers.setStaticLongField(clazz, luaFieldName.checkjstring(), luaValue.checknumber().tolong()) 509 | return NIL 510 | } 511 | 512 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 513 | XposedHelpers.setStaticLongField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring(), luaValue.checknumber().tolong()) 514 | return NIL 515 | } 516 | } 517 | 518 | private class SetStaticShortField : VarArgFunction() { 519 | override fun call(luaClassName: LuaValue, luaClassLoader: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 520 | val clazz = XposedHelpers.findClass(luaClassName.checkjstring(), luaClassLoader.checkuserdata() as ClassLoader) 521 | XposedHelpers.setStaticShortField(clazz, luaFieldName.checkjstring(), luaValue.checknumber().toshort()) 522 | return NIL 523 | } 524 | 525 | override fun call(luaClass: LuaValue, luaFieldName: LuaValue, luaValue: LuaValue): LuaValue { 526 | XposedHelpers.setStaticShortField(luaClass.checkuserdata() as Class<*>, luaFieldName.checkjstring(), luaValue.checknumber().toshort()) 527 | return NIL 528 | } 529 | } 530 | 531 | private class CallMethod : VarArgFunction() { 532 | override fun invoke(args: Varargs): Varargs { 533 | val patternList: ArrayList = ArrayList() 534 | for (i in 3..args.narg()) { 535 | patternList.add(CoerceLuaToJava.coerce(args.arg(i), Any::class.java)) 536 | } 537 | val patternArray: Array = patternList.toArray() 538 | return XposedHelpers.callMethod(args.checkuserdata(1), args.checkjstring(2), *patternArray).toLuaObject() 539 | } 540 | } 541 | 542 | private class CallStaticMethod : VarArgFunction() { 543 | override fun invoke(args: Varargs): Varargs { 544 | return when { 545 | args.isstring(1) -> invoke(className = args.checkjstring(1), classLoader = args.checkuserdata(2) as ClassLoader, methodName = args.checkjstring(3), args = args) 546 | args.isuserdata(1) -> invoke(className = args.checkuserdata(1) as Class<*>, methodName = args.checkjstring(2), args = args) 547 | else -> throw IllegalArgumentException() 548 | } 549 | } 550 | 551 | private fun invoke(className: String, classLoader: ClassLoader, methodName: String, args: Varargs): LuaValue { 552 | val clazz: Class<*> = XposedHelpers.findClass(className, classLoader) 553 | val patternList: ArrayList = ArrayList() 554 | for (i in 4..args.narg()) { 555 | patternList.add(CoerceLuaToJava.coerce(args.arg(i), Any::class.java)) 556 | } 557 | val patternArray: Array = patternList.toArray() 558 | return XposedHelpers.callStaticMethod(clazz, methodName, *patternArray).toLuaObject() 559 | } 560 | 561 | private fun invoke(className: Class<*>, methodName: String, args: Varargs): LuaValue { 562 | val patternList: ArrayList = ArrayList() 563 | for (i in 3..args.narg()) { 564 | patternList.add(CoerceLuaToJava.coerce(args.arg(i), Any::class.java)) 565 | } 566 | val patternArray: Array = patternList.toArray() 567 | return XposedHelpers.callMethod(className, methodName, *patternArray).toLuaObject() 568 | } 569 | } 570 | 571 | private class NewInstance : VarArgFunction() { 572 | override fun invoke(args: Varargs): Varargs { 573 | return when { 574 | args.isstring(1) -> invoke(className = args.checkjstring(1), classLoader = args.checkuserdata(2) as ClassLoader, methodName = args.checkjstring(3), args = args) 575 | args.isuserdata(1) -> invoke(className = args.checkuserdata(1) as Class<*>, methodName = args.checkjstring(2), args = args) 576 | else -> throw IllegalArgumentException() 577 | } 578 | } 579 | 580 | private fun invoke(className: String, classLoader: ClassLoader, methodName: String, args: Varargs): LuaValue { 581 | val clazz: Class<*> = XposedHelpers.findClass(className, classLoader) 582 | val patternList: ArrayList = ArrayList() 583 | for (i in 4..args.narg()) { 584 | patternList.add(CoerceLuaToJava.coerce(args.arg(i), Any::class.java)) 585 | } 586 | val patternArray: Array = patternList.toArray() 587 | return XposedHelpers.newInstance(clazz, methodName, *patternArray).toLuaObject() 588 | } 589 | 590 | private fun invoke(className: Class<*>, methodName: String, args: Varargs): LuaValue { 591 | val patternList: ArrayList = ArrayList() 592 | for (i in 3..args.narg()) { 593 | patternList.add(CoerceLuaToJava.coerce(args.arg(i), Any::class.java)) 594 | } 595 | val patternArray: Array = patternList.toArray() 596 | return XposedHelpers.newInstance(className, methodName, *patternArray).toLuaObject() 597 | } 598 | 599 | } 600 | 601 | 602 | } 603 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/uhsk/lua/utils/UtilLuaValue.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022. sollyu 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * 17 | */ 18 | 19 | package io.github.uhsk.lua.utils 20 | 21 | import de.robv.android.xposed.XC_MethodHook 22 | import de.robv.android.xposed.XC_MethodReplacement 23 | import io.github.uhsk.lua.extensions.toJavaObject 24 | import io.github.uhsk.lua.extensions.toLuaObject 25 | import org.luaj.vm2.LuaTable 26 | 27 | /** 28 | * Lua工具类 29 | * 30 | * @since 1.0.0 31 | * @author sollyu 32 | * @date 2022-09-13 33 | */ 34 | object UtilLuaValue { 35 | 36 | /** 37 | * 将LuaTable转换成XC_Method 38 | * 39 | * ```lua 40 | * xposed.findAndHook('test', 'test', { 41 | * // 此处为LuaTable 42 | * }) 43 | * ``` 44 | * 45 | * @since 1.0.0 46 | */ 47 | fun luaTableToXcMethod(table: LuaTable): XC_MethodHook { 48 | 49 | // 50 | // 如果包含 replaceHookedMethod 就返回 51 | // 52 | if (table.get("replaceHookedMethod").isfunction()) { 53 | return object : XC_MethodReplacement() { 54 | override fun replaceHookedMethod(param: MethodHookParam): Any { 55 | return table.get("replaceHookedMethod").call(param.toLuaObject()).toJavaObject() 56 | } 57 | } 58 | } 59 | 60 | if (table.get("beforeHookedMethod").isfunction() || table.get("afterHookedMethod").isfunction()) { 61 | return object : XC_MethodHook() { 62 | override fun beforeHookedMethod(methodHookParam: MethodHookParam) { 63 | super.beforeHookedMethod(methodHookParam) 64 | methodHookParam.thisObject 65 | if (table.get("beforeHookedMethod").isfunction()) { 66 | table.get("beforeHookedMethod").call(methodHookParam.toLuaObject()) 67 | } 68 | } 69 | 70 | override fun afterHookedMethod(methodHookParam: MethodHookParam) { 71 | super.afterHookedMethod(methodHookParam) 72 | if (table.get("afterHookedMethod").isfunction()) { 73 | table.get("afterHookedMethod").call(methodHookParam.toLuaObject()) 74 | } 75 | } 76 | } 77 | } 78 | 79 | throw IllegalArgumentException() 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 28 | 31 | 34 | 37 | 40 | 43 | 46 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | #FFBB86FC 22 | #FF6200EE 23 | #FF3700B3 24 | #FF03DAC5 25 | #FF018786 26 | #FF000000 27 | #FFFFFFFF 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | #FFFFFF 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | XposedLua 21 | 使用Lua写Xposed脚本 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 22 | 23 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022. sollyu 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * 17 | */ 18 | 19 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 20 | plugins { 21 | id 'com.android.application' version '7.2.2' apply false 22 | id 'com.android.library' version '7.2.2' apply false 23 | id 'org.jetbrains.kotlin.android' version '1.7.10' apply false 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2022. sollyu 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # 17 | # 18 | 19 | # Project-wide Gradle settings. 20 | # IDE (e.g. Android Studio) users: 21 | # Gradle settings configured through the IDE *will override* 22 | # any settings specified in this file. 23 | # For more details on how to configure your build environment visit 24 | # http://www.gradle.org/docs/current/userguide/build_environment.html 25 | # Specifies the JVM arguments used for the daemon process. 26 | # The setting is particularly useful for tweaking memory settings. 27 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 28 | # When configured, Gradle will run in incubating parallel mode. 29 | # This option should only be used with decoupled projects. More details, visit 30 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 31 | # org.gradle.parallel=true 32 | # AndroidX package structure to make it clearer which packages are bundled with the 33 | # Android operating system, and which are packaged with your app"s APK 34 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 35 | android.useAndroidX=true 36 | # Kotlin code style for this project: "official" or "obsolete": 37 | kotlin.code.style=official 38 | # Enables namespacing of each library's R class so that its R class includes only the 39 | # resources declared in the library itself and none from the library's dependencies, 40 | # thereby reducing the size of the R class for that library 41 | android.nonTransitiveRClass=true 42 | android.injected.testOnly=false 43 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | compileSdk = '31' 3 | minSdk = '21' 4 | 5 | [libraries] 6 | # 7 | # androidx & kotlin 8 | # 9 | androidx-core = 'androidx.core:core-ktx:1.7.0' 10 | androidx-appcompat = 'androidx.appcompat:appcompat:1.4.1' 11 | kotlin-coroutines = 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0' 12 | kotlin-extension = 'com.github.uhsk:kotlin-android-extension:develop-SNAPSHOT' 13 | 14 | # 15 | # slf4j 16 | # 17 | slf4j-api = 'org.slf4j:slf4j-api:1.7.32' 18 | slf4j-logback = 'com.github.tony19:logback-android:2.0.0' 19 | 20 | # 21 | # koin 22 | # 23 | koin-android = 'io.insert-koin:koin-android:3.2.0' 24 | koin-compat = 'io.insert-koin:koin-android-compat:3.2.0' 25 | 26 | # 27 | # commons 28 | # 29 | common-lua = 'com.wind.xposed:xposed-api-lib:0.1.3' 30 | common-gson = 'com.google.code.gson:gson:2.8.6' 31 | common-guava = 'com.google.guava:guava:30.1.1-android' 32 | common-joor = 'org.jooq:joor-java-8:0.9.13' # https://github.com/jOOQ/jOOR 33 | common-xposed = 'com.wind.xposed:xposed-api-lib:0.1.3' 34 | 35 | 36 | 37 | [bundles] 38 | slf4j = ['slf4j-api', 'slf4j-logback'] 39 | koin = ['koin-android', 'koin-compat'] 40 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2022. sollyu 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # 17 | # 18 | 19 | #Wed Sep 07 09:27:32 CST 2022 20 | distributionBase=GRADLE_USER_HOME 21 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip 22 | distributionPath=wrapper/dists 23 | zipStorePath=wrapper/dists 24 | zipStoreBase=GRADLE_USER_HOME 25 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /key.store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uhsk/XposedLua/31f0a098fe5b729cfff146a13a49d7f1ab544e76/key.store -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # XposedLua 2 | 3 | ## 说明 4 | 5 | 使用Lua代码来编写Xposed的模块。可以让Xposed模块开发者快速测试hook功能,拥有免重启特性。 6 | 7 | ## 示例 8 | 9 | ```lua 10 | function handleLoadPackage(loadPackageParam) 11 | XposedHelpers.findAndHookMethod('android.app.Application', loadPackageParam.classLoader, 'onCreate', { 12 | beforeHookedMethod = function(methodHookParam) 13 | XposedBridge.log('xposed lua hook beforeHookedMethod: ' .. methodHookParam.thisObject) 14 | end, 15 | afterHookedMethod = function(methodHookParam) 16 | XposedBridge.log('xposed lua hook afterHookedMethod: ' .. methodHookParam.thisObject) 17 | end 18 | }) 19 | end 20 | ``` 21 | 22 | ## 文档 23 | 24 | 更为详细内容请参阅:[WIKI](https://github.com/uhsk/XposedLua/wiki) 25 | 26 | ## 下载 27 | 28 | 前往[Release](https://github.com/uhsk/XposedLua/releases)页面下载APK安装并激活. 29 | 30 | > #### 备注 31 | > - 正常此项目不出现兼容性或bug,不会更新。 32 | > - 如果使用中有任何问题,欢迎提交issue。 33 | 34 | ## LICENSE 35 | 36 | ```c++ 37 | /* 38 | * Copyright (C) 2022. sollyu 39 | * 40 | * Licensed under the Apache License, Version 2.0 (the "License"); 41 | * you may not use this file except in compliance with the License. 42 | * You may obtain a copy of the License at 43 | * 44 | * http://www.apache.org/licenses/LICENSE-2.0 45 | * 46 | * Unless required by applicable law or agreed to in writing, software 47 | * distributed under the License is distributed on an "AS IS" BASIS, 48 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 49 | * See the License for the specific language governing permissions and 50 | * limitations under the License. 51 | */ 52 | ``` 53 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022. sollyu 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * 17 | */ 18 | 19 | pluginManagement { 20 | repositories { 21 | gradlePluginPortal() 22 | google() 23 | mavenCentral() 24 | } 25 | } 26 | enableFeaturePreview('VERSION_CATALOGS') 27 | dependencyResolutionManagement { 28 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 29 | repositories { 30 | google() 31 | mavenCentral() 32 | maven { url 'https://jitpack.io' } 33 | jcenter() 34 | } 35 | } 36 | rootProject.name = "XposedLua" 37 | include ':app' 38 | --------------------------------------------------------------------------------