Skip to content

Commit

Permalink
test hook sensor service
Browse files Browse the repository at this point in the history
  • Loading branch information
fuqiuluo committed Oct 17, 2024
1 parent 53d968a commit de4a289
Show file tree
Hide file tree
Showing 22 changed files with 720 additions and 11 deletions.
8 changes: 7 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

ndk {
abiFilters.clear()
abiFilters.addAll(listOf("arm64-v8a"))
}
}
Expand Down Expand Up @@ -54,7 +55,7 @@ android {
ndk {
println("Full architecture and full compilation.")
abiFilters.add("arm64-v8a")
//abiFilters.add("x86_64") // todo: may crash?
abiFilters.add("x86_64")
}
}
create("arm64") {
Expand Down Expand Up @@ -88,6 +89,11 @@ android {
useLegacyPackaging = true
excludes += "lib/armeabi/**"
excludes += "lib/x86/**"
excludes += "lib/x86_64/libBaiduMapSDK**"
excludes += "lib/x86_64/libc++_shared.so"
excludes += "lib/x86_64/libc++_shared.so"
excludes += "lib/x86_64/liblocSDK8b.so"
excludes += "lib/x86_64/libtiny_magic.so"
}
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:extractNativeLibs="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/java/moe/fuqiuluo/portal/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import com.baidu.mapapi.search.sug.SuggestionSearchOption
import com.google.android.material.navigation.NavigationView
import kotlinx.coroutines.launch
import moe.fuqiuluo.portal.android.permission.RequestPermissions
import moe.fuqiuluo.portal.android.root.ShellUtils
import moe.fuqiuluo.portal.android.window.OverlayUtils
import moe.fuqiuluo.portal.android.window.StatusBarUtil
import moe.fuqiuluo.portal.databinding.ActivityMainBinding
Expand Down Expand Up @@ -153,6 +154,10 @@ class MainActivity : AppCompatActivity() {
StatusBarUtil.fullScreen(this)
}

if (!ShellUtils.hasRoot()) {
Toast.makeText(this, "无Root可能导致传感器Hook失效", Toast.LENGTH_LONG).show()
}

lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
if(checkPermission()) {
Expand Down
47 changes: 47 additions & 0 deletions app/src/main/java/moe/fuqiuluo/portal/android/root/ShellUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package moe.fuqiuluo.portal.android.root

object ShellUtils {
fun hasRoot(): Boolean {
val runtime = Runtime.getRuntime()
try {
val process = runtime.exec("su")
process.outputStream.write("exit\n".toByteArray())
process.outputStream.flush()
process.waitFor()
return process.exitValue() == 0
} catch (e: Exception) {
return false
}
}

fun setEnforceMode(enabled: Boolean) {
val runtime = Runtime.getRuntime()
try {
val process = runtime.exec("su")
process.outputStream.write("setenforce ${if (enabled) "1" else "0"}\n".toByteArray())
process.outputStream.write("exit\n".toByteArray())
process.outputStream.flush()
process.waitFor()
} catch (e: Exception) {
e.printStackTrace()
}
}

fun executeCommand(command: String): String {
val runtime = Runtime.getRuntime()
try {
val process = runtime.exec("su")
process.outputStream.write("$command\n".toByteArray())
process.outputStream.write("exit\n".toByteArray())
process.outputStream.flush()
process.waitFor()
if (process.exitValue() != 0) {
return process.errorStream.bufferedReader().readText()
}
return process.inputStream.bufferedReader().readText()
} catch (e: Exception) {
e.printStackTrace()
return ""
}
}
}
74 changes: 74 additions & 0 deletions app/src/main/java/moe/fuqiuluo/portal/service/MockServiceHelper.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package moe.fuqiuluo.portal.service

import android.annotation.SuppressLint
import android.content.Context
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import moe.fuqiuluo.portal.android.root.ShellUtils
import moe.fuqiuluo.xposed.utils.FakeLoc
import java.io.File

object MockServiceHelper {
const val PROVIDER_NAME = "portal"
Expand Down Expand Up @@ -188,8 +193,77 @@ object MockServiceHelper {
return locationManager.sendExtraCommand(PROVIDER_NAME, randomKey, rely)
}

fun loadLibrary(locationManager: LocationManager, path: String): String? {
if (!::randomKey.isInitialized) {
return null
}
val rely = Bundle()
rely.putString("command_id", "load_library")
rely.putString("path", path)
if(locationManager.sendExtraCommand(PROVIDER_NAME, randomKey, rely)) {
return rely.getString("result")
}
return null
}

fun isServiceInit(): Boolean {
return ::randomKey.isInitialized
}

@SuppressLint("DiscouragedPrivateApi")
fun copyPortalLibrary(context: Context) {
if (!ShellUtils.hasRoot()) return

val isX86: Boolean = runCatching {
if (Build.SUPPORTED_ABIS.any { it.contains("x86") }) {
return@runCatching true
}
val clazz = Class.forName("dalvik.system.VMRuntime")
val method = clazz.getDeclaredMethod("getRuntime")
val runtime = method.invoke(null)
val field = clazz.getDeclaredField("vmInstructionSet")
field.isAccessible = true
val instructionSet = field.get(runtime) as String
if (instructionSet.contains("x86") ) {
true
} else false
}.getOrElse { false }
// todo: support x86

val soDir = File("/data/local/portal-lib")
if (!soDir.exists()) {
ShellUtils.executeCommand("mkdir ${soDir.absolutePath}")
}
val soFile = File(soDir, "libportal.so")
runCatching {
val tmpSoFile = File(soDir, "libportal.so.tmp").also { file ->
var nativeDir = context.applicationInfo.nativeLibraryDir
val soFile = File(nativeDir, "libportal.so")
if (soFile.exists()) {
ShellUtils.executeCommand("cp ${soFile.absolutePath} ${file.absolutePath}")
} else {
Log.e("MockServiceHelper", "Failed to copy portal library: ${soFile.absolutePath}")
return@runCatching
}
}
if (soDir.exists()) {
val originalHash = ShellUtils.executeCommand("head -c 32 ${soFile.absolutePath}")
val newHash = ShellUtils.executeCommand("head -c 32 ${tmpSoFile.absolutePath}")
if (originalHash != newHash) {
ShellUtils.executeCommand("rm ${soFile.absolutePath}")
ShellUtils.executeCommand("mv ${tmpSoFile.absolutePath} ${soFile.absolutePath}")
}
} else if (tmpSoFile.exists()) {
ShellUtils.executeCommand("mv ${tmpSoFile.absolutePath} ${soFile.absolutePath}")
}
}.onFailure {
Log.w("MockServiceHelper", "Failed to copy portal library", it)
}

ShellUtils.executeCommand("chmod 777 ${soFile.absolutePath}")

val result = loadLibrary(context.getSystemService(Context.LOCATION_SERVICE) as LocationManager, soFile.absolutePath)

Log.d("MockServiceHelper", "load portal library result: $result")
}
}
6 changes: 6 additions & 0 deletions app/src/main/java/moe/fuqiuluo/portal/ui/mock/MockFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import moe.fuqiuluo.portal.R
import moe.fuqiuluo.portal.android.root.ShellUtils
import moe.fuqiuluo.portal.android.widget.RockerView
import moe.fuqiuluo.portal.android.window.OverlayUtils
import moe.fuqiuluo.portal.databinding.FragmentMockBinding
Expand Down Expand Up @@ -212,6 +213,11 @@ class MockFragment : Fragment() {
return
}

if (ShellUtils.hasRoot()) {
ShellUtils.setEnforceMode(false) // 关闭SELinux
MockServiceHelper.copyPortalLibrary(requireContext())
}

lifecycleScope.launch {
button.isClickable = false
try {
Expand Down
25 changes: 24 additions & 1 deletion xposed/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@ plugins {
android {
namespace = "moe.fuqiuluo.xposed"
compileSdk = 34
ndkVersion = "26.1.10909125"

defaultConfig {
minSdk = 24

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
externalNativeBuild {
cmake {
cppFlags += ""
}
}
ndk {
abiFilters.addAll(arrayOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64"))
}
}

buildTypes {
Expand All @@ -23,21 +32,35 @@ android {
)
}
}
buildFeatures {
prefab = true
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
}
}
}

dependencies {
compileOnly(libs.xposed.api)
compileOnly(project(":system-api"))

implementation(project(":nmea"))

// Just Test?
//noinspection GradleDynamicVersion
//implementation("org.lsposed.lsplant:lsplant-standalone:+")
//noinspection UseTomlInstead
implementation("io.github.vvb2060.ndk:dobby:1.2")

testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
Expand Down
19 changes: 19 additions & 0 deletions xposed/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.22.1)

project("Portal")

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# MumuEmulator crash? if enable x86_64

#find_package(lsplant REQUIRED CONFIG)
find_package(dobby REQUIRED CONFIG)

add_library(portal SHARED
main.cpp
elf_util.cpp
sensor_hook.cpp)

target_link_libraries(portal android log)
target_link_libraries(portal dobby::dobby)
#target_link_libraries(${CMAKE_PROJECT_NAME} lsplant::lsplant)
7 changes: 7 additions & 0 deletions xposed/src/main/cpp/dobby_hook.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef PORTAL_DOBBY_HOOK_H
#define PORTAL_DOBBY_HOOK_H

#include <unistd.h>
#include <dobby.h>

#endif //PORTAL_DOBBY_HOOK_H
Loading

0 comments on commit de4a289

Please sign in to comment.