From 8a655ca0a547c1f6bc6934c95be6ef24cb395bb1 Mon Sep 17 00:00:00 2001 From: littleWhiteDuck <965265562@qq.com> Date: Sun, 29 Jan 2023 18:56:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=EF=BC=9A=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=B3=BB=E7=BB=9Fapi=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E7=AD=BE=E5=90=8D=E7=9A=84=E8=B0=83=E7=94=A8=E5=A0=86=E6=A0=88?= =?UTF-8?q?=EF=BC=9B=E5=A2=9E=E5=8A=A0=EF=BC=9A=E9=98=BB=E6=AD=A2=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E8=81=94=E7=B3=BB=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hook/FieldHook.kt | 66 ++++----- hook/HookInit.kt | 12 +- hook/MainHook.kt | 205 ++++++++++++++++---------- hook/extension/AESHook.kt | 11 +- hook/extension/ApplicationHook.kt | 14 +- hook/extension/Base64Hook.kt | 32 ++-- hook/extension/BaseHook.kt | 4 +- hook/extension/ClickEventHook.kt | 9 +- hook/extension/ClipboardFilterHook.kt | 10 +- hook/extension/ContactHook.kt | 23 +++ hook/extension/DialogHook.kt | 23 ++- hook/extension/HMACHook.kt | 9 +- hook/extension/HotFixHook.kt | 17 ++- hook/extension/IntentHook.kt | 29 ++-- hook/extension/JSONHook.kt | 27 ++-- hook/extension/PopupWindowHook.kt | 27 ++-- hook/extension/SHAHook.kt | 7 +- hook/extension/SignatureHook.kt | 48 ++++++ hook/extension/ToastHook.kt | 11 +- hook/extension/VpnCheckHook.kt | 6 +- hook/extension/WebHook.kt | 18 +-- hook/utils/ConfigUtil.kt | 64 +++++++- hook/utils/HookHelper.kt | 34 +++++ hook/utils/HookUtils.kt | 13 +- hook/utils/LogUtil.kt | 66 ++++----- 25 files changed, 510 insertions(+), 275 deletions(-) create mode 100644 hook/extension/ContactHook.kt create mode 100644 hook/extension/SignatureHook.kt create mode 100644 hook/utils/HookHelper.kt diff --git a/hook/FieldHook.kt b/hook/FieldHook.kt index 5ec29d8..4ca4fa1 100644 --- a/hook/FieldHook.kt +++ b/hook/FieldHook.kt @@ -1,8 +1,5 @@ package me.simpleHook.hook -import android.content.Context -import com.github.kyuubiran.ezxhelper.init.InitFields.appContext -import com.github.kyuubiran.ezxhelper.init.InitFields.ezXClassLoader import com.github.kyuubiran.ezxhelper.utils.* import com.google.gson.Gson import de.robv.android.xposed.XC_MethodHook @@ -13,6 +10,8 @@ import me.simpleHook.bean.LogBean import me.simpleHook.constant.Constant import me.simpleHook.hook.Tip.getTip import me.simpleHook.hook.utils.* +import me.simpleHook.hook.utils.HookHelper.appClassLoader +import me.simpleHook.hook.utils.HookHelper.hostPackageName import me.simpleHook.util.LanguageUtils import me.simpleHook.util.log @@ -20,74 +19,76 @@ object FieldHook { /** * @author littleWhiteDuck * @param configBean 配置类 - * @param packageName 目标应用包名 */ @JvmStatic - fun hookStaticField(configBean: ConfigBean, packageName: String) { + fun hookStaticField(configBean: ConfigBean) { configBean.apply { if (className.isEmpty() && methodName.isEmpty() && params.isEmpty()) { // 直接hook - hookStaticField(fieldClassName, ezXClassLoader, resultValues, fieldName) + hookStaticField(fieldClassName, resultValues, fieldName) return } val hooker: Hooker = if (mode == Constant.HOOK_RECORD_STATIC_FIELD) { - { recordStaticField(appContext, fieldClassName, packageName, fieldName) } + { recordStaticField(fieldClassName, fieldName) } } else { - { hookStaticField(fieldClassName, ezXClassLoader, resultValues, fieldName) } + { hookStaticField(fieldClassName, resultValues, fieldName) } } - hookField(hooker, packageName) + hookField(hooker, hostPackageName) } } private fun ConfigBean.hookField( hooker: Hooker, packageName: String ) { + val isBeforeHook = hookPoint == "before" try { if (methodName == "*") { findAllMethods(className) { true - }.hook(hookPoint == "before", hooker) + }.hook(isBeforeHook, hooker) } else if (params == "*") { if (methodName == "") { - hookAllConstructorAfter(className, hooker = hooker) + findAllConstructors(className) { + true + }.hook(isBeforeHook, hooker) } else { findAllMethods(className) { name == methodName - }.hook(hookPoint == "before", hooker) + }.hook(isBeforeHook, hooker) } } else { if (methodName == "") { findConstructor(className) { isSearchConstructor(params) - }.hookAfter(hooker) + }.hook(isBeforeHook, hooker) } else { findMethod(className) { name == methodName && isSearchMethod(params) - }.hook(hookPoint == "before", hooker) + }.hook(isBeforeHook, hooker) } } } catch (e: NoSuchMethodError) { LogUtil.noSuchMethod( - packageName, className, "$methodName($params)", e.stackTraceToString() + className, "$methodName($params)", e.stackTraceToString() ) getTip("noSuchMethod").log(packageName) XposedBridge.log(e.stackTraceToString()) } catch (e: NoSuchMethodException) { LogUtil.noSuchMethod( - packageName, className, "$methodName($params)", e.stackTraceToString() + className, "$methodName($params)", e.stackTraceToString() ) getTip("noSuchMethod").log(packageName) XposedBridge.log(e.stackTraceToString()) } catch (e: XposedHelpers.ClassNotFoundError) { LogUtil.notFoundClass( - packageName, className, "$methodName($params)", e.stackTraceToString() + className, "$methodName($params)", e.stackTraceToString() ) getTip("notFoundClass").log(packageName) XposedBridge.log(e.stackTraceToString()) } catch (e: ClassNotFoundException) { LogUtil.notFoundClass( - packageName, className, "$methodName($params)", e.stackTraceToString() + className, "$methodName($params)", e.stackTraceToString() ) getTip("notFoundClass").log(packageName) XposedBridge.log(e.stackTraceToString()) @@ -95,46 +96,43 @@ object FieldHook { } private fun recordStaticField( - context: Context, fieldClassName: String, packageName: String, fieldName: String + fieldClassName: String, fieldName: String ) { val type = if (LanguageUtils.isNotChinese()) "Static field" else "静态变量" - val hookClass = XposedHelpers.findClass(fieldClassName, context.classLoader) + val hookClass = XposedHelpers.findClass(fieldClassName, appClassLoader) val result = XposedHelpers.getStaticObjectField(hookClass, fieldName) val list = listOf( getTip("className") + fieldClassName, getTip("fieldName") + fieldName, getTip("fieldValue") + result ) - val logBean = LogBean(type = type, other = list, packageName = packageName) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, type) + val logBean = LogBean(type = type, other = list, packageName = hostPackageName) + LogUtil.toLogMsg(Gson().toJson(logBean), type) } private fun hookStaticField( - fieldClassName: String, classLoader: ClassLoader, values: String, fieldName: String + fieldClassName: String, values: String, fieldName: String ) { - val clazz: Class<*> = XposedHelpers.findClass(fieldClassName, classLoader) + val clazz: Class<*> = XposedHelpers.findClass(fieldClassName, appClassLoader) XposedHelpers.setStaticObjectField(clazz, fieldName, Type.getDataTypeValue(values)) } @JvmStatic fun hookInstanceField( - configBean: ConfigBean, packageName: String + configBean: ConfigBean ) { configBean.apply { - val hooker: Hooker = if (mode == Constant.HOOK_RECORD_STATIC_FIELD) { - { recordInstanceField(className, packageName, it, fieldName) } + val hooker: Hooker = if (mode == Constant.HOOK_RECORD_INSTANCE_FIELD) { + { recordInstanceField(className, it, fieldName) } } else { { hookInstanceField(it, resultValues, fieldName) } } - hookField(hooker, packageName) + hookField(hooker, hostPackageName) } } private fun recordInstanceField( - className: String, - packageName: String, - param: XC_MethodHook.MethodHookParam, - fieldName: String + className: String, param: XC_MethodHook.MethodHookParam, fieldName: String ) { val type = if (LanguageUtils.isNotChinese()) "Instance field" else "实例变量" val thisObj = param.thisObject @@ -144,8 +142,8 @@ object FieldHook { getTip("fieldName") + fieldName, getTip("fieldValue") + result ) - val logBean = LogBean(type = type, other = list, packageName = packageName) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, type) + val logBean = LogBean(type = type, other = list, packageName = hostPackageName) + LogUtil.toLogMsg(Gson().toJson(logBean), type) } private fun hookInstanceField( diff --git a/hook/HookInit.kt b/hook/HookInit.kt index 9adc934..a43ad3a 100644 --- a/hook/HookInit.kt +++ b/hook/HookInit.kt @@ -7,10 +7,12 @@ import com.github.kyuubiran.ezxhelper.utils.findMethod import com.github.kyuubiran.ezxhelper.utils.hookAfter import com.github.kyuubiran.ezxhelper.utils.hookReturnConstant import de.robv.android.xposed.IXposedHookLoadPackage +import de.robv.android.xposed.IXposedHookZygoteInit import de.robv.android.xposed.callbacks.XC_LoadPackage import me.simpleHook.BuildConfig +import me.simpleHook.hook.utils.HookHelper -class HookInit : IXposedHookLoadPackage { +class HookInit : IXposedHookLoadPackage, IXposedHookZygoteInit { override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { EzXHelperInit.initHandleLoadPackage(lpparam) @@ -20,12 +22,18 @@ class HookInit : IXposedHookLoadPackage { }.hookReturnConstant(true) } else { + if (HookHelper.isAppContextInitialized) return findMethod(Application::class.java) { name == "attach" }.hookAfter { - EzXHelperInit.initAppContext(context = it.args[0] as Context) + HookHelper.initFields(context = it.args[0] as Context, lpparam) MainHook.startHook(lpparam.packageName) } } } + + override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { + EzXHelperInit.initZygote(startupParam) + } + } \ No newline at end of file diff --git a/hook/MainHook.kt b/hook/MainHook.kt index c7b7f07..6c16104 100644 --- a/hook/MainHook.kt +++ b/hook/MainHook.kt @@ -3,82 +3,124 @@ package me.simpleHook.hook import android.annotation.SuppressLint import android.app.AndroidAppHelper import android.content.Context -import com.github.kyuubiran.ezxhelper.init.InitFields.ezXClassLoader +import com.github.kyuubiran.ezxhelper.init.InitFields import com.github.kyuubiran.ezxhelper.utils.* import com.google.gson.Gson import com.google.gson.reflect.TypeToken import de.robv.android.xposed.XC_MethodHook +import de.robv.android.xposed.XSharedPreferences import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedHelpers +import me.simpleHook.BuildConfig import me.simpleHook.bean.ConfigBean import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean import me.simpleHook.constant.Constant import me.simpleHook.database.entity.AppConfig +import me.simpleHook.hook.Tip.getTip +import me.simpleHook.hook.extension.* +import me.simpleHook.hook.utils.* +import me.simpleHook.hook.utils.HookHelper.hostPackageName +import me.simpleHook.hook.utils.LogUtil.getStackTrace import me.simpleHook.hook.utils.LogUtil.noSuchMethod import me.simpleHook.hook.utils.LogUtil.notFoundClass -import me.simpleHook.hook.utils.LogUtil.getStackTrace import me.simpleHook.hook.utils.LogUtil.toLogMsg -import me.simpleHook.hook.Tip.getTip import me.simpleHook.hook.utils.Type.getDataTypeValue -import me.simpleHook.hook.extension.* -import me.simpleHook.hook.utils.* import me.simpleHook.util.* +import org.json.JSONArray import org.json.JSONObject object MainHook { - /* private val uri = Uri.parse("content://littleWhiteDuck/app_configs") - private val assistUri = Uri.parse("content://littleWhiteDuck/assist_configs")*/ - /* private val prefHookConfig by lazy { getHookConfigPref() } - private val prefAssistConfig by lazy { getHookConfigPref("assistConfig") }*/ + + private val prefHookConfig by lazy { getPref(Constant.CUSTOM_CONFIG_PREF) } + private val prefExHookConfig by lazy { getPref(Constant.EXTENSION_CONFIG_PREF) } fun startHook(packageName: String) { - ConfigUtil.getConfigFromFile(packageName)?.let { - "get custom config succeed".log(packageName) - readHook(it, packageName) - } ?: "get custom config failed".log(packageName) - ConfigUtil.getConfigFromFile(packageName, Constant.EXTENSION_CONFIG_NAME)?.let { - "get extension config succeed".log(packageName) - readyExtensionHook(it, packageName) - } ?: "get extension config failed".log(packageName) + if (BuildConfig.FLAVOR == "lite") { + readyXmlHook() + } else { + var internalCount = 0 + ConfigUtil.getConfigFromFile()?.let { + "get custom config succeed from file".log(packageName) + readyHook(it) + } ?: run { + "get custom config failed from file".log(packageName) + ConfigUtil.getCustomConfigFromDB()?.let { + "get custom config succeed from db".log(packageName) + readyHook(it) + } ?: run { + "get custom config failed from db".log(packageName) + internalCount++ + } + } + ConfigUtil.getConfigFromFile(Constant.EXTENSION_CONFIG_NAME)?.let { + "get extension config succeed from file".log(packageName) + readyExtensionHook(it) + } ?: run { + "get extension config failed from file".log(packageName) + ConfigUtil.getExConfigFromDB()?.let { + "get extension config succeed from db".log(packageName) + readyExtensionHook(it) + } ?: run { + "get extension config failed from db".log(packageName) + internalCount++ + } + } + // 特殊情况, 仅支持自定义hook功能 + if (internalCount == 2) readyInternalConfigHook() + } } - /* private fun xmlHook( - packageName: String - ) { - val error = "no have config or error" - prefHookConfig?.let { - val strConfig = it.getString(packageName, error) - if (strConfig == null || strConfig == error) { - error.log() - "准备使用Context获取配置".log() - contextHook(packageName) - } else { - // xml读取配置成功 - determineCan(strConfig, packageName) - } - } ?: contextHook(packageName) + private fun readyInternalConfigHook() { + try { + HookHelper.enableRecord = false + val internalConfigs = AssetsUtil.getText(InitFields.moduleRes.assets.open("configs")) + ?.replace(Regex("<---.*--->"), "")?.trim() + if (internalConfigs?.isEmpty() == true) return + val jsonArray = JSONArray(internalConfigs) + for (i in 0 until jsonArray.length()) { + val jsonObject = jsonArray.getJSONObject(i) + if (jsonObject.optString("packageName") == hostPackageName) { + readyHook(jsonObject.toString()) + } + } + } catch (e: Throwable) { + //e.stackTraceToString().log(hostPackageName) + } - }*/ + } - private fun readHook(strConfig: String, packageName: String) { + private fun readyXmlHook() { + prefHookConfig?.let { sp -> + sp.getString(hostPackageName, null)?.let { + readyHook(it) + } ?: "not have the custom config".log(hostPackageName) + } ?: "null: XSharedPreferences".log(hostPackageName) + prefExHookConfig?.let { sp -> + sp.getString(hostPackageName, null)?.let { + readyExtensionHook(it) + } ?: "not have the extension config".log(hostPackageName) + } ?: "null: XSharedPreferences".log(hostPackageName) + } + + private fun readyHook(strConfig: String) { if (strConfig.trim().isEmpty()) return try { val appConfig = Gson().fromJson(strConfig, AppConfig::class.java) if (!appConfig.enable) return val listType = object : TypeToken>() {}.type val configs = Gson().fromJson>(appConfig.configs, listType) - getTip("startCustomHook").log(packageName) + getTip("startCustomHook").log(hostPackageName) configs.forEach { if (!it.enable) return@forEach it.apply { when (it.mode) { Constant.HOOK_STATIC_FIELD, Constant.HOOK_RECORD_STATIC_FIELD -> FieldHook.hookStaticField( - configBean = it, packageName + configBean = it ) Constant.HOOK_FIELD, Constant.HOOK_RECORD_INSTANCE_FIELD -> FieldHook.hookInstanceField( - it, packageName = packageName + it ) else -> specificHook( className = className, @@ -86,7 +128,6 @@ object MainHook { values = resultValues, params = params, mode = mode, - packageName = packageName, returnClassName = returnClassName ) } @@ -104,9 +145,9 @@ object MainHook { getTip("errorType") + getTip("unknownError"), "config: $configTemp", getTip("detailReason") + e.stackTraceToString() - ), packageName, "Error Unknown Error" + ), "Error Unknown Error" ) - "config error".log(packageName) + "config error".log(hostPackageName) XposedBridge.log(e.stackTraceToString()) } } @@ -118,7 +159,6 @@ object MainHook { values: String, params: String, mode: Int, - packageName: String, returnClassName: String ) { val hooker: Hooker = when (mode) { @@ -132,16 +172,16 @@ object MainHook { {} } Constant.HOOK_PARAM -> { - { hookParamsValue(it, values, className, methodName, params, packageName) } + { hookParamsValue(it, values, className, methodName, params) } } Constant.HOOK_RECORD_PARAMS -> { - { recordParamsValue(className, it, packageName) } + { recordParamsValue(className, it) } } Constant.HOOK_RECORD_RETURN -> { - { recordReturnValue(className, it, packageName) } + { recordReturnValue(className, it) } } Constant.HOOK_RECORD_PARAMS_RETURN -> { - { recordParamsAndReturn(className, it, packageName) } + { recordParamsAndReturn(className, it) } } else -> { throw Exception("读不懂配置") @@ -154,7 +194,7 @@ object MainHook { }.hook(mode, hooker) } else if (params == "*") { if (methodName == "") { - hookAllConstructorAfter(className, hooker = hooker) + hookAllConstructorBefore(className, hooker = hooker) } else { findAllMethods(className) { name == methodName @@ -164,7 +204,7 @@ object MainHook { if (methodName == "") { findConstructor(className) { isSearchConstructor(params) - }.hookAfter(hooker) + }.hookBefore(hooker) } else { findMethod(className) { name == methodName && isSearchMethod(params) @@ -173,27 +213,27 @@ object MainHook { } } catch (e: NoSuchMethodError) { noSuchMethod( - packageName, className, "$methodName($params)", e.stackTraceToString() + className, "$methodName($params)", e.stackTraceToString() ) - getTip("noSuchMethod").log(packageName) + getTip("noSuchMethod").log(hostPackageName) XposedBridge.log(e.stackTraceToString()) } catch (e: NoSuchMethodException) { noSuchMethod( - packageName, className, "$methodName($params)", e.stackTraceToString() + className, "$methodName($params)", e.stackTraceToString() ) - getTip("noSuchMethod").log(packageName) + getTip("noSuchMethod").log(hostPackageName) XposedBridge.log(e.stackTraceToString()) } catch (e: XposedHelpers.ClassNotFoundError) { notFoundClass( - packageName, className, "$methodName($params)", e.stackTraceToString() + className, "$methodName($params)", e.stackTraceToString() ) - getTip("notFoundClass").log(packageName) + getTip("notFoundClass").log(hostPackageName) XposedBridge.log(e.stackTraceToString()) } catch (e: ClassNotFoundException) { notFoundClass( - packageName, className, "$methodName($params)", e.stackTraceToString() + className, "$methodName($params)", e.stackTraceToString() ) - getTip("notFoundClass").log(packageName) + getTip("notFoundClass").log(hostPackageName) XposedBridge.log(e.stackTraceToString()) } @@ -202,7 +242,7 @@ object MainHook { private fun hookReturnValuePro( values: String, param: XC_MethodHook.MethodHookParam, returnClassName: String ) { - val hookClass = XposedHelpers.findClass(returnClassName, ezXClassLoader) + val hookClass = XposedHelpers.findClass(returnClassName, HookHelper.appClassLoader) try { val hookObject = Gson().fromJson(values, hookClass) param.result = hookObject @@ -257,8 +297,7 @@ object MainHook { values: String, className: String, methodName: String, - params: String, - packageName: String + params: String ) { try { for (i in param.args.indices) { @@ -274,12 +313,12 @@ object MainHook { getTip("filledMethodParams") + "$methodName($params)", getTip("detailReason") + e.stackTraceToString() ) - LogUtil.toLog(list, packageName, "Error HookParamsError") + LogUtil.toLog(list, "Error HookParamsError") } } private fun recordParamsValue( - className: String, param: XC_MethodHook.MethodHookParam, packageName: String + className: String, param: XC_MethodHook.MethodHookParam ) { val type = if (LanguageUtils.isNotChinese()) "Param value" else "参数值" val list = mutableListOf() @@ -294,14 +333,12 @@ object MainHook { } } val items = getStackTrace() - val logBean = LogBean( - type, list + items, packageName - ) - toLogMsg(Gson().toJson(logBean), packageName, type) + val logBean = LogBean(type, list + items, hostPackageName) + toLogMsg(Gson().toJson(logBean), type) } private fun recordReturnValue( - className: String, param: XC_MethodHook.MethodHookParam, packageName: String + className: String, param: XC_MethodHook.MethodHookParam ) { val list = mutableListOf() val type = if (LanguageUtils.isNotChinese()) "Return value" else "返回值" @@ -310,14 +347,12 @@ object MainHook { val result = getObjectString(param.result ?: "null") list.add(getTip("returnValue") + result) val items = getStackTrace() - val logBean = LogBean( - type, list + items, packageName - ) - toLogMsg(Gson().toJson(logBean), packageName, type) + val logBean = LogBean(type, list + items, hostPackageName) + toLogMsg(Gson().toJson(logBean), type) } private fun recordParamsAndReturn( - className: String, param: XC_MethodHook.MethodHookParam, packageName: String + className: String, param: XC_MethodHook.MethodHookParam ) { val type = if (LanguageUtils.isNotChinese()) "Param&Return Value" else "参返" val list = mutableListOf() @@ -334,10 +369,8 @@ object MainHook { val result = getObjectString(param.result ?: "null") list.add(getTip("returnValue") + result) val items = getStackTrace() - val logBean = LogBean( - type, list + items, packageName - ) - toLogMsg(Gson().toJson(logBean), packageName, type) + val logBean = LogBean(type, list + items, hostPackageName) + toLogMsg(Gson().toJson(logBean), type) } private fun getObjectString(value: Any): String { @@ -349,16 +382,15 @@ object MainHook { } private fun readyExtensionHook( - strConfig: String, packageName: String + strConfig: String ) { try { if (strConfig.trim().isEmpty()) return - getTip("startExtensionHook").log(packageName) + getTip("startExtensionHook").log(hostPackageName) val configBean = Gson().fromJson(strConfig, ExtensionConfigBean::class.java) if (!configBean.all) return initExtensionHook( configBean, - packageName, DialogHook, PopupWindowHook, ToastHook, @@ -373,7 +405,9 @@ object MainHook { JSONHook, WebHook, ClipboardFilterHook, - ApplicationHook + ApplicationHook, + SignatureHook, + ContactHook ) } catch (e: java.lang.Exception) { LogUtil.toLog( @@ -381,17 +415,26 @@ object MainHook { getTip("errorType") + getTip("unknownError"), "config: ${JsonUtil.formatJson(strConfig)}", getTip("detailReason") + e.stackTraceToString() - ), packageName, "Error Unknown Error" + ), "Error Unknown Error" ) } } private fun initExtensionHook( - configBean: ExtensionConfigBean, packageName: String, vararg hooks: BaseHook + configBean: ExtensionConfigBean, vararg hooks: BaseHook ) { hooks.forEach { - it.startHook(configBean, packageName) + if (it.isInit) return@forEach + it.isInit + it.startHook(configBean) } } + + + private fun getPref(path: String): XSharedPreferences? { + val pref = XSharedPreferences(BuildConfig.APPLICATION_ID, path) + return if (pref.file.canRead()) pref else null + } + } diff --git a/hook/extension/AESHook.kt b/hook/extension/AESHook.kt index c3e4b57..4825d06 100644 --- a/hook/extension/AESHook.kt +++ b/hook/extension/AESHook.kt @@ -5,15 +5,16 @@ import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XposedBridge import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean -import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper +import me.simpleHook.hook.utils.LogUtil import java.security.spec.EncodedKeySpec import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec object AESHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.crypt) return val map: HashMap = HashMap() XposedBridge.hookAllConstructors(IvParameterSpec::class.java, object : XC_MethodHook() { @@ -107,11 +108,9 @@ object AESHook : BaseHook() { ) val items = LogUtil.getStackTrace() val logBean = LogBean( - map["algorithmType"] ?: "null", list + items, packageName - ) - LogUtil.toLogMsg( - Gson().toJson(logBean), packageName, logBean.type + map["algorithmType"] ?: "null", list + items, HookHelper.hostPackageName ) + LogUtil.toLogMsg(Gson().toJson(logBean), logBean.type) map.clear() } } diff --git a/hook/extension/ApplicationHook.kt b/hook/extension/ApplicationHook.kt index e1d03cc..36974c4 100644 --- a/hook/extension/ApplicationHook.kt +++ b/hook/extension/ApplicationHook.kt @@ -8,22 +8,26 @@ import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip.getTip +import me.simpleHook.hook.utils.HookHelper object ApplicationHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.application) return - XposedHelpers.findAndHookMethod( - Application::class.java, "onCreate", object : XC_MethodHook() { + XposedHelpers.findAndHookMethod(Application::class.java, + "onCreate", + object : XC_MethodHook() { override fun afterHookedMethod(param: MethodHookParam) { val className = param.thisObject.javaClass.name val type = "Application" val log = Gson().toJson( LogBean( - type, listOf(getTip("applicationName") + className), packageName + type, + listOf(getTip("applicationName") + className), + HookHelper.hostPackageName ) ) - LogUtil.toLogMsg(log, packageName, type) + LogUtil.toLogMsg(log, type) } }) } diff --git a/hook/extension/Base64Hook.kt b/hook/extension/Base64Hook.kt index 89c1f36..eaaeba6 100644 --- a/hook/extension/Base64Hook.kt +++ b/hook/extension/Base64Hook.kt @@ -1,23 +1,22 @@ package me.simpleHook.hook.extension import android.util.Base64 -import com.github.kyuubiran.ezxhelper.init.InitFields import com.google.gson.Gson import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XposedHelpers import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean -import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper +import me.simpleHook.hook.utils.LogUtil import java.nio.charset.Charset object Base64Hook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.base64) return - XposedHelpers.findAndHookMethod( - "java.util.Base64.Encoder", - InitFields.ezXClassLoader, + XposedHelpers.findAndHookMethod("java.util.Base64.Encoder", + HookHelper.appClassLoader, "encode", ByteArray::class.java, object : XC_MethodHook() { @@ -30,17 +29,16 @@ object Base64Hook : BaseHook() { Tip.getTip("isEncrypt"), Tip.getTip("rawData") + String(data), Tip.getTip("encryptResult") + result - ) + items, packageName + ) + items, HookHelper.hostPackageName ) LogUtil.toLogMsg( - Gson().toJson(logBean), packageName, logBean.type + Gson().toJson(logBean), logBean.type ) } }) - XposedHelpers.findAndHookMethod( - "java.util.Base64.Decoder", - InitFields.ezXClassLoader, + XposedHelpers.findAndHookMethod("java.util.Base64.Decoder", + HookHelper.appClassLoader, "decode", ByteArray::class.java, object : XC_MethodHook() { @@ -53,10 +51,10 @@ object Base64Hook : BaseHook() { Tip.getTip("isDecrypt"), Tip.getTip("rawData") + String(data), Tip.getTip("decryptResult") + result - ) + items, packageName + ) + items, HookHelper.hostPackageName ) LogUtil.toLogMsg( - Gson().toJson(logBean), packageName, logBean.type + Gson().toJson(logBean), logBean.type ) } }) @@ -85,9 +83,9 @@ object Base64Hook : BaseHook() { Tip.getTip("isEncrypt"), Tip.getTip("rawData") + String(rawData), Tip.getTip("encryptResult") + result - ) + items, packageName + ) + items, HookHelper.hostPackageName ) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, logBean.type) + LogUtil.toLogMsg(Gson().toJson(logBean), logBean.type) } }) @@ -111,9 +109,9 @@ object Base64Hook : BaseHook() { Tip.getTip("isDecrypt"), Tip.getTip("rawData") + String(rawData), Tip.getTip("decryptResult") + result - ) + items, packageName + ) + items, HookHelper.hostPackageName ) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, logBean.type) + LogUtil.toLogMsg(Gson().toJson(logBean), logBean.type) } }) } diff --git a/hook/extension/BaseHook.kt b/hook/extension/BaseHook.kt index 2b03c9f..dad43d1 100644 --- a/hook/extension/BaseHook.kt +++ b/hook/extension/BaseHook.kt @@ -7,6 +7,6 @@ import me.simpleHook.util.LanguageUtils abstract class BaseHook { protected val isShowEnglish = LanguageUtils.isNotChinese() - - abstract fun startHook(configBean: ExtensionConfigBean, packageName: String) + var isInit = false + abstract fun startHook(configBean: ExtensionConfigBean) } \ No newline at end of file diff --git a/hook/extension/ClickEventHook.kt b/hook/extension/ClickEventHook.kt index 7c4c2b1..1e6f2f9 100644 --- a/hook/extension/ClickEventHook.kt +++ b/hook/extension/ClickEventHook.kt @@ -11,11 +11,12 @@ import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper import me.simpleHook.hook.utils.getAllTextView import me.simpleHook.util.log object ClickEventHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.click) return XposedBridge.hookAllMethods(View::class.java, "performClick", object : XC_MethodHook() { override fun afterHookedMethod(param: MethodHookParam) { @@ -40,12 +41,12 @@ object ClickEventHook : BaseHook() { } val log = Gson().toJson( LogBean( - type, list + LogUtil.getStackTrace(), packageName + type, list + LogUtil.getStackTrace(), HookHelper.hostPackageName ) ) - LogUtil.toLogMsg(log, packageName, type) + LogUtil.toLogMsg(log, type) } catch (e: Exception) { - "error: click".log(packageName) + "error: click".log(HookHelper.hostPackageName) } } }) diff --git a/hook/extension/ClipboardFilterHook.kt b/hook/extension/ClipboardFilterHook.kt index 8a81ff6..218779b 100644 --- a/hook/extension/ClipboardFilterHook.kt +++ b/hook/extension/ClipboardFilterHook.kt @@ -9,12 +9,12 @@ import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper object ClipboardFilterHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.filterClipboard.enable) return - XposedHelpers.findAndHookMethod( - ClipboardManager::class.java, + XposedHelpers.findAndHookMethod(ClipboardManager::class.java, "setPrimaryClip", ClipData::class.java, object : XC_MethodHook() { @@ -30,10 +30,10 @@ object ClipboardFilterHook : BaseHook() { val logBean = LogBean( type, arrayListOf(Tip.getTip("clipboardInfo") + info) + items, - packageName + HookHelper.hostPackageName ) LogUtil.toLogMsg( - Gson().toJson(logBean), packageName, type + Gson().toJson(logBean), type ) return@forEach } diff --git a/hook/extension/ContactHook.kt b/hook/extension/ContactHook.kt new file mode 100644 index 0000000..0384577 --- /dev/null +++ b/hook/extension/ContactHook.kt @@ -0,0 +1,23 @@ +package me.simpleHook.hook.extension + +import android.content.ContentResolver +import android.net.Uri +import android.provider.ContactsContract +import com.github.kyuubiran.ezxhelper.utils.findAllMethods +import com.github.kyuubiran.ezxhelper.utils.hookBefore +import me.simpleHook.bean.ExtensionConfigBean + +object ContactHook : BaseHook() { + override fun startHook(configBean: ExtensionConfigBean) { + if (!configBean.contact) return + findAllMethods(ContentResolver::class.java) { + name == "query" + }.hookBefore { + val uri = it.args[0] as Uri + if (uri == ContactsContract.CommonDataKinds.Phone.CONTENT_URI) { + it.result = null + } + } + } + +} \ No newline at end of file diff --git a/hook/extension/DialogHook.kt b/hook/extension/DialogHook.kt index 7a60b9f..d70e208 100644 --- a/hook/extension/DialogHook.kt +++ b/hook/extension/DialogHook.kt @@ -4,18 +4,27 @@ import android.app.Dialog import android.view.View import android.view.ViewGroup import android.widget.TextView +import com.github.kyuubiran.ezxhelper.utils.findAllMethods +import com.github.kyuubiran.ezxhelper.utils.hookReturnConstant import com.google.gson.Gson import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XposedBridge import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean -import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper +import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.utils.getAllTextView object DialogHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { + + if (configBean.stopDialog.enable) { + findAllMethods(Dialog::class.java) { + name == "setOnCancelListener" || name == "setOnDismissListener" || name == "setOnShowListener" + }.hookReturnConstant(null) + } if (configBean.dialog || configBean.diaCancel || configBean.stopDialog.enable) { XposedBridge.hookAllMethods(Dialog::class.java, "show", object : XC_MethodHook() { override fun afterHookedMethod(param: MethodHookParam?) { @@ -42,10 +51,12 @@ object DialogHook : BaseHook() { if (isShowEnglish) "Dialog(blocked display)" else "弹窗(已拦截)" val log = Gson().toJson( LogBean( - type, list + LogUtil.getStackTrace(), packageName + type, + list + LogUtil.getStackTrace(), + HookHelper.hostPackageName ) ) - LogUtil.toLogMsg(log, packageName, type) + LogUtil.toLogMsg(log, type) return } } @@ -54,10 +65,10 @@ object DialogHook : BaseHook() { val type = if (isShowEnglish) "Dialog" else "弹窗" val log = Gson().toJson( LogBean( - type, list + LogUtil.getStackTrace(), packageName + type, list + LogUtil.getStackTrace(), HookHelper.hostPackageName ) ) - LogUtil.toLogMsg(log, packageName, type) + LogUtil.toLogMsg(log, type) } } }) diff --git a/hook/extension/HMACHook.kt b/hook/extension/HMACHook.kt index 75e9460..73c9bc7 100644 --- a/hook/extension/HMACHook.kt +++ b/hook/extension/HMACHook.kt @@ -5,13 +5,14 @@ import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XposedBridge import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean -import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper +import me.simpleHook.hook.utils.LogUtil import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec object HMACHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.hmac) return val hasMap = HashMap() XposedBridge.hookAllMethods(Mac::class.java, "init", object : XC_MethodHook() { @@ -78,9 +79,9 @@ object HMACHook : BaseHook() { ) val items = LogUtil.getStackTrace().toList() val logBean = LogBean( - hasMap["algorithmType"] ?: "null", list + items, packageName + hasMap["algorithmType"] ?: "null", list + items, HookHelper.hostPackageName ) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, logBean.type) + LogUtil.toLogMsg(Gson().toJson(logBean), logBean.type) hasMap.clear() } }) diff --git a/hook/extension/HotFixHook.kt b/hook/extension/HotFixHook.kt index a28f947..52f683a 100644 --- a/hook/extension/HotFixHook.kt +++ b/hook/extension/HotFixHook.kt @@ -1,10 +1,11 @@ package me.simpleHook.hook.extension -import com.github.kyuubiran.ezxhelper.init.InitFields + import dalvik.system.BaseDexClassLoader import dalvik.system.DexClassLoader import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.constant.Constant +import me.simpleHook.hook.utils.HookHelper import me.simpleHook.util.FlavorUtils import me.simpleHook.util.log import me.simpleHook.util.tip @@ -12,13 +13,13 @@ import java.io.File object HotFixHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.hotFix) return val dexFilePaths: MutableList = mutableListOf() val pathName = if (FlavorUtils.isNormal()) { - Constant.ANDROID_DATA_PATH + packageName + "/simpleHook/dex/" + Constant.ANDROID_DATA_PATH + HookHelper.hostPackageName + "/simpleHook/dex/" } else { - Constant.ROOT_CONFIG_MAIN_DIRECTORY + packageName + "/dex/" + Constant.ROOT_CONFIG_MAIN_DIRECTORY + HookHelper.hostPackageName + "/dex/" } val fileTree: FileTreeWalk = File(pathName).walk() fileTree.maxDepth(1).filter { it.isFile && it.extension == "dex" }.forEach {//循环处理符合条件的文件 @@ -26,10 +27,10 @@ object HotFixHook : BaseHook() { } try { for (index in 0 until dexFilePaths.size) { - dexFilePaths[index].log(packageName) - val originalLoader = InitFields.ezXClassLoader + dexFilePaths[index].log(HookHelper.hostPackageName) + val originalLoader = HookHelper.appClassLoader val classLoader = DexClassLoader( - dexFilePaths[index], InitFields.appContext.cacheDir.path, null, null + dexFilePaths[index], HookHelper.appContext.cacheDir.path, null, null ) val loaderClass: Class<*> = BaseDexClassLoader::class.java val pathListField = loaderClass.getDeclaredField("pathList") @@ -65,7 +66,7 @@ object HotFixHook : BaseHook() { } } catch (e: Exception) { - "hot fix error".tip(packageName) + "hot fix error".tip(HookHelper.hostPackageName) } } } \ No newline at end of file diff --git a/hook/extension/IntentHook.kt b/hook/extension/IntentHook.kt index 2425591..20998b7 100644 --- a/hook/extension/IntentHook.kt +++ b/hook/extension/IntentHook.kt @@ -2,7 +2,6 @@ package me.simpleHook.hook.extension import android.content.Intent import android.os.Bundle -import com.github.kyuubiran.ezxhelper.init.InitFields import com.google.gson.Gson import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XposedHelpers @@ -10,6 +9,7 @@ import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.ExtraBean import me.simpleHook.bean.IntentBean import me.simpleHook.bean.LogBean +import me.simpleHook.hook.utils.HookHelper import me.simpleHook.hook.utils.LogUtil private const val ACTIVITY = "android.app.Activity" @@ -18,56 +18,55 @@ private const val START_ACTIVITY = "startActivity" private const val START_ACTIVITY_FOR_RESULT = "startActivityForResult" object IntentHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.intent) return XposedHelpers.findAndHookMethod(ACTIVITY, - InitFields.ezXClassLoader, + HookHelper.appClassLoader, START_ACTIVITY, Intent::class.java, object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { val intent = param.args[0] as Intent - saveLog(intent, packageName) + saveLog(intent, HookHelper.hostPackageName) } }) XposedHelpers.findAndHookMethod(CONTEXT_WRAPPER, - InitFields.ezXClassLoader, + HookHelper.appClassLoader, START_ACTIVITY, Intent::class.java, object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { val intent = param.args[0] as Intent - saveLog(intent, packageName) + saveLog(intent, HookHelper.hostPackageName) } }) XposedHelpers.findAndHookMethod(CONTEXT_WRAPPER, - InitFields.ezXClassLoader, + HookHelper.appClassLoader, START_ACTIVITY, Intent::class.java, Bundle::class.java, object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { val intent = param.args[0] as Intent - saveLog(intent, packageName) + saveLog(intent, HookHelper.hostPackageName) } }) XposedHelpers.findAndHookMethod(ACTIVITY, - InitFields.ezXClassLoader, + HookHelper.appClassLoader, START_ACTIVITY_FOR_RESULT, Intent::class.java, Int::class.java, object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { val intent = param.args[0] as Intent - saveLog(intent, packageName) + saveLog(intent, HookHelper.hostPackageName) } }) - XposedHelpers.findAndHookMethod( - ACTIVITY, - InitFields.ezXClassLoader, + XposedHelpers.findAndHookMethod(ACTIVITY, + HookHelper.appClassLoader, START_ACTIVITY_FOR_RESULT, Intent::class.java, Int::class.java, @@ -76,7 +75,7 @@ object IntentHook : BaseHook() { override fun beforeHookedMethod(param: MethodHookParam) { val intent = param.args[0] as Intent - saveLog(intent, packageName) + saveLog(intent, HookHelper.hostPackageName) } }) } @@ -105,6 +104,6 @@ object IntentHook : BaseHook() { val logBean = LogBean( "intent", listOf(configBean), packName ) - LogUtil.toLogMsg(Gson().toJson(logBean), packName, "intent") + LogUtil.toLogMsg(Gson().toJson(logBean), "intent") } } \ No newline at end of file diff --git a/hook/extension/JSONHook.kt b/hook/extension/JSONHook.kt index 196add4..3775660 100644 --- a/hook/extension/JSONHook.kt +++ b/hook/extension/JSONHook.kt @@ -6,22 +6,23 @@ import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedHelpers import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean +import me.simpleHook.hook.utils.HookHelper import me.simpleHook.hook.utils.LogUtil import org.json.JSONArray import org.json.JSONObject object JSONHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (configBean.jsonObject) { - hookJSONObject(packageName) + hookJSONObject() } if (configBean.jsonArray) { - hookJSONArray(packageName) + hookJSONArray() } } - private fun hookJSONObject(packageName: String) { + private fun hookJSONObject() { XposedBridge.hookAllMethods(JSONObject::class.java, "put", object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { val type = if (isShowEnglish) "JSON put" else "JSON 增加" @@ -30,9 +31,9 @@ object JSONHook : BaseHook() { val list = arrayListOf("Name: $name", "Value: $value") val items = LogUtil.getStackTrace() val logBean = LogBean( - type, list + items, packageName + type, list + items, HookHelper.hostPackageName ) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, type) + LogUtil.toLogMsg(Gson().toJson(logBean), type) } }) @@ -48,14 +49,14 @@ object JSONHook : BaseHook() { val list = arrayListOf("Value: $value") val items = LogUtil.getStackTrace() val logBean = LogBean( - type, list + items, packageName + type, list + items, HookHelper.hostPackageName ) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, type) + LogUtil.toLogMsg(Gson().toJson(logBean), type) } }) } - private fun hookJSONArray(packageName: String) { + private fun hookJSONArray() { XposedBridge.hookAllMethods(JSONArray::class.java, "put", object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { @@ -65,9 +66,9 @@ object JSONHook : BaseHook() { val list = arrayListOf("Name: $name", "Value: $value") val items = LogUtil.getStackTrace() val logBean = LogBean( - type, list + items, packageName + type, list + items, HookHelper.hostPackageName ) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, type) + LogUtil.toLogMsg(Gson().toJson(logBean), type) } }) @@ -83,9 +84,9 @@ object JSONHook : BaseHook() { val list = arrayListOf("Value: $value") val items = LogUtil.getStackTrace() val logBean = LogBean( - type, list + items, packageName + type, list + items, HookHelper.hostPackageName ) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, type) + LogUtil.toLogMsg(Gson().toJson(logBean), type) } }) } diff --git a/hook/extension/PopupWindowHook.kt b/hook/extension/PopupWindowHook.kt index 784f4d7..d36ab78 100644 --- a/hook/extension/PopupWindowHook.kt +++ b/hook/extension/PopupWindowHook.kt @@ -10,28 +10,27 @@ import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper import me.simpleHook.hook.utils.getAllTextView object PopupWindowHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (configBean.popup || configBean.popCancel || configBean.stopDialog.enable) { - XposedBridge.hookAllMethods( - PopupWindow::class.java, + XposedBridge.hookAllMethods(PopupWindow::class.java, "showAtLocation", object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam?) { hookPopupWindowDetail( - param, packageName, configBean + param, configBean ) } }) - XposedBridge.hookAllMethods( - PopupWindow::class.java, + XposedBridge.hookAllMethods(PopupWindow::class.java, "showAsDropDown", object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam?) { hookPopupWindowDetail( - param, packageName, configBean + param, configBean ) } }) @@ -39,7 +38,7 @@ object PopupWindowHook : BaseHook() { } private fun hookPopupWindowDetail( - param: XC_MethodHook.MethodHookParam?, packageName: String, configBean: ExtensionConfigBean + param: XC_MethodHook.MethodHookParam?, configBean: ExtensionConfigBean ) { val popupWindow = param?.thisObject as PopupWindow if (configBean.popCancel) { @@ -62,10 +61,10 @@ object PopupWindowHook : BaseHook() { if (isShowEnglish) "PopupWindow(blocked display)" else "PopupWindow(已拦截)" val log = Gson().toJson( LogBean( - type, list + LogUtil.getStackTrace(), packageName + type, list + LogUtil.getStackTrace(), HookHelper.hostPackageName ) ) - LogUtil.toLogMsg(log, packageName, type) + LogUtil.toLogMsg(log, type) param.result = null return } @@ -73,8 +72,12 @@ object PopupWindowHook : BaseHook() { } if (configBean.popup) { val type = "PopupWindow" - val log = Gson().toJson(LogBean(type, list + LogUtil.getStackTrace(), packageName)) - LogUtil.toLogMsg(log, packageName, type) + val log = Gson().toJson( + LogBean( + type, list + LogUtil.getStackTrace(), HookHelper.hostPackageName + ) + ) + LogUtil.toLogMsg(log, type) } } diff --git a/hook/extension/SHAHook.kt b/hook/extension/SHAHook.kt index defedbc..c4f51e4 100644 --- a/hook/extension/SHAHook.kt +++ b/hook/extension/SHAHook.kt @@ -7,12 +7,13 @@ import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper import me.simpleHook.hook.utils.byte2Sting import java.security.MessageDigest object SHAHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.digest) return val hashMap = HashMap() XposedBridge.hookAllMethods(MessageDigest::class.java, "update", object : XC_MethodHook() { @@ -56,10 +57,10 @@ object SHAHook : BaseHook() { Tip.getTip("isEncrypt"), Tip.getTip("rawData") + hashMap["rawData"], Tip.getTip("encryptResult") + result - ) + items, packageName + ) + items, HookHelper.hostPackageName ) LogUtil.toLogMsg( - Gson().toJson(logBean), packageName, logBean.type + Gson().toJson(logBean), logBean.type ) } }) diff --git a/hook/extension/SignatureHook.kt b/hook/extension/SignatureHook.kt new file mode 100644 index 0000000..04146c6 --- /dev/null +++ b/hook/extension/SignatureHook.kt @@ -0,0 +1,48 @@ +package me.simpleHook.hook.extension + +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.os.Build +import com.github.kyuubiran.ezxhelper.utils.findMethod +import com.github.kyuubiran.ezxhelper.utils.hookAfter +import com.google.gson.Gson +import me.simpleHook.bean.ExtensionConfigBean +import me.simpleHook.bean.LogBean +import me.simpleHook.hook.utils.HookHelper +import me.simpleHook.hook.utils.LogUtil +import me.simpleHook.util.ToolUtils + +object SignatureHook : BaseHook() { + override fun startHook(configBean: ExtensionConfigBean) { + if (configBean.signature) { + findMethod("android.app.ApplicationPackageManager") { + name == "getPackageInfo" && parameterTypes[0] == String::class.java + }.hookAfter { + val flag = it.args[1] as Int + if (flag != PackageManager.GET_SIGNING_CERTIFICATES && flag != PackageManager.GET_SIGNATURES) return@hookAfter + val packInfo = it.result as PackageInfo + val items = LogUtil.getStackTrace() + var md5 = "" + var sha1 = "" + var sha256 = "" + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && flag == PackageManager.GET_SIGNING_CERTIFICATES) { + val byteArray = packInfo.signingInfo.apkContentsSigners[0].toByteArray() + md5 = ToolUtils.getDigest(byteArray) + sha1 = ToolUtils.getDigest(byteArray, "SHA-1") + sha256 = ToolUtils.getDigest(byteArray, "SHA-256") + } else { + val byteArray2 = packInfo.signatures[0].toByteArray() + md5 = ToolUtils.getDigest(byteArray2) + sha1 = ToolUtils.getDigest(byteArray2, "SHA-1") + sha256 = ToolUtils.getDigest(byteArray2, "SHA-256") + } + val list = listOf( + "Signature(MD5): $md5", "Signature(SHA-1): $sha1", "Signature(SHA-256): $sha256" + ) + val logBean = LogBean("Signature", list + items, HookHelper.hostPackageName) + LogUtil.toLogMsg(Gson().toJson(logBean), logBean.type) + } + } + } + +} \ No newline at end of file diff --git a/hook/extension/ToastHook.kt b/hook/extension/ToastHook.kt index 187a1b8..3ea2f8d 100644 --- a/hook/extension/ToastHook.kt +++ b/hook/extension/ToastHook.kt @@ -11,12 +11,13 @@ import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean import me.simpleHook.hook.utils.LogUtil import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper import me.simpleHook.hook.utils.getAllTextView import me.simpleHook.util.log object ToastHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.toast) return XposedHelpers.findAndHookMethod(Toast::class.java, "show", object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam?) { @@ -28,7 +29,7 @@ object ToastHook : BaseHook() { list.add(Tip.getTip("text") + it) } } catch (e: NoSuchFieldError) { - "toast error1".log(packageName) + "toast error1".log(HookHelper.hostPackageName) try { XposedHelpers.getObjectField(toast, "mNextView")?.also { val toastView = it as View @@ -39,16 +40,16 @@ object ToastHook : BaseHook() { } } } catch (e: NoSuchFieldError) { - "toast error2".log(packageName) + "toast error2".log(HookHelper.hostPackageName) } } val type = "Toast" val log = Gson().toJson( LogBean( - type, list + LogUtil.getStackTrace(), packageName + type, list + LogUtil.getStackTrace(), HookHelper.hostPackageName ) ) - LogUtil.toLogMsg(log, packageName, type) + LogUtil.toLogMsg(log, type) } }) } diff --git a/hook/extension/VpnCheckHook.kt b/hook/extension/VpnCheckHook.kt index 4146ae0..0f86ed7 100644 --- a/hook/extension/VpnCheckHook.kt +++ b/hook/extension/VpnCheckHook.kt @@ -1,16 +1,16 @@ package me.simpleHook.hook.extension -import com.github.kyuubiran.ezxhelper.init.InitFields import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XposedHelpers import me.simpleHook.bean.ExtensionConfigBean +import me.simpleHook.hook.utils.HookHelper object VpnCheckHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (!configBean.vpn) return XposedHelpers.findAndHookMethod("java.net.NetworkInterface", - InitFields.ezXClassLoader, + HookHelper.appClassLoader, "getName", object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { diff --git a/hook/extension/WebHook.kt b/hook/extension/WebHook.kt index ede7885..b526c1b 100644 --- a/hook/extension/WebHook.kt +++ b/hook/extension/WebHook.kt @@ -1,28 +1,28 @@ package me.simpleHook.hook.extension import android.webkit.WebView -import com.github.kyuubiran.ezxhelper.init.InitFields import com.google.gson.Gson import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedHelpers import me.simpleHook.bean.ExtensionConfigBean import me.simpleHook.bean.LogBean +import me.simpleHook.hook.utils.HookHelper import me.simpleHook.hook.utils.LogUtil object WebHook : BaseHook() { - override fun startHook(configBean: ExtensionConfigBean, packageName: String) { + override fun startHook(configBean: ExtensionConfigBean) { if (configBean.webLoadUrl) { - hookWebLoadUrl(packageName) + hookWebLoadUrl() } if (configBean.webDebug) { - hookWebDebug(packageName) + hookWebDebug() } } - private fun hookWebLoadUrl(packageName: String) { + private fun hookWebLoadUrl() { XposedBridge.hookAllMethods(WebView::class.java, "loadUrl", object : XC_MethodHook() { override fun afterHookedMethod(param: MethodHookParam) { val type = "WEB" @@ -33,14 +33,14 @@ object WebHook : BaseHook() { val headers = Gson().toJson(param.args[1]) list.add("Header: $headers") } - val logBean = LogBean(type, list, packageName) - LogUtil.toLogMsg(Gson().toJson(logBean), packageName, type) + val logBean = LogBean(type, list, HookHelper.hostPackageName) + LogUtil.toLogMsg(Gson().toJson(logBean), type) } }) } - private fun hookWebDebug(packageName: String) { - val webClass = XposedHelpers.findClass("android.webkit.WebView", InitFields.ezXClassLoader) + private fun hookWebDebug() { + val webClass = XposedHelpers.findClass("android.webkit.WebView", HookHelper.appClassLoader) XposedBridge.hookAllConstructors(webClass, object : XC_MethodHook() { override fun afterHookedMethod(param: MethodHookParam) { XposedHelpers.callStaticMethod(webClass, "setWebContentsDebuggingEnabled", true) diff --git a/hook/utils/ConfigUtil.kt b/hook/utils/ConfigUtil.kt index 982e681..6f29660 100644 --- a/hook/utils/ConfigUtil.kt +++ b/hook/utils/ConfigUtil.kt @@ -1,27 +1,83 @@ package me.simpleHook.hook.utils +import android.annotation.SuppressLint +import android.net.Uri +import com.google.gson.Gson import me.simpleHook.constant.Constant +import me.simpleHook.database.entity.AppConfig +import me.simpleHook.hook.utils.HookHelper.appContext +import me.simpleHook.hook.utils.HookHelper.hostPackageName import me.simpleHook.util.FlavorUtils import me.simpleHook.util.log import java.io.File import java.io.FileNotFoundException object ConfigUtil { + private val uri = Uri.parse("content://me.simplehook.provider/app_configs") + private val assistUri = Uri.parse("content://me.simplehook.provider/assist_configs") fun getConfigFromFile( - packageName: String, configName: String = Constant.APP_CONFIG_NAME ): String? { val configPath = if (FlavorUtils.isNormal()) { - Constant.ANDROID_DATA_PATH + packageName + "/simpleHook/config/" + Constant.ANDROID_DATA_PATH + hostPackageName + "/simpleHook/config/" } else { - Constant.ROOT_CONFIG_MAIN_DIRECTORY + packageName + "/config/" + Constant.ROOT_CONFIG_MAIN_DIRECTORY + hostPackageName + "/config/" } + configName return try { val strConfig = File(configPath).reader().use { it.readText() } strConfig } catch (e: FileNotFoundException) { - "failed: $configPath".log(packageName) + "failed: $configPath".log(hostPackageName) + null + } + } + + @SuppressLint("Range") + fun getCustomConfigFromDB(): String? { + return try { + var config: String? = null + appContext.contentResolver?.query( + uri, null, "packageName = ?", arrayOf(hostPackageName), null + )?.apply { + while (moveToNext()) { + if (getInt(getColumnIndex("enable")) == 1) { + val configString = getString(getColumnIndex("config")) + val appConfig = AppConfig( + configs = configString, + packageName = hostPackageName, + appName = "", + versionName = "", + description = "" + ) + config = Gson().toJson(appConfig) + break + } + } + close() + } + config + } catch (e: Throwable) { + null + } + } + + @SuppressLint("Range") + fun getExConfigFromDB(): String? { + return try { + var config: String? = null + appContext.contentResolver?.query( + assistUri, null, "packageName = ?", arrayOf(hostPackageName), null + )?.apply { + while (moveToNext()) { + if (getInt(getColumnIndex("allSwitch")) == 1) { + config = getString(getColumnIndex("config")) + } + } + close() + } + config + } catch (e: Throwable) { null } } diff --git a/hook/utils/HookHelper.kt b/hook/utils/HookHelper.kt new file mode 100644 index 0000000..4786701 --- /dev/null +++ b/hook/utils/HookHelper.kt @@ -0,0 +1,34 @@ +package me.simpleHook.hook.utils + +import android.content.Context +import android.content.pm.ApplicationInfo +import de.robv.android.xposed.callbacks.XC_LoadPackage + +object HookHelper { + + fun initFields(context: Context, lpparam: XC_LoadPackage.LoadPackageParam) { + appContext = context + appClassLoader = context.classLoader + hostPackageName = lpparam.packageName + appInfo = lpparam.appInfo + } + + lateinit var appContext: Context + private set + + val isAppContextInitialized: Boolean + get() = this::appContext.isInitialized + + lateinit var appClassLoader: ClassLoader + private set + + + lateinit var hostPackageName: String + private set + + lateinit var appInfo: ApplicationInfo + + var enableRecord: Boolean = true + + +} \ No newline at end of file diff --git a/hook/utils/HookUtils.kt b/hook/utils/HookUtils.kt index 6699a4d..9fef948 100644 --- a/hook/utils/HookUtils.kt +++ b/hook/utils/HookUtils.kt @@ -1,5 +1,6 @@ package me.simpleHook.hook.utils +import android.util.Log import android.view.ViewGroup import android.widget.Button import android.widget.TextView @@ -54,7 +55,16 @@ fun Method.hook(hookMode: Int, hooker: Hooker) { } fun Method.hook(hookBefore: Boolean, hooker: Hooker) { - if (hookBefore) this.hookBefore(hooker) else hookAfter(hooker) + if (hookBefore) hookBefore(hooker) else hookAfter(hooker) +} + +fun Constructor<*>.hook(hookBefore: Boolean, hooker: Hooker) { + if (hookBefore) hookBefore(hooker) else hookAfter(hooker) +} + +@JvmName("hookConstructor") +fun List>.hook(hookBefore: Boolean, hooker: Hooker) { + if (hookBefore) hookBefore(hooker) else hookAfter(hooker) } fun List.hook(hookMode: Int, hooker: Hooker) { @@ -67,6 +77,7 @@ fun List.hook(hookMode: Int, hooker: Hooker) { } } +@JvmName("hookMethod") fun List.hook(hookBefore: Boolean, hooker: Hooker) { if (hookBefore) hookBefore(hooker) else hookAfter(hooker) } diff --git a/hook/utils/LogUtil.kt b/hook/utils/LogUtil.kt index 6547569..aa11976 100644 --- a/hook/utils/LogUtil.kt +++ b/hook/utils/LogUtil.kt @@ -3,50 +3,51 @@ package me.simpleHook.hook.utils import android.net.Uri import android.os.Build.VERSION_CODES import androidx.core.content.contentValuesOf -import com.github.kyuubiran.ezxhelper.init.InitFields import com.google.gson.Gson import me.simpleHook.bean.LogBean import me.simpleHook.constant.Constant import me.simpleHook.database.entity.PrintLog import me.simpleHook.hook.Tip +import me.simpleHook.hook.utils.HookHelper.hostPackageName import me.simpleHook.util.* object LogUtil { - private val PRINT_URI = Uri.parse("content://littleWhiteDuck/print_logs") - fun toLogMsg(log: String, packageName: String, type: String) { - if (type == "null") return - InitFields.appContext.getExternalFilesDirs("") + private const val filterClass = + """(?i)EdHooker|LspHooker|littleWhiteDuck|me.simpleHook|me.weishu|de.robv.android.xposed""" + private val PRINT_URI = Uri.parse("content://me.simplehook.provider/print_logs") + fun toLogMsg(log: String, type: String) { + if (type == "null" || !HookHelper.enableRecord) return + HookHelper.appContext.getExternalFilesDirs("") val time = TimeUtil.getDateTime(System.currentTimeMillis(), "yy-MM-dd HH:mm:ss") - val tempPackageName = if (type.startsWith("Error")) "error.hook.tip" else packageName - val targetSdkVersion = AppUtils.getTargetSdkVer(InitFields.appContext, packageName) - targetSdkVersion?.let { - if (it > VERSION_CODES.Q) { - outLogFile(log, packageName, tempPackageName, type, time) - } else { - outLogDB(log, packageName, tempPackageName, type, time) - } - } ?: outLogFile(log, packageName, tempPackageName, type, time) + val tempPackageName = if (type.startsWith("Error")) "error.hook.tip" else hostPackageName + if (FlavorUtils.isLiteVersion) { + log.log(hostPackageName) + } else if (HookHelper.appInfo.targetSdkVersion > VERSION_CODES.Q) { + outLogDB(log, tempPackageName, type, time) + } else { + outLogFile(log, tempPackageName, type, time) + } } private fun outLogFile( - log: String, packageName: String, tempPackageName: String, type: String, time: String + log: String, tempPackageName: String, type: String, time: String ) { try { val printLog = PrintLog(log = log, packageName = tempPackageName, type = type, time = time) val printLogStr = Gson().toJson(printLog) val filePath = - Constant.ANDROID_DATA_PATH + packageName + "/simpleHook/" + Constant.RECORD_TEMP_DIRECTORY + Constant.ANDROID_DATA_PATH + hostPackageName + "/simpleHook/" + Constant.RECORD_TEMP_DIRECTORY FileUtils.writeLogToFile(content = printLogStr, filePath = filePath) } catch (e: Exception) { - "error occurred while saving log to the file, 此次log打印在下方".tip(packageName) - log.log(packageName) + "error occurred while saving log to the file, 此次log打印在下方".tip(hostPackageName) + log.log(hostPackageName) } } private fun outLogDB( - log: String, packageName: String, tempPackageName: String, type: String, time: String + log: String, tempPackageName: String, type: String, time: String ) { try { val contentValues = contentValuesOf( @@ -57,10 +58,10 @@ object LogUtil { "time" to time, "isMark" to 0 ) - InitFields.appContext.contentResolver?.insert(PRINT_URI, contentValues) + HookHelper.appContext.contentResolver?.insert(PRINT_URI, contentValues) } catch (e: Exception) { - "error occurred while saving log to the database".tip(packageName) - outLogFile(log, packageName, tempPackageName, type, time) + "error occurred while saving log to the database".tip(hostPackageName) + outLogFile(log, tempPackageName, type, time) } } @@ -71,14 +72,7 @@ object LogUtil { var notBug = 0 for (element in stackTrace) { val className = element.className - if (className.startsWith("me.simpleHook") || className.startsWith("littleWhiteDuck") || className.startsWith( - "de.robv.android.xposed" - ) || className.contains( - "LspHooker", true - ) || className.contains("EdHooker") || className.startsWith( - "me.weishu" - ) - ) continue + if (className.contains(Regex(filterClass))) continue if (notBug == 0) { items.add(if (isNotChinese) "Call stack: " else "调用堆栈:") } @@ -90,14 +84,14 @@ object LogUtil { fun toLog( - list: List, packageName: String, type: String + list: List, type: String ) { val logBean = LogBean(type = type, other = list, "error.hook.tip") - toLogMsg(Gson().toJson(logBean), packageName, type) + toLogMsg(Gson().toJson(logBean), type) } fun notFoundClass( - packageName: String, className: String, methodName: String, error: String + className: String, methodName: String, error: String ) { val list = listOf( Tip.getTip("errorType") + "ClassNotFoundError", @@ -106,11 +100,11 @@ object LogUtil { Tip.getTip("filledMethodOrField") + methodName, Tip.getTip("detailReason") + error ) - toLog(list, packageName, "Error ClassNotFoundError") + toLog(list, "Error ClassNotFoundError") } fun noSuchMethod( - packageName: String, className: String, methodName: String, error: String + className: String, methodName: String, error: String ) { val list = listOf( Tip.getTip("errorType") + "NoSuchMethodError", @@ -119,6 +113,6 @@ object LogUtil { Tip.getTip("filledMethodParams") + methodName, Tip.getTip("detailReason") + error ) - toLog(list, packageName, "Error NoSuchMethodError") + toLog(list, "Error NoSuchMethodError") } } \ No newline at end of file