Skip to content

Commit

Permalink
Merge pull request WankkoRee#33 from srdr0p/master
Browse files Browse the repository at this point in the history
feat: Add support for packed app
  • Loading branch information
WankkoRee committed May 7, 2023
2 parents e044166 + 8b65c92 commit 1756b1d
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 77 deletions.
4 changes: 4 additions & 0 deletions app/src/main/java/cn/wankkoree/xp/webviewpp/activity/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ class App : AppCompatActivity() {
menuInflater.inflate(R.menu.app_toolbar_menu, menu)
with(modulePrefs("apps_$pkg")) {
menu.findItem(R.id.app_toolbar_menu_debug_mode).isChecked = get(AppSP.debug_mode)
menu.findItem(R.id.app_toolbar_menu_byass_packer).isChecked = get(AppSP.bypass_packer)
}
setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
Expand All @@ -300,6 +301,9 @@ class App : AppCompatActivity() {
}.show()
}
}
R.id.app_toolbar_menu_byass_packer -> {
modulePrefs("apps_$pkg").put(AppSP.bypass_packer, !menuItem.isChecked)
}
R.id.app_toolbar_menu_configure_in_other_apps -> {
startActivity(Intent.createChooser(
Intent(Intent.ACTION_SHOW_APP_INFO).putExtra(Intent.EXTRA_PACKAGE_NAME, pkg),
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/cn/wankkoree/xp/webviewpp/data/AppSP.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
object AppSP {
val is_enabled = PrefsData("is_enabled", false)
val debug_mode = PrefsData("debug_mode", false)
val bypass_packer = PrefsData("bypass_packer", false)
/**
* 哈希去重的 Hook 规则名称集合,以|分隔,并且有多个对应的"hook_entry_$name"子变量
*/
Expand Down
186 changes: 109 additions & 77 deletions app/src/main/java/cn/wankkoree/xp/webviewpp/hook/Main.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cn.wankkoree.xp.webviewpp.hook

import android.content.Context
import cn.wankkoree.xp.webviewpp.BuildConfig
import cn.wankkoree.xp.webviewpp.data.AppSP
import cn.wankkoree.xp.webviewpp.data.getSet
Expand All @@ -9,8 +10,10 @@ import cn.wankkoree.xp.webviewpp.http.bean.HookRules
import com.google.gson.Gson
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
import com.highcapable.yukihookapi.hook.log.*
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit

@InjectYukiHookWithXposed(entryClassName = "Entry", isUsingResourcesHook = false)
class Main : IYukiHookXposedInit {
Expand Down Expand Up @@ -64,91 +67,120 @@ class Main : IYukiHookXposedInit {

loggerI(msg = "hook $mProcessName which run in $processName")

val cpuArch = with(appInfo.nativeLibraryDir) {
when {
endsWith("arm64") -> "arm64-v8a"
endsWith("arm") -> "armeabi-v7a"
else -> {
loggerE(msg = "the cpuArch(${toString()}) is not supported")
null
val mAppClassname = this.appInfo.className
if (pref.get(AppSP.bypass_packer) && mAppClassname != null && mAppClassname != "android.app.Application") {
loggerI(msg = "Try to get packer's classloader")
mAppClassname.hook {
injectMember {
method {
name = "attachBaseContext"
param("android.content.Context")
}
afterHook {
val context = args(0).any()
if (context != null) {
appClassLoader = (context as Context).classLoader
loggerI(msg = "Get packer's classloader success")
} else {
loggerI(msg = "Get packer's classloader failed! Will use default classloader")
}
doHook(pref)
}
}
}
} else {
doHook(pref)
}
}
}

loggerI(msg = "loading rules")
}

if (pref.get(AppSP.debug_mode)) {
findWebViewMethods()
private fun PackageParam.doHook(pref: YukiHookModulePrefs) {

val cpuArch = with(appInfo.nativeLibraryDir) {
when {
endsWith("arm64") -> "arm64-v8a"
endsWith("arm") -> "armeabi-v7a"
else -> {
loggerE(msg = "the cpuArch(${toString()}) is not supported")
null
}
}
}

pref.getSet(AppSP.hooks).forEach { name ->
val hookJson = pref.getString("hook_entry_$name", "{}")
try {
when(val hookMethod = Gson().fromJson(hookJson, HookRules.HookRule::class.java).name) {
// TODO: 添加更多 hook 方法
"hookWebView" -> {
val hookEntry = Gson().fromJson(hookJson, HookRules.HookRuleWebView::class.java)
hookWebView(
Class_WebView = hookEntry.Class_WebView,
Method_getSettings = hookEntry.Method_getSettings,
Method_setWebContentsDebuggingEnabled = hookEntry.Method_setWebContentsDebuggingEnabled,
Method_setJavaScriptEnabled = hookEntry.Method_setJavaScriptEnabled,
Method_loadUrl = hookEntry.Method_loadUrl,
Method_setWebViewClient = hookEntry.Method_setWebViewClient,
)
}
"hookWebViewClient" -> {
val hookEntry = Gson().fromJson(hookJson, HookRules.HookRuleWebViewClient::class.java)
hookWebViewClient(
Class_WebViewClient = hookEntry.Class_WebViewClient,
Method_onPageFinished = hookEntry.Method_onPageFinished,
Class_WebView = hookEntry.Class_WebView,
Method_evaluateJavascript = hookEntry.Method_evaluateJavascript,
)
}
"replaceNebulaUCSDK" -> {
if (cpuArch != null) {
val hookEntry = Gson().fromJson(hookJson, HookRules.ReplaceNebulaUCSDK::class.java)
replaceNebulaUCSDK(
Class_UcServiceSetup = hookEntry.Class_UcServiceSetup,
Method_updateUCVersionAndSdcardPath = hookEntry.Method_updateUCVersionAndSdcardPath,
Field_sInitUcFromSdcardPath = hookEntry.Field_sInitUcFromSdcardPath,
cpuArch = cpuArch,
)
}
}
"hookCrossWalk" -> {
val hookEntry = Gson().fromJson(hookJson, HookRules.HookCrossWalk::class.java)
hookCrossWalk(
Class_XWalkView = hookEntry.Class_XWalkView,
Method_getSettings = hookEntry.Method_getSettings,
Method_setJavaScriptEnabled = hookEntry.Method_setJavaScriptEnabled,
Method_loadUrl = hookEntry.Method_loadUrl,
Method_setResourceClient = hookEntry.Method_setResourceClient,
Class_XWalkPreferences = hookEntry.Class_XWalkPreferences,
Method_setValue = hookEntry.Method_setValue,
)
}
"hookXWebView" -> {
val hookEntry = Gson().fromJson(hookJson, HookRules.HookXWebView::class.java)
hookXWebView(
Class_XWebView = hookEntry.Class_XWebView,
Method_initWebviewCore = hookEntry.Method_initWebviewCore,
Method_isXWeb = hookEntry.Method_isXWeb,
Method_isSys = hookEntry.Method_isSys,
Class_XWebPreferences = hookEntry.Class_XWebPreferences,
Method_setValue = hookEntry.Method_setValue,
)
}
else -> {
loggerE(msg = "Unknown Hook Method: $hookMethod")
}
loggerI(msg = "loading rules")

if (pref.get(AppSP.debug_mode)) {
findWebViewMethods()
}

pref.getSet(AppSP.hooks).forEach { name ->
val hookJson = pref.getString("hook_entry_$name", "{}")
try {
when(val hookMethod = Gson().fromJson(hookJson, HookRules.HookRule::class.java).name) {
// TODO: 添加更多 hook 方法
"hookWebView" -> {
val hookEntry = Gson().fromJson(hookJson, HookRules.HookRuleWebView::class.java)
hookWebView(
Class_WebView = hookEntry.Class_WebView,
Method_getSettings = hookEntry.Method_getSettings,
Method_setWebContentsDebuggingEnabled = hookEntry.Method_setWebContentsDebuggingEnabled,
Method_setJavaScriptEnabled = hookEntry.Method_setJavaScriptEnabled,
Method_loadUrl = hookEntry.Method_loadUrl,
Method_setWebViewClient = hookEntry.Method_setWebViewClient,
)
}
"hookWebViewClient" -> {
val hookEntry = Gson().fromJson(hookJson, HookRules.HookRuleWebViewClient::class.java)
hookWebViewClient(
Class_WebViewClient = hookEntry.Class_WebViewClient,
Method_onPageFinished = hookEntry.Method_onPageFinished,
Class_WebView = hookEntry.Class_WebView,
Method_evaluateJavascript = hookEntry.Method_evaluateJavascript,
)
}
"replaceNebulaUCSDK" -> {
if (cpuArch != null) {
val hookEntry = Gson().fromJson(hookJson, HookRules.ReplaceNebulaUCSDK::class.java)
replaceNebulaUCSDK(
Class_UcServiceSetup = hookEntry.Class_UcServiceSetup,
Method_updateUCVersionAndSdcardPath = hookEntry.Method_updateUCVersionAndSdcardPath,
Field_sInitUcFromSdcardPath = hookEntry.Field_sInitUcFromSdcardPath,
cpuArch = cpuArch,
)
}
} catch (e : Exception) {
loggerE(msg = "Parse Failed!", e = e)
return@forEach // continue
}
"hookCrossWalk" -> {
val hookEntry = Gson().fromJson(hookJson, HookRules.HookCrossWalk::class.java)
hookCrossWalk(
Class_XWalkView = hookEntry.Class_XWalkView,
Method_getSettings = hookEntry.Method_getSettings,
Method_setJavaScriptEnabled = hookEntry.Method_setJavaScriptEnabled,
Method_loadUrl = hookEntry.Method_loadUrl,
Method_setResourceClient = hookEntry.Method_setResourceClient,
Class_XWalkPreferences = hookEntry.Class_XWalkPreferences,
Method_setValue = hookEntry.Method_setValue,
)
}
"hookXWebView" -> {
val hookEntry = Gson().fromJson(hookJson, HookRules.HookXWebView::class.java)
hookXWebView(
Class_XWebView = hookEntry.Class_XWebView,
Method_initWebviewCore = hookEntry.Method_initWebviewCore,
Method_isXWeb = hookEntry.Method_isXWeb,
Method_isSys = hookEntry.Method_isSys,
Class_XWebPreferences = hookEntry.Class_XWebPreferences,
Method_setValue = hookEntry.Method_setValue,
)
}
else -> {
loggerE(msg = "Unknown Hook Method: $hookMethod")
}
}
} catch (e : Exception) {
loggerE(msg = "Parse Failed!", e = e)
return@forEach // continue
}
}
}
}
6 changes: 6 additions & 0 deletions app/src/main/res/menu/app_toolbar_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
android:id="@+id/app_toolbar_menu_checking_for_rules_updates"
android:title="@string/checking_for_rules_updates"
app:showAsAction="never"/>
<item
android:id="@+id/app_toolbar_menu_byass_packer"
android:title="@string/bypass_packer"
app:showAsAction="never"
android:checkable="true"
/>
<item
android:id="@+id/app_toolbar_menu_debug_mode"
android:title="@string/debug_mode"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@
<string name="advance_setting_auto_check_update_desc">模块启动时是否检查更新。</string>
<string name="advance_setting_app_center_desc">AppCenter 是一个来自微软的数据匿名收集方案。我们使用它来匿名收集您使用本模块期间的崩溃日志、性能指标、交互习惯等数据。</string>
<string name="dialog_support_desc">对于中国用户:\n\t1. 支付宝红包码可以每天领取免费的红包,你可以把这个红包免费捐赠给我。\n\t2. 推荐通过支付宝捐赠,因为可以使用一些支付宝发放的红包,比如说上面那个(通过相册扫描可能不行,建议通过另一个屏幕扫码)。\n\t3. 不推荐通过微信捐赠,因为它存在手续费。\n\n对于全球用户:\n\t由于手续费等原因,我暂时不支持接受捐款。</string>
<string name="bypass_packer">支持加固应用</string>
</resources>
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@
<string name="advance_setting_auto_check_update_desc">Auto check update or not when module launched.</string>
<string name="advance_setting_app_center_desc">AppCenter is an anonymous data collection solution from Microsoft. We use it to anonymously collect crash logs, performance indicators, interaction habits and other data during your use of this module.</string>
<string name="dialog_support_desc">For Chinese user:\n\t1. Alipay Red Packet is which you can get a free red packet and pay it to me every day.\n\t2. AliPay is recommended because it can pay with some red packets you got from Alipay just like #1(Scanning through the album may not work, it is recommended to scan through another screen).\n\t3. WeChat is not recommended because of its handling fee for me.\n\nFor global user:\n\tI do not support accepting donations for the time being due to the handling fee and other reasons.</string>
<string name="bypass_packer">Support packed app</string>
</resources>

0 comments on commit 1756b1d

Please sign in to comment.