generated from KyuubiRan/EzXHepler-template
-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add kotlin formatter and format old codes
- Loading branch information
1 parent
44a7f4c
commit c3fd130
Showing
5 changed files
with
169 additions
and
164 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,43 @@ | ||
package org.matrix.chromext | ||
|
||
import org.matrix.chromext.hook.BaseHook | ||
import org.matrix.chromext.hook.ChromeHook | ||
import com.github.kyuubiran.ezxhelper.init.EzXHelperInit | ||
import com.github.kyuubiran.ezxhelper.utils.Log | ||
import com.github.kyuubiran.ezxhelper.utils.Log.logexIfThrow | ||
import de.robv.android.xposed.IXposedHookLoadPackage | ||
import de.robv.android.xposed.IXposedHookZygoteInit | ||
import de.robv.android.xposed.callbacks.XC_LoadPackage | ||
import org.matrix.chromext.hook.BaseHook | ||
import org.matrix.chromext.hook.ChromeHook | ||
|
||
private const val PACKAGE_NAME_HOOKED = "com.android.chrome" | ||
private const val TAG = "ChromeXt" | ||
|
||
class MainHook : IXposedHookLoadPackage, IXposedHookZygoteInit /* Optional */ { | ||
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { | ||
if (lpparam.packageName == PACKAGE_NAME_HOOKED ) { | ||
// Init EzXHelper | ||
EzXHelperInit.initHandleLoadPackage(lpparam) | ||
EzXHelperInit.setLogTag(TAG) | ||
EzXHelperInit.setToastTag(TAG) | ||
// Init hooks | ||
initHooks(ChromeHook) | ||
} | ||
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { | ||
if (lpparam.packageName == PACKAGE_NAME_HOOKED) { | ||
// Init EzXHelper | ||
EzXHelperInit.initHandleLoadPackage(lpparam) | ||
EzXHelperInit.setLogTag(TAG) | ||
EzXHelperInit.setToastTag(TAG) | ||
// Init hooks | ||
initHooks(ChromeHook) | ||
} | ||
} | ||
|
||
// Optional | ||
override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { | ||
EzXHelperInit.initZygote(startupParam) | ||
} | ||
// Optional | ||
override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { | ||
EzXHelperInit.initZygote(startupParam) | ||
} | ||
|
||
private fun initHooks(vararg hook: BaseHook) { | ||
hook.forEach { | ||
runCatching { | ||
if (it.isInit) return@forEach | ||
it.init() | ||
it.isInit = true | ||
Log.i("Inited hook: ${it.javaClass.simpleName}") | ||
}.logexIfThrow("Failed init hook: ${it.javaClass.simpleName}") | ||
} | ||
private fun initHooks(vararg hook: BaseHook) { | ||
hook.forEach { | ||
runCatching { | ||
if (it.isInit) return@forEach | ||
it.init() | ||
it.isInit = true | ||
Log.i("Inited hook: ${it.javaClass.simpleName}") | ||
} | ||
.logexIfThrow("Failed init hook: ${it.javaClass.simpleName}") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,16 @@ | ||
package org.matrix.chromext.hook | ||
|
||
abstract class BaseHook { | ||
var isInit: Boolean = false | ||
abstract fun init() | ||
companion object { | ||
// Use frida-trace to find common method | ||
const val SHOW_URL = "j" | ||
// grep smali code with Tab.loadUrl to get the loadUrl function | ||
const val LOAD_URL = "h" | ||
// get TabImpl field Lorg/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl | ||
const val TAB_FIELD = "a" | ||
} | ||
var isInit: Boolean = false | ||
abstract fun init() | ||
companion object { | ||
// Use frida-trace to find method for casting GURL to String in org/chromium/url/GURL.smali | ||
const val SHOW_URL = "j" | ||
// grep smali code with Tab.loadUrl to get the loadUrl function in | ||
// org/chromium/chrome/browser/tab/TabImpl.smali | ||
const val LOAD_URL = "h" | ||
// get TabImpl field in | ||
// org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.smali | ||
const val TAB_FIELD = "a" | ||
} | ||
} |
176 changes: 92 additions & 84 deletions
176
app/src/main/java/org/matrix/chromext/hook/ChromeHook.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,100 +1,108 @@ | ||
package org.matrix.chromext.hook | ||
|
||
import com.github.kyuubiran.ezxhelper.utils.findAllMethods | ||
import android.content.Context | ||
import com.github.kyuubiran.ezxhelper.utils.Log | ||
import com.github.kyuubiran.ezxhelper.utils.findMethod | ||
import com.github.kyuubiran.ezxhelper.utils.hookBefore | ||
import com.github.kyuubiran.ezxhelper.utils.hookAfter | ||
import com.github.kyuubiran.ezxhelper.utils.hookBefore | ||
import com.github.kyuubiran.ezxhelper.utils.invokeMethod | ||
import com.github.kyuubiran.ezxhelper.utils.paramCount | ||
import com.github.kyuubiran.ezxhelper.utils.Log | ||
import com.github.kyuubiran.ezxhelper.utils.Log.logexIfThrow | ||
import android.content.Context | ||
import dalvik.system.PathClassLoader | ||
import java.lang.reflect.Field | ||
import java.net.URL | ||
|
||
const val youtubeScript = """ | ||
const val youtubeScript = | ||
""" | ||
setTimeout(()=>{ | ||
const skipAds = () => { | ||
let btn = document | ||
.getElementsByClassName("ytp-ad-skip-button ytp-button") | ||
.item(0); | ||
if (btn) { | ||
btn.click(); | ||
} | ||
const skipAds = () => { | ||
let btn = document | ||
.getElementsByClassName("ytp-ad-skip-button ytp-button") | ||
.item(0); | ||
if (btn) { | ||
btn.click(); | ||
} | ||
const ad = [...document.querySelectorAll(".ad-showing")][0]; | ||
const vid = document.querySelector("video"); | ||
if (ad) { | ||
vid.muted = true; | ||
vid.currentTime = vid.duration; | ||
} else { | ||
if (vid != undefined) { | ||
vid.muted = false; | ||
} | ||
} | ||
}; | ||
const main = new MutationObserver(() => { | ||
let adComponent = document.querySelector("ytd-ad-slot-renderer"); | ||
if (adComponent) { | ||
const node = adComponent.closest('ytd-rich-item-renderer') | ||
|| adComponent.closest('ytd-search-pyv-renderer') || adComponent; | ||
node.remove(); | ||
} | ||
let shortsNav = document.querySelector("div.pivot-bar-item-tab.pivot-shorts"); | ||
if (shortsNav) { | ||
const node = shortsNav.closest('ytm-pivot-bar-item-renderer') || shortsNav; | ||
node.remove(); | ||
} | ||
const ad = [...document.querySelectorAll(".ad-showing")][0]; | ||
const vid = document.querySelector("video"); | ||
if (ad) { | ||
vid.muted = true; | ||
vid.currentTime = vid.duration; | ||
} else { | ||
if (vid != undefined) { | ||
vid.muted = false; | ||
} | ||
} | ||
}; | ||
const main = new MutationObserver(() => { | ||
let adComponent = document.querySelector("ytd-ad-slot-renderer"); | ||
if (adComponent) { | ||
const node = adComponent.closest('ytd-rich-item-renderer') | ||
|| adComponent.closest('ytd-search-pyv-renderer') || adComponent; | ||
node.remove(); | ||
} | ||
let shortsNav = document.querySelector("div.pivot-bar-item-tab.pivot-shorts"); | ||
if (shortsNav) { | ||
const node = shortsNav.closest('ytm-pivot-bar-item-renderer') || shortsNav; | ||
node.remove(); | ||
} | ||
const adContainer = document | ||
.getElementsByClassName("video-ads ytp-ad-module") | ||
.item(0); | ||
if (adContainer) { | ||
new MutationObserver(skipAds).observe(adContainer, { | ||
attributes: true, | ||
characterData: true, | ||
childList: true, | ||
}); | ||
} | ||
}); | ||
const adContainer = document | ||
.getElementsByClassName("video-ads ytp-ad-module") | ||
.item(0); | ||
if (adContainer) { | ||
new MutationObserver(skipAds).observe(adContainer, { | ||
attributes: true, | ||
characterData: true, | ||
childList: true, | ||
}); | ||
} | ||
}); | ||
main.observe(document.body, { | ||
attributes: false, | ||
characterData: false, | ||
childList: true, | ||
subtree: true, | ||
}); | ||
main.observe(document.body, { | ||
attributes: false, | ||
characterData: false, | ||
childList: true, | ||
subtree: true, | ||
}); | ||
}, 50); | ||
""" | ||
|
||
object ChromeHook : BaseHook() { | ||
override fun init() { | ||
findMethod("org.chromium.chrome.browser.base.SplitChromeApplication") { | ||
name == "attachBaseContext" | ||
}.hookAfter{ | ||
val ctx: Context = (it.args[0] as Context).createContextForSplit("chrome") | ||
val UrlParams = ctx.getClassLoader().loadClass("org.chromium.content_public.browser.LoadUrlParams").getDeclaredConstructor(String::class.java) | ||
val tabDelegateImpl = ctx.getClassLoader().loadClass( | ||
"org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroidImpl") | ||
val tabImpl: Field = tabDelegateImpl.getDeclaredField(TAB_FIELD) | ||
tabImpl.setAccessible(true); | ||
findMethod(tabDelegateImpl) { name == "onUpdateUrl" }.hookBefore { | ||
val url = it.args[0].invokeMethod() {name == SHOW_URL} as String | ||
Log.d("Load ${url}") | ||
if (url.startsWith("chrome://xt")) { | ||
// Reserve chrome://xt for futur usage | ||
it.thisObject.invokeMethod() { name == "closeContents"} | ||
} else if (url.startsWith("https://m.youtube.com")) { | ||
Log.d("Inject userscript for m.youtube.com") | ||
tabImpl.get(it.thisObject).invokeMethod(UrlParams.newInstance("javascript: ${youtubeScript}")) { name == LOAD_URL } | ||
} | ||
} | ||
override fun init() { | ||
findMethod("org.chromium.chrome.browser.base.SplitChromeApplication") { | ||
name == "attachBaseContext" | ||
} | ||
.hookAfter { | ||
val ctx: Context = (it.args[0] as Context).createContextForSplit("chrome") | ||
val UrlParams = | ||
ctx.getClassLoader() | ||
.loadClass("org.chromium.content_public.browser.LoadUrlParams") | ||
.getDeclaredConstructor(String::class.java) | ||
val tabDelegateImpl = | ||
ctx.getClassLoader() | ||
.loadClass("org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroidImpl") | ||
val tabImpl: Field = tabDelegateImpl.getDeclaredField(TAB_FIELD) | ||
tabImpl.setAccessible(true) | ||
findMethod(tabDelegateImpl) { name == "onUpdateUrl" } | ||
.hookBefore { | ||
val url = it.args[0].invokeMethod() { name == SHOW_URL } as String | ||
Log.d("Load ${url}") | ||
if (url.startsWith("chrome://xt")) { | ||
// Reserve chrome://xt for futur usage | ||
it.thisObject.invokeMethod() { name == "closeContents" } | ||
} else if (url.startsWith("https://m.youtube.com")) { | ||
Log.d("Inject userscript for m.youtube.com") | ||
if (it.thisObject != null) { | ||
tabImpl.get(it.thisObject).invokeMethod( | ||
UrlParams.newInstance("javascript: ${youtubeScript}")) { | ||
name == LOAD_URL | ||
} | ||
} | ||
} | ||
} | ||
|
||
findMethod(tabDelegateImpl) { name == "addMessageToConsole" }.hookAfter { | ||
// addMessageToConsole(int level, String message, int lineNumber, String sourceId) { | ||
Log.i("[${it.args[0]}] ${it.args[1]} @${it.args[3]}:${it.args[2]}") | ||
} | ||
} | ||
} | ||
} | ||
findMethod(tabDelegateImpl) { name == "addMessageToConsole" } | ||
.hookAfter { | ||
// addMessageToConsole(int level, String message, int lineNumber, String sourceId) { | ||
Log.i("[${it.args[0]}] ${it.args[1]} @${it.args[3]}:${it.args[2]}") | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,47 @@ | ||
package org.matrix.chromext.hook | ||
|
||
import com.github.kyuubiran.ezxhelper.utils.* | ||
import com.github.kyuubiran.ezxhelper.utils.Log.logexIfThrow | ||
import android.content.Context | ||
import dalvik.system.PathClassLoader | ||
|
||
object InfoHook : BaseHook() { | ||
override fun init() { | ||
findAllMethods("J.N") { | ||
paramCount == 3 | ||
}.hookBefore { | ||
if ( | ||
it.args[0]::class.simpleName == "Long" && | ||
it.args[1]::class.simpleName == "String" | ||
) { | ||
Log.d("${Thread.currentThread().getStackTrace()[9].getClassName()} > ${Thread.currentThread().getStackTrace()[8].getClassName()} > ${Thread.currentThread().getStackTrace()[7].getClassName()} call with ${it.args[0]} ${it.args[1]} ${it.args[2]}") | ||
if (it.args[2]::class.simpleName == "JavaScriptCallback") { | ||
Log.d("Call ${it.method.getName()} with ${it.args[2]::class.simpleName}") | ||
} | ||
} | ||
} | ||
override fun init() { | ||
findAllMethods("J.N") { paramCount == 3 } | ||
.hookBefore { | ||
if (it.args[0]::class.simpleName == "Long" && it.args[1]::class.simpleName == "String") { | ||
Log.d( | ||
"${Thread.currentThread().getStackTrace()[9].getClassName()} > ${Thread.currentThread().getStackTrace()[8].getClassName()} > ${Thread.currentThread().getStackTrace()[7].getClassName()} call with ${it.args[0]} ${it.args[1]} ${it.args[2]}") | ||
if (it.args[2]::class.simpleName == "JavaScriptCallback") { | ||
Log.d("Call ${it.method.getName()} with ${it.args[2]::class.simpleName}") | ||
} | ||
} | ||
} | ||
|
||
// One can use signature to identify JNI, for example | ||
// Mi3V1mlO(JLjava/lang/Object;ZIZLjava/lang/Object;)I must be | ||
// int downloadImage(long nativeWebContentsAndroid, GURL url, boolean isFavicon, int maxBitmapSize, boolean bypassCache, ImageDownloadCallback callback); | ||
// One can use signature to identify JNI, for example | ||
// Mi3V1mlO(JLjava/lang/Object;ZIZLjava/lang/Object;)I must be | ||
// int downloadImage(long nativeWebContentsAndroid, GURL url, boolean isFavicon, int | ||
// maxBitmapSize, boolean bypassCache, ImageDownloadCallback callback); | ||
|
||
// We want to test out which one is | ||
// void evaluateJavaScriptForTests(long nativeWebContentsAndroid, String script, JavaScriptCallback callback); | ||
// Currently, there are 11 options to test with: (JLjava/lang/String;Ljava/lang/Object;)V | ||
// We want to test out which one is | ||
// void evaluateJavaScriptForTests(long nativeWebContentsAndroid, String script, | ||
// JavaScriptCallback callback); | ||
// Currently, there are 11 options to test with: (JLjava/lang/String;Ljava/lang/Object;)V | ||
|
||
findMethod("J.N") { | ||
name == "Mi3V1mlO" | ||
}.hookBefore { | ||
Log.d("Call downloadImage with url: ${it.args[1].invokeMethod() {name == SHOW_URL}}") | ||
} | ||
findMethod("J.N") { name == "Mi3V1mlO" } | ||
.hookBefore { | ||
Log.d("Call downloadImage with url: ${it.args[1].invokeMethod() {name == SHOW_URL}}") | ||
} | ||
|
||
findMethod("java.lang.Runtime") { | ||
name == "loadLibrary0" }.hookAfter { | ||
if ("${it.args[1]}".startsWith("class org.chromium.base.library_loader", false)) { | ||
Log.i("${it.args[0]} load ${it.args[1]}") | ||
} | ||
} | ||
findAllMethods("org.chromium.chrome.browser.base.SplitChromeApplication") { | ||
true | ||
}.forEach { | ||
var info: String = it.getName() + ": " | ||
it.getParameterTypes().forEach { | ||
info = info + it.getName() + " " | ||
} | ||
Log.i(info) | ||
} | ||
} | ||
} | ||
findMethod("java.lang.Runtime") { name == "loadLibrary0" } | ||
.hookAfter { | ||
if ("${it.args[1]}".startsWith("class org.chromium.base.library_loader", false)) { | ||
Log.i("${it.args[0]} load ${it.args[1]}") | ||
} | ||
} | ||
|
||
findAllMethods("org.chromium.chrome.browser.base.SplitChromeApplication") { true } | ||
.forEach { | ||
var info: String = it.getName() + ": " | ||
it.getParameterTypes().forEach { info = info + it.getName() + " " } | ||
Log.i(info) | ||
} | ||
} | ||
} |