├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── drawable
│ │ │ │ ├── log_bg.xml
│ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── layout
│ │ │ │ └── activity_main.xml
│ │ │ └── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── zaze
│ │ │ └── hook
│ │ │ └── checker
│ │ │ ├── App.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── DeviceChecker.kt
│ │ │ └── MyLogClient.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── zaze
│ │ │ └── hook
│ │ │ └── checker
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── zaze
│ │ └── hook
│ │ └── checker
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── checker
├── consumer-rules.pro
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── zaze
│ │ │ └── hook
│ │ │ └── checker
│ │ │ ├── log
│ │ │ ├── CheckerLogClient.kt
│ │ │ └── CheckerLog.kt
│ │ │ ├── DebuggerChecker.kt
│ │ │ ├── CheckResult.kt
│ │ │ ├── RootChecker.kt
│ │ │ ├── CheckerUtil.kt
│ │ │ ├── ExecUtil.kt
│ │ │ ├── XposedChecker.kt
│ │ │ └── QemuChecker.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── zaze
│ │ │ └── hook
│ │ │ └── checker
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── zaze
│ │ └── hook
│ │ └── checker
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── xposed
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── assets
│ │ │ └── xposed_init
│ │ ├── res
│ │ │ ├── values
│ │ │ │ └── strings.xml
│ │ │ └── layout
│ │ │ │ └── device_hook_act.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── zaze
│ │ │ │ └── hook
│ │ │ │ └── xposed
│ │ │ │ ├── devices
│ │ │ │ ├── DeviceInfo.kt
│ │ │ │ ├── DeviceHookActivity.kt
│ │ │ │ ├── DeviceInfoHooker.kt
│ │ │ │ └── DeviceUtil.kt
│ │ │ │ ├── core
│ │ │ │ ├── HookCore.kt
│ │ │ │ ├── ApplicationHook.kt
│ │ │ │ ├── XC_ResultHook.kt
│ │ │ │ ├── TelephonyManagerHook.kt
│ │ │ │ ├── StackTraceElementHook.kt
│ │ │ │ ├── SettingsHook.kt
│ │ │ │ └── BuildHook.kt
│ │ │ │ ├── view
│ │ │ │ └── ViewHooker.kt
│ │ │ │ ├── MyXposedHookLoadPackage.kt
│ │ │ │ ├── HookFilter.kt
│ │ │ │ ├── Utils.kt
│ │ │ │ ├── data
│ │ │ │ ├── PropertiesHelper.kt
│ │ │ │ ├── XposedSharedPreferencesHelper.kt
│ │ │ │ └── HookProvider.kt
│ │ │ │ └── XposedTest.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── zaze
│ │ │ └── hook
│ │ │ └── xposed
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── zaze
│ │ └── hook
│ │ └── xposed
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/checker/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/xposed/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/xposed/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/checker/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':checker', ':xposed'
2 | rootProject.name='HookChecker'
3 |
--------------------------------------------------------------------------------
/xposed/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.zaze.hook.xposed.XposedTest
2 | com.zaze.hook.xposed.devices.DeviceInfoHooker
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | HookChecker
3 |
4 |
--------------------------------------------------------------------------------
/checker/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | checker
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/xposed/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | xposed
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 | .cxx
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/checker/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaze359/HookChecker/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Dec 13 14:08:08 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/log_bg.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/zaze/hook/checker/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/xposed/src/test/java/com/zaze/hook/xposed/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/checker/src/test/java/com/zaze/hook/checker/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/devices/DeviceInfo.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.devices
2 |
3 | /**
4 | * Description :
5 | * @author : ZAZE
6 | * @version : 2019-12-13 - 16:33
7 | */
8 | data class DeviceInfo(val deviceId: String? = null, val deviceModel: String? = null) {
9 |
10 | // fun copy(deviceInfo: DeviceInfo?) {
11 | // deviceInfo?.let {
12 | // deviceId = it.deviceId
13 | // deviceModel = it.deviceModel
14 | // } ?: DeviceInfo()
15 | //
16 | // }
17 |
18 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/core/HookCore.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.core
2 |
3 | import de.robv.android.xposed.callbacks.XC_LoadPackage
4 |
5 | /**
6 | * Description :
7 | * @author : ZAZE
8 | * @version : 2019-12-16 - 15:07
9 | */
10 | class HookCore(lpparam: XC_LoadPackage.LoadPackageParam) {
11 | val TelephonyManager = TelephonyManagerHook(lpparam)
12 | val Settings = SettingsHook(lpparam)
13 | val Build = BuildHook(lpparam)
14 | val Application = ApplicationHook()
15 | val StackTraceElement = StackTraceElementHook()
16 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/view/ViewHooker.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.view
2 |
3 | import com.zaze.hook.xposed.MyXposedHookLoadPackage
4 | import de.robv.android.xposed.IXposedHookLoadPackage
5 | import de.robv.android.xposed.callbacks.XC_LoadPackage
6 |
7 | /**
8 | * Description :
9 | *
10 | * @author : ZAZE
11 | * @version : 2020-02-09 - 21:09
12 | */
13 | class ViewHooker: MyXposedHookLoadPackage() {
14 |
15 |
16 | override fun actualHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
17 | }
18 |
19 |
20 | private fun hookTextView() {
21 |
22 | }
23 | }
--------------------------------------------------------------------------------
/checker/src/main/java/com/zaze/hook/checker/log/CheckerLogClient.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker.log
2 |
3 | /**
4 | * Description :
5 | *
6 | * @author : ZAZE
7 | * @version : 2019-05-24 - 15:33
8 | */
9 | open class CheckerLogClient {
10 |
11 | open fun v(tag: String, msg: String) {}
12 | open fun d(tag: String, msg: String) {}
13 | open fun i(tag: String, msg: String) {}
14 | open fun w(tag: String, msg: String) {}
15 | open fun w(tag: String, msg: String, tr: Throwable) {}
16 | open fun e(tag: String, msg: String) {}
17 | open fun e(tag: String, msg: String, tr: Throwable) {}
18 | }
19 |
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/core/ApplicationHook.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.core
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import de.robv.android.xposed.XC_MethodHook
6 | import de.robv.android.xposed.XposedHelpers
7 |
8 | /**
9 | * Description :
10 | * @author : ZAZE
11 | * @version : 2019-12-17 - 14:40
12 | */
13 | class ApplicationHook internal constructor() {
14 |
15 | fun getContext(methodHook: XC_MethodHook) {
16 | XposedHelpers.findAndHookMethod(
17 | Application::class.java,
18 | "attach",
19 | Context::class.java,
20 | methodHook
21 | )
22 | }
23 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/core/XC_ResultHook.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.core
2 |
3 | import de.robv.android.xposed.XC_MethodHook
4 | import de.robv.android.xposed.XposedBridge
5 |
6 | /**
7 | * Description :
8 | * @author : ZAZE
9 | * @version : 2019-12-16 - 15:33
10 | */
11 | class XC_ResultHook(private val result: Any) : XC_MethodHook() {
12 | override fun afterHookedMethod(param: MethodHookParam?) {
13 | if (param != null) {
14 | XposedBridge.log("${param.method.declaringClass.name} ${param.method.name} result: ${param.result}; hooked : ${result}")
15 | param.result = result
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/core/TelephonyManagerHook.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.core
2 |
3 | import android.telephony.TelephonyManager
4 | import de.robv.android.xposed.XposedHelpers
5 | import de.robv.android.xposed.callbacks.XC_LoadPackage
6 |
7 | /**
8 | * Description :
9 | * @author : ZAZE
10 | * @version : 2019-12-16 - 15:12
11 | */
12 | class TelephonyManagerHook internal constructor(lpparam: XC_LoadPackage.LoadPackageParam) {
13 | companion object {
14 | const val TAG = "TelephonyManagerHook"
15 | val clazz = TelephonyManager::class.java
16 | }
17 |
18 | fun getDeviceId(result: String) {
19 | XposedHelpers.findAndHookMethod(clazz, "getDeviceId", XC_ResultHook(result))
20 | }
21 | }
--------------------------------------------------------------------------------
/checker/src/main/java/com/zaze/hook/checker/DebuggerChecker.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import android.content.Context
4 | import android.content.pm.ApplicationInfo
5 | import android.os.Debug
6 |
7 | /**
8 | * Description :
9 | * @author : ZAZE
10 | * @version : 2019-11-27 - 14:07
11 | */
12 | object DebuggerChecker {
13 | private const val TAG = "DebuggerChecker"
14 | fun detectDebugger(context: Context): Boolean {
15 | return context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE > 0 || Debug.isDebuggerConnected()
16 | // CheckerLog.i(
17 | // TAG,
18 | // "FLAG_DEBUGGABLE : ${}"
19 | // )
20 | // CheckerLog.i(TAG, "isDebuggerConnected : ${Debug.isDebuggerConnected()}")
21 | }
22 | }
--------------------------------------------------------------------------------
/checker/src/main/java/com/zaze/hook/checker/CheckResult.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | /**
4 | * Description :
5 | * @author : ZAZE
6 | * @version : 2020-02-19 - 14:33
7 | */
8 | class CheckResult {
9 |
10 | /**
11 | * flag > 0 表示存在问题
12 | */
13 | private var flags = 0
14 | /**
15 | *
16 | */
17 | var messageBuilder = StringBuilder()
18 |
19 | fun addError(message: String) {
20 | flags++
21 | addMessageNoError(message)
22 | }
23 |
24 | fun addMessageNoError(message: String) {
25 | messageBuilder.append("$message \n")
26 | }
27 |
28 | fun isError(): Boolean {
29 | return flags > 0
30 | }
31 |
32 | fun clear() {
33 | flags = 0
34 | messageBuilder.clear()
35 | }
36 |
37 |
38 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/zaze/hook/checker/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.zaze.hook.checker", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/checker/src/androidTest/java/com/zaze/hook/checker/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.zaze.hook.checker.test", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/xposed/src/androidTest/java/com/zaze/hook/xposed/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.zaze.hook.xposed.test", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/MyXposedHookLoadPackage.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed
2 |
3 | import de.robv.android.xposed.IXposedHookLoadPackage
4 | import de.robv.android.xposed.callbacks.XC_LoadPackage
5 |
6 | /**
7 | * Description :
8 | *
9 | * @author : ZAZE
10 | * @version : 2020-02-09 - 21:10
11 | */
12 | abstract class MyXposedHookLoadPackage : IXposedHookLoadPackage {
13 |
14 | override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
15 | if (HookFilter.handleLoadPackage(lpparam)) {
16 | return
17 | }
18 | try {
19 | actualHandleLoadPackage(lpparam)
20 | } catch (e: Throwable) {
21 | e.printStackTrace()
22 | }
23 | }
24 |
25 | abstract fun actualHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam)
26 |
27 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/checker/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/xposed/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/HookFilter.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed
2 |
3 | import android.content.pm.ApplicationInfo
4 | import de.robv.android.xposed.XposedBridge
5 | import de.robv.android.xposed.callbacks.XC_LoadPackage
6 |
7 | /**
8 | * Description :
9 | * @author : ZAZE
10 | * @version : 2019-12-16 - 10:51
11 | */
12 | object HookFilter {
13 |
14 | val pkgSet = setOf("android", "com.topjohnwu.magisk", "de.robv.android.xposed.installer")
15 |
16 | fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam): Boolean {
17 | if (pkgSet.contains(lpparam.packageName)) {
18 | XposedBridge.log("过滤重要应用不hook: ${lpparam.packageName}")
19 | return true
20 | }
21 | if (lpparam.appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) {
22 | return true
23 | }
24 | return false
25 | }
26 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed
2 |
3 | import com.google.gson.GsonBuilder
4 |
5 | /**
6 | * Description :
7 | * @author : ZAZE
8 | * @version : 2019-12-17 - 14:13
9 | */
10 | object Utils {
11 | private val gsonBuilder = GsonBuilder()
12 |
13 | fun objToJson(any: Any?): String? {
14 | return try {
15 | gsonBuilder.create().toJson(any)
16 | } catch (e: Exception) {
17 | null
18 | }
19 | }
20 |
21 | fun parseJson(json: String?, classOfT: Class?): T? {
22 | if (json == null || classOfT == null) {
23 | return null
24 | }
25 | return try {
26 | gsonBuilder.create().fromJson(json, classOfT)
27 | } catch (e: Throwable) {
28 | e.printStackTrace()
29 | null
30 | }
31 |
32 | }
33 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/core/StackTraceElementHook.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.core
2 |
3 | import de.robv.android.xposed.XC_MethodHook
4 | import de.robv.android.xposed.XposedHelpers
5 |
6 | /**
7 | * Description :
8 | * @author : ZAZE
9 | * @version : 2019-12-17 - 17:50
10 | */
11 | class StackTraceElementHook internal constructor() {
12 | init {
13 | XposedHelpers.findAndHookMethod(
14 | StackTraceElement::class.java,
15 | "getClassName",
16 | object : XC_MethodHook() {
17 | override fun afterHookedMethod(param: MethodHookParam?) {
18 | param?.result?.toString()?.let {
19 | if (it.contains("de.robv.android.xposed.")) {
20 | param.result = "hooked"
21 | }
22 | }
23 | }
24 | })
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zaze/hook/checker/App.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import android.app.Application
4 | import com.zaze.hook.checker.log.CheckerLog
5 |
6 | /**
7 | * Description :
8 | * @author : ZAZE
9 | * @version : 2019-12-18 - 13:52
10 | */
11 | class App : Application() {
12 |
13 | private lateinit var mdmLogClient: MyLogClient
14 |
15 | fun getMdmLogClient(): MyLogClient {
16 | return mdmLogClient
17 | }
18 |
19 | companion object {
20 | private lateinit var INSTANCE: Application
21 |
22 | fun getInstance(): App {
23 | return INSTANCE as App
24 | }
25 | }
26 |
27 | override fun onCreate() {
28 | super.onCreate()
29 | INSTANCE = this
30 | mdmLogClient = MyLogClient()
31 | CheckerLog.setLogClient(mdmLogClient)
32 | }
33 |
34 |
35 | fun getLogDir(): String {
36 | return this.externalCacheDir!!.absolutePath
37 | }
38 | }
--------------------------------------------------------------------------------
/checker/src/main/java/com/zaze/hook/checker/RootChecker.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import java.io.File
4 |
5 | /**
6 | * Description :
7 | * @author : ZAZE
8 | * @version : 2019-12-19 - 13:46
9 | */
10 | class RootChecker {
11 |
12 | companion object {
13 | const val TAG = "RootChecker"
14 | }
15 |
16 | val result = CheckResult()
17 |
18 | fun detectRoot() {
19 | detectByFile()
20 | detectByCmd()
21 | }
22 |
23 | private fun detectByCmd() {
24 | val cmdResult = ExecUtil.exec(arrayOf("su"))
25 | if (cmdResult.first == ExecUtil.SUCCESS) {
26 | result.addError("$TAG hit detectByCmd: su ${cmdResult.second} ")
27 |
28 | }
29 | // return !TextUtils.isEmpty().toString())
30 | }
31 |
32 | private fun detectByFile() {
33 | arrayOf(
34 | "/system/bin/",
35 | "/system/xbin/",
36 | "/system/sbin/",
37 | "/sbin/",
38 | "/vendor/bin/"
39 | ).forEach {
40 | if (File("${it}su").exists()) {
41 | result.addError("$TAG hit detectByFile: ${it}su")
42 | }
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/xposed/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
15 |
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/checker/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | android {
5 | compileSdkVersion 29
6 | buildToolsVersion "29.0.2"
7 |
8 |
9 | defaultConfig {
10 | minSdkVersion 15
11 | targetSdkVersion 29
12 | versionCode 1
13 | versionName "1.0"
14 |
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | consumerProguardFiles 'consumer-rules.pro'
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 |
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: 'libs', include: ['*.jar'])
30 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
31 | implementation 'androidx.appcompat:appcompat:1.1.0'
32 | implementation 'androidx.core:core-ktx:1.0.2'
33 | testImplementation 'junit:junit:4.12'
34 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
35 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
36 | }
37 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zaze/hook/checker/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.text.method.ScrollingMovementMethod
6 | import androidx.appcompat.app.AppCompatActivity
7 | import com.zaze.common.thread.ThreadPlugins
8 | import com.zaze.hook.xposed.devices.DeviceHookActivity
9 | import kotlinx.android.synthetic.main.activity_main.*
10 |
11 | class MainActivity : AppCompatActivity() {
12 |
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setContentView(R.layout.activity_main)
16 | debugLogContent.movementMethod = ScrollingMovementMethod.getInstance()
17 | App.getInstance().getMdmLogClient().bind(debugLogContent)
18 |
19 | checkDeviceBtn.setOnClickListener {
20 | ThreadPlugins.runInUIThread(Runnable {
21 | DeviceChecker.detectSafely()
22 | }, 0)
23 | }
24 | changedDeviceInfo.setOnClickListener {
25 | startActivity(Intent(this, DeviceHookActivity::class.java))
26 | }
27 | }
28 |
29 | override fun onDestroy() {
30 | super.onDestroy()
31 | App.getInstance().getMdmLogClient().unBind()
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/xposed/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | android {
5 | compileSdkVersion 29
6 | buildToolsVersion "29.0.2"
7 |
8 |
9 | defaultConfig {
10 | minSdkVersion 15
11 | targetSdkVersion 29
12 | versionCode 1
13 | versionName "1.0"
14 |
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | consumerProguardFiles 'consumer-rules.pro'
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 |
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: 'libs', include: ['*.jar'])
30 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
31 | implementation 'androidx.appcompat:appcompat:1.1.0'
32 | implementation 'androidx.core:core-ktx:1.1.0'
33 | implementation 'com.google.code.gson:gson:2.8.5'
34 | testImplementation 'junit:junit:4.12'
35 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
36 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
37 | // implementation 'com.squareup.okhttp3:okhttp:3.11.0'
38 |
39 | compileOnly 'de.robv.android.xposed:api:82'
40 | compileOnly 'de.robv.android.xposed:api:82:sources'
41 | }
42 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 |
5 | apply plugin: 'kotlin-android-extensions'
6 |
7 | android {
8 | compileSdkVersion 29
9 | buildToolsVersion "29.0.2"
10 | defaultConfig {
11 | applicationId "com.zaze.hook.checker"
12 | minSdkVersion 16
13 | targetSdkVersion 29
14 | versionCode 1
15 | versionName "1.0"
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | }
25 |
26 | configurations.all {
27 | // check for updates every build
28 | resolutionStrategy.cacheChangingModulesFor 1, 'seconds'
29 | resolutionStrategy.cacheDynamicVersionsFor 1, 'seconds'
30 | }
31 |
32 | dependencies {
33 | implementation fileTree(dir: 'libs', include: ['*.jar'])
34 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
35 | implementation 'androidx.appcompat:appcompat:1.1.0'
36 | implementation 'androidx.core:core-ktx:1.0.2'
37 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
38 | // implementation 'com.github.zaze359.test:zazeutil:1.0.5'
39 | implementation 'com.github.zaze359:test:master-SNAPSHOT'
40 |
41 | testImplementation 'junit:junit:4.12'
42 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
44 |
45 | implementation project(':checker')
46 | implementation project(':xposed')
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/checker/src/main/java/com/zaze/hook/checker/log/CheckerLog.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker.log
2 |
3 | import android.util.Log
4 |
5 | /**
6 | * Description :
7 | * @author : ZAZE
8 | * @version : 2019-04-02 - 16:08
9 | */
10 | object CheckerLog {
11 |
12 | private var logClient: CheckerLogClient? = null
13 |
14 | private fun getLogClient(): CheckerLogClient? {
15 | return logClient
16 | }
17 |
18 | @JvmStatic
19 | fun setLogClient(logClient: CheckerLogClient) {
20 | CheckerLog.logClient = logClient
21 | }
22 |
23 | @JvmStatic
24 | fun v(tag: String, msg: String) {
25 | getLogClient()?.v(tag, msg) ?: Log.v(tag, msg)
26 | }
27 |
28 | @JvmStatic
29 | fun d(tag: String, msg: String) {
30 | getLogClient()?.d(tag, msg) ?: Log.d(tag, msg)
31 | }
32 |
33 | @JvmStatic
34 | fun i(tag: String, msg: String) {
35 | getLogClient()?.i(tag, msg) ?: Log.i(tag, msg)
36 | }
37 |
38 | @JvmStatic
39 | fun w(tag: String, msg: String) {
40 | getLogClient()?.w(tag, msg) ?: Log.w(tag, msg)
41 | }
42 |
43 | @JvmStatic
44 | fun w(tag: String, msg: String, tr: Throwable) {
45 | getLogClient()?.w(tag, msg, tr) ?: Log.w(tag, msg, tr)
46 | }
47 |
48 | @JvmStatic
49 | fun e(tag: String, msg: String) {
50 | getLogClient()?.e(tag, msg) ?: Log.e(tag, msg)
51 | }
52 |
53 | @JvmStatic
54 | fun e(tag: String, msg: String, tr: Throwable) {
55 | getLogClient()?.e(tag, msg, tr) ?: Log.e(tag, msg, tr)
56 | }
57 |
58 | @JvmStatic
59 | fun log(tag: String, msg: String, isImportant: Boolean? = null) {
60 | when {
61 | isImportant == null -> v(tag, msg)
62 | isImportant -> e(tag, msg)
63 | else -> d(tag, msg)
64 | }
65 |
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/checker/src/main/java/com/zaze/hook/checker/CheckerUtil.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import java.io.BufferedReader
4 | import java.io.IOException
5 | import java.io.InputStream
6 | import java.io.Reader
7 |
8 | /**
9 | * Description :
10 | * @author : ZAZE
11 | * @version : 2019-12-19 - 13:28
12 | */
13 | object CheckerUtil {
14 |
15 | @JvmStatic
16 | fun readByBytes(inputStream: InputStream, bufferSize: Int = 1024): StringBuilder {
17 | val results = StringBuilder()
18 | try {
19 | val bytes = ByteArray(bufferSize)
20 | var byteLength = inputStream.read(bytes)
21 | while (byteLength != -1) {
22 | results.append(String(bytes, 0, byteLength))
23 | byteLength = inputStream.read(bytes)
24 | }
25 | } catch (e: Exception) {
26 | e.printStackTrace()
27 | } finally {
28 | try {
29 | inputStream.close()
30 | } catch (e: IOException) {
31 | e.printStackTrace()
32 | }
33 | }
34 | return results
35 | }
36 |
37 | @JvmStatic
38 | fun readLine(reader: Reader): StringBuilder {
39 | var bfReader: BufferedReader? = null
40 | val results = StringBuilder()
41 | try {
42 | bfReader = BufferedReader(reader)
43 | var line = bfReader.readLine()
44 | while (line != null) {
45 | results.append(line)
46 | line = bfReader.readLine()
47 | }
48 | } catch (e: Exception) {
49 | e.printStackTrace()
50 | } finally {
51 | try {
52 | bfReader?.close()
53 | } catch (e: IOException) {
54 | e.printStackTrace()
55 | }
56 | }
57 | return results
58 | }
59 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/data/PropertiesHelper.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.data
2 |
3 | import android.util.Log
4 | import java.io.File
5 | import java.io.FileInputStream
6 | import java.io.FileOutputStream
7 | import java.io.IOException
8 | import java.util.*
9 |
10 | /**
11 | * Description :
12 | * @author : ZAZE
13 | * @version : 2019-12-13 - 16:24
14 | */
15 | internal object PropertiesHelper {
16 |
17 | /**
18 | * 加载
19 | *
20 | * @param file
21 | * @return
22 | */
23 | fun load(file: File): Properties {
24 | val properties = Properties()
25 | if (file.exists()) {
26 | var inputStream: FileInputStream? = null
27 | try {
28 | inputStream = FileInputStream(file)
29 | properties.load(inputStream)
30 | } catch (e: Exception) {
31 | Log.e("DeviceInfoLoader", "load error", e)
32 | } finally {
33 | try {
34 | inputStream?.close()
35 | } catch (e: Exception) {
36 | // ignore
37 | }
38 | }
39 | }
40 | return properties
41 | }
42 |
43 | fun store(file: File, properties: Properties) {
44 | if (!file.exists()) {
45 | file.parentFile?.mkdirs()
46 | file.createNewFile()
47 | }
48 |
49 | var outputStream: FileOutputStream? = null
50 | try {
51 | outputStream = FileOutputStream(file, false)
52 | properties.store(outputStream, "")
53 | } catch (e: Exception) {
54 | Log.e("DeviceInfoLoader", "store error", e)
55 | } finally {
56 | try {
57 | outputStream?.close()
58 | } catch (e: IOException) {
59 | // ignore
60 | }
61 | }
62 | }
63 |
64 |
65 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
24 |
25 |
33 |
34 |
43 |
44 |
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/core/SettingsHook.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.core
2 |
3 | import android.provider.Settings
4 | import de.robv.android.xposed.XC_MethodHook
5 | import de.robv.android.xposed.XposedBridge
6 | import de.robv.android.xposed.callbacks.XC_LoadPackage
7 |
8 | /**
9 | * Description :
10 | * @author : ZAZE
11 | * @version : 2019-12-16 - 15:12
12 | */
13 | class SettingsHook internal constructor(lpparam: XC_LoadPackage.LoadPackageParam) {
14 | companion object {
15 | const val TAG = "Settings"
16 | }
17 |
18 | val Secure = SecureHook(lpparam)
19 |
20 | class SecureHook(lpparam: XC_LoadPackage.LoadPackageParam) {
21 | private val hashMap = HashMap()
22 |
23 |
24 | companion object {
25 | const val TAG = SettingsHook.TAG + ".Secure"
26 | val clazz = Settings.Secure::class.java
27 | }
28 |
29 | init {
30 | XposedBridge.hookAllMethods(
31 | clazz, "getString",
32 | object : XC_MethodHook() {
33 | override fun afterHookedMethod(param: MethodHookParam?) {
34 | if (param?.args == null || param.args.size <= 1) {
35 | return
36 | }
37 | param.args.forEach {
38 | XposedBridge.log("${BuildHook.TAG} $it")
39 | }
40 | XposedBridge.log("$TAG result ${param.result}")
41 | if (hashMap.contains(param.args[1].toString())) {
42 | param.result = hashMap[param.args[1].toString()]
43 | }
44 | XposedBridge.log("$TAG result hooked : ${param.result}")
45 | }
46 | })
47 | }
48 |
49 | fun getString(name: String, result: String) {
50 | hashMap[name] = result
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/checker/src/main/java/com/zaze/hook/checker/ExecUtil.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import com.zaze.hook.checker.log.CheckerLog
4 | import java.io.BufferedReader
5 | import java.io.DataOutputStream
6 | import java.io.InputStreamReader
7 |
8 | /**
9 | * Description :
10 | * @author : ZAZE
11 | * @version : 2019-12-03 - 14:14
12 | */
13 | object ExecUtil {
14 | val SUCCESS = 0
15 |
16 | fun exec(commands: Array): Pair {
17 | var code = -1
18 | val builder = StringBuilder()
19 | var process: Process? = null
20 | var os: DataOutputStream? = null
21 | try {
22 | process = Runtime.getRuntime().exec(commands[0])
23 | os = DataOutputStream(process.outputStream)
24 | repeat(commands.size) {
25 | val command = commands[it]
26 | if (it != 0 && command.isNotEmpty() && command.isNotBlank()) {
27 | os.write(command.toByteArray())
28 | os.writeBytes("\n")
29 | }
30 | }
31 | os.writeBytes("exit\n")
32 | os.flush()
33 | code = process.waitFor()
34 | val inputStream = if (code == SUCCESS) {
35 | process.inputStream
36 | } else {
37 | process.errorStream
38 | }
39 | val reader = BufferedReader(InputStreamReader(inputStream))
40 | var line = reader.readLine()
41 | while (line != null) {
42 | builder.append(line + "\n")
43 | line = reader.readLine()
44 | }
45 | } catch (e: Exception) {
46 | CheckerLog.e("CheckQemu", "exec error", e)
47 | } finally {
48 | try {
49 | os?.close()
50 | } catch (e: Exception) {
51 | // ignore
52 | }
53 | process?.destroy()
54 | }
55 | return Pair(code, builder)
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zaze/hook/checker/DeviceChecker.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import com.zaze.common.thread.ThreadPlugins
4 | import com.zaze.hook.checker.log.CheckerLog
5 | import java.util.concurrent.CountDownLatch
6 | import java.util.concurrent.TimeUnit
7 |
8 | /**
9 | * Description :
10 | * @author : ZAZE
11 | * @version : 2019-11-27 - 13:54
12 | */
13 | object DeviceChecker {
14 |
15 | private const val TAG = "DeviceChecker"
16 |
17 |
18 | /**
19 | * 检测安全
20 | */
21 | fun detectSafely() {
22 | ThreadPlugins.runInWorkThread(Runnable {
23 | val messageBuilder = StringBuilder()
24 | val xposedChecker = XposedChecker().apply {
25 | detectByClassLoader()
26 | detectByMaps()
27 | }
28 | val qemuChecker = QemuChecker().apply {
29 | detectEmulator()
30 | }
31 | val rootChecker = RootChecker().apply {
32 | detectRoot()
33 | }
34 |
35 | val countDownLatch = CountDownLatch(1)
36 | ThreadPlugins.runInUIThread(Runnable {
37 | xposedChecker.detectByStackTrace()
38 | countDownLatch.countDown()
39 | })
40 | countDownLatch.await(5000L, TimeUnit.SECONDS)
41 |
42 | messageBuilder.append(qemuChecker.result.messageBuilder)
43 | messageBuilder.append(rootChecker.result.messageBuilder)
44 | messageBuilder.append(xposedChecker.result.messageBuilder)
45 |
46 | log("Emulator", qemuChecker.result.isError())
47 | log("Root", rootChecker.result.isError())
48 | log("Xposed", xposedChecker.result.isError())
49 | CheckerLog.log(TAG, messageBuilder.toString(), true)
50 | // CheckerLog.log(TAG, "All Prop ${qemuChecker.getAllProp()}", true)
51 | })
52 |
53 | }
54 |
55 |
56 | fun log(tag: String, bool: Boolean) {
57 | CheckerLog.log(TAG, "$tag : $bool", bool)
58 | }
59 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/data/XposedSharedPreferencesHelper.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.data
2 |
3 | import android.content.Context
4 | import android.content.SharedPreferences
5 | import android.database.Cursor
6 | import android.net.Uri
7 | import com.zaze.hook.xposed.Utils
8 | import com.zaze.hook.xposed.devices.DeviceInfo
9 |
10 | /**
11 | * Description :
12 | * @author : ZAZE
13 | * @version : 2019-12-17 - 13:30
14 | */
15 | object XposedSharedPreferencesHelper {
16 |
17 | /**
18 | *
19 | */
20 | fun getSharePreferences(context: Context): SharedPreferences {
21 | return context.getSharedPreferences("xposed_sp", Context.MODE_PRIVATE)
22 | }
23 |
24 | // fun getCustomDeviceInfo(context: Context): DeviceInfo? {
25 | // return Utils.parseJson(
26 | // getSharePreferences(context).getString("deviceInfo", "{}"), DeviceInfo::class.java
27 | // )
28 | // }
29 |
30 | fun getCustomDeviceInfo(context: Context): DeviceInfo? {
31 | var cursor: Cursor? = null
32 | try {
33 | cursor = context.contentResolver.query(
34 | Uri.parse(HookProvider.URI_DEVICE_INFO),
35 | null,
36 | null,
37 | null,
38 | null
39 | )
40 | if (cursor != null && cursor.moveToNext()) {
41 | return Utils.parseJson(
42 | cursor.getString(cursor.getColumnIndex("customDeviceInfo")),
43 | DeviceInfo::class.java
44 | )
45 | }
46 | } catch (e: Exception) {
47 | e.printStackTrace()
48 | } finally {
49 | cursor?.close()
50 | }
51 | return null
52 | }
53 |
54 | fun saveCustomDeviceInfo(context: Context, deviceInfo: DeviceInfo?) {
55 | getSharePreferences(context).edit().putString("customDeviceInfo", Utils.objToJson(deviceInfo))
56 | .apply()
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/data/HookProvider.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.data
2 |
3 | import android.content.ContentProvider
4 | import android.content.ContentValues
5 | import android.database.Cursor
6 | import android.database.MatrixCursor
7 | import android.net.Uri
8 | import java.io.File
9 |
10 | /**
11 | * Description :
12 | * @author : ZAZE
13 | * @version : 2019-12-16 - 18:29
14 | */
15 | class HookProvider : ContentProvider() {
16 | companion object {
17 | val AUTHORITY = "com.zaze.hook.xposed.provider"
18 | val URI_DEVICE_INFO = "content://$AUTHORITY/device/info"
19 | // val deviceProperties = PropertiesHelper.load(File("/sdcard/zaze/deviceInfo"))
20 | }
21 |
22 | override fun insert(uri: Uri, values: ContentValues?): Uri? {
23 | return null
24 | }
25 |
26 | override fun query(
27 | uri: Uri,
28 | projection: Array?,
29 | selection: String?,
30 | selectionArgs: Array?,
31 | sortOrder: String?
32 | ): Cursor? {
33 | context?.let {
34 | val map = XposedSharedPreferencesHelper.getSharePreferences(it).all
35 | if (map == null || map.isEmpty()) {
36 | return null
37 | }
38 | val cursor = MatrixCursor(map.keys.toTypedArray())
39 | cursor.addRow(map.values.toTypedArray())
40 | return cursor
41 | }
42 | return null
43 | }
44 |
45 | override fun onCreate(): Boolean {
46 | return true
47 | }
48 |
49 | override fun update(
50 | uri: Uri,
51 | values: ContentValues?,
52 | selection: String?,
53 | selectionArgs: Array?
54 | ): Int {
55 | return 0
56 | }
57 |
58 | override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int {
59 | return 0
60 | }
61 |
62 | override fun getType(uri: Uri): String? {
63 | return null
64 | }
65 |
66 | }
--------------------------------------------------------------------------------
/xposed/src/main/res/layout/device_hook_act.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
23 |
24 |
25 |
26 |
27 |
31 |
32 |
36 |
37 |
41 |
42 |
43 |
44 |
48 |
49 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/devices/DeviceHookActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.devices
2 |
3 | import android.Manifest
4 | import android.app.Activity
5 | import android.content.pm.PackageManager
6 | import android.os.Build
7 | import android.os.Bundle
8 | import androidx.core.app.ActivityCompat
9 | import androidx.core.content.ContextCompat
10 | import com.zaze.hook.xposed.R
11 | import com.zaze.hook.xposed.data.XposedSharedPreferencesHelper
12 | import kotlinx.android.synthetic.main.device_hook_act.*
13 |
14 | /**
15 | * Description :
16 | * @author : ZAZE
17 | * @version : 2019-12-13 - 16:48
18 | */
19 | class DeviceHookActivity : Activity() {
20 | private var deviceInfo: DeviceInfo? = null
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | setContentView(R.layout.device_hook_act)
24 | if (checkAndReqPermission()) {
25 | init()
26 | }
27 | }
28 |
29 | fun init() {
30 | deviceInfo = XposedSharedPreferencesHelper.getCustomDeviceInfo(this)
31 | ?: DeviceInfo(
32 | DeviceUtil.getUUID(this), Build.MODEL
33 | )
34 | hookDeviceIdEt.setText(deviceInfo?.deviceId)
35 | hookDeviceNameEt.setText(deviceInfo?.deviceModel)
36 | hookDeviceInfoSaveBtn.setOnClickListener {
37 | deviceInfo?.copy(
38 | deviceId = hookDeviceIdEt.text.toString(),
39 | deviceModel = hookDeviceNameEt.text.toString()
40 | )
41 | XposedSharedPreferencesHelper.saveCustomDeviceInfo(this, deviceInfo)
42 | }
43 | }
44 |
45 | fun checkAndReqPermission(): Boolean {
46 | val permissionCheck =
47 | ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
48 | return if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
49 | ActivityCompat.requestPermissions(
50 | this,
51 | arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
52 | 1
53 | )
54 | false
55 | } else {
56 | true
57 | }
58 | }
59 |
60 | override fun onRequestPermissionsResult(
61 | requestCode: Int,
62 | permissions: Array,
63 | grantResults: IntArray
64 | ) {
65 | super.onRequestPermissionsResult(requestCode, permissions, grantResults)
66 | if (!grantResults.contains(PackageManager.PERMISSION_DENIED)) {
67 | init()
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/devices/DeviceInfoHooker.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.devices
2 |
3 | import android.content.Context
4 | import android.provider.Settings
5 | import com.zaze.hook.xposed.HookFilter
6 | import com.zaze.hook.xposed.MyXposedHookLoadPackage
7 | import com.zaze.hook.xposed.core.HookCore
8 | import com.zaze.hook.xposed.data.XposedSharedPreferencesHelper
9 | import de.robv.android.xposed.IXposedHookLoadPackage
10 | import de.robv.android.xposed.XC_MethodHook
11 | import de.robv.android.xposed.XposedBridge
12 | import de.robv.android.xposed.callbacks.XC_LoadPackage
13 |
14 | /**
15 | * Description :
16 | * @author : ZAZE
17 | * @version : 2019-12-13 - 16:21
18 | */
19 | class DeviceInfoHooker : MyXposedHookLoadPackage() {
20 |
21 | companion object {
22 | private const val TAG = "HookDeviceInfo"
23 | }
24 |
25 | override fun actualHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
26 | val hookCore = HookCore(lpparam)
27 | hookCore.Application.getContext(object : XC_MethodHook() {
28 | override fun afterHookedMethod(param: MethodHookParam) {
29 | XposedBridge.log("$TAG application : ${param.thisObject}")
30 | val context = param.args[0] as Context
31 | XposedBridge.log("$TAG context : $context")
32 | val deviceInfo = XposedSharedPreferencesHelper.getCustomDeviceInfo(context)
33 | deviceInfo?.deviceId?.let {
34 | XposedBridge.log("$TAG getDeviceId : $it")
35 | hookCore.TelephonyManager.getDeviceId(it)
36 | hookCore.Build.SERIAL(it)
37 | hookCore.Build.getSerial(it)
38 | hookCore.Settings.Secure.getString(Settings.Secure.ANDROID_ID, it)
39 | }
40 | deviceInfo?.deviceModel?.let {
41 | XposedBridge.log("$TAG getDeviceModel : $it")
42 | hookCore.Build.MODEL(it)
43 | hookCore.Build.DEVICE(it)
44 | hookCore.Build.HARDWARE(it)
45 | hookCore.Build.MANUFACTURER(it)
46 | hookCore.Build.BRAND(it)
47 | hookCore.Build.BOOTLOADER(it)
48 | hookCore.Build.DISPLAY(it)
49 | hookCore.Build.PRODUCT(it)
50 | hookCore.Build.BOARD(it)
51 | hookCore.Build.TYPE(it)
52 | hookCore.Build.TAGS(it)
53 | hookCore.Build.FINGERPRINT(it)
54 | hookCore.Build.USER(it)
55 | hookCore.Build.HOST(it)
56 | }
57 | }
58 | })
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/checker/src/main/java/com/zaze/hook/checker/XposedChecker.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import android.os.Process
4 | import com.zaze.hook.checker.log.CheckerLog
5 | import java.io.FileInputStream
6 |
7 | /**
8 | * Description : 检测 Xposed
9 | * @author : ZAZE
10 | * @version : 2019-12-13 - 15:02
11 | */
12 | class XposedChecker {
13 | companion object {
14 | const val TAG = "XposedChecker"
15 | }
16 |
17 | val result = CheckResult()
18 |
19 | /**
20 | * 检测能否构建XposedHelpers类
21 | * 正常设备应该抛出ClassNotFoundException
22 | */
23 | fun detectByClassLoader() {
24 | try {
25 | ClassLoader.getSystemClassLoader()
26 | .loadClass("de.robv.android.xposed.XposedHelpers")
27 | .newInstance() != null
28 | } catch (e: Exception) {
29 | CheckerLog.e(TAG, "detectByClassLoader flag ", e)
30 | if (e !is ClassNotFoundException) {
31 | result.addError("$TAG hit detectByClassLoader : $e")
32 | }
33 | }
34 | }
35 |
36 | /**
37 | * 1. 检测栈信息包含xposed包名
38 | * 2. 检测栈信息中ZygoteInit, 一般最底层栈为 com.android.internal.os.ZygoteInit.main
39 | * 需要在主线中调用
40 | */
41 | fun detectByStackTrace() {
42 | if (Thread.currentThread().id == Process.myPid().toLong()) {
43 | throw IllegalThreadStateException("必须在主线程调用")
44 | }
45 | val stackTrace = Throwable("detect Xposed").apply {
46 | this.printStackTrace()
47 | }.stackTrace
48 | var hasZygote = false
49 | var bottomStackIsZygote = false
50 | var flag = 0
51 | repeat(stackTrace.count()) {
52 | val stackStr = stackTrace[it].toString()
53 | // CheckerLog.v("XposedChecker $it", stackStr)
54 | if (stackStr.contains("de.robv.android.xposed")) {
55 | flag = flag or 1
56 | }
57 | if (stackStr.contains("com.android.internal.os.ZygoteInit")) {
58 | hasZygote = true
59 | if (stackTrace.size - 1 == it) {
60 | bottomStackIsZygote = true
61 | }
62 | }
63 | }
64 | CheckerLog.e(TAG, "hasXposed flag : $flag; hasZygote: $hasZygote; bottomStackIsZygote: ${bottomStackIsZygote}")
65 | result.addMessageNoError("$TAG detectByStackTrace: ${stackTrace.toList()}")
66 | when {
67 | flag > 0 -> {
68 | result.addError("$TAG hit detectByStackTrace: 包含了xposed的栈信息 $flag")
69 | }
70 | !bottomStackIsZygote -> {
71 | result.addError("$TAG hit detectByStackTrace: 最底下栈没有包含zygote信息 $bottomStackIsZygote")
72 | }
73 | !hasZygote -> {
74 | result.addError("$TAG hit detectByStackTrace: 没有Zygote栈信息")
75 | }
76 | else -> {
77 | // safe
78 |
79 | }
80 | }
81 | }
82 |
83 | /**
84 | * 去读maps检测是否加载类xposed 的so 和jar
85 | */
86 | fun detectByMaps() {
87 | val hashSet = HashSet()
88 | val buffer = CheckerUtil.readByBytes(FileInputStream("/proc/${Process.myPid()}/maps"))
89 | buffer.toString().split("\n").forEach { line ->
90 | if ((line.endsWith(".so") || line.endsWith(".jar"))
91 | && line.contains("xposed", true)
92 | ) {
93 | hashSet.add(line)
94 | CheckerLog.d(TAG, "line $line")
95 | }
96 | }
97 | if (hashSet.isNotEmpty()) {
98 | result.addError("$TAG hit detectByMaps: 加载了 xposed 的so 和jar")
99 | }
100 | CheckerLog.e(TAG, "has Xposed lib ${hashSet.size}")
101 | }
102 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/devices/DeviceUtil.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.devices
2 |
3 | import android.Manifest
4 | import android.annotation.SuppressLint
5 | import android.app.ActivityManager
6 | import android.content.Context
7 | import android.content.Context.ACTIVITY_SERVICE
8 | import android.content.SharedPreferences
9 | import android.content.pm.PackageManager
10 | import android.os.Build
11 | import android.os.Environment
12 | import android.preference.PreferenceManager
13 | import android.provider.Settings
14 | import android.telephony.TelephonyManager
15 | import android.text.TextUtils
16 | import com.zaze.hook.xposed.data.XposedSharedPreferencesHelper
17 | import java.util.*
18 |
19 |
20 | /**
21 | * Description :
22 | * @author : ZAZE
23 | * @version : 2017-08-01 - 13:43
24 | */
25 | @SuppressLint("HardwareIds")
26 | object DeviceUtil {
27 | /**
28 | * 设备第一次启动时产生和存储的64bit的一个数,当设备被wipe后该数重置
29 | */
30 | @JvmStatic
31 | fun getAndroidId(context: Context): String {
32 | return Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
33 | }
34 |
35 | @SuppressLint("MissingPermission")
36 | @JvmStatic
37 | fun getDeviceId(context: Context): String? {
38 | return getTelephonyManager(context).deviceId
39 | }
40 |
41 | @SuppressLint("MissingPermission")
42 | @JvmStatic
43 | fun getSimSerialNumber(context: Context): String? {
44 | return getTelephonyManager(context).simSerialNumber
45 | }
46 |
47 | @JvmStatic
48 | fun getTelephonyManager(context: Context): TelephonyManager {
49 | return context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
50 | }
51 |
52 | /**
53 | * SimSerialNumber -> DeviceId(IMEI) -> AndroidId -> randomId
54 | * [context] context
55 | */
56 | @JvmStatic
57 | fun getUUID(context: Context): String {
58 | val key = "getUUID"
59 | var id = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
60 | && context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
61 | Build.getSerial()
62 | } else {
63 | Build.SERIAL
64 | }
65 | if (TextUtils.isEmpty(id)) {
66 | id = getSimSerialNumber(context)
67 | if (TextUtils.isEmpty(id)) {
68 | id = getDeviceId(context)
69 | if (TextUtils.isEmpty(id)) {
70 | id = getAndroidId(context)
71 | if ("9774d56d682e549c" == id) {
72 | val sp = XposedSharedPreferencesHelper.getSharePreferences(context)
73 | id = sp.getString(key, "")
74 | if (TextUtils.isEmpty(id)) {
75 | id = UUID.randomUUID().toString()
76 | sp.edit().putString(key, id).apply()
77 | }
78 | }
79 | }
80 | }
81 | }
82 | return id
83 | }
84 |
85 | /**
86 | * Runtime Max Memory
87 | * 单个应用 最大运存
88 | * @return
89 | */
90 | @JvmStatic
91 | fun getRuntimeMaxMemory(): Long {
92 | return Runtime.getRuntime().maxMemory()
93 | }
94 |
95 | /**
96 | * Runtime Free Memory
97 | * 当前 从机器内存中取过来的 内存的 中的空闲内存
98 | * @return
99 | */
100 | @JvmStatic
101 | fun getRuntimeFreeMemory(): Long {
102 | return Runtime.getRuntime().freeMemory()
103 | }
104 |
105 | /**
106 | * Runtime Total Memory
107 | * 当前 从机器内存中取过来 的 总内存(包括使用了的和 freeMemory)
108 | * @return
109 | */
110 | @JvmStatic
111 | fun getRuntimeTotalMemory(): Long {
112 | return Runtime.getRuntime().totalMemory()
113 | }
114 |
115 | // --------------------------------------------------
116 | // --------------------------------------------------
117 |
118 | @JvmStatic
119 | fun getDeviceMemory(context: Context): ActivityManager.MemoryInfo {
120 | val am = context.getSystemService(ACTIVITY_SERVICE) as ActivityManager
121 | val outInfo = ActivityManager.MemoryInfo()
122 | am.getMemoryInfo(outInfo)
123 | return outInfo
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zaze/hook/checker/MyLogClient.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import android.graphics.Color
4 | import android.text.SpannableString
5 | import android.text.style.ForegroundColorSpan
6 | import android.util.Log
7 | import android.widget.TextView
8 | import androidx.annotation.ColorInt
9 | import com.zaze.hook.checker.log.CheckerLogClient
10 | import com.zaze.utils.FileUtil
11 | import com.zaze.utils.date.DateUtil
12 | import java.util.*
13 |
14 | /**
15 | * 自定义 MDM Log Client
16 | */
17 | class MyLogClient : CheckerLogClient() {
18 | private val LOG_FILE_PATH =
19 | App.getInstance().getLogDir() + "/device_checker_log.log"
20 | private var textView: TextView? = null
21 |
22 | /**
23 | * 获取本地已记录的mdm error log
24 | *
25 | * @return mdm error log
26 | */
27 | val mdmErrorLog: String
28 | get() = FileUtil.readFromFile(LOG_FILE_PATH).toString()
29 |
30 | fun bind(textView: TextView) {
31 | this.textView = textView
32 | }
33 |
34 | fun unBind() {
35 | this.textView = null
36 | }
37 |
38 | fun clear() {
39 | textView?.let {
40 | it.text = ""
41 | it.scrollTo(0, 0)
42 | }
43 | FileUtil.deleteFile(LOG_FILE_PATH)
44 | }
45 |
46 | private fun log(tag: String, msg: String, @ColorInt colorInt: Int) {
47 | log(SpannableString("$tag: $msg"), colorInt)
48 | }
49 |
50 | /**
51 | * Log results to a textView in application UI
52 | */
53 | private fun log(text: SpannableString, @ColorInt colorInt: Int) {
54 | textView?.post {
55 | textView?.let {
56 | text.setSpan(
57 | ForegroundColorSpan(colorInt),
58 | 0,
59 | text.length,
60 | SpannableString.SPAN_INCLUSIVE_INCLUSIVE
61 | )
62 | it.append(text)
63 | it.append("\n\n")
64 | val offset = it.lineCount * it.lineHeight
65 | val height = it.height
66 | if (offset > height) {
67 | // 超出了TextView的范围
68 | it.scrollTo(0, offset - height)
69 | }
70 | it.invalidate()
71 | }
72 | }
73 | }
74 |
75 | // --------------------------------------------------
76 | override fun v(tag: String, msg: String) {
77 | Log.v(tag, msg)
78 | // log(tag, msg, Color.parseColor("#000000"))
79 | }
80 |
81 | override fun d(tag: String, msg: String) {
82 | Log.d(tag, msg)
83 | log(tag, msg, Color.BLUE)
84 | }
85 |
86 | override fun i(tag: String, msg: String) {
87 | Log.i(tag, msg)
88 | log(tag, msg, Color.parseColor("#008B38"))
89 | }
90 |
91 | override fun w(tag: String, msg: String) {
92 | Log.w(tag, msg)
93 | log(tag, msg, Color.parseColor("#C58F02"))
94 | dumpMdmError(tag, msg)
95 | }
96 |
97 | override fun w(tag: String, msg: String, throwable: Throwable) {
98 | Log.w(tag, msg, throwable)
99 | log(tag, msg + "\n >>> " + throwable.message, Color.parseColor("#C58F02"))
100 | dumpMdmError(tag, msg + "\n >>> " + throwable.message)
101 | }
102 |
103 | override fun e(tag: String, msg: String) {
104 | Log.e(tag, msg)
105 | log(tag, msg, Color.RED)
106 | dumpMdmError(tag, msg)
107 | }
108 |
109 | override fun e(tag: String, msg: String, throwable: Throwable) {
110 | Log.e(tag, msg, throwable)
111 | log(tag, msg + "\n >>> " + throwable.message, Color.RED)
112 | dumpMdmError(tag, msg + "\n >>> " + throwable.message)
113 | }
114 |
115 | /**
116 | * 将错误信息写入sdcard
117 | *
118 | * @param tag tag
119 | * @param message message
120 | */
121 | private fun dumpMdmError(tag: String, message: String) {
122 | val log = String.format(
123 | "%s %s %s\n---------\n",
124 | DateUtil.timeMillisToString(
125 | System.currentTimeMillis(),
126 | "yyyy-MM-dd HH:mm:ss",
127 | TimeZone.getDefault()
128 | ),
129 | tag,
130 | message
131 | )
132 | // ThreadPlugins.runInLogThread(Runnable {
133 | // FileUtil.writeToFile(
134 | // LOG_FILE_PATH,
135 | // log,
136 | // 10L shl 20
137 | // )
138 | // })
139 | }
140 | }
--------------------------------------------------------------------------------
/checker/src/main/java/com/zaze/hook/checker/QemuChecker.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.checker
2 |
3 | import android.os.Build
4 | import com.zaze.hook.checker.log.CheckerLog
5 |
6 | /**
7 | * Description : 检测模拟器
8 | * @author : ZAZE
9 | * @version : 2019-12-02 - 18:54
10 | */
11 | class QemuChecker {
12 | companion object {
13 | private const val TAG = "QemuChecker"
14 | }
15 |
16 | val result = CheckResult()
17 | val propMap = HashMap()
18 |
19 | // val pattern = Pattern.compile("[.*]:[.*]\n")
20 |
21 | fun detectEmulator() {
22 | propMap.clear()
23 | propMap.putAll(getAllProp())
24 | detectEmulatorByProp(propMap)
25 | checkFingerprintMatched(propMap)
26 | }
27 |
28 | /**
29 | * 通过Prop 判断是否在模拟器中
30 | * @return true 在模拟器中运行
31 | */
32 | private fun detectEmulatorByProp(propMap: HashMap) {
33 | val matchKv = { key: String, value: String? ->
34 | when (key) {
35 | "ro.kernel.qemu" -> {
36 | // 模拟器中为1,通常在正常手机中没有该属性
37 | "1" == value
38 | }
39 | "ro.build.tags" -> {
40 | // 部分模拟器中为test-keys,通常在正常手机中它的值为release-keys
41 | "release-keys" != value
42 | }
43 | "ro.product.model" -> {
44 | // 模拟器中为sdk,通常在正常手机中它的值为手机的型号
45 | value?.let {
46 | it.contains("Android SDK") || (it == "sdk")
47 | } ?: false
48 | }
49 | "ro.product.cpu.abi" -> {
50 | // x86架构在真机中极少,后续若出现单独适配
51 | "x86" == value
52 | }
53 | else -> {
54 | false
55 | }
56 | }
57 | }
58 | propMap.keys.forEach { key ->
59 | val value = propMap[key]
60 | if (matchKv(key, value)) {
61 | result.addError("$TAG hit detectEmulatorByProp $key: $value")
62 | }
63 | }
64 | }
65 |
66 | /**
67 | * 检测fingerpring是否能正常匹配
68 | * [samsung/wisdomwifizc/wisdomwifi:9/PPR1.180610.011/P200ZCU2ASJ3_B2BF:user/release-keys]
69 | * getString("ro.product.brand") + '/' +
70 | * getString("ro.product.name") + '/' +
71 | * getString("ro.product.device") + ':' + getString("ro.build.version.release") + '/' +
72 | * getString("ro.build.id") + '/' +
73 | * getString("ro.build.version.incremental") + ':' + getString("ro.build.type") + '/' +
74 | * getString("ro.build.tags");
75 | */
76 | private fun checkFingerprintMatched(propMap: HashMap) {
77 | CheckerLog.d(TAG, "Build.FINGERPRINT : ${Build.FINGERPRINT}")
78 | val propFingerPrint = propMap["ro.build.fingerprint"]
79 | CheckerLog.d(TAG, "ro.build.fingerprint : $propFingerPrint")
80 | val isMatched = propFingerPrint?.split("/")?.let {
81 | it.contains(propMap["ro.product.brand"] ?: "")
82 | && it.contains(propMap["ro.product.name"] ?: "")
83 | && it.contains("${propMap["ro.product.device"]}:${propMap["ro.build.version.release"]}")
84 | && it.contains(propMap["ro.build.id"] ?: "")
85 | // && it.contains("${propMap["ro.build.version.incremental"]}:${propMap["ro.build.type"]}") // 定制存在 xxx.DM
86 | && it.contains(propMap["ro.build.tags"] ?: "")
87 | } ?: false
88 | if (!isMatched) {
89 | result.addError("$TAG hit checkFingerprintMatched false: $propFingerPrint")
90 | }
91 | // val roBootimageBuildFingerprint = propMap["ro.bootimage.build.fingerprint"]
92 | // if (TextUtils.isEmpty(roBootimageBuildFingerprint) || TextUtils.isEmpty(roBuildFingerprint)) {
93 | // return false
94 | // }
95 | // if (Build.VERSION.SDK_// return roBootimageBuildFingerprint == roBuildFingerprintINT >= Build.VERSION_CODES.O) {
96 | // } else {
97 | // }
98 | }
99 |
100 | fun getAllProp(): HashMap {
101 | val propMap = HashMap()
102 | ExecUtil.exec(arrayOf("getprop")).second.toString()
103 | .replace("[", "")
104 | .replace("]", "")
105 | .split("\n").forEach {
106 | val kv = it.split(": ")
107 | // CheckerLog.d(TAG, "kv : $it")
108 | if (kv.size >= 2) {
109 | propMap[kv[0]] = kv[1]
110 | }
111 | }
112 | return propMap
113 | }
114 | }
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/XposedTest.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import de.robv.android.xposed.IXposedHookLoadPackage
6 | import de.robv.android.xposed.XC_MethodHook
7 | import de.robv.android.xposed.XposedBridge
8 | import de.robv.android.xposed.XposedHelpers
9 | import de.robv.android.xposed.callbacks.XC_LoadPackage
10 |
11 | /**
12 | * Description :
13 | *
14 | * @author : ZAZE
15 | * @version : 2019-12-13 - 13:21
16 | */
17 | class XposedTest : IXposedHookLoadPackage {
18 |
19 | companion object {
20 | private val TAG = "XposedTest"
21 | }
22 |
23 | @Throws(Throwable::class)
24 | override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
25 | // XposedBridge.log("$TAG >> handleLoadPackage : ${lpparam.packageName}")
26 | if (HookFilter.handleLoadPackage(lpparam)) {
27 | return
28 | }
29 | // HookCore(lpparam)
30 | XposedBridge.hookAllMethods(
31 | Intent::class.java,
32 | "setAction",
33 | object : XC_MethodHook() {
34 | override fun beforeHookedMethod(param: MethodHookParam?) {
35 | super.beforeHookedMethod(param)
36 | XposedBridge.log("$TAG >> beforeHookedMethod setAction ${param?.thisObject} >> ${param?.result}")
37 | XposedBridge.log("$TAG >> beforeHookedMethod ${param?.args?.get(0)}")
38 | if (param?.args?.get(0) == "android.settings.WIFI_DISPLAY_SETTINGS") {
39 | param.args.set(0, "android.settings.DISPLAY_SETTINGS")
40 | }
41 | }
42 | })
43 |
44 |
45 | if ("com.zaze.demo" == lpparam.packageName) {
46 | val testDebugClass = lpparam.classLoader.loadClass("com.zaze.demo.debug.TestDebug")
47 | XposedHelpers.findAndHookMethod(
48 | testDebugClass,
49 | "test",
50 | Context::class.java,
51 | object : XC_MethodHook() {
52 | override fun afterHookedMethod(param: MethodHookParam?) {
53 | super.afterHookedMethod(param)
54 | XposedBridge.log("$TAG >> afterHookedMethod ${param?.args?.get(0)}")
55 |
56 | }
57 |
58 | override fun beforeHookedMethod(param: MethodHookParam?) {
59 | super.beforeHookedMethod(param)
60 | XposedBridge.log("$TAG >> beforeHookedMethod ${param?.args?.get(0)}")
61 | }
62 | })
63 |
64 | val entity = lpparam.classLoader.loadClass("com.zaze.demo.model.entity.BaseEntity")
65 | XposedHelpers.findAndHookMethod(entity, "getName", object : XC_MethodHook() {
66 | override fun afterHookedMethod(param: MethodHookParam?) {
67 | super.beforeHookedMethod(param)
68 | XposedBridge.log("$TAG >> beforeHookedMethod ${param?.thisObject} >> ${param?.result}")
69 | param?.result = "Hooked ${param?.result}"
70 | }
71 | })
72 | // XposedBridge.hookAllMethods(
73 | // ClassLoader::class.java,
74 | // "defineClass",
75 | // object : XC_MethodHook() {
76 | // override fun afterHookedMethod(param: MethodHookParam?) {
77 | // super.beforeHookedMethod(param)
78 | // XposedBridge.log("$TAG >> beforeHookedMethod defineClass ${param?.thisObject} >> ${param?.result}")
79 | // }
80 | // })
81 | //
82 | // XposedBridge.hookAllMethods(
83 | // ClassLoader::class.java,
84 | // "loadClass",
85 | // object : XC_MethodHook() {
86 | // override fun afterHookedMethod(param: MethodHookParam?) {
87 | // super.beforeHookedMethod(param)
88 | // XposedBridge.log("$TAG >> beforeHookedMethod loadClass ${param?.thisObject} >> ${param?.result}")
89 | // }
90 | // })
91 | // XposedBridge.hookAllMethods(
92 | // Class::class.java,
93 | // "forName",
94 | // object : XC_MethodHook() {
95 | // override fun afterHookedMethod(param: MethodHookParam?) {
96 | // super.beforeHookedMethod(param)
97 | // XposedBridge.log("$TAG >> beforeHookedMethod classForName ${param?.thisObject} >> ${param?.result}")
98 | // }
99 | // })
100 |
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/xposed/src/main/java/com/zaze/hook/xposed/core/BuildHook.kt:
--------------------------------------------------------------------------------
1 | package com.zaze.hook.xposed.core
2 |
3 | import android.os.Build
4 | import de.robv.android.xposed.XC_MethodHook
5 | import de.robv.android.xposed.XposedBridge
6 | import de.robv.android.xposed.XposedHelpers
7 | import de.robv.android.xposed.callbacks.XC_LoadPackage
8 |
9 | /**
10 | * Description :
11 | * @author : ZAZE
12 | * @version : 2019-12-16 - 15:12
13 | */
14 | class BuildHook internal constructor(lpparam: XC_LoadPackage.LoadPackageParam) {
15 | private val buildMap = HashMap()
16 |
17 | companion object {
18 | const val TAG = "Build"
19 | }
20 |
21 | init {
22 | XposedBridge.hookAllMethods(
23 | XposedHelpers.findClass(
24 | "android.os.SystemProperties",
25 | lpparam.classLoader
26 | ), "get", object : XC_MethodHook() {
27 | override fun afterHookedMethod(param: MethodHookParam?) {
28 | if (param?.args == null || param.args.isEmpty()) {
29 | return
30 | }
31 | val result = param.result
32 | val stringArg = param.args?.get(0)?.toString() ?: ""
33 | if (buildMap.contains(stringArg)) {
34 | param.result = buildMap[stringArg]
35 | }
36 | XposedBridge.log("$TAG args:${param.args?.toList()}; result:$result; hookedResult: ${param.result}")
37 | }
38 | })
39 | }
40 |
41 |
42 | fun MANUFACTURER(value: String) {
43 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "MANUFACTURER", value)
44 | buildMap["ro.product.manufacturer"] = value
45 | }
46 |
47 | fun BRAND(value: String) {
48 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "BRAND", value)
49 | buildMap["ro.product.brand"] = value
50 | }
51 |
52 | fun BOOTLOADER(value: String) {
53 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "BOOTLOADER", value)
54 | buildMap["ro.bootloader"] = value
55 | }
56 |
57 | fun MODEL(value: String) {
58 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "MODEL", value)
59 | buildMap["ro.product.model"] = value
60 | }
61 |
62 | fun DEVICE(value: String) {
63 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "DEVICE", value)
64 | buildMap["ro.product.device"] = value
65 | }
66 |
67 | fun DISPLAY(value: String) {
68 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "DISPLAY", value)
69 | buildMap["ro.build.display.id"] = value
70 | }
71 |
72 | fun PRODUCT(value: String) {
73 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "PRODUCT", value)
74 | buildMap["ro.product.name"] = value
75 | }
76 |
77 | fun BOARD(value: String) {
78 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "BOARD", value)
79 | buildMap["ro.product.board"] = value
80 | }
81 |
82 | fun HARDWARE(value: String) {
83 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "HARDWARE", value)
84 | buildMap["ro.hardware"] = value
85 | }
86 |
87 | fun SERIAL(value: String) {
88 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "SERIAL", value)
89 | buildMap["ro.serialno"] = value
90 | buildMap["no.such.thing"] = value
91 | }
92 |
93 | fun getSerial(value: String) {
94 | XposedHelpers.findAndHookMethod(
95 | Build::class.java,
96 | "getSerial", XC_ResultHook(value)
97 | )
98 | }
99 |
100 | fun TYPE(value: String) {
101 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "TYPE", value)
102 | buildMap["ro.build.type"] = value
103 | }
104 |
105 | fun TAGS(value: String) {
106 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "TAGS", value)
107 | buildMap["ro.build.tags"] = value
108 | }
109 |
110 | fun FINGERPRINT(value: String) {
111 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "FINGERPRINT", value)
112 | buildMap["ro.build.fingerprint"] = value
113 | }
114 |
115 | fun USER(value: String) {
116 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "USER", value)
117 | buildMap["ro.build.user"] = value
118 | }
119 |
120 | fun HOST(value: String) {
121 | XposedHelpers.setStaticObjectField(android.os.Build::class.java, "HOST", value)
122 | buildMap["ro.build.host"] = value
123 | }
124 | }
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------