Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/src/main/java/mba/vm/onhit/Constant.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package mba.vm.onhit

import android.content.pm.PackageManager

class Constant {
companion object {
const val NFC_SERVICE_PACKAGE_NAME = "com.android.nfc"
// Hide on Android API
const val PACKAGE_MANAGER_FEATURE_NFC_ANY = "android.hardware.nfc.any"
const val BROADCAST_TAG_EMULATOR_REQUEST = "${BuildConfig.APPLICATION_ID}.TAG_EMULATOR_REQUEST"
const val SHARED_PREFERENCES_NAME = BuildConfig.APPLICATION_ID
const val SHARED_PREFERENCES_CHOSEN_FOLDER = "chosen_folder"
Expand All @@ -11,5 +15,7 @@ class Constant {
const val PREF_RANDOM_UID_LEN = "pref_random_uid_len"
const val MAX_OF_BROADCAST_SIZE = 1048576
const val GITHUB_URL = "https://github.com/0penPublic/onHit"

val PACKAGE_MANAGER_SYSTEM_NFC_FEATURES = setOf(PackageManager.FEATURE_NFC, PACKAGE_MANAGER_FEATURE_NFC_ANY)
}
}
2 changes: 1 addition & 1 deletion app/src/main/java/mba/vm/onhit/helper/DialogHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ object DialogHelper {
ConfigManager.setFixedUidValue(context, hex)
} else {
val len = input.toIntOrNull()
if (len != null && len in 0..65536) {
if (len != null && len in 0..65535) {
setNormalTextColor(etUidConfig, context)
ConfigManager.setRandomUidLen(context, input)
} else {
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/mba/vm/onhit/hook/BaseHook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import mba.vm.onhit.BuildConfig
abstract class BaseHook {

abstract val name: String
abstract fun init(classLoader: ClassLoader?)
abstract fun init(classLoader: ClassLoader)

fun log(text: String) = if (BuildConfig.DEBUG) Logger.i("[ onHit ] [ ${NfcServiceHook.name} ] $text") else Unit
fun log(text: String) = if (BuildConfig.DEBUG) Logger.i("[ onHit ] [ $name ] $text") else Unit
}
17 changes: 10 additions & 7 deletions app/src/main/java/mba/vm/onhit/hook/MainHook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import de.robv.android.xposed.IXposedHookLoadPackage
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_LoadPackage
import io.github.kyuubiran.ezxhelper.xposed.EzXposed
import mba.vm.onhit.BuildConfig
import mba.vm.onhit.Constant.Companion.NFC_SERVICE_PACKAGE_NAME

class MainHook : IXposedHookLoadPackage {
Expand All @@ -12,17 +13,19 @@ class MainHook : IXposedHookLoadPackage {
EzXposed.initHandleLoadPackage(lpparam)
when (lpparam.packageName) {
NFC_SERVICE_PACKAGE_NAME -> {
initHook(NfcServiceHook, lpparam.classLoader)
initHook(NfcDispatchManagerHook, lpparam.classLoader)
initHook(lpparam.classLoader, NfcServiceHook, NfcDispatchManagerHook, PackageManagerHook)
}
else -> initHook(lpparam.classLoader, PackageManagerHook)
}
}

private fun initHook(hook: BaseHook, classLoader: ClassLoader?) {
try {
hook.init(classLoader)
} catch (e: Exception) {
XposedBridge.log(e)
private fun initHook(classLoader: ClassLoader, vararg hooks: BaseHook) {
hooks.forEach { hook ->
try {
hook.init(classLoader)
} catch (e: Exception) {
XposedBridge.log("[ ${BuildConfig.APPLICATION_ID} ] Failed to Init ${hook.name}, ${e.message}")
}
}
}
}
8 changes: 2 additions & 6 deletions app/src/main/java/mba/vm/onhit/hook/NfcDispatchManagerHook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,9 @@ import mba.vm.onhit.BuildConfig
* when this app is in the foreground.
*/
object NfcDispatchManagerHook : BaseHook() {
override val name: String = this::class.simpleName!!
override val name: String = this.javaClass.simpleName

override fun init(classLoader: ClassLoader?) {
classLoader ?: run {
log("nfcClassLoader is null")
return
}
override fun init(classLoader: ClassLoader) {
val clazz = try {
Class.forName("com.oplus.nfc.dispatch.NfcDispatchManager", false, classLoader)
} catch (_: ClassNotFoundException) {
Expand Down
40 changes: 22 additions & 18 deletions app/src/main/java/mba/vm/onhit/hook/NfcServiceHook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,32 @@ import android.app.Application
import android.content.IntentFilter
import android.nfc.NdefMessage
import android.os.Bundle
import android.os.Handler
import androidx.core.content.ContextCompat
import de.robv.android.xposed.XposedHelpers.findClass
import io.github.kyuubiran.ezxhelper.core.finder.MethodFinder
import io.github.kyuubiran.ezxhelper.core.helper.ObjectHelper.`-Static`.objectHelper
import io.github.kyuubiran.ezxhelper.xposed.dsl.HookFactory.`-Static`.createHook
import mba.vm.onhit.BuildConfig
import mba.vm.onhit.Constant
import mba.vm.onhit.Constant.Companion.MAX_OF_BROADCAST_SIZE
import mba.vm.onhit.core.TagTechnology
import mba.vm.onhit.hook.boardcast.NfcServiceHookBroadcastReceiver
import java.lang.reflect.Method
import java.lang.reflect.Proxy


object NfcServiceHook : BaseHook() {
private lateinit var nfcServiceHandler: Any
private lateinit var nfcService: Any
private lateinit var nfcServiceHandler: Handler
private lateinit var nfcClassLoader: ClassLoader
private lateinit var dispatchTagEndpoint: Method
private lateinit var tagEndpointInterface: Class<*>

override val name: String = this::class.simpleName!!
override val name: String = this.javaClass.simpleName

override fun init(classLoader: ClassLoader?) {
classLoader?.let {
nfcClassLoader = classLoader
} ?: run {
log("nfcClassLoader is null")
return
}
override fun init(classLoader: ClassLoader) {
nfcClassLoader = classLoader
tagEndpointInterface = findClass($$"com.android.nfc.DeviceHost$TagEndpoint", nfcClassLoader)
MethodFinder.fromClass("com.android.nfc.NfcApplication", nfcClassLoader)
.filterByName("onCreate")
Expand All @@ -42,10 +39,14 @@ object NfcServiceHook : BaseHook() {
val app = params.thisObject as? Application
app?.let {
nfcService = app.objectHelper().getObjectOrNull("mNfcService") ?: run {
log("Cannot get NFC Service now")
log("Cannot get NFC Service now, Hook Failed. Is NFC Service Working?")
return@after
}
nfcServiceHandler = nfcService.objectHelper().getObjectOrNull("mHandler") as? Handler?: run {
log("Cannot get NFC Service Handler, Hook Failed.")
return@after
}
nfcServiceHandler = nfcService.objectHelper().getObjectOrNull("mHandler")!!
dispatchTagEndpoint = MethodFinder.fromClass(nfcServiceHandler::class)
dispatchTagEndpoint = MethodFinder.fromClass(nfcServiceHandler.javaClass)
.filterByName("dispatchTagEndpoint")
.first()
if (BuildConfig.DEBUG) nfcService.objectHelper().setObject("DBG", true)
Expand All @@ -67,13 +68,16 @@ object NfcServiceHook : BaseHook() {
ndef: NdefMessage?
) {
val tag = buildFakeTag(uid, ndef)
dispatchTagEndpoint.invoke(
nfcServiceHandler,
tag, nfcService.objectHelper().getObjectOrNull("mReaderModeParams")) ?: run {
log("mReaderModeParams is null")
nfcServiceHandler.post {
dispatchTagEndpoint.invoke(
nfcServiceHandler,
tag,
nfcService.objectHelper().getObjectOrNull("mReaderModeParams")
)
}
}


private fun buildFakeTag(
uid: ByteArray,
ndef: NdefMessage?,
Expand All @@ -94,9 +98,9 @@ object NfcServiceHook : BaseHook() {
"getTechExtras" -> {
val ndefBundle = Bundle().apply {
putParcelable("ndefmsg", ndef)
putInt("ndefmaxlength", Int.MAX_VALUE)
putInt("ndefmaxlength", MAX_OF_BROADCAST_SIZE)
putInt("ndefcardstate", 1)
putInt("ndeftype", 4)
putInt("ndeftype", 2)
}
arrayOf(ndefBundle)
}
Expand Down
24 changes: 24 additions & 0 deletions app/src/main/java/mba/vm/onhit/hook/PackageManagerHook.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package mba.vm.onhit.hook

import io.github.kyuubiran.ezxhelper.core.finder.MethodFinder
import io.github.kyuubiran.ezxhelper.xposed.dsl.HookFactory.`-Static`.createHook
import mba.vm.onhit.Constant.Companion.PACKAGE_MANAGER_SYSTEM_NFC_FEATURES

object PackageManagerHook : BaseHook() {
override val name: String = this.javaClass.simpleName
override fun init(classLoader: ClassLoader) {
MethodFinder.fromClass(
"android.app.ApplicationPackageManager",
classLoader
)
.filterByName("hasSystemFeature")
.first()
.createHook {
before { param ->
log("hasSystemFeature called in ${param.thisObject.javaClass.name}")
if (param.args.isEmpty()) return@before
if (param.args[0] as? String in PACKAGE_MANAGER_SYSTEM_NFC_FEATURES) param.result = false
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import android.content.Context
import android.content.Intent
import android.nfc.NdefMessage
import androidx.core.content.IntentCompat
import io.github.kyuubiran.ezxhelper.android.logging.Logger
import mba.vm.onhit.Constant
import mba.vm.onhit.hook.NfcDispatchManagerHook.log
import mba.vm.onhit.hook.NfcServiceHook

class NfcServiceHookBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Logger.i("${this.javaClass.name} onReceive: ${intent.action}")
log("${this.javaClass.name} onReceive: ${intent.action}")
when (intent.action) {
Constant.BROADCAST_TAG_EMULATOR_REQUEST -> {
val uid = intent.getByteArrayExtra("uid")
Expand Down