├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── CMakeLists.txt
├── build.gradle
├── debug-proguard-rules.pro
├── libs
│ ├── api-82.jar
│ └── okhttp-3.11.0.jar
├── proguard-rules.pro
├── release
│ ├── app-release.apk
│ └── output.json
├── simpleImg
│ ├── Screenshot_20181109-111112_滴滴无障碍.png
│ ├── Screenshot_20181109-111238_滴滴无障碍.png
│ └── Screenshot_20181109-111312_滴滴无障碍.png
├── src
│ ├── androidTest
│ │ └── java
│ │ │ ├── android
│ │ │ └── app
│ │ │ │ └── ActivityManager.java
│ │ │ ├── cn
│ │ │ └── zr
│ │ │ │ └── ExampleInstrumentedTest.kt
│ │ │ └── com
│ │ │ └── android
│ │ │ └── server
│ │ │ └── accessibility
│ │ │ ├── AESCrypt.java
│ │ │ ├── AccessibilityManagerService.java
│ │ │ ├── AccessibilityManagerServiceHelper.java
│ │ │ └── remotePreferences
│ │ │ ├── RemoteContract.java
│ │ │ ├── RemotePreferenceAccessException.java
│ │ │ ├── RemotePreferenceProvider.java
│ │ │ ├── RemotePreferences.java
│ │ │ └── RemoteUtils.java
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── cpp
│ │ │ ├── elf_utils.c
│ │ │ ├── hook4.c
│ │ │ ├── include
│ │ │ │ ├── config.h
│ │ │ │ ├── elf_utils.h
│ │ │ │ ├── injector.h
│ │ │ │ ├── ptrace.h
│ │ │ │ └── utils.h
│ │ │ ├── injector.c
│ │ │ ├── log.h
│ │ │ ├── main.c
│ │ │ ├── native-lib.cpp
│ │ │ ├── ptrace.c
│ │ │ ├── share.c
│ │ │ └── utils.c
│ │ ├── java
│ │ │ └── cn
│ │ │ │ └── zr
│ │ │ │ ├── AccessibilityServiceDiDiBean.kt
│ │ │ │ ├── BaseApplication.java
│ │ │ │ ├── CrashHandler.java
│ │ │ │ ├── IAccessibilityManager.aidl
│ │ │ │ ├── Module.java
│ │ │ │ ├── MyAccessibilityService.java
│ │ │ │ ├── Other.java
│ │ │ │ ├── PackageHooker.java
│ │ │ │ ├── SuspensionWindow.java
│ │ │ │ ├── TestModule.java
│ │ │ │ ├── XposedInit.java
│ │ │ │ ├── Zr.java
│ │ │ │ ├── activity
│ │ │ │ ├── BaseAppCompatActivity.kt
│ │ │ │ └── MainActivity.kt
│ │ │ │ ├── config
│ │ │ │ └── TimeQuantum.kt
│ │ │ │ ├── contentProviderPreference
│ │ │ │ ├── MyPreferenceProvider.java
│ │ │ │ ├── RemoteContract.java
│ │ │ │ ├── RemotePreferenceAccessException.java
│ │ │ │ ├── RemotePreferenceProvider.java
│ │ │ │ ├── RemotePreferences.java
│ │ │ │ └── RemoteUtils.java
│ │ │ │ ├── didi
│ │ │ │ ├── DidiConfigManager.kt
│ │ │ │ ├── DidiOrderState.kt
│ │ │ │ └── DidiPrefsFragment.kt
│ │ │ │ ├── helper
│ │ │ │ ├── DebugHelper.kt
│ │ │ │ └── DidiAccessibilityServiceHelper.java
│ │ │ │ ├── preferens
│ │ │ │ └── TimeQuantumAlertDialog.kt
│ │ │ │ └── util
│ │ │ │ ├── AESCrypt.java
│ │ │ │ ├── CheckUtil.kt
│ │ │ │ ├── ConfigUtil.kt
│ │ │ │ ├── DensityUtils.java
│ │ │ │ ├── LLog.kt
│ │ │ │ ├── ShellUtil.java
│ │ │ │ ├── Util.java
│ │ │ │ └── shell
│ │ │ │ ├── CommandResult.java
│ │ │ │ ├── Shell.java
│ │ │ │ ├── ShellExitCode.java
│ │ │ │ ├── ShellNotFoundException.java
│ │ │ │ └── StreamGobbler.java
│ │ └── res
│ │ │ ├── drawable-v21
│ │ │ ├── ic_menu_credit_card.xml
│ │ │ ├── ic_menu_send.xml
│ │ │ └── ic_menu_share.xml
│ │ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── drawable
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── side_nav_bar.xml
│ │ │ ├── layout
│ │ │ ├── activity_main.xml
│ │ │ ├── app_bar_main.xml
│ │ │ ├── content_main.xml
│ │ │ ├── nav_header_main.xml
│ │ │ └── view_time_quantum_select.xml
│ │ │ ├── menu
│ │ │ └── activity_main_drawer.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.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
│ │ │ ├── values-v21
│ │ │ └── styles.xml
│ │ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ │ └── xml
│ │ │ ├── accessible_service_config.xml
│ │ │ ├── file_paths.xml
│ │ │ └── preferences_didi.xml
│ └── test
│ │ └── java
│ │ └── cn
│ │ └── zr
│ │ └── ExampleUnitTest.kt
└── zr.jks
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── mylibrary
├── .gitignore
├── CMakeLists.txt
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── vixkw
│ │ └── pubgmhd
│ │ └── mylibrary
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── jni
│ │ ├── share.c
│ │ ├── test.c
│ │ └── test.h
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── vixkw
│ └── pubgmhd
│ └── mylibrary
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches/build_file_checksums.ser
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | .DS_Store
9 | /build
10 | /captures
11 | .externalNativeBuild
12 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DiDiHelper
2 | Android滴滴无障碍服务
3 |
4 |
5 | 提供给残障人士,根据规则自动抢预约单
6 |
7 |
8 |
9 |
10 |
11 | 1.支持滴滴最新5.1.28版本
12 |
13 | 2.服务对于手机应用完全透明,具有不可检测性
14 |
15 |
16 |
17 |
18 |
19 | 如何编译进行测试?
20 |
21 |
22 | 1.Android Studio 3.2.1 导入编译apk
23 |
24 | 2.编译lineageos系统,将修改的android系统源码放置到android/framework/base/..里对应的文件夹,具体看packagename (找不到请根据文件名在framework中搜索)
25 |
26 | 3.安装lineageos系统后,刷入对应su,授予软件长期root权限
27 |
28 |
29 |
30 |
31 |
32 | 声明:
33 |
34 | 纯粹的爱好,无商业目的,如有不满请联系
35 |
36 |
37 | [**下载apk**](https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/master/app/release/app-release.apk)
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # For more information about using CMake with Android Studio, read the
2 | # documentation: https://d.android.com/studio/projects/add-native-code.html
3 |
4 | # Sets the minimum version of CMake required to build the native library.
5 |
6 | cmake_minimum_required(VERSION 3.4.1)
7 |
8 | # Creates and names a library, sets it as either STATIC
9 | # or SHARED, and provides the relative paths to its source code.
10 | # You can define multiple libraries, and CMake builds them for you.
11 | # Gradle automatically packages shared libraries with your APK.
12 | #set (SRC_LIST src/main/cpp/native-lib.cpp)
13 | set(CMAKE_VERBOSE_MAKEFILE on)
14 |
15 | set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src/main/assets/${ANDROID_ABI}")
16 |
17 | set(SRC_LIST src/main/cpp/injector.c src/main/cpp/main.c src/main/cpp/ptrace.c src/main/cpp/utils.c src/main/cpp/share.c src/main/cpp/utils.c src/main/cpp/elf_utils.c)
18 | add_executable( # Sets the name of the library.
19 | zr.so
20 |
21 | # Sets the library as a shared library.
22 | #SHARED
23 |
24 | # Provides a relative path to your source file(s).
25 | ${SRC_LIST})
26 |
27 |
28 | set(SRC_LIST2 src/main/cpp/share.c)
29 | add_library( # Sets the name of the library.
30 | share
31 |
32 | # Sets the library as a shared library.
33 | SHARED
34 |
35 | # Provides a relative path to your source file(s).
36 | ${SRC_LIST2})
37 |
38 | #[[set(SRC_LIST3 src/main/cpp/dll/test.c)
39 | add_executable( # Sets the name of the library.
40 | test
41 |
42 | # Sets the library as a shared library.
43 | #SHARED
44 |
45 | # Provides a relative path to your source file(s).
46 | ${SRC_LIST3})]]
47 |
48 | # Searches for a specified prebuilt library and stores the path as a
49 | # variable. Because CMake includes system libraries in the search path by
50 | # default, you only need to specify the name of the public NDK library
51 | # you want to add. CMake verifies that the library exists before
52 | # completing its build.
53 |
54 | find_library( # Sets the name of the path variable.
55 | log-lib
56 |
57 | # Specifies the name of the NDK library that
58 | # you want CMake to locate.
59 | log)
60 |
61 | # Specifies libraries CMake should link to your target library. You
62 | # can link multiple libraries, such as libraries you define in this
63 | # build script, prebuilt third-party libraries, or system libraries.
64 |
65 | target_link_libraries( # Specifies the target library.
66 | zr.so
67 |
68 | # Links the target library to the log library
69 | # included in the NDK.
70 | ${log-lib})
71 |
72 | target_link_libraries( # Specifies the target library.
73 | share
74 |
75 | # Links the target library to the log library
76 | # included in the NDK.
77 | ${log-lib})
78 |
79 |
80 | #[[
81 | target_link_libraries( # Specifies the target library.
82 | test
83 |
84 | # Links the target library to the log library
85 | # included in the NDK.
86 | ${log-lib})]]
87 |
--------------------------------------------------------------------------------
/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 28
9 | defaultConfig {
10 | applicationId "cn.zr"
11 | minSdkVersion 19
12 | targetSdkVersion 28
13 | versionCode 1
14 | versionName "1.0"
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | /*externalNativeBuild {
17 | cmake {
18 | cppFlags ""
19 | abiFilters 'arm64-v8a'
20 | }
21 | }*/
22 | }
23 | buildTypes {
24 | release {
25 | zipAlignEnabled true
26 | minifyEnabled true
27 | shrinkResources true
28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
29 | }
30 |
31 | debug {
32 | zipAlignEnabled true
33 | minifyEnabled false
34 | shrinkResources false
35 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'debug-proguard-rules.pro'
36 | }
37 |
38 | }
39 | /*externalNativeBuild {
40 | cmake {
41 | path "CMakeLists.txt"
42 | }
43 | }*/
44 | }
45 |
46 | dependencies {
47 | //implementation fileTree(dir: 'libs', include: ['*.jar'])
48 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
49 | implementation 'com.android.support:preference-v7:28.0.0'
50 | implementation 'com.android.support:preference-v14:28.0.0'
51 | implementation 'com.takisoft.fix:preference-v7-extras:28.0.0.0'
52 | implementation 'com.android.support:appcompat-v7:28.0.0'
53 | implementation 'com.android.support:design:28.0.0'
54 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
55 | testImplementation 'junit:junit:4.12'
56 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
57 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
58 | compileOnly 'de.robv.android.xposed:api:82'
59 | //implementation project(':mylibrary')
60 | }
61 |
--------------------------------------------------------------------------------
/app/debug-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 |
23 | -keep class cn.zr.XposedInit {*;}
24 | -keep class cn.zr.Module {*;}
25 |
26 |
27 | -dontwarn android.support.v7.widget.**
28 | -keep class android.support.v7.widget.** {*;}
29 |
--------------------------------------------------------------------------------
/app/libs/api-82.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/libs/api-82.jar
--------------------------------------------------------------------------------
/app/libs/okhttp-3.11.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/libs/okhttp-3.11.0.jar
--------------------------------------------------------------------------------
/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 |
23 | -keep class cn.zr.XposedInit {*;}
24 |
25 | -assumenosideeffects class cn.zr.PackageHooker{
26 | private void print(...);
27 | }
28 |
29 | -assumenosideeffects class cn.zr.Moudule{
30 | private void print(...);
31 | }
32 |
33 | -dontwarn android.support.v7.widget.**
34 | -keep class android.support.v7.widget.** {*;}
--------------------------------------------------------------------------------
/app/release/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/release/app-release.apk
--------------------------------------------------------------------------------
/app/release/output.json:
--------------------------------------------------------------------------------
1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
--------------------------------------------------------------------------------
/app/simpleImg/Screenshot_20181109-111112_滴滴无障碍.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/simpleImg/Screenshot_20181109-111112_滴滴无障碍.png
--------------------------------------------------------------------------------
/app/simpleImg/Screenshot_20181109-111238_滴滴无障碍.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/simpleImg/Screenshot_20181109-111238_滴滴无障碍.png
--------------------------------------------------------------------------------
/app/simpleImg/Screenshot_20181109-111312_滴滴无障碍.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/simpleImg/Screenshot_20181109-111312_滴滴无障碍.png
--------------------------------------------------------------------------------
/app/src/androidTest/java/cn/zr/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package cn.zr
2 |
3 | import android.support.test.InstrumentationRegistry
4 | import android.support.test.runner.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.getTargetContext()
22 | assertEquals("cn.zr", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/android/server/accessibility/AESCrypt.java:
--------------------------------------------------------------------------------
1 | package com.android.server.accessibility;
2 |
3 | import android.util.Base64;
4 | import android.util.Log;
5 |
6 | import java.io.UnsupportedEncodingException;
7 | import java.security.GeneralSecurityException;
8 | import java.security.MessageDigest;
9 | import java.security.NoSuchAlgorithmException;
10 |
11 | import javax.crypto.Cipher;
12 | import javax.crypto.spec.IvParameterSpec;
13 | import javax.crypto.spec.SecretKeySpec;
14 |
15 | /**
16 | *
17 | * https://github.com/scottyab/AESCrypt-Android
18 | * Encrypt and decrypt messages using AES 256 bit encryption that are compatible with AESCrypt-ObjC and AESCrypt Ruby.
19 | *
20 | * Created by scottab on 04/10/2014.
21 | */
22 | public final class AESCrypt {
23 |
24 | private static final String TAG = "AESCrypt";
25 |
26 | //AESCrypt-ObjC uses CBC and PKCS7Padding
27 | private static final String AES_MODE = "AES/CBC/PKCS7Padding";
28 | private static final String CHARSET = "UTF-8";
29 |
30 | //AESCrypt-ObjC uses SHA-256 (and so a 256-bit key)
31 | private static final String HASH_ALGORITHM = "SHA-256";
32 |
33 | //AESCrypt-ObjC uses blank IV (not the best security, but the aim here is compatibility)
34 | private static final byte[] ivBytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
35 |
36 | //togglable log option (please turn off in live!)
37 | public static boolean DEBUG_LOG_ENABLED = false;
38 |
39 |
40 | /**
41 | * Generates SHA256 hash of the password which is used as key
42 | *
43 | * @param password used to generated key
44 | * @return SHA256 of the password
45 | */
46 | private static SecretKeySpec generateKey(final String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
47 | final MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
48 | byte[] bytes = password.getBytes("UTF-8");
49 | digest.update(bytes, 0, bytes.length);
50 | byte[] key = digest.digest();
51 |
52 | log("SHA-256 key ", key);
53 |
54 | SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
55 | return secretKeySpec;
56 | }
57 |
58 |
59 | /**
60 | * Encrypt and encode message using 256-bit AES with key generated from password.
61 | *
62 | *
63 | * @param password used to generated key
64 | * @param message the thing you want to encrypt assumed String UTF-8
65 | * @return Base64 encoded CipherText
66 | * @throws GeneralSecurityException if problems occur during encryption
67 | */
68 | public static String encrypt(final String password, String message)
69 | throws GeneralSecurityException {
70 |
71 | try {
72 | final SecretKeySpec key = generateKey(password);
73 |
74 | log("message", message);
75 |
76 | byte[] cipherText = encrypt(key, ivBytes, message.getBytes(CHARSET));
77 |
78 | //NO_WRAP is important as was getting \n at the end
79 | String encoded = Base64.encodeToString(cipherText, Base64.NO_WRAP);
80 | log("Base64.NO_WRAP", encoded);
81 | return encoded;
82 | } catch (UnsupportedEncodingException e) {
83 | if (DEBUG_LOG_ENABLED)
84 | Log.e(TAG, "UnsupportedEncodingException ", e);
85 | throw new GeneralSecurityException(e);
86 | }
87 | }
88 |
89 |
90 | /**
91 | * More flexible AES encrypt that doesn't encode
92 | * @param key AES key typically 128, 192 or 256 bit
93 | * @param iv Initiation Vector
94 | * @param message in bytes (assumed it's already been decoded)
95 | * @return Encrypted cipher text (not encoded)
96 | * @throws GeneralSecurityException if something goes wrong during encryption
97 | */
98 | public static byte[] encrypt(final SecretKeySpec key, final byte[] iv, final byte[] message)
99 | throws GeneralSecurityException {
100 | final Cipher cipher = Cipher.getInstance(AES_MODE);
101 | IvParameterSpec ivSpec = new IvParameterSpec(iv);
102 | cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
103 | byte[] cipherText = cipher.doFinal(message);
104 |
105 | log("cipherText", cipherText);
106 |
107 | return cipherText;
108 | }
109 |
110 |
111 | /**
112 | * Decrypt and decode ciphertext using 256-bit AES with key generated from password
113 | *
114 | * @param password used to generated key
115 | * @param base64EncodedCipherText the encrpyted message encoded with base64
116 | * @return message in Plain text (String UTF-8)
117 | * @throws GeneralSecurityException if there's an issue decrypting
118 | */
119 | public static String decrypt(final String password, String base64EncodedCipherText)
120 | throws GeneralSecurityException {
121 |
122 | try {
123 | final SecretKeySpec key = generateKey(password);
124 |
125 | log("base64EncodedCipherText", base64EncodedCipherText);
126 | byte[] decodedCipherText = Base64.decode(base64EncodedCipherText, Base64.NO_WRAP);
127 | log("decodedCipherText", decodedCipherText);
128 |
129 | byte[] decryptedBytes = decrypt(key, ivBytes, decodedCipherText);
130 |
131 | log("decryptedBytes", decryptedBytes);
132 | String message = new String(decryptedBytes, CHARSET);
133 | log("message", message);
134 |
135 |
136 | return message;
137 | } catch (UnsupportedEncodingException e) {
138 | if (DEBUG_LOG_ENABLED)
139 | Log.e(TAG, "UnsupportedEncodingException ", e);
140 |
141 | throw new GeneralSecurityException(e);
142 | }
143 | }
144 |
145 |
146 | /**
147 | * More flexible AES decrypt that doesn't encode
148 | *
149 | * @param key AES key typically 128, 192 or 256 bit
150 | * @param iv Initiation Vector
151 | * @param decodedCipherText in bytes (assumed it's already been decoded)
152 | * @return Decrypted message cipher text (not encoded)
153 | * @throws GeneralSecurityException if something goes wrong during encryption
154 | */
155 | public static byte[] decrypt(final SecretKeySpec key, final byte[] iv, final byte[] decodedCipherText)
156 | throws GeneralSecurityException {
157 | final Cipher cipher = Cipher.getInstance(AES_MODE);
158 | IvParameterSpec ivSpec = new IvParameterSpec(iv);
159 | cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
160 | byte[] decryptedBytes = cipher.doFinal(decodedCipherText);
161 |
162 | log("decryptedBytes", decryptedBytes);
163 |
164 | return decryptedBytes;
165 | }
166 |
167 |
168 |
169 |
170 | private static void log(String what, byte[] bytes) {
171 | if (DEBUG_LOG_ENABLED)
172 | Log.d(TAG, what + "[" + bytes.length + "] [" + bytesToHex(bytes) + "]");
173 | }
174 |
175 | private static void log(String what, String value) {
176 | if (DEBUG_LOG_ENABLED)
177 | Log.d(TAG, what + "[" + value.length() + "] [" + value + "]");
178 | }
179 |
180 |
181 | /**
182 | * Converts byte array to hexidecimal useful for logging and fault finding
183 | * @param bytes
184 | * @return
185 | */
186 | private static String bytesToHex(byte[] bytes) {
187 | final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
188 | '9', 'A', 'B', 'C', 'D', 'E', 'F'};
189 | char[] hexChars = new char[bytes.length * 2];
190 | int v;
191 | for (int j = 0; j < bytes.length; j++) {
192 | v = bytes[j] & 0xFF;
193 | hexChars[j * 2] = hexArray[v >>> 4];
194 | hexChars[j * 2 + 1] = hexArray[v & 0x0F];
195 | }
196 | return new String(hexChars);
197 | }
198 |
199 | private AESCrypt() {
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/android/server/accessibility/remotePreferences/RemoteContract.java:
--------------------------------------------------------------------------------
1 | package com.android.server.accessibility.remotePreferences;
2 |
3 | /**
4 | * Constants used for communicating with the preference provider.
5 | * These are implementation details of the RemotePreferences API,
6 | * and should not be used by client code.
7 | */
8 | /* package */ class RemoteContract {
9 | public static final String COLUMN_KEY = "key";
10 | public static final String COLUMN_TYPE = "type";
11 | public static final String COLUMN_VALUE = "value";
12 | public static final String[] COLUMN_ALL = {
13 | RemoteContract.COLUMN_KEY,
14 | RemoteContract.COLUMN_TYPE,
15 | RemoteContract.COLUMN_VALUE
16 | };
17 |
18 | public static final int TYPE_NULL = 0;
19 | public static final int TYPE_STRING = 1;
20 | public static final int TYPE_STRING_SET = 2;
21 | public static final int TYPE_INT = 3;
22 | public static final int TYPE_LONG = 4;
23 | public static final int TYPE_FLOAT = 5;
24 | public static final int TYPE_BOOLEAN = 6;
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/android/server/accessibility/remotePreferences/RemotePreferenceAccessException.java:
--------------------------------------------------------------------------------
1 | package com.android.server.accessibility.remotePreferences;
2 |
3 | /**
4 | * Thrown if the preference provider could not be accessed.
5 | * This is commonly thrown under these conditions:
6 | *
7 | * Preference provider component is disabled
8 | * Preference provider denied access via {@link RemotePreferenceProvider#checkAccess(String, String, boolean)}
9 | * Insufficient permissions to access provider (via {@code AndroidManifest.xml})
10 | * Incorrect provider authority/file name passed to constructor
11 | *
12 | */
13 | public class RemotePreferenceAccessException extends RuntimeException {
14 | public RemotePreferenceAccessException() {
15 |
16 | }
17 |
18 | public RemotePreferenceAccessException(String detailMessage) {
19 | super(detailMessage);
20 | }
21 |
22 | public RemotePreferenceAccessException(String detailMessage, Throwable throwable) {
23 | super(detailMessage, throwable);
24 | }
25 |
26 | public RemotePreferenceAccessException(Throwable throwable) {
27 | super(throwable);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/android/server/accessibility/remotePreferences/RemoteUtils.java:
--------------------------------------------------------------------------------
1 | package com.android.server.accessibility.remotePreferences;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * Common utilities used to serialize and deserialize
8 | * preferences_didi between the preference provider and caller.
9 | */
10 | /* package */ class RemoteUtils {
11 | /**
12 | * Casts the parameter to a string set. Useful to avoid the unchecked
13 | * warning that would normally come with the cast. The value must
14 | * already be a string set; this does not deserialize it.
15 | *
16 | * @param value The value, as type {@link Object}.
17 | * @return The value, as type {@link Set}.
18 | */
19 | @SuppressWarnings("unchecked")
20 | public static Set castStringSet(Object value) {
21 | return (Set)value;
22 | }
23 |
24 | /**
25 | * Returns the {@code TYPE_*} constant corresponding to the given
26 | * object's type.
27 | *
28 | * @param value The original object.
29 | * @return One of the {@link RemoteContract}{@code .TYPE_*} constants.
30 | */
31 | public static int getPreferenceType(Object value) {
32 | if (value == null) return RemoteContract.TYPE_NULL;
33 | if (value instanceof String) return RemoteContract.TYPE_STRING;
34 | if (value instanceof Set>) return RemoteContract.TYPE_STRING_SET;
35 | if (value instanceof Integer) return RemoteContract.TYPE_INT;
36 | if (value instanceof Long) return RemoteContract.TYPE_LONG;
37 | if (value instanceof Float) return RemoteContract.TYPE_FLOAT;
38 | if (value instanceof Boolean) return RemoteContract.TYPE_BOOLEAN;
39 | throw new AssertionError("Unknown preference type: " + value.getClass());
40 | }
41 |
42 | /**
43 | * Serializes the specified object to a format that is safe to use
44 | * with {@link android.content.ContentValues}. To recover the original
45 | * object, use {@link #deserializeInput(Object, int)}.
46 | *
47 | * @param value The object to serialize.
48 | * @return The serialized object.
49 | */
50 | public static Object serializeOutput(Object value) {
51 | if (value instanceof Boolean) {
52 | return serializeBoolean((Boolean)value);
53 | } else if (value instanceof Set>) {
54 | return serializeStringSet(castStringSet(value));
55 | } else {
56 | return value;
57 | }
58 | }
59 |
60 | /**
61 | * Deserializes an object that was serialized using
62 | * {@link #serializeOutput(Object)}. If the expected type does
63 | * not match the actual type of the object, a {@link ClassCastException}
64 | * will be thrown.
65 | *
66 | * @param value The object to deserialize.
67 | * @param expectedType The expected type of the deserialized object.
68 | * @return The deserialized object.
69 | */
70 | @SuppressWarnings("RedundantCast")
71 | public static Object deserializeInput(Object value, int expectedType) {
72 | if (expectedType == RemoteContract.TYPE_NULL) {
73 | if (value != null) {
74 | throw new IllegalArgumentException("Expected null, got non-null value");
75 | } else {
76 | return null;
77 | }
78 | }
79 | try {
80 | switch (expectedType) {
81 | case RemoteContract.TYPE_STRING:
82 | return (String)value;
83 | case RemoteContract.TYPE_STRING_SET:
84 | return deserializeStringSet((String)value);
85 | case RemoteContract.TYPE_INT:
86 | return (Integer)value;
87 | case RemoteContract.TYPE_LONG:
88 | return (Long)value;
89 | case RemoteContract.TYPE_FLOAT:
90 | return (Float)value;
91 | case RemoteContract.TYPE_BOOLEAN:
92 | return deserializeBoolean(value);
93 | }
94 | } catch (ClassCastException e) {
95 | throw new IllegalArgumentException("Expected type " + expectedType + ", got " + value.getClass(), e);
96 | }
97 | throw new IllegalArgumentException("Unknown type: " + expectedType);
98 | }
99 |
100 | /**
101 | * Serializes a {@link Boolean} to a format that is safe to use
102 | * with {@link android.content.ContentValues}.
103 | *
104 | * @param value The {@link Boolean} to serialize.
105 | * @return 1 if {@code value} is {@code true}, 0 if {@code value} is {@code false}.
106 | */
107 | private static Integer serializeBoolean(Boolean value) {
108 | if (value == null) {
109 | return null;
110 | } else {
111 | return value ? 1 : 0;
112 | }
113 | }
114 |
115 | /**
116 | * Deserializes a {@link Boolean} that was serialized using
117 | * {@link #serializeBoolean(Boolean)}.
118 | *
119 | * @param value The {@link Boolean} to deserialize.
120 | * @return {@code true} if {@code value} is 1, {@code false} if {@code value} is 0.
121 | */
122 | private static Boolean deserializeBoolean(Object value) {
123 | if (value == null) {
124 | return null;
125 | } else if (value instanceof Boolean) {
126 | return (Boolean)value;
127 | } else {
128 | return (Integer)value != 0;
129 | }
130 | }
131 |
132 | /**
133 | * Serializes a {@link Set} to a format that is safe to use
134 | * with {@link android.content.ContentValues}.
135 | *
136 | * @param stringSet The {@link Set} to serialize.
137 | * @return The serialized string set.
138 | */
139 | public static String serializeStringSet(Set stringSet) {
140 | if (stringSet == null) {
141 | return null;
142 | }
143 | StringBuilder sb = new StringBuilder();
144 | for (String s : stringSet) {
145 | sb.append(s.replace("\\", "\\\\").replace(";", "\\;"));
146 | sb.append(';');
147 | }
148 | return sb.toString();
149 | }
150 |
151 | /**
152 | * Deserializes a {@link Set} that was serialized using
153 | * {@link #serializeStringSet(Set)}.
154 | *
155 | * @param serializedString The {@link Set} to deserialize.
156 | * @return The deserialized string set.
157 | */
158 | public static Set deserializeStringSet(String serializedString) {
159 | if (serializedString == null) {
160 | return null;
161 | }
162 | HashSet stringSet = new HashSet();
163 | StringBuilder sb = new StringBuilder();
164 | for (int i = 0; i < serializedString.length(); ++i) {
165 | char c = serializedString.charAt(i);
166 | if (c == '\\') {
167 | char next = serializedString.charAt(++i);
168 | sb.append(next);
169 | } else if (c == ';') {
170 | stringSet.add(sb.toString());
171 | sb.setLength(0);
172 | } else {
173 | sb.append(c);
174 | }
175 | }
176 |
177 | // Our implementation always ensures a trailing semicolon, but
178 | // as the saying goes - be conservative in what you do, be
179 | // liberal in what you accept.
180 | if (sb.length() != 0) {
181 | stringSet.add(sb.toString());
182 | }
183 |
184 | return stringSet;
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
37 |
40 |
41 |
42 |
43 |
46 |
47 |
48 |
53 |
56 |
57 |
58 |
59 |
60 |
63 |
64 |
67 |
68 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/cpp/elf_utils.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "include/config.h"
7 | #include "include/elf_utils.h"
8 | #include "include/ptrace.h"
9 | #include "include/utils.h"
10 |
11 | FILE* OpenElfFile(const char* library_path) {
12 | if (library_path != NULL) {
13 | if (DEBUG) {
14 | printf("Open ELF file: %s\n", library_path);
15 | }
16 | FILE* fp = fopen(library_path, "r");
17 | return fp;
18 | }
19 | return NULL;
20 | }
21 |
22 | void CloseElfFile(FILE* elf_file) {
23 | if (elf_file != NULL) {
24 | if (DEBUG) {
25 | printf("Close ELF file\n");
26 | }
27 | fclose(elf_file);
28 | }
29 | }
30 |
31 | void GetElfHeader(Elf64_Ehdr* elf_header, FILE* elf_file) {
32 | if (elf_header == NULL || elf_file == NULL) {
33 | return;
34 | }
35 | fseek(elf_file, 0, SEEK_SET);
36 | fread(elf_header, sizeof(Elf64_Ehdr), 1, elf_file);
37 | }
38 |
39 | size_t GetShstrtabContent(char** shstrtab_content, FILE* elf_file) {
40 | if (elf_file == NULL) {
41 | return -1;
42 | }
43 | Elf64_Ehdr* elf_header = (Elf64_Ehdr*) malloc(sizeof(Elf64_Ehdr));
44 | GetElfHeader(elf_header, elf_file);
45 | off_t shstrtab_header_offset = elf_header->e_shoff + elf_header->e_shstrndx * sizeof(Elf64_Shdr);
46 | if (DEBUG) {
47 | printf("shstrtab header offset: %lx\n", shstrtab_header_offset);
48 | }
49 | free(elf_header);
50 | Elf64_Shdr* shstrtab_header = (Elf64_Shdr*) malloc(sizeof(Elf64_Shdr));
51 | fseek(elf_file, shstrtab_header_offset, SEEK_SET);
52 | fread(shstrtab_header, sizeof(Elf64_Shdr), 1, elf_file);
53 | off_t shstrtab_base_offset = shstrtab_header->sh_offset;
54 | size_t shstrtab_size = shstrtab_header->sh_size;
55 | if (DEBUG) {
56 | printf("shstrtab base offset: %ld, shstrtab size: %u\n", shstrtab_base_offset, shstrtab_size);
57 | }
58 | free(shstrtab_header);
59 | if (shstrtab_content == NULL) {
60 | *shstrtab_content = (char*) malloc(shstrtab_size * sizeof(char));
61 | } else {
62 | *shstrtab_content = (char*) realloc(shstrtab_content, shstrtab_size * sizeof(char));
63 | }
64 | fseek(elf_file, shstrtab_base_offset, SEEK_SET);
65 | fread(*shstrtab_content, shstrtab_size, 1, elf_file);
66 | return shstrtab_size;
67 | }
68 |
69 | void GetSectionHeaderByName(Elf64_Shdr* section_header, FILE* elf_file, const char* target_section_name) {
70 | if (elf_file == NULL || target_section_name == NULL || section_header == NULL) {
71 | return;
72 | }
73 | Elf64_Ehdr* elf_header = (Elf64_Ehdr*) malloc(sizeof(Elf64_Ehdr));
74 | GetElfHeader(elf_header, elf_file);
75 | size_t section_count = elf_header->e_shnum;
76 | off_t base_section_header_offset = elf_header->e_shoff;
77 | free(elf_header);
78 | if (DEBUG) {
79 | printf("section count: %u, base section header offset: %lx\n", section_count, base_section_header_offset);
80 | }
81 | char* shstrtab_content = NULL;
82 | GetShstrtabContent(&shstrtab_content, elf_file);
83 | for(int i = 0; i < section_count; ++i) {
84 | fseek(elf_file, base_section_header_offset, SEEK_SET);
85 | fread(section_header, sizeof(Elf64_Shdr), 1, elf_file);
86 | char* section_name = shstrtab_content + section_header->sh_name;
87 | if (strcmp(section_name, target_section_name) == 0) {
88 | if (DEBUG) {
89 | printf("index: %d, section name: %s\n", i, section_name);
90 | }
91 | break;
92 | }
93 | base_section_header_offset += sizeof(Elf64_Shdr);
94 | }
95 | free(shstrtab_content);
96 | }
97 |
98 | void PatchRemoteGot(pid_t pid, const char* library_path, long original_function_addr, long target_function_addr) {
99 | if (DEBUG) {
100 | printf("Get got content of %s in process %d\n", library_path, pid);
101 | }
102 | PtraceAttach(pid);
103 | FILE* elf_file = OpenElfFile(library_path);
104 | Elf64_Shdr* got_section_header = (Elf64_Shdr*) malloc(sizeof(Elf64_Shdr));
105 | GetSectionHeaderByName(got_section_header, elf_file, ".got");
106 | size_t got_section_size = got_section_header->sh_size;
107 | off_t got_addr_offset = got_section_header->sh_addr;
108 | free(got_section_header);
109 | if (DEBUG) {
110 | printf("got section size: %u, got addr offset: %lx\n", got_section_size, got_addr_offset);
111 | }
112 | long module_base_addr = GetModuleBaseAddr(pid, library_path);
113 | long got_section_address = module_base_addr + got_addr_offset;
114 | if (DEBUG) {
115 | printf("module base addr: %lx, got section address: %lx\n", module_base_addr, got_section_address);
116 | }
117 | for (int i = 0; i < got_section_size; i += sizeof(long)) {
118 | long got_entry = ptrace(PTRACE_PEEKDATA, pid, (void *)(got_section_address + i), NULL);
119 | if (got_entry == original_function_addr) {
120 | PtraceWrite(pid, (uint8_t*)(got_section_address + i), (uint8_t*)&target_function_addr, sizeof(long));
121 | if (DEBUG) {
122 | printf("hooked got entry %d: %lx with %lx\n", i / sizeof(long), got_entry, target_function_addr);
123 | }
124 | }
125 | }
126 | PtraceDetach(pid);
127 | CloseElfFile(elf_file);
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/cpp/include/config.h:
--------------------------------------------------------------------------------
1 | #ifndef CONFIG_H_
2 | #define CONFIG_H_
3 | #define DEBUG 1
4 | #endif
5 |
--------------------------------------------------------------------------------
/app/src/main/cpp/include/elf_utils.h:
--------------------------------------------------------------------------------
1 | #ifndef ELF_UTILS_H_
2 | #define ELF_UTILS_H_
3 | #include
4 | #include
5 |
6 | FILE* OpenElfFile(const char* library_path);
7 | void CloseElfFile(FILE* elf_file);
8 | void GetElfHeader(Elf64_Ehdr* elf_header, FILE* elf_file);
9 | size_t GetShstrtabContent(char** shstrtab_content, FILE* elf_file);
10 | void GetSectionHeaderByName(Elf64_Shdr* section_header, FILE* elf_file, const char* target_section_name);
11 | void PatchRemoteGot(pid_t pid, const char* library_path, long original_function_addr, long target_function_addr);
12 | #endif
13 |
--------------------------------------------------------------------------------
/app/src/main/cpp/include/injector.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #ifndef INJECTOR_H_
4 | #define INJECTOR_H_
5 |
6 | #if defined(__aarch64__)
7 | #define LIBC_PATH "/system/lib64/libc.so"
8 | #define LINKER_PATH "/system/lib64/libdl.so"
9 | #define VNDK_LIB_PATH "/system/lib64/libRS.so"
10 | #define SHARE_LIB_PATH "/data/local2/libshare.so"
11 | #else
12 | #define LIBC_PATH "/system/lib/libc.so"
13 | #define LINKER_PATH "/system/lib/libdl.so"
14 | #define VNDK_LIB_PATH "/system/lib/libRS.so"
15 | #endif
16 |
17 | long CallMmap(pid_t pid, size_t length);
18 | long CallDlopen(pid_t pid, const char* library_path);
19 | long CallDlsym(pid_t pid, long so_handle, const char* symbol);
20 | long CallDlclose(pid_t pid, long so_handle);
21 | long InjectLibrary(pid_t pid, const char* library_path);
22 | #endif
23 |
--------------------------------------------------------------------------------
/app/src/main/cpp/include/ptrace.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #ifndef PTRACE_H_
4 | #define PTRACE_H_
5 | #define CPSR_T_MASK (1u << 5)
6 |
7 | int PtraceAttach(pid_t pid);
8 | int PtraceDetach(pid_t pid);
9 | void PtraceWrite(pid_t pid, uint8_t* addr, uint8_t* data, size_t size);
10 | long CallRemoteFunction(pid_t pid, long function_addr, long* args, size_t argc); // call function in remote process
11 | long CallRemoteFunctionFromNamespace(pid_t pid, long function_addr, long namespace_addr, long* args, size_t argc);
12 | #endif
13 |
--------------------------------------------------------------------------------
/app/src/main/cpp/include/utils.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #ifndef UTILS_H_
5 | #define UTILS_H_
6 | pid_t GetPid(const char* process_name); // get pid of specified process
7 | bool IsSelinuxEnabled(); // check the status of SELinux
8 | void DisableSelinux(); // disable SELinux
9 | long GetModuleBaseAddr(pid_t pid, const char* module_name); // get base address of specified module in given process
10 | long GetRemoteFuctionAddr(pid_t remote_pid, const char* module_name, long local_function_addr); // get fuction address in remote process
11 | #endif
12 |
--------------------------------------------------------------------------------
/app/src/main/cpp/injector.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "include/config.h"
6 | #include "include/injector.h"
7 | #include "include/ptrace.h"
8 | #include "include/utils.h"
9 |
10 | long CallMmap(pid_t pid, size_t length) {
11 | long function_addr = GetRemoteFuctionAddr(pid, LIBC_PATH, ((long) (void *) mmap));
12 | long params[6];
13 | params[0] = 0;
14 | params[1] = length;
15 | params[2] = PROT_READ | PROT_WRITE;
16 | params[3] = MAP_PRIVATE | MAP_ANONYMOUS;
17 | params[4] = 0;
18 | params[5] = 0;
19 | if (DEBUG) {
20 | printf("mmap called, function address %lx process %d size %zu\n", function_addr, pid,
21 | length);
22 | }
23 | return CallRemoteFunction(pid, function_addr, params, 6);
24 | }
25 |
26 | long CallMunmap(pid_t pid, long addr, size_t length) {
27 | long function_addr = GetRemoteFuctionAddr(pid, LIBC_PATH, ((long) (void *) munmap));
28 | long params[2];
29 | params[0] = addr;
30 | params[1] = length;
31 | if (DEBUG) {
32 | printf("munmap called, function address %lx process %d address %lx size %zu\n",
33 | function_addr, pid, addr, length);
34 | }
35 | return CallRemoteFunction(pid, function_addr, params, 2);
36 | }
37 |
38 |
39 |
40 | long CallDlopen(pid_t pid, const char *library_path) {
41 | long function_addr = GetRemoteFuctionAddr(pid, LINKER_PATH, ((long) (void *) dlopen));
42 | long mmap_ret = CallMmap(pid, 0x400);
43 | PtraceWrite(pid, (uint8_t *) mmap_ret, (uint8_t *) library_path, strlen(library_path) + 1);
44 | long params[2];
45 | params[0] = mmap_ret;
46 | params[1] = RTLD_NOW | RTLD_LOCAL;
47 | if (DEBUG) {
48 | printf("dlopen called, function address %lx process %d library path %s\n", function_addr,
49 | pid, library_path);
50 | }
51 | long vndk_return_addr = GetModuleBaseAddr(pid, VNDK_LIB_PATH);
52 | long ret = CallRemoteFunctionFromNamespace(pid, function_addr, vndk_return_addr, params, 2);
53 |
54 | CallMunmap(pid, mmap_ret, 0x400);
55 | return ret;
56 | }
57 |
58 | long CallDlsym(pid_t pid, long so_handle, const char *symbol) {
59 | long function_addr = GetRemoteFuctionAddr(pid, LINKER_PATH, ((long) (void *) dlsym));
60 | long mmap_ret = CallMmap(pid, 0x400);
61 | PtraceWrite(pid, (uint8_t *) mmap_ret, (uint8_t *) symbol, strlen(symbol) + 1);
62 | long params[2];
63 | params[0] = so_handle;
64 | params[1] = mmap_ret;
65 | if (DEBUG) {
66 | printf("dlsym called, function address %lx process %d so handle %lx symbol name %s\n",
67 | function_addr, pid, so_handle, symbol);
68 | }
69 | long ret = CallRemoteFunction(pid, function_addr, params, 2);
70 | CallMunmap(pid, mmap_ret, 0x400);
71 | return ret;
72 | }
73 |
74 |
75 |
76 |
77 | long CallDlclose(pid_t pid, long so_handle) {
78 | long function_addr = GetRemoteFuctionAddr(pid, LINKER_PATH, ((long) (void *) dlclose));
79 | long params[1];
80 | params[0] = so_handle;
81 | if (DEBUG) {
82 | printf("dlclose called, function address %lx process %d so handle %lx\n", function_addr,
83 | pid, so_handle);
84 | }
85 | return CallRemoteFunction(pid, function_addr, params, 1);
86 | }
87 |
88 |
89 | long InjectLibrary(pid_t pid, const char *library_path) {
90 | if (DEBUG) {
91 | printf("Injection started...\n");
92 | }
93 | PtraceAttach(pid);
94 | long so_handle = CallDlopen(pid, library_path);
95 | if (DEBUG) {
96 | if (!so_handle) {
97 | printf("Injection failed...\n");
98 | } else {
99 | printf("Injection ended succesfully...\n");
100 | }
101 | }
102 |
103 | /*long long addr = 0;
104 | void (*func)(int);
105 | addr = (long long)dlsym(so_handle, "hookLoad");
106 | func = addr;
107 | func(1);*/
108 |
109 |
110 | PtraceDetach(pid);
111 | return so_handle;
112 | }
113 |
--------------------------------------------------------------------------------
/app/src/main/cpp/log.h:
--------------------------------------------------------------------------------
1 | #ifndef LOG_H_
2 | #define LOG_H_
3 |
4 | #include
5 |
6 | #define ENABLE_DEBUG 1
7 |
8 | #if ENABLE_DEBUG
9 | #define LOG_TAG "INJECT"
10 | #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
11 | // #define DEBUG_PRINT(format,args...) \
12 | // LOGD(format, ##args)
13 | #define DEBUG_PRINT(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
14 | #else
15 | // #define DEBUG_PRINT(format,args...)
16 | #define DEBUG_PRINT(...)
17 | #endif
18 |
19 | #endif
--------------------------------------------------------------------------------
/app/src/main/cpp/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "include/config.h"
4 | #include "include/injector.h"
5 | #include "include/utils.h"
6 | #include "include/ptrace.h"
7 | #include "include/elf_utils.h"
8 |
9 | int main(int argc, char const *argv[]) {
10 | if (argc != 3) {
11 | printf("Usage: %s [process name] [library path]\n", argv[0]);
12 | return -1;
13 | }
14 |
15 | const char *process_name = argv[1];
16 | const char *library_path = argv[2];
17 |
18 |
19 | pid_t pid = GetPid(process_name);
20 | if (DEBUG) {
21 | printf("process name: %s, library path: %s, pid: %d\n", process_name, library_path, pid);
22 | }
23 |
24 | if (IsSelinuxEnabled()) {
25 | DisableSelinux();
26 | printf("IsSelinuxEnabled %d\n", IsSelinuxEnabled());
27 | }
28 |
29 |
30 | /*long so_handle = InjectLibrary(pid, library_path);
31 | PtraceAttach(pid);
32 | long hook_fuction_addr = CallDlsym(pid, so_handle, "my_printf");
33 |
34 | long params[1];
35 | params[0] = so_handle;
36 | params[1] = "11";
37 | if (DEBUG) {
38 | printf("dlclose called, hook_fuction_addr %lx process %d so handle %lx\n", hook_fuction_addr,
39 | pid, so_handle);
40 | }
41 | long z = CallRemoteFunction(pid, hook_fuction_addr, params, 2);
42 | PtraceDetach(pid);
43 |
44 | if (DEBUG) {
45 | printf("z = %lx\n", z);
46 | }*/
47 |
48 |
49 | long so_handle = InjectLibrary(pid, library_path);
50 | PtraceAttach(pid);
51 | long hook_fuction_addr = CallDlsym(pid, so_handle, "my_printf");
52 | long params[1];
53 | params[0] = 123;
54 | if (DEBUG) {
55 | printf("dlclose called, hook_fuction_addr %lx process %d so handle %lx\n", hook_fuction_addr,
56 | pid, so_handle);
57 | }
58 | long z = CallRemoteFunction(pid, hook_fuction_addr, params, 1);
59 | PtraceDetach(pid);
60 |
61 | if (DEBUG) {
62 | printf("z = %ld\n", z);
63 | }
64 |
65 |
66 | /*
67 | long so_handle = InjectLibrary(pid, library_path);
68 | PtraceAttach(pid);
69 | long hook_fuction_addr = CallDlsym(pid, so_handle, "my_printf");
70 | PtraceDetach(pid);
71 | long original_function_addr = GetRemoteFuctionAddr(pid, LIBC_PATH, (long)printf);
72 | if (DEBUG) {
73 | printf("hook_fuction_addr: %lx, original_function_addr: %lx\n", hook_fuction_addr, original_function_addr);
74 | }
75 |
76 | PatchRemoteGot(pid,"/data/app/com.vixkw.pubgmhd.myapplication-Vg936qRTyzMWUmeyxi4ZcQ==/lib/arm64/libnative-lib.so", original_function_addr, hook_fuction_addr);
77 |
78 | */
79 |
80 |
81 | return 0;
82 | }
83 |
--------------------------------------------------------------------------------
/app/src/main/cpp/native-lib.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #define LOG_TAG "native-lib"
10 | #define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
11 |
12 | extern "C" JNIEXPORT jstring JNICALL
13 | stringFromJNI(
14 | JNIEnv *env,
15 | jobject /* this */) {
16 |
17 |
18 | uint8_t data;
19 | int stat;
20 | int pid = 32340;//atoi() ;
21 | ptrace(PTRACE_ATTACH, pid, NULL, NULL);
22 | wait(&stat); // 如果不wait,马上进行下一个ptrace的PEEK操作会造成 no such process 错误
23 | int addr = 0x12c000000;
24 | for (; addr < 0x52c000000; ++addr) {
25 | data = ptrace(PTRACE_PEEKDATA, pid, addr, NULL); // 一次读一个字节
26 | /*if (data == 0x17 || data == 0xce) {
27 | printf("data = %x , addr = %x\n", data, addr);
28 | }*/
29 | LOG_D("data = %x , addr = %x\n", data, addr);
30 | }
31 |
32 | ptrace(PTRACE_DETACH, pid, NULL, NULL);
33 |
34 | std::string hello = "Hello from C++";
35 | return env->NewStringUTF(hello.c_str());
36 |
37 |
38 | /*
39 | uint8_t data ;
40 | int stat ;
41 | int pid = 23249;//atoi() ;
42 | ptrace(PTRACE_ATTACH, pid, NULL, NULL) ;
43 | wait(&stat) ; // 如果不wait,马上进行下一个ptrace的PEEK操作会造成 no such process 错误
44 | int addr = 0x00009000 ;
45 | for (; addr < 0x0000a000; ++addr)
46 | {
47 | data = ptrace(PTRACE_PEEKDATA, pid, addr, NULL); // 一次读一个字节
48 | if(data == 0x17 || data == 0xce){
49 | printf("data = %x , addr = %x\n" , data , addr) ;
50 | }
51 | }
52 |
53 | ptrace(PTRACE_DETACH, pid, NULL, NULL);
54 |
55 | return 1 ;*/
56 |
57 | }
--------------------------------------------------------------------------------
/app/src/main/cpp/ptrace.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "include/config.h"
7 | #include "include/ptrace.h"
8 |
9 | #if defined(__aarch64__)
10 | #define pt_regs user_pt_regs
11 | #define uregs regs
12 | #define ARM_r0 regs[0]
13 | #define ARM_lr regs[30]
14 | #define ARM_sp sp
15 | #define ARM_pc pc
16 | #define ARM_cpsr pstate
17 | #endif
18 |
19 | static void PtraceGetRegs(pid_t pid, struct pt_regs *regs);
20 | static void PtraceSetRegs(pid_t pid, struct pt_regs *regs);
21 | static void PtraceCont(pid_t pid);
22 |
23 | int PtraceAttach(pid_t pid) {
24 | if (pid == -1) {
25 | return -1;
26 | }
27 | if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
28 | perror(NULL);
29 | return -1;
30 | }
31 | waitpid(pid, NULL, WUNTRACED);
32 | if (DEBUG) {
33 | printf("Attached to process %d\n", pid);
34 | }
35 | return 0;
36 | }
37 |
38 | int PtraceDetach(pid_t pid) {
39 | if (pid == -1) {
40 | return -1;
41 | }
42 | if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {
43 | perror(NULL);
44 | return -1;
45 | }
46 | if (DEBUG) {
47 | printf("Detached from process %d\n", pid);
48 | }
49 | return 0;
50 | }
51 |
52 | void PtraceWrite(pid_t pid, uint8_t* addr, uint8_t* data, size_t size) {
53 | const size_t WORD_SIZE = sizeof(long);
54 | int mod = size % WORD_SIZE;
55 | int loop_count = size / WORD_SIZE;
56 | uint8_t* tmp_addr = addr;
57 | uint8_t* tmp_data = data;
58 | for(int i = 0; i < loop_count; ++i) {
59 | ptrace(PTRACE_POKEDATA, pid, tmp_addr, *((long*)tmp_data));
60 | tmp_addr += WORD_SIZE;
61 | tmp_data += WORD_SIZE;
62 | }
63 | if (mod > 0) {
64 | long val = ptrace(PTRACE_PEEKDATA, pid, tmp_addr, NULL);
65 | uint8_t* p = (uint8_t*) &val;
66 | for(int i = 0; i < mod; ++i) {
67 | *p = *(tmp_data);
68 | p++;
69 | tmp_data++;
70 | }
71 | ptrace(PTRACE_POKEDATA, pid, tmp_addr, val);
72 | }
73 | if (DEBUG) {
74 | printf("Write %zu bytes to %p process %d\n", size, addr, pid);
75 | }
76 | }
77 |
78 | static void PtraceGetRegs(pid_t pid, struct pt_regs *regs) {
79 | #if defined(__aarch64__)
80 | struct {
81 | void* ufb;
82 | size_t len;
83 | } regsvec = { regs, sizeof(struct pt_regs) };
84 |
85 | ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ®svec);
86 | #else
87 | ptrace(PTRACE_GETREGS, pid, NULL, regs);
88 | #endif
89 | }
90 |
91 | static void PtraceSetRegs(pid_t pid, struct pt_regs *regs) {
92 | #if defined(__aarch64__)
93 | struct {
94 | void* ufb;
95 | size_t len;
96 | } regsvec = { regs, sizeof(struct pt_regs) };
97 |
98 | ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, ®svec);
99 | #else
100 | ptrace(PTRACE_SETREGS, pid, NULL, regs);
101 | #endif
102 | }
103 |
104 | static void PtraceCont(pid_t pid) {
105 | ptrace(PTRACE_CONT, pid, NULL, NULL);
106 | }
107 |
108 | long CallRemoteFunction(pid_t pid, long function_addr, long* args, size_t argc) {
109 | return CallRemoteFunctionFromNamespace(pid, function_addr, 0, args, argc);
110 | }
111 |
112 | long CallRemoteFunctionFromNamespace(pid_t pid, long function_addr, long return_addr, long* args, size_t argc) {
113 | #if defined(__aarch64__)
114 | #define REGS_ARG_NUM 6
115 | #else
116 | #define REGS_ARG_NUM 4
117 | #endif
118 |
119 | struct pt_regs regs;
120 | // backup the original regs
121 | struct pt_regs backup_regs;
122 |
123 | PtraceGetRegs(pid, ®s);
124 | memcpy(&backup_regs, ®s, sizeof(struct pt_regs));
125 | // put the first 4 args to r0-r3
126 | for(int i = 0; i < argc && i < REGS_ARG_NUM; ++i) {
127 | regs.uregs[i] = args[i];
128 | }
129 | // push the remainder to stack
130 | if (argc > REGS_ARG_NUM) {
131 | regs.ARM_sp -= (argc - REGS_ARG_NUM) * sizeof(long);
132 | long* data = args + REGS_ARG_NUM;
133 | PtraceWrite(pid, (uint8_t*)regs.ARM_sp, (uint8_t*)data, (argc - REGS_ARG_NUM) * sizeof(long));
134 | }
135 | // set return addr to 0, so we could catch SIGSEGV
136 | regs.ARM_lr = return_addr;
137 | regs.ARM_pc = function_addr;
138 |
139 | #if !defined(__aarch64__)
140 | if (regs.ARM_pc & 1) {
141 | // thumb
142 | regs.ARM_pc &= (~1u);
143 | regs.ARM_cpsr |= CPSR_T_MASK;
144 | } else {
145 | // arm
146 | regs.ARM_cpsr &= ~CPSR_T_MASK;
147 | }
148 | #endif
149 |
150 | PtraceSetRegs(pid, ®s);
151 | PtraceCont(pid);
152 |
153 | waitpid(pid, NULL, WUNTRACED);
154 |
155 | // to get return value;
156 | PtraceGetRegs(pid, ®s);
157 | PtraceSetRegs(pid, &backup_regs);
158 | // Fuction return value
159 | if (DEBUG) {
160 | printf("Call remote function %lx with %zu arguments, return value is %llx\n",
161 | function_addr, argc, (long long)regs.ARM_r0);
162 | }
163 | return regs.ARM_r0;
164 | }
165 |
--------------------------------------------------------------------------------
/app/src/main/cpp/share.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 |
7 | #define TAG "Hook Library"
8 | #define LOG_TAG "Debug"
9 | #define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
10 |
11 | int my_printf(long l) {
12 |
13 |
14 |
15 | LOG_D("---->data = %s<-----12345 %d %ld\n", "in", getpid(),l);
16 | va_list args;
17 | /*va_start(args, format);
18 | int ret = __android_log_vprint(ANDROID_LOG_DEBUG, TAG, format, args);
19 | va_end(args);*/
20 | return 12;
21 | }
--------------------------------------------------------------------------------
/app/src/main/cpp/utils.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "include/config.h"
8 | #include "include/utils.h"
9 |
10 | pid_t GetPid(const char* process_name) {
11 | if (process_name == NULL) {
12 | return -1;
13 | }
14 | DIR* dir = opendir("/proc");
15 | if (dir == NULL) {
16 | return -1;
17 | }
18 | struct dirent* entry;
19 | while((entry = readdir(dir)) != NULL) {
20 | size_t pid = atoi(entry->d_name);
21 | if (pid != 0) {
22 | char file_name[30];
23 | snprintf(file_name, 30, "/proc/%zu/cmdline", pid);
24 | FILE *fp = fopen(file_name, "r");
25 | char temp_name[50];
26 | if (fp != NULL) {
27 | fgets(temp_name, 50, fp);
28 | fclose(fp);
29 | if (strcmp(process_name, temp_name) == 0) {
30 | return pid;
31 | }
32 | }
33 | }
34 | }
35 | return -1;
36 | }
37 |
38 | bool IsSelinuxEnabled() {
39 | FILE* fp = fopen("/proc/filesystems", "r");
40 | char* line = (char*) calloc(50, sizeof(char));
41 | bool result = false;
42 | while(fgets(line, 50, fp)) {
43 | if (strstr(line, "selinuxfs")) {
44 | result = true;
45 | }
46 | }
47 | if (line) {
48 | free(line);
49 | }
50 | fclose(fp);
51 | return result;
52 | }
53 |
54 | void DisableSelinux() {
55 | FILE* fp = fopen("/proc/mounts", "r");
56 | char* line = (char*) calloc(1024, sizeof(char));
57 | while(fgets(line, 1024, fp)) {
58 | if (strstr(line, "selinuxfs")) {
59 | strtok(line, " ");
60 | char* selinux_dir = strtok(NULL, " ");
61 | char* selinux_path = strcat(selinux_dir, "/enforce");
62 | FILE* fp_selinux = fopen(selinux_path, "w");
63 | char* buf = "0"; // set selinux to permissive
64 | fwrite(buf, strlen(buf), 1, fp_selinux);
65 | fclose(fp_selinux);
66 | break;
67 | }
68 | }
69 | fclose(fp);
70 | if (line) {
71 | free(line);
72 | }
73 | }
74 |
75 | long GetModuleBaseAddr(pid_t pid, const char* module_name) {
76 | long base_addr_long = 0;
77 | if (pid == -1) {
78 | return 0;
79 | }
80 | char* file_name = (char*) calloc(50, sizeof(char));
81 | snprintf(file_name, 50, "/proc/%d/maps", pid);
82 | FILE* fp = fopen(file_name, "r");
83 | free(file_name);
84 | char line[512];
85 | if (fp != NULL) {
86 | while(fgets(line, 512, fp) != NULL) {
87 | if (strstr(line, module_name) != NULL) {
88 | char* base_addr = strtok(line, "-");
89 | base_addr_long = strtoul(base_addr, NULL, 16);
90 | break;
91 | }
92 | }
93 | fclose(fp);
94 | }
95 | return base_addr_long;
96 | }
97 |
98 | long GetRemoteFuctionAddr(pid_t remote_pid, const char* module_name, long local_function_addr) {
99 | pid_t pid = getpid();
100 | long local_base_addr = GetModuleBaseAddr(pid, module_name);
101 | long remote_base_addr = GetModuleBaseAddr(remote_pid, module_name);
102 | if (local_base_addr == 0 || remote_base_addr == 0) {
103 | return 0;
104 | }
105 | return local_function_addr + (remote_base_addr - local_base_addr);
106 | }
107 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/AccessibilityServiceDiDiBean.kt:
--------------------------------------------------------------------------------
1 | package cn.zr
2 |
3 | import cn.zr.util.ConfigUtil
4 | import java.text.SimpleDateFormat
5 | import java.util.*
6 |
7 | class AccessibilityServiceDiDiBean(var useCarTime: Date?=null, var iDistanceUsers: Float?=null, var usersDistanceDestination: Float?=null,
8 | var theStartingPoint: CharSequence?=null, val destination: CharSequence?=null){
9 |
10 | override fun toString(): String {
11 | return "AccessibilityServiceDiDiBean(useCarTime=${SimpleDateFormat(ConfigUtil.SIMPLE_DATA_FORMAT).format(useCarTime)}, iDistanceUsers=$iDistanceUsers, usersDistanceDestination=$usersDistanceDestination, theStartingPoint=$theStartingPoint, destination=$destination)"
12 | }
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/BaseApplication.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 | import android.app.Activity;
4 | import android.app.Application;
5 | import android.util.Log;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import cn.zr.didi.DidiConfigManager;
11 |
12 | public class BaseApplication extends Application {
13 | private static final String TAG = "BaseApplication";
14 |
15 | private static final List list = new ArrayList();
16 |
17 | @Override
18 | public void onCreate() {
19 | super.onCreate();
20 | Log.d(TAG, "onCreate()");
21 | CrashHandler.getInstance().init(this);
22 | DidiConfigManager.Companion.init(this);
23 | /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
24 | String channelId = "1";
25 | NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
26 | NotificationChannel notificationChannel = new NotificationChannel(channelId, getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH);
27 | notificationChannel.setDescription(getString(R.string.description));
28 | mNotificationManager.createNotificationChannel(notificationChannel);
29 | }*/
30 | }
31 | public final void add(Activity activity){
32 | list.add(activity);
33 | }
34 | public final void remove(Activity activity){
35 | list.remove(activity);
36 | }
37 |
38 | public final void exit() {
39 | for (Activity activity : list) {
40 | if (activity != null) {
41 | activity.finish();
42 | }
43 | }
44 | System.exit(0);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/CrashHandler.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 | import android.content.Context;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.os.Build;
7 | import android.os.Environment;
8 | import android.os.Process;
9 | import android.util.Log;
10 | import android.widget.Toast;
11 |
12 | import java.io.BufferedWriter;
13 | import java.io.File;
14 | import java.io.FileWriter;
15 | import java.io.IOException;
16 | import java.io.PrintWriter;
17 | import java.io.StringWriter;
18 | import java.io.Writer;
19 | import java.lang.Thread.UncaughtExceptionHandler;
20 | import java.text.SimpleDateFormat;
21 | import java.util.Date;
22 |
23 | import cn.zr.util.ConfigUtil;
24 | import cn.zr.util.LLog;
25 |
26 | /**
27 | * Create by ChenHao on 2018/6/299:30
28 | * use : 应用异常处理类
29 | * 使用方式: 在Application 中初始化 CrashHandler.getInstance().init(this);
30 | */
31 | public class CrashHandler implements UncaughtExceptionHandler {
32 | private static final String LOG_TAG = "CrashHandler";
33 | public static final String LOG_FILE_NAME = "CrashHandlerLog.txt";
34 |
35 | private static CrashHandler sInstance = new CrashHandler();
36 | private UncaughtExceptionHandler mDefaultCrashHandler;
37 | private Context mContext;
38 |
39 |
40 | private CrashHandler() {
41 | }
42 |
43 | public static CrashHandler getInstance() {
44 | return sInstance;
45 | }
46 |
47 | public void init(Context context) {
48 | mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
49 | Thread.setDefaultUncaughtExceptionHandler(this);
50 | mContext = context.getApplicationContext();
51 |
52 | }
53 |
54 | @Override
55 | public void uncaughtException(Thread thread, Throwable ex) {
56 |
57 | LLog.Companion.d(LOG_TAG, ex + " " + ex.getMessage());
58 | if (mDefaultCrashHandler != null) {
59 | if(ex!=null){
60 | LLog.Companion.saveRuntimeLog(mContext);
61 | LLog.Companion.saveLog(mContext,LOG_FILE_NAME,(new SimpleDateFormat(LLog.SIMPLE_DATA_FORMAT).format(new Date())+"\n"+collectExceptionInfo(ex)+"\n\n\n\n\n\n\n\n").getBytes(),true);
62 | }
63 | mDefaultCrashHandler.uncaughtException(thread, ex);
64 | } else {
65 | Process.killProcess(Process.myPid());
66 | }
67 |
68 | }
69 |
70 |
71 | /**
72 | * 获取捕获异常的信息
73 | */
74 | private String collectExceptionInfo(Throwable ex) {
75 | Writer mWriter = new StringWriter();
76 | PrintWriter mPrintWriter = new PrintWriter(mWriter);
77 | ex.printStackTrace(mPrintWriter);
78 | //ex.printStackTrace();
79 | Throwable mThrowable = ex.getCause();
80 | // 迭代栈队列把所有的异常信息写入writer中
81 | while (mThrowable != null) {
82 | mThrowable.printStackTrace(mPrintWriter);
83 | // 换行 每个个异常栈之间换行
84 | mPrintWriter.append("\r\n");
85 | mThrowable = mThrowable.getCause();
86 | }
87 | // 记得关闭
88 | mPrintWriter.close();
89 | return mWriter.toString();
90 | }
91 |
92 |
93 | }
94 |
95 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/IAccessibilityManager.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | ** Copyright 2009, The Android Open Source Project
3 | **
4 | ** Licensed under the Apache License, Version 2.0 (the "License");
5 | ** you may not use this file except in compliance with the License.
6 | ** You may obtain a copy of the License at
7 | **
8 | ** http://www.apache.org/licenses/LICENSE-2.0
9 | **
10 | ** Unless required by applicable law or agreed to in writing, software
11 | ** distributed under the License is distributed on an "AS IS" BASIS,
12 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | ** See the License for the specific language governing permissions and
14 | ** limitations under the License.
15 | */
16 |
17 | package android.view.accessibility;
18 |
19 | import android.accessibilityservice.AccessibilityServiceInfo;
20 | import android.accessibilityservice.IAccessibilityServiceConnection;
21 | import android.accessibilityservice.IAccessibilityServiceClient;
22 | import android.content.ComponentName;
23 | import android.view.accessibility.AccessibilityEvent;
24 | import android.view.accessibility.AccessibilityNodeInfo;
25 | import android.view.accessibility.IAccessibilityInteractionConnection;
26 | import android.view.accessibility.IAccessibilityManagerClient;
27 | import android.view.IWindow;
28 |
29 | /**
30 | * Interface implemented by the AccessibilityManagerService called by
31 | * the AccessibilityManagers.
32 | *
33 | * @hide
34 | */
35 | interface IAccessibilityManager {
36 |
37 | oneway void interrupt(int userId);
38 |
39 | oneway void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
40 |
41 | long addClient(IAccessibilityManagerClient client, int userId);
42 |
43 | List getInstalledAccessibilityServiceList(int userId);
44 |
45 | List getEnabledAccessibilityServiceList(int feedbackType, int userId);
46 |
47 | int addAccessibilityInteractionConnection(IWindow windowToken,
48 | in IAccessibilityInteractionConnection connection, String packageName, int userId);
49 |
50 | void removeAccessibilityInteractionConnection(IWindow windowToken);
51 |
52 | void setPictureInPictureActionReplacingConnection(
53 | in IAccessibilityInteractionConnection connection);
54 |
55 | void registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient client,
56 | in AccessibilityServiceInfo info, int flags);
57 |
58 | void unregisterUiTestAutomationService(IAccessibilityServiceClient client);
59 |
60 | void temporaryEnableAccessibilityStateUntilKeyguardRemoved(in ComponentName service,
61 | boolean touchExplorationEnabled);
62 |
63 | IBinder getWindowToken(int windowId, int userId);
64 |
65 | void notifyAccessibilityButtonClicked();
66 |
67 | void notifyAccessibilityButtonVisibilityChanged(boolean available);
68 |
69 | // Requires WRITE_SECURE_SETTINGS
70 | void performAccessibilityShortcut();
71 |
72 | // System process only
73 | boolean sendFingerprintGesture(int gestureKeyCode);
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/Module.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 | import android.accessibilityservice.AccessibilityServiceInfo;
4 | import android.content.Context;
5 | import android.widget.Toast;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import cn.zr.activity.MainActivity;
11 | import de.robv.android.xposed.IXposedHookLoadPackage;
12 | import de.robv.android.xposed.XC_MethodHook;
13 | import de.robv.android.xposed.XposedBridge;
14 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
15 |
16 | import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
17 |
18 | /**
19 | * Created by lanxiaobin on 2018/1/29.
20 | * https://api.xposed.info/reference/android/app/AndroidAppHelper.html
21 | */
22 |
23 | public class Module implements IXposedHookLoadPackage {
24 |
25 | private void print(String s) {
26 | XposedBridge.log("Module" + "-->" + s + "<");
27 | }
28 |
29 | private final List prepare(List services) {
30 | if (services == null || services.isEmpty() || !(services instanceof ArrayList)) {
31 | return services;
32 | }
33 | List infos = (ArrayList) (((ArrayList) services).clone());
34 | for (int i = 0; i < services.size(); i++) {
35 | AccessibilityServiceInfo info = services.get(i);
36 | if (info.packageNames != null && info.packageNames.length > 1) {
37 | if (info.packageNames[0].equals("zzr") && info.packageNames[1].equals("com.sdu.didi.gui") && info.getSettingsActivityName().equals("cn.zr.activity.MainActivity")) {
38 | info.packageNames[1] = "kankan";
39 | return infos;
40 | }
41 | }
42 | }
43 | return services;
44 | }
45 |
46 | /**
47 | * 入口,通过反射调用
48 | *
49 | * @param loadPackageParam
50 | */
51 | @Override
52 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
53 | if (loadPackageParam.packageName.equals(BuildConfig.APPLICATION_ID)) {
54 |
55 | XC_MethodHook callback = new XC_MethodHook() {
56 |
57 | @Override
58 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
59 | super.afterHookedMethod(param);
60 | param.setResult("zr");
61 | Toast.makeText((Context) param.thisObject, "demo", Toast.LENGTH_SHORT).show();
62 | }
63 | };
64 | findAndHookMethod(MainActivity.class, "getResult", callback);
65 |
66 | }
67 |
68 | }
69 |
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/MyAccessibilityService.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 | import android.accessibilityservice.AccessibilityService;
4 | import android.util.Log;
5 | import android.view.accessibility.AccessibilityEvent;
6 |
7 | import cn.zr.helper.DidiAccessibilityServiceHelper;
8 | import cn.zr.util.LLog;
9 |
10 | public class MyAccessibilityService extends AccessibilityService {
11 | private static final String LOG_TAG = "MyAccessibilityService";
12 |
13 | private DidiAccessibilityServiceHelper didiAccessibilityServiceHelper;
14 |
15 | @Override
16 | public void onCreate() {
17 | super.onCreate();
18 | didiAccessibilityServiceHelper = new DidiAccessibilityServiceHelper(this);
19 | LLog.Companion.d(LOG_TAG, "onCreate()");
20 | didiAccessibilityServiceHelper.onCreate();
21 | /* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
22 | *//*NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
23 | NotificationChannel notificationChannel = new NotificationChannel(channelId, getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH);
24 | notificationChannel.setDescription(getString(R.string.description));
25 | mNotificationManager.createNotificationChannel(notificationChannel);*//*
26 |
27 |
28 | Notification.Builder builder = new Notification.Builder(this, "1");
29 | builder.setContentIntent(PendingIntent.getActivity(this, 0,
30 | new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT));
31 | builder.setSmallIcon(R.mipmap.ic_launcher);
32 | builder.setTicker(getString(R.string.app_name));
33 | builder.setContentTitle(getString(R.string.app_name));
34 | builder.setContentText(getString(R.string.description));
35 | Notification notification = builder.build();
36 | startForeground(1, notification);
37 | }*/
38 | }
39 | @Override
40 | public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
41 | Log.d(LOG_TAG, "onAccessibilityEvent(AccessibilityEvent accessibilityEvent)" );
42 | didiAccessibilityServiceHelper.onAccessibilityEvent(accessibilityEvent);
43 |
44 |
45 | }
46 | @Override
47 | public void onDestroy() {
48 | super.onDestroy();
49 | LLog.Companion.d(LOG_TAG, "onDestroy()");
50 | didiAccessibilityServiceHelper.onDestroy();
51 | //stopForeground(true);
52 | }
53 |
54 | @Override
55 | public void onInterrupt() {
56 | LLog.Companion.d(LOG_TAG, "onInterrupt()");
57 | }
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/Other.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Binder;
6 | import android.util.Log;
7 |
8 | import java.io.File;
9 | import java.util.Date;
10 |
11 | import de.robv.android.xposed.XposedBridge;
12 |
13 | public class Other {
14 |
15 | static {
16 | //System.loadLibrary("native-lib");
17 | //System.loadLibrary("share");
18 | }
19 |
20 | private static final String TAG = "Other";
21 |
22 | //public native String stringFromJNI();
23 | public Other() {
24 | }
25 |
26 | public static File getApk() {
27 | for (File file : new File("data/app/").listFiles()) {
28 | if (file.getName().startsWith(BuildConfig.APPLICATION_ID)) {
29 | return new File(file.getPath(), "base.apk");
30 | }
31 | }
32 | return null;
33 | }
34 |
35 | public String getCallerProcessName(Context context) {
36 | int uid = Binder.getCallingUid();
37 | String callingApp = context.getPackageManager().getNameForUid(uid);
38 | Log.d(TAG, "callingApp: " + callingApp);
39 | if (callingApp != null) {
40 | return callingApp;
41 | }
42 | return "";
43 | }
44 |
45 |
46 | public static final String getRandomPackageName() {
47 | String packageName = "com.";
48 |
49 | int ra0 = (int) (Math.random() * 11 + 1);
50 | int ra1 = (int) (Math.random() * 6);
51 |
52 | for (int i = 0; i < ra0; i++) {
53 | packageName += (char) (Math.random() * 26 + 'a');
54 | }
55 | packageName += ".";
56 | for (int i = 0; i < ra0; i++) {
57 | packageName += (char) (Math.random() * 26 + 'a');
58 | }
59 |
60 | return packageName;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/PackageHooker.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 | import java.awt.font.TextAttribute;
4 | import java.io.IOException;
5 | import java.lang.reflect.Method;
6 | import java.lang.reflect.Modifier;
7 | import java.util.Enumeration;
8 |
9 | import dalvik.system.DexFile;
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 | * Created by mbpeele on 2/24/16.//https://github.com/UMLGenerator/Android-UML-Generator/blob/f26521e9420d4be032c2e4a1a872ac0c945c7c2e/xposed/src/main/java/software/umlgenerator/PackageHooker.java
16 | *adb shell uiautomator dump /data/local/tmp/app.uix
17 | * adb pull /data/local/tmp/app.uix C:\Users\Administrator\Desktop
18 | *
19 | * adb shell screencap -p /data/local/tmp/app.png
20 | * adb pull /data/local/tmp/app.png C:\Users\Administrator\Desktop
21 |
22 | */
23 | public class PackageHooker {
24 |
25 |
26 | private final XC_LoadPackage.LoadPackageParam loadPackageParam;
27 |
28 | private void print(String s) {
29 | XposedBridge.log("PackageHooker" + "-->" + s + "<");
30 | }
31 |
32 | private PackageHooker(XC_LoadPackage.LoadPackageParam param) {
33 | loadPackageParam = param;
34 | }
35 |
36 | public static void assist(XC_LoadPackage.LoadPackageParam param) {
37 | try {
38 | new PackageHooker(param).hook();
39 | } catch (IOException e) {
40 | e.printStackTrace();
41 | } catch (ClassNotFoundException e) {
42 | e.printStackTrace();
43 | }
44 | }
45 |
46 | private void hook() throws IOException, ClassNotFoundException {
47 | DexFile dexFile = new DexFile(loadPackageParam.appInfo.sourceDir);
48 | Enumeration classNames = dexFile.entries();
49 | while (classNames.hasMoreElements()) {
50 | String className = classNames.nextElement();
51 | /*if (className.startsWith("de.robv.android.xposed") || className.startsWith(Module.class.getCanonicalName())) {
52 | continue;
53 | }*/
54 | //print("className-->" + className);
55 | if (isClassNameValid(className)) {
56 | Class clazz = Class.forName(className, false, loadPackageParam.classLoader);
57 |
58 | for (Method method : clazz.getDeclaredMethods()) {
59 | if (!Modifier.isAbstract(method.getModifiers())) {
60 | XposedBridge.hookMethod(method, new XC_MethodHook() {
61 | @Override
62 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
63 | StringBuilder sb = new StringBuilder();
64 | sb.append(param.method.getName() + " " + param.method.getDeclaringClass() + " ");
65 |
66 | if (param.args != null) {
67 | sb.append(param.args.length + "(");
68 | for (Object obj : param.args) {
69 | sb.append((obj == null ? null : obj.getClass().getCanonicalName()) + " " + getValue(obj) + " ");
70 | }
71 | sb.append(") ");
72 | }
73 | Object result = param.getResultOrThrowable();
74 | sb.append("(" + (result == null ? null : result.getClass().getCanonicalName()) + " " + getValue(result) + ")");
75 | print("HOOKED: " + sb.toString());
76 | }
77 | });
78 | }
79 | }
80 | }
81 | }
82 | }
83 |
84 | public boolean isClassNameValid(String className) {
85 | return
86 | className.startsWith(loadPackageParam.packageName)
87 | //&& !className.contains("$")
88 | &&
89 |
90 | !className.contains("BuildConfig")
91 | && !className.equals(loadPackageParam.packageName + ".R");
92 | }
93 |
94 | private final String getValue(Object obj) {
95 | if (obj == null) {
96 | return "";
97 | } else if (obj instanceof Boolean) {
98 | return (Boolean) obj + "";
99 | } else if (obj instanceof Integer) {
100 | return (Integer) obj + "";
101 | } else if (obj instanceof Short) {
102 | return (Short) obj + "";
103 | } else if (obj instanceof Float) {
104 | return (Float) obj + "";
105 | } else if (obj instanceof Double) {
106 | return (Double) obj + "";
107 | } else if (obj instanceof Character) {
108 | return (Character) obj + "";
109 | } else if (obj instanceof Long) {
110 | return (Long) obj + "";
111 | } else if (obj instanceof Byte) {
112 | return (Byte) obj + "";
113 | } else if (obj instanceof String) {
114 | return (String) obj;
115 | } else if (obj instanceof Object) {
116 | return "";
117 | } else {
118 | return "";
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/SuspensionWindow.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.graphics.PixelFormat;
6 | import android.os.Build;
7 | import android.os.Handler;
8 | import android.os.Looper;
9 | import android.os.Message;
10 | import android.util.Log;
11 | import android.view.Gravity;
12 | import android.view.MotionEvent;
13 | import android.view.View;
14 | import android.view.WindowManager;
15 | import android.widget.TextView;
16 |
17 | import cn.zr.activity.MainActivity;
18 | import cn.zr.util.DensityUtils;
19 |
20 | /**
21 | * Created by zhongxiang.huang on 2017/6/23.
22 | */
23 |
24 | public class SuspensionWindow implements View.OnTouchListener {
25 |
26 |
27 | private static SuspensionWindow INSTANCE = null;
28 |
29 | public static void showSuspensionWindow(Context context) {
30 | if (INSTANCE == null) {
31 | INSTANCE = new SuspensionWindow(context.getApplicationContext());
32 | }
33 | INSTANCE.show();
34 | }
35 |
36 | public static void dismissSuspensionWindow() {
37 | if (INSTANCE != null) {
38 | INSTANCE.hide();
39 | }
40 | }
41 |
42 | private static final String TAG = "SuspensionWindow";
43 |
44 |
45 | private WindowManager.LayoutParams layoutParams;
46 | private WindowManager windowManager;
47 |
48 | private View view;
49 |
50 | private int width, height;
51 |
52 |
53 | private static final Handler handler = new Handler(Looper.getMainLooper()) {
54 | @Override
55 | public void handleMessage(Message msg) {
56 | super.handleMessage(msg);
57 | if (INSTANCE != null) {
58 | INSTANCE.textView.setText((CharSequence) msg.obj);
59 | }
60 | }
61 | };
62 |
63 | public static void showMsg(CharSequence charSequence) {
64 | if (charSequence == null || INSTANCE == null) {
65 | return;
66 | }
67 | Message msg = Message.obtain();
68 | msg.obj = charSequence;
69 | handler.sendMessage(msg);
70 | }
71 |
72 | private TextView textView;
73 |
74 | private SuspensionWindow(final Context context) {
75 | width = height = DensityUtils.dp2px(context, 46);
76 |
77 | Log.d(TAG, "SuspensionWindow(Context context)");
78 |
79 | textView = new TextView(context);
80 | textView.setBackgroundColor(0xaa000000);
81 | textView.setTextColor(0xffffffff);
82 | textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
83 | textView.setText(context.getString(R.string.app_name));
84 | textView.setOnClickListener(new View.OnClickListener() {
85 | @Override
86 | public void onClick(View view) {
87 | Intent intent = new Intent(context, MainActivity.class);
88 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
89 | context.startActivity(intent);
90 | }
91 | });
92 | view = textView;
93 | view.setOnTouchListener(this);
94 |
95 | layoutParams = new WindowManager.LayoutParams();
96 | windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
97 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//8.0新特性
98 | layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
99 | } else {
100 | layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
101 | }
102 | layoutParams.format = PixelFormat.RGBA_8888;
103 | layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
104 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
105 | layoutParams.flags = layoutParams.flags | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
106 | }
107 | layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
108 | layoutParams.width = width;
109 | layoutParams.height = height;
110 | }
111 |
112 |
113 | @Override
114 | public boolean onTouch(View view, MotionEvent motionEvent) {
115 | return floatLayoutTouch(motionEvent);
116 | }
117 |
118 |
119 | private float rawX0, rawY0, rawX, rawY, x, y;
120 |
121 |
122 | private boolean move = false;
123 |
124 | private boolean floatLayoutTouch(MotionEvent motionEvent) {
125 |
126 | switch (motionEvent.getAction()) {
127 | case MotionEvent.ACTION_DOWN:
128 | x = motionEvent.getX();
129 | y = motionEvent.getY();
130 | rawX0 = motionEvent.getRawX();
131 | rawY0 = motionEvent.getRawY();
132 | move = false;
133 | break;
134 | case MotionEvent.ACTION_MOVE:
135 | rawX = motionEvent.getRawX();
136 | rawY = motionEvent.getRawY();
137 | layoutParams.x = (int) (rawX - x);
138 | layoutParams.y = (int) (rawY - y);
139 | windowManager.updateViewLayout(view, layoutParams);
140 | if (Math.abs(rawX0 - rawX) > 10 || Math.abs(rawY0 - rawY) > 10) {
141 | move = true;
142 | } else {
143 | move = false;
144 | }
145 | break;
146 | case MotionEvent.ACTION_UP:
147 | break;
148 | }
149 | return move;
150 | }
151 |
152 | public void show() {
153 | Log.d(TAG, "show()" + view.getParent() + "" + this.hashCode());
154 |
155 | if (view.getParent() == null) {
156 | Context context = view.getContext();
157 | layoutParams.x = context.getResources().getDisplayMetrics().widthPixels;
158 | layoutParams.y = DensityUtils.dp2px(context, 122);
159 | windowManager.addView(view, layoutParams);
160 | }
161 | }
162 |
163 | public void hide() {
164 | Log.d(TAG, "hide()" + view.getParent());
165 | if (view.getParent() != null)
166 | windowManager.removeView(view);
167 | }
168 |
169 |
170 | }
171 |
172 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/TestModule.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 | import android.accessibilityservice.AccessibilityServiceInfo;
4 | import android.content.Context;
5 | import android.content.SharedPreferences;
6 | import android.content.pm.PackageManager;
7 | import android.util.Log;
8 | import android.view.accessibility.AccessibilityManager;
9 |
10 | import java.lang.reflect.Method;
11 | import java.util.List;
12 |
13 | import cn.zr.contentProviderPreference.RemotePreferences;
14 | import dalvik.system.PathClassLoader;
15 | import de.robv.android.xposed.IXposedHookLoadPackage;
16 | import de.robv.android.xposed.IXposedHookZygoteInit;
17 | import de.robv.android.xposed.XC_MethodReplacement;
18 | import de.robv.android.xposed.XposedBridge;
19 | import de.robv.android.xposed.XposedHelpers;
20 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
21 |
22 | /*
23 |
24 | adb install C:\Users\Administrator\Desktop\backup\release\app-release.apk
25 | adb push C:\Users\Administrator\Desktop\backup\release\app-release.apk sdcard/Download/
26 |
27 | com.sdu.didi.gsui
28 | */
29 | public class TestModule implements IXposedHookLoadPackage {
30 | private void print(String s) {
31 | XposedBridge.log("TestModule" + "-->" + s + "<");
32 | }
33 |
34 | @Override
35 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
36 | Context systemContext = (Context) XposedHelpers.callMethod(XposedHelpers.callStaticMethod(XposedHelpers.findClass("android.app.ActivityThread", lpparam.classLoader), "currentActivityThread"), "getSystemContext");
37 | SharedPreferences prefs = new RemotePreferences(systemContext, "cn.zr.preferences_didi", "other_preferences");
38 |
39 | print(lpparam.packageName + " " + systemContext.getPackageManager().getPackageInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_ACTIVITIES).versionCode + "");
40 | String packageSourceDir;
41 | if (lpparam.packageName.equals(BuildConfig.APPLICATION_ID)) {
42 | prefs.edit().putString("sourceDir", packageSourceDir = lpparam.appInfo.sourceDir).apply();
43 | } else {
44 | packageSourceDir = prefs.getString("sourceDir", systemContext.getPackageManager().getApplicationInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_META_DATA).sourceDir);
45 | }
46 | //print("getString sourceDir" + packageSourceDir);
47 |
48 |
49 | PathClassLoader pathClassLoader = new PathClassLoader(packageSourceDir, ClassLoader.getSystemClassLoader());
50 | Class> aClass = Class.forName(Module.class.getCanonicalName(), true, pathClassLoader);
51 | Method aClassMethod = aClass.getMethod("handleLoadPackage", XC_LoadPackage.LoadPackageParam.class);
52 | aClassMethod.invoke(aClass.newInstance(), lpparam);
53 | }
54 |
55 |
56 |
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/XposedInit.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 |
4 | import android.accessibilityservice.AccessibilityServiceInfo;
5 | import android.app.AndroidAppHelper;
6 | import android.content.Context;
7 | import android.content.SharedPreferences;
8 | import android.content.pm.PackageManager;
9 | import android.content.res.XResources;
10 | import android.view.accessibility.AccessibilityManager;
11 |
12 | import java.lang.reflect.Method;
13 | import java.util.List;
14 |
15 | import cn.zr.contentProviderPreference.RemotePreferenceAccessException;
16 | import cn.zr.contentProviderPreference.RemotePreferences;
17 | import dalvik.system.PathClassLoader;
18 | import de.robv.android.xposed.IXposedHookLoadPackage;
19 | import de.robv.android.xposed.IXposedHookZygoteInit;
20 | import de.robv.android.xposed.XC_MethodHook;
21 | import de.robv.android.xposed.XC_MethodReplacement;
22 | import de.robv.android.xposed.XSharedPreferences;
23 | import de.robv.android.xposed.XposedBridge;
24 | import de.robv.android.xposed.XposedHelpers;
25 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
26 |
27 | import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
28 | import static de.robv.android.xposed.XposedHelpers.findClass;
29 |
30 | public class XposedInit implements IXposedHookLoadPackage, IXposedHookZygoteInit {
31 |
32 | @Override
33 | public void initZygote(StartupParam startupParam) throws Throwable {
34 | try {
35 | Zr.assist();
36 | } catch (Throwable t) {
37 | print(t.getMessage());
38 | }
39 | }
40 |
41 | private void print(String s) {
42 | XposedBridge.log("XposedInit" + "-->" + s + "<");
43 | }
44 |
45 | @Override
46 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
47 | print(lpparam.packageName);
48 |
49 | if (BuildConfig.DEBUG) {
50 | new TestModule().handleLoadPackage(lpparam);
51 | } else {
52 | new Module().handleLoadPackage(lpparam);
53 | }
54 |
55 | }
56 |
57 |
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/Zr.java:
--------------------------------------------------------------------------------
1 | package cn.zr;
2 |
3 | import android.accessibilityservice.AccessibilityServiceInfo;
4 | import android.view.accessibility.AccessibilityManager;
5 |
6 | import java.util.List;
7 |
8 | import de.robv.android.xposed.XC_MethodHook;
9 | import de.robv.android.xposed.XposedBridge;
10 | import de.robv.android.xposed.XposedHelpers;
11 |
12 | public class Zr {
13 | private void print(String s) {
14 | XposedBridge.log("XposedInit" + "-->" + s + "<");
15 | }
16 | public static void assist(){
17 | new Zr().zr();
18 | }
19 | private void zr(){
20 | XposedHelpers.findAndHookMethod(AccessibilityManager.class, "getEnabledAccessibilityServiceList", Integer.TYPE, new XC_MethodHook() {
21 | @Override
22 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
23 | super.afterHookedMethod(param);
24 | Object obj = param.getResult();
25 | if (obj != null) {
26 | List list = (List) obj;
27 | for (int i = 0; i < list.size(); i++) {
28 | StringBuilder sb = new StringBuilder();
29 |
30 | String[] arr = list.get(i).packageNames;
31 | for (int z = 0; z < arr.length; z++) {
32 | sb.append(arr[z] + "\t");
33 | StringBuilder sb0 = new StringBuilder();
34 | sb0.append("com");
35 | sb0.append("sdu");
36 | sb0.append("didi");
37 | sb0.append("gsui");
38 | if (arr[z].equals(sb0.toString())) {
39 | arr[z] = "com.google.check";
40 | }
41 | }
42 |
43 | print("emptyList" + sb.toString());
44 | }
45 | }
46 | param.setResult(obj);
47 |
48 | }
49 |
50 |
51 | });
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/activity/BaseAppCompatActivity.kt:
--------------------------------------------------------------------------------
1 | package cn.zr.activity
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.AppCompatActivity
5 | import cn.zr.BaseApplication
6 |
7 | open class BaseAppCompatActivity: AppCompatActivity() {
8 |
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | (applicationContext as BaseApplication).add(this)
12 | }
13 |
14 | override fun onDestroy() {
15 | super.onDestroy()
16 | (applicationContext as BaseApplication).remove(this)
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/config/TimeQuantum.kt:
--------------------------------------------------------------------------------
1 | package cn.zr.config
2 |
3 | import java.util.*
4 |
5 | class TimeQuantum(var startTime: Date, var endTime: Date)
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/contentProviderPreference/MyPreferenceProvider.java:
--------------------------------------------------------------------------------
1 | package cn.zr.contentProviderPreference;
2 |
3 | //Outgoing transactions from this process must be FLAG_ONEWAY
4 | public class MyPreferenceProvider extends RemotePreferenceProvider {
5 | public MyPreferenceProvider() {
6 |
7 | super("cn.zr.preferences", new String[]{"main_prefs"});
8 | /*super("cn.zr.preferences_didi", new RemotePreferenceFile[] {
9 | new RemotePreferenceFile("main_prefs", true)
10 | });*/
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/contentProviderPreference/RemoteContract.java:
--------------------------------------------------------------------------------
1 | package cn.zr.contentProviderPreference;
2 |
3 | /**
4 | * Constants used for communicating with the preference provider.
5 | * These are implementation details of the RemotePreferences API,
6 | * and should not be used by client code.
7 | */
8 | /* package */ class RemoteContract {
9 | public static final String COLUMN_KEY = "key";
10 | public static final String COLUMN_TYPE = "type";
11 | public static final String COLUMN_VALUE = "value";
12 | public static final String[] COLUMN_ALL = {
13 | RemoteContract.COLUMN_KEY,
14 | RemoteContract.COLUMN_TYPE,
15 | RemoteContract.COLUMN_VALUE
16 | };
17 |
18 | public static final int TYPE_NULL = 0;
19 | public static final int TYPE_STRING = 1;
20 | public static final int TYPE_STRING_SET = 2;
21 | public static final int TYPE_INT = 3;
22 | public static final int TYPE_LONG = 4;
23 | public static final int TYPE_FLOAT = 5;
24 | public static final int TYPE_BOOLEAN = 6;
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/contentProviderPreference/RemotePreferenceAccessException.java:
--------------------------------------------------------------------------------
1 | package cn.zr.contentProviderPreference;
2 |
3 | /**
4 | * Thrown if the preference provider could not be accessed.
5 | * This is commonly thrown under these conditions:
6 | *
7 | * Preference provider component is disabled
8 | * Preference provider denied access via {@link RemotePreferenceProvider#checkAccess(String, String, boolean)}
9 | * Insufficient permissions to access provider (via {@code AndroidManifest.xml})
10 | * Incorrect provider authority/file name passed to constructor
11 | *
12 | */
13 | public class RemotePreferenceAccessException extends RuntimeException {
14 | public RemotePreferenceAccessException() {
15 |
16 | }
17 |
18 | public RemotePreferenceAccessException(String detailMessage) {
19 | super(detailMessage);
20 | }
21 |
22 | public RemotePreferenceAccessException(String detailMessage, Throwable throwable) {
23 | super(detailMessage, throwable);
24 | }
25 |
26 | public RemotePreferenceAccessException(Throwable throwable) {
27 | super(throwable);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/contentProviderPreference/RemoteUtils.java:
--------------------------------------------------------------------------------
1 | package cn.zr.contentProviderPreference;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * Common utilities used to serialize and deserialize
8 | * preferences_didi between the preference provider and caller.
9 | */
10 | /* package */ class RemoteUtils {
11 | /**
12 | * Casts the parameter to a string set. Useful to avoid the unchecked
13 | * warning that would normally come with the cast. The value must
14 | * already be a string set; this does not deserialize it.
15 | *
16 | * @param value The value, as type {@link Object}.
17 | * @return The value, as type {@link Set}.
18 | */
19 | @SuppressWarnings("unchecked")
20 | public static Set castStringSet(Object value) {
21 | return (Set)value;
22 | }
23 |
24 | /**
25 | * Returns the {@code TYPE_*} constant corresponding to the given
26 | * object's type.
27 | *
28 | * @param value The original object.
29 | * @return One of the {@link RemoteContract}{@code .TYPE_*} constants.
30 | */
31 | public static int getPreferenceType(Object value) {
32 | if (value == null) return RemoteContract.TYPE_NULL;
33 | if (value instanceof String) return RemoteContract.TYPE_STRING;
34 | if (value instanceof Set>) return RemoteContract.TYPE_STRING_SET;
35 | if (value instanceof Integer) return RemoteContract.TYPE_INT;
36 | if (value instanceof Long) return RemoteContract.TYPE_LONG;
37 | if (value instanceof Float) return RemoteContract.TYPE_FLOAT;
38 | if (value instanceof Boolean) return RemoteContract.TYPE_BOOLEAN;
39 | throw new AssertionError("Unknown preference type: " + value.getClass());
40 | }
41 |
42 | /**
43 | * Serializes the specified object to a format that is safe to use
44 | * with {@link android.content.ContentValues}. To recover the original
45 | * object, use {@link #deserializeInput(Object, int)}.
46 | *
47 | * @param value The object to serialize.
48 | * @return The serialized object.
49 | */
50 | public static Object serializeOutput(Object value) {
51 | if (value instanceof Boolean) {
52 | return serializeBoolean((Boolean)value);
53 | } else if (value instanceof Set>) {
54 | return serializeStringSet(castStringSet(value));
55 | } else {
56 | return value;
57 | }
58 | }
59 |
60 | /**
61 | * Deserializes an object that was serialized using
62 | * {@link #serializeOutput(Object)}. If the expected type does
63 | * not match the actual type of the object, a {@link ClassCastException}
64 | * will be thrown.
65 | *
66 | * @param value The object to deserialize.
67 | * @param expectedType The expected type of the deserialized object.
68 | * @return The deserialized object.
69 | */
70 | @SuppressWarnings("RedundantCast")
71 | public static Object deserializeInput(Object value, int expectedType) {
72 | if (expectedType == RemoteContract.TYPE_NULL) {
73 | if (value != null) {
74 | throw new IllegalArgumentException("Expected null, got non-null value");
75 | } else {
76 | return null;
77 | }
78 | }
79 | try {
80 | switch (expectedType) {
81 | case RemoteContract.TYPE_STRING:
82 | return (String)value;
83 | case RemoteContract.TYPE_STRING_SET:
84 | return deserializeStringSet((String)value);
85 | case RemoteContract.TYPE_INT:
86 | return (Integer)value;
87 | case RemoteContract.TYPE_LONG:
88 | return (Long)value;
89 | case RemoteContract.TYPE_FLOAT:
90 | return (Float)value;
91 | case RemoteContract.TYPE_BOOLEAN:
92 | return deserializeBoolean(value);
93 | }
94 | } catch (ClassCastException e) {
95 | throw new IllegalArgumentException("Expected type " + expectedType + ", got " + value.getClass(), e);
96 | }
97 | throw new IllegalArgumentException("Unknown type: " + expectedType);
98 | }
99 |
100 | /**
101 | * Serializes a {@link Boolean} to a format that is safe to use
102 | * with {@link android.content.ContentValues}.
103 | *
104 | * @param value The {@link Boolean} to serialize.
105 | * @return 1 if {@code value} is {@code true}, 0 if {@code value} is {@code false}.
106 | */
107 | private static Integer serializeBoolean(Boolean value) {
108 | if (value == null) {
109 | return null;
110 | } else {
111 | return value ? 1 : 0;
112 | }
113 | }
114 |
115 | /**
116 | * Deserializes a {@link Boolean} that was serialized using
117 | * {@link #serializeBoolean(Boolean)}.
118 | *
119 | * @param value The {@link Boolean} to deserialize.
120 | * @return {@code true} if {@code value} is 1, {@code false} if {@code value} is 0.
121 | */
122 | private static Boolean deserializeBoolean(Object value) {
123 | if (value == null) {
124 | return null;
125 | } else if (value instanceof Boolean) {
126 | return (Boolean)value;
127 | } else {
128 | return (Integer)value != 0;
129 | }
130 | }
131 |
132 | /**
133 | * Serializes a {@link Set} to a format that is safe to use
134 | * with {@link android.content.ContentValues}.
135 | *
136 | * @param stringSet The {@link Set} to serialize.
137 | * @return The serialized string set.
138 | */
139 | public static String serializeStringSet(Set stringSet) {
140 | if (stringSet == null) {
141 | return null;
142 | }
143 | StringBuilder sb = new StringBuilder();
144 | for (String s : stringSet) {
145 | sb.append(s.replace("\\", "\\\\").replace(";", "\\;"));
146 | sb.append(';');
147 | }
148 | return sb.toString();
149 | }
150 |
151 | /**
152 | * Deserializes a {@link Set} that was serialized using
153 | * {@link #serializeStringSet(Set)}.
154 | *
155 | * @param serializedString The {@link Set} to deserialize.
156 | * @return The deserialized string set.
157 | */
158 | public static Set deserializeStringSet(String serializedString) {
159 | if (serializedString == null) {
160 | return null;
161 | }
162 | HashSet stringSet = new HashSet();
163 | StringBuilder sb = new StringBuilder();
164 | for (int i = 0; i < serializedString.length(); ++i) {
165 | char c = serializedString.charAt(i);
166 | if (c == '\\') {
167 | char next = serializedString.charAt(++i);
168 | sb.append(next);
169 | } else if (c == ';') {
170 | stringSet.add(sb.toString());
171 | sb.setLength(0);
172 | } else {
173 | sb.append(c);
174 | }
175 | }
176 |
177 | // Our implementation always ensures a trailing semicolon, but
178 | // as the saying goes - be conservative in what you do, be
179 | // liberal in what you accept.
180 | if (sb.length() != 0) {
181 | stringSet.add(sb.toString());
182 | }
183 |
184 | return stringSet;
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/didi/DidiConfigManager.kt:
--------------------------------------------------------------------------------
1 | package cn.zr.didi
2 |
3 | import android.content.Context
4 | import android.support.v7.preference.PreferenceManager
5 | import cn.zr.AccessibilityServiceDiDiBean
6 | import cn.zr.util.ConfigUtil
7 | import cn.zr.config.TimeQuantum
8 | import cn.zr.util.LLog
9 | import java.text.SimpleDateFormat
10 | import java.util.ArrayList
11 |
12 | class DidiConfigManager private constructor() {
13 |
14 | lateinit var useCarTime: TimeQuantum
15 | var useCarTimeSate: String = "0"
16 |
17 | var iDistanceUsers: Float = 0.0f
18 | var iDistanceUsersSate: String = "0"
19 | var usersDistanceDestination: Float = 0.0f
20 | var userDistanceDestinationState: String = "0"
21 |
22 | var theStartingPointKeywords: ArrayList? = null
23 | var theStartingPointState: String = "0"
24 | var destinationKeywords: ArrayList? = null
25 | var destinationState: String = "0"
26 |
27 | /*var farthestDrive: Double = 0.0
28 | var farthestDriveState: String = "0"*/
29 |
30 | var clickRandomDelay: Int = 20
31 |
32 |
33 | var isShowSuspensionWindow: Boolean = false
34 |
35 |
36 | fun check(accessibilityServiceDiDiBean: AccessibilityServiceDiDiBean): Boolean {
37 | if (
38 | accessibilityServiceDiDiBean.useCarTime == null ||
39 | accessibilityServiceDiDiBean.iDistanceUsers == null ||
40 | accessibilityServiceDiDiBean.usersDistanceDestination == null ||
41 | accessibilityServiceDiDiBean.theStartingPoint == null ||
42 | accessibilityServiceDiDiBean.destination == null
43 | ) {
44 | LLog.d(LOG_TAG, "check error")
45 | return false
46 | }
47 |
48 |
49 |
50 | accessibilityServiceDiDiBean.useCarTime?.apply {
51 | if (useCarTimeSate != "0") {
52 | if (!(useCarTime.startTime <= this && this <= useCarTime.endTime)) {
53 | return false
54 | }
55 | }
56 | }
57 |
58 |
59 | accessibilityServiceDiDiBean.iDistanceUsers?.apply {
60 | if (iDistanceUsersSate != "0" && iDistanceUsers >= this) {
61 | return false
62 | }
63 | }
64 | accessibilityServiceDiDiBean.usersDistanceDestination?.apply {
65 | if (userDistanceDestinationState != "0" && usersDistanceDestination <= this) {
66 | return false
67 | }
68 | }
69 |
70 |
71 |
72 | accessibilityServiceDiDiBean.theStartingPoint?.apply {
73 | var contains = false
74 | theStartingPointKeywords?.forEach {
75 | if (this.contains(it)) {
76 | contains = true
77 | return@forEach
78 | }
79 | }
80 | when (theStartingPointState) {
81 | "2" -> {
82 | if (!contains) {
83 | return false
84 | }
85 | }
86 | "1" -> {
87 | if (contains) {
88 | return false
89 | }
90 | }
91 | }
92 | }
93 | accessibilityServiceDiDiBean.destination?.apply {
94 | var contains = false
95 | destinationKeywords?.forEach {
96 | if (this.contains(it)) {
97 | contains = true
98 | return@forEach
99 | }
100 | }
101 | when (destinationState) {
102 | "2" -> {
103 | if (!contains) {
104 | return false
105 | }
106 | }
107 | "1" -> {
108 | if (contains) {
109 | return false
110 | }
111 | }
112 | }
113 | }
114 |
115 |
116 |
117 |
118 |
119 |
120 | return true
121 | }
122 |
123 | override fun toString(): String {
124 | return "DidiConfigManager(useCarTime=$useCarTime, useCarTimeSate='$useCarTimeSate', iDistanceUsers=$iDistanceUsers, iDistanceUsersSate='$iDistanceUsersSate', usersDistanceDestination=$usersDistanceDestination, userDistanceDestinationState='$userDistanceDestinationState', theStartingPointKeywords=$theStartingPointKeywords, theStartingPointState='$theStartingPointState', destinationKeywords=$destinationKeywords, destinationState='$destinationState', clickRandomDelay=$clickRandomDelay, isShowSuspensionWindow=$isShowSuspensionWindow)"
125 | }
126 |
127 |
128 | companion object {
129 |
130 | private const val LOG_TAG = "DidiConfigManager"
131 | private val configManager = DidiConfigManager()
132 |
133 |
134 | fun init(context: Context) {
135 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
136 | val simpleDateFormat = SimpleDateFormat(ConfigUtil.SIMPLE_DATA_FORMAT)
137 | configManager.useCarTime = ConfigUtil.parseTimeQuantum(sharedPreferences.getString("use_car_time_key", "${simpleDateFormat.format(System.currentTimeMillis())}" +
138 | "${ConfigUtil.SPLIT_FLAG}" +
139 | "${simpleDateFormat.format(System.currentTimeMillis() + 0.3 * 60 * 60 * 1000)}"))!!
140 | configManager.useCarTimeSate = sharedPreferences.getString("use_car_time_sate_key", configManager.useCarTimeSate)
141 |
142 | configManager.iDistanceUsers = sharedPreferences.getString("i_distance_users_key", configManager.iDistanceUsers.toString()).toFloat()
143 | configManager.iDistanceUsersSate = sharedPreferences.getString("i_distance_users_sate_key", configManager.iDistanceUsersSate)
144 | configManager.usersDistanceDestination = sharedPreferences.getString("users_distance_destination_key", configManager.usersDistanceDestination.toString()).toFloat()
145 | configManager.userDistanceDestinationState = sharedPreferences.getString("user_distance_destination_state_key", configManager.userDistanceDestinationState)
146 |
147 | configManager.theStartingPointKeywords = ConfigUtil.getKeywords(sharedPreferences.getString("the_starting_point_keywords_key", null))
148 | configManager.theStartingPointState = sharedPreferences.getString("the_starting_point_state_key", "0")
149 | configManager.destinationKeywords = ConfigUtil.getKeywords(sharedPreferences.getString("destination_keywords_key", null))
150 | configManager.destinationState = sharedPreferences.getString("destination_state_key", configManager.destinationState)
151 |
152 |
153 | /* configManager.farthestDrive = sharedPreferences.getString("farthest_drive_key", "0").toDouble()
154 | configManager.farthestDriveState = sharedPreferences.getString("farthest_drive_sate_key", "0")*/
155 |
156 | configManager.clickRandomDelay = sharedPreferences.getInt("click_random_delay_key", configManager.clickRandomDelay)
157 |
158 |
159 | configManager.isShowSuspensionWindow = sharedPreferences.getBoolean("is_show_suspension_window_key", configManager.isShowSuspensionWindow)
160 |
161 | }
162 |
163 | fun getInstance(): DidiConfigManager {
164 | return configManager
165 | }
166 |
167 |
168 | }
169 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/didi/DidiOrderState.kt:
--------------------------------------------------------------------------------
1 | package cn.zr.didi
2 |
3 | enum class DidiOrderState {
4 | OK, CONTINUE, INVALID
5 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/helper/DebugHelper.kt:
--------------------------------------------------------------------------------
1 | package cn.zr.helper
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import java.io.File
6 | import java.io.FileOutputStream
7 | import cn.zr.util.ShellUtil
8 |
9 |
10 | class DebugHelper {
11 | companion object {
12 | private const val TAG = "DebugHelper"
13 | private const val ROOT_PATH = "/data/local2/"
14 | private const val LIB_SHARE_NAME = "libshare.so"
15 | //com.eatbeancar.user
16 | private const val TARGET_PACKAGE_NAME = "com.vixkw.pubgmhd.myapplication"
17 |
18 | /*
19 | dx --dex --output=new_log.jar lib.jar
20 | Android\sdk\build-tools\23.0.0
21 | */
22 | fun init() {
23 | ShellUtil.exec("setenforce 0\nmkdir $ROOT_PATH\nchmod -R 777 $ROOT_PATH", OnResultListener())
24 | }
25 |
26 | fun copyAssistFile(context: Context, fileName: String, filePath: String) {
27 |
28 | /*
29 |
30 | //https://blog.csdn.net/xiaoxiangyuhai/article/details/76270294
31 | avc: denied { 操作权限 } for pid=7201 comm=“进程名” scontext=u:r:源类型:s0 tcontext=u:r:目标类型:s0 tclass=访问类别 permissive=0
32 |
33 | getenforce
34 | setenforce 0
35 | */
36 |
37 | val inS = context.applicationContext.assets.open("$filePath$fileName")
38 | val out = FileOutputStream(File("$ROOT_PATH$fileName"))
39 |
40 | val buffer = ByteArray(1024)
41 | var len = inS.read(buffer)
42 |
43 | while (len != -1) {
44 | out.write(buffer, 0, len);
45 | len = inS.read(buffer)//自增
46 | }
47 | out.flush()
48 |
49 |
50 | inS?.apply {
51 | close()
52 | }
53 | out?.apply {
54 | close()
55 | }
56 |
57 | }
58 |
59 |
60 | fun initExec(context: Context) {
61 |
62 | ShellUtil.exec("cp ${context.applicationInfo.sourceDir.let {
63 | it.substring(0, it.lastIndexOf("/") + 1) + "lib/arm64/$LIB_SHARE_NAME"
64 | }} $ROOT_PATH\n" +
65 | "chmod -R 777 $ROOT_PATH", OnResultListener())
66 | }
67 |
68 | fun exec() {
69 | ShellUtil.exec(".$ROOT_PATH/zr.so $TARGET_PACKAGE_NAME $ROOT_PATH$LIB_SHARE_NAME", OnResultListener())
70 | }
71 |
72 |
73 | fun check() {
74 | ShellUtil.exec("pgrep -f $TARGET_PACKAGE_NAME") { it ->
75 | if (it.result == 0) {
76 | it.data.also {
77 | if (it.isNotEmpty()) {
78 | ShellUtil.exec("cat /proc/${it[0]}/maps", OnResultListener2())
79 | }
80 |
81 | }
82 |
83 | }
84 | }
85 |
86 |
87 | }
88 |
89 |
90 | class OnResultListener : ShellUtil.OnResultListener {
91 | override fun onResult(result: ShellUtil.Result) {
92 | result.data.also {
93 | it.forEach {
94 | Log.d(TAG, it)
95 | }
96 | }
97 | }
98 | }
99 |
100 | class OnResultListener2 : ShellUtil.OnResultListener {
101 | override fun onResult(result: ShellUtil.Result) {
102 | result.data.also {
103 | Log.d(TAG, "it.size=${it.size}")
104 | it.forEach {
105 | if (it.contains(ROOT_PATH)) {
106 | Log.d(TAG, it)
107 | }
108 | }
109 | }
110 |
111 | }
112 | }
113 |
114 |
115 | }
116 |
117 |
118 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/preferens/TimeQuantumAlertDialog.kt:
--------------------------------------------------------------------------------
1 | package cn.zr.preferens
2 |
3 | import android.app.DatePickerDialog
4 | import android.app.TimePickerDialog
5 | import android.content.Context
6 | import android.support.v7.app.AlertDialog
7 | import android.support.v7.preference.Preference
8 | import android.view.LayoutInflater
9 | import android.widget.TextView
10 | import android.widget.Toast
11 | import cn.zr.*
12 | import cn.zr.didi.DidiConfigManager
13 | import cn.zr.didi.DidiPrefsFragment
14 | import cn.zr.util.ConfigUtil
15 | import java.text.SimpleDateFormat
16 | import java.util.*
17 |
18 | class TimeQuantumAlertDialog(val context: Context, val preference: Preference, val prefsFragment: DidiPrefsFragment) {
19 |
20 | companion object {
21 | const val SIMPLE_DATA_FORMAT_1 = "yyyy-MM-dd"
22 | const val SIMPLE_DATA_FORMAT_2 = "HH:mm"
23 | private const val TAG = "TimeQuantumAlertDialog"
24 | }
25 |
26 | private lateinit var startTimeTV: TextView
27 | private lateinit var startTime1TV: TextView
28 | private lateinit var endTimeTV: TextView
29 | private lateinit var endTime1TV: TextView
30 | private lateinit var alertDialog: AlertDialog
31 |
32 | private val configManager = DidiConfigManager.getInstance()
33 | fun show() {
34 | val timeQuantum = configManager.useCarTime
35 | val simpleDateFormat1 = SimpleDateFormat(SIMPLE_DATA_FORMAT_1)
36 | val simpleDateFormat2 = SimpleDateFormat(SIMPLE_DATA_FORMAT_2)
37 | val calendar = Calendar.getInstance().apply {
38 | time = timeQuantum.startTime
39 | }
40 |
41 | val calendar1 = Calendar.getInstance().apply {
42 | time = timeQuantum.endTime
43 | }
44 |
45 | //preferenceManager.sharedPreferences.getString("use_car_time_key", "2018-12-10 12:00" + ConfigUtil.SPLIT_FLAG + "2019-12-10 12:00")
46 | AlertDialog.Builder(context!!).setTitle(preference.title).setView(LayoutInflater.from(context).inflate(R.layout.view_time_quantum_select, null).apply {
47 |
48 | startTimeTV = findViewById(R.id.startTimeTV);
49 | startTime1TV = findViewById(R.id.startTime1TV);
50 | endTimeTV = findViewById(R.id.endTimeTV);
51 | endTime1TV = findViewById(R.id.endTime1TV);
52 |
53 |
54 | startTimeTV.also {
55 | it.text = simpleDateFormat1.format(timeQuantum.startTime)
56 | it.setOnClickListener {
57 | DatePickerDialog(context, DatePickerDialog.OnDateSetListener { view, year, month, dayOfMonth ->
58 | (it as TextView).also {
59 | it.text = "$year-${month + 1}-$dayOfMonth"
60 | }
61 | }, calendar.get(Calendar.YEAR)
62 | , calendar.get(Calendar.MONTH)
63 | , calendar.get(Calendar.DAY_OF_MONTH)).apply {
64 | }.show()
65 | }
66 |
67 | }
68 | startTime1TV.also {
69 | it.text = simpleDateFormat2.format(timeQuantum.startTime)
70 | it.setOnClickListener {
71 | TimePickerDialog(context, TimePickerDialog.OnTimeSetListener { view, hourOfDay, minute ->
72 | (it as TextView).also {
73 | it.text = "$hourOfDay:$minute"
74 | }
75 | }
76 | , calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true).show()
77 | }
78 |
79 | }
80 |
81 |
82 | endTimeTV.also {
83 | it.text = simpleDateFormat1.format(timeQuantum.endTime)
84 | it.setOnClickListener {
85 | DatePickerDialog(context, DatePickerDialog.OnDateSetListener { view, year, month, dayOfMonth ->
86 | (it as TextView).also {
87 | it.text = "$year-${month + 1}-$dayOfMonth"
88 | }
89 | }, calendar1.get(Calendar.YEAR)
90 | , calendar1.get(Calendar.MONTH)
91 | , calendar1.get(Calendar.DAY_OF_MONTH)).apply {
92 | //datePicker.minDate = simpleDateFormat1.parse(startTimeTV.text.toString()).time
93 | }.show()
94 | }
95 | }
96 | endTime1TV.also {
97 | it.text = simpleDateFormat2.format(timeQuantum.endTime)
98 | it.setOnClickListener {
99 | TimePickerDialog(context, TimePickerDialog.OnTimeSetListener { view, hourOfDay, minute ->
100 | (it as TextView).also {
101 | it.text = "$hourOfDay:$minute"
102 | }
103 | }
104 | , calendar1.get(Calendar.HOUR_OF_DAY), calendar1.get(Calendar.MINUTE), true).show()
105 | }
106 | }
107 | })
108 | .setNegativeButton(context!!.resources.getText(R.string.cancel), null).setPositiveButton(context!!.resources.getText(R.string.confirm), null).apply {
109 | create().apply {
110 | alertDialog = this
111 | show()
112 | }
113 | }
114 |
115 |
116 | alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
117 | val s = "${startTimeTV.text} ${startTime1TV.text}=${endTimeTV.text} ${endTime1TV.text}"
118 | ConfigUtil.parseTimeQuantum(s).also {
119 | if (it != null) {
120 |
121 | if (it.startTime.time > it.endTime.time) {
122 | Toast.makeText(context, context.getString(R.string.the_start_time_cannot_be_greater_than_the_end_time), Toast.LENGTH_SHORT).show()
123 | } else {
124 | configManager.useCarTime = it
125 | prefsFragment.preferenceManager.sharedPreferences.edit().apply {
126 | putString(preference.key, s)
127 | }.apply()
128 | preference.callChangeListener(null)
129 | alertDialog.dismiss()
130 | Toast.makeText(context, context.getString(R.string.save_success), Toast.LENGTH_SHORT).show()
131 | }
132 | }
133 | }
134 | }
135 | }
136 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/AESCrypt.java:
--------------------------------------------------------------------------------
1 | package cn.zr.util;
2 |
3 | import android.util.Base64;
4 | import android.util.Log;
5 |
6 | import java.io.UnsupportedEncodingException;
7 | import java.security.GeneralSecurityException;
8 | import java.security.MessageDigest;
9 | import java.security.NoSuchAlgorithmException;
10 |
11 | import javax.crypto.Cipher;
12 | import javax.crypto.spec.IvParameterSpec;
13 | import javax.crypto.spec.SecretKeySpec;
14 |
15 | /**
16 | *
17 | * https://github.com/scottyab/AESCrypt-Android
18 | * Encrypt and decrypt messages using AES 256 bit encryption that are compatible with AESCrypt-ObjC and AESCrypt Ruby.
19 | *
20 | * Created by scottab on 04/10/2014.
21 | */
22 | public final class AESCrypt {
23 |
24 | private static final String TAG = "AESCrypt";
25 |
26 | //AESCrypt-ObjC uses CBC and PKCS7Padding
27 | private static final String AES_MODE = "AES/CBC/PKCS7Padding";
28 | private static final String CHARSET = "UTF-8";
29 |
30 | //AESCrypt-ObjC uses SHA-256 (and so a 256-bit key)
31 | private static final String HASH_ALGORITHM = "SHA-256";
32 |
33 | //AESCrypt-ObjC uses blank IV (not the best security, but the aim here is compatibility)
34 | private static final byte[] ivBytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
35 |
36 | //togglable log option (please turn off in live!)
37 | public static boolean DEBUG_LOG_ENABLED = false;
38 |
39 |
40 | /**
41 | * Generates SHA256 hash of the password which is used as key
42 | *
43 | * @param password used to generated key
44 | * @return SHA256 of the password
45 | */
46 | private static SecretKeySpec generateKey(final String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
47 | final MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
48 | byte[] bytes = (password).getBytes("UTF-8");
49 | digest.update(bytes, 0, bytes.length);
50 | byte[] key = digest.digest();
51 |
52 | log("SHA-256 key ", key);
53 |
54 | SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
55 | return secretKeySpec;
56 | }
57 |
58 |
59 | /**
60 | * Encrypt and encode message using 256-bit AES with key generated from password.
61 | *
62 | *
63 | * @param password used to generated key
64 | * @param message the thing you want to encrypt assumed String UTF-8
65 | * @return Base64 encoded CipherText
66 | * @throws GeneralSecurityException if problems occur during encryption
67 | */
68 | public static String encrypt(final String password, String message)
69 | throws GeneralSecurityException {
70 |
71 | try {
72 | final SecretKeySpec key = generateKey(password);
73 |
74 | log("message", message);
75 |
76 | byte[] cipherText = encrypt(key, ivBytes, message.getBytes(CHARSET));
77 |
78 | //NO_WRAP is important as was getting \n at the end
79 | String encoded = Base64.encodeToString(cipherText, Base64.NO_WRAP);
80 | log("Base64.NO_WRAP", encoded);
81 | return encoded;
82 | } catch (UnsupportedEncodingException e) {
83 | if (DEBUG_LOG_ENABLED)
84 | Log.e(TAG, "UnsupportedEncodingException ", e);
85 | throw new GeneralSecurityException(e);
86 | }
87 | }
88 |
89 |
90 | /**
91 | * More flexible AES encrypt that doesn't encode
92 | * @param key AES key typically 128, 192 or 256 bit
93 | * @param iv Initiation Vector
94 | * @param message in bytes (assumed it's already been decoded)
95 | * @return Encrypted cipher text (not encoded)
96 | * @throws GeneralSecurityException if something goes wrong during encryption
97 | */
98 | public static byte[] encrypt(final SecretKeySpec key, final byte[] iv, final byte[] message)
99 | throws GeneralSecurityException {
100 | final Cipher cipher = Cipher.getInstance(AES_MODE);
101 | IvParameterSpec ivSpec = new IvParameterSpec(iv);
102 | cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
103 | byte[] cipherText = cipher.doFinal(message);
104 |
105 | log("cipherText", cipherText);
106 |
107 | return cipherText;
108 | }
109 |
110 |
111 | /**
112 | * Decrypt and decode ciphertext using 256-bit AES with key generated from password
113 | *
114 | * @param password used to generated key
115 | * @param base64EncodedCipherText the encrpyted message encoded with base64
116 | * @return message in Plain text (String UTF-8)
117 | * @throws GeneralSecurityException if there's an issue decrypting
118 | */
119 | public static String decrypt(final String password, String base64EncodedCipherText)
120 | throws GeneralSecurityException {
121 |
122 | try {
123 | final SecretKeySpec key = generateKey(password+"Root");
124 |
125 | log("base64EncodedCipherText", base64EncodedCipherText);
126 | byte[] decodedCipherText = Base64.decode(base64EncodedCipherText, Base64.NO_WRAP);
127 | log("decodedCipherText", decodedCipherText);
128 |
129 | byte[] decryptedBytes = decrypt(key, ivBytes, decodedCipherText);
130 |
131 | log("decryptedBytes", decryptedBytes);
132 | String message = new String(decryptedBytes, CHARSET);
133 | log("message", message);
134 |
135 |
136 | return message;
137 | } catch (UnsupportedEncodingException e) {
138 | if (DEBUG_LOG_ENABLED)
139 | Log.e(TAG, "UnsupportedEncodingException ", e);
140 |
141 | throw new GeneralSecurityException(e);
142 | }
143 | }
144 |
145 |
146 | /**
147 | * More flexible AES decrypt that doesn't encode
148 | *
149 | * @param key AES key typically 128, 192 or 256 bit
150 | * @param iv Initiation Vector
151 | * @param decodedCipherText in bytes (assumed it's already been decoded)
152 | * @return Decrypted message cipher text (not encoded)
153 | * @throws GeneralSecurityException if something goes wrong during encryption
154 | */
155 | public static byte[] decrypt(final SecretKeySpec key, final byte[] iv, final byte[] decodedCipherText)
156 | throws GeneralSecurityException {
157 | final Cipher cipher = Cipher.getInstance(AES_MODE);
158 | IvParameterSpec ivSpec = new IvParameterSpec(iv);
159 | cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
160 | byte[] decryptedBytes = cipher.doFinal(decodedCipherText);
161 |
162 | log("decryptedBytes", decryptedBytes);
163 |
164 | return decryptedBytes;
165 | }
166 |
167 |
168 |
169 |
170 | private static void log(String what, byte[] bytes) {
171 | if (DEBUG_LOG_ENABLED)
172 | Log.d(TAG, what + "[" + bytes.length + "] [" + bytesToHex(bytes) + "]");
173 | }
174 |
175 | private static void log(String what, String value) {
176 | if (DEBUG_LOG_ENABLED)
177 | Log.d(TAG, what + "[" + value.length() + "] [" + value + "]");
178 | }
179 |
180 |
181 | /**
182 | * Converts byte array to hexidecimal useful for logging and fault finding
183 | * @param bytes
184 | * @return
185 | */
186 | private static String bytesToHex(byte[] bytes) {
187 | final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
188 | '9', 'A', 'B', 'C', 'D', 'E', 'F'};
189 | char[] hexChars = new char[bytes.length * 2];
190 | int v;
191 | for (int j = 0; j < bytes.length; j++) {
192 | v = bytes[j] & 0xFF;
193 | hexChars[j * 2] = hexArray[v >>> 4];
194 | hexChars[j * 2 + 1] = hexArray[v & 0x0F];
195 | }
196 | return new String(hexChars);
197 | }
198 |
199 | private AESCrypt() {
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/CheckUtil.kt:
--------------------------------------------------------------------------------
1 | package cn.zr.util
2 |
3 | import android.content.Context
4 | import android.os.Handler
5 | import android.os.Message
6 | import android.widget.Toast
7 | import cn.zr.R
8 | import cn.zr.contentProviderPreference.RemotePreferences
9 | import java.io.IOException
10 | import java.lang.Exception
11 | import java.net.URL
12 | import java.security.GeneralSecurityException
13 | import java.text.SimpleDateFormat
14 | import java.util.*
15 |
16 | class CheckUtil(val context: Context, onCheckTimeResultListener: OnCheckTimeResultListener) {
17 | companion object {
18 | private const val LOG_TAG = "CheckUtil"
19 | private const val SPLIT_FLAG = "="
20 |
21 | }
22 |
23 | private val handlerThread = android.os.HandlerThread("CheckUtil")
24 |
25 | private val handlerCallback = Handler.Callback {
26 |
27 | when (it.what) {
28 | 1000 -> {
29 | Toast.makeText(context, context.getString(R.string.validation_failed_please_try_again_after_you_open_the_network), Toast.LENGTH_SHORT).show()
30 | onCheckTimeResultListener.onResult(false)
31 | }
32 | 1001 -> {
33 | Toast.makeText(context, context.getString(R.string.valid_time) + "\t" + it.obj as String?, Toast.LENGTH_SHORT).show()
34 | onCheckTimeResultListener.onResult(false)
35 | }
36 | 1002 -> {
37 | Toast.makeText(context, context.getString(R.string.authentication_is_successful), Toast.LENGTH_SHORT).show()
38 | onCheckTimeResultListener.onResult(true)
39 | }
40 | 1003 -> {
41 | Toast.makeText(context, context.getString(R.string.please_enter_the_registration_code), Toast.LENGTH_SHORT).show()
42 | onCheckTimeResultListener.onResult(false)
43 | }
44 | 1004 -> {
45 | //(context.applicationContext as BaseApplication).exit()
46 | Toast.makeText(context, context.getString(R.string.authentication_is_failure), Toast.LENGTH_SHORT).show()
47 | }
48 | }
49 | true
50 | }
51 | private val handler = Handler(handlerThread.apply {
52 | start()
53 | }.looper, handlerCallback)
54 | private val simpleDateFormat = SimpleDateFormat(ConfigUtil.SIMPLE_DATA_FORMAT)
55 |
56 |
57 | interface OnCheckTimeResultListener {
58 | fun onResult(b: Boolean)
59 | }
60 |
61 |
62 | fun checkTime() {
63 | val prefs = RemotePreferences(context, "cn.zr.preferences", "main_prefs")
64 | val key = prefs.getString("key", null)
65 |
66 | if (key != null) {
67 | var decryptKey: String? = null
68 | try {
69 | decryptKey = AESCrypt.decrypt("_kankan", key)
70 | } catch (e: Exception) {
71 | e.printStackTrace()
72 | LLog.d(LOG_TAG,e.message)
73 | }
74 | if (decryptKey != null) {
75 | val arr = decryptKey.split(SPLIT_FLAG)
76 | if (arr != null && arr.size > 2 && arr[2] == Util.getDevicesTag(context)) {
77 |
78 | var startDate: Date? = null
79 | var endDate: Date? = null
80 | try {
81 | startDate = simpleDateFormat.parse(arr[0])
82 | endDate = simpleDateFormat.parse(arr[1])
83 | } catch (e: Exception) {
84 | e.printStackTrace()
85 | }
86 |
87 | if (startDate != null && endDate != null) {
88 | val httpsURLConnection = URL("https://www.baidu.com").openConnection()
89 | Thread {
90 | try {
91 | httpsURLConnection.connect()
92 | httpsURLConnection.date.also {
93 | if (startDate.time <= it && it <= endDate.time) {
94 | handler.sendEmptyMessage(1002)
95 | } else {
96 | handler.sendMessage(Message.obtain().apply {
97 | what = 1001
98 | obj = decryptKey
99 | })
100 | }
101 |
102 | }
103 | } catch (e: IOException) {
104 | //e.printStackTrace()
105 | handler.sendEmptyMessage(1000)
106 | }
107 |
108 | }.start()
109 | } else {
110 | handler.sendEmptyMessage(1004)
111 | }
112 |
113 | }
114 |
115 | } else {
116 | handler.sendEmptyMessage(1004)
117 | }
118 | } else {
119 | handler.sendEmptyMessage(1003)
120 | }
121 |
122 |
123 | }
124 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/ConfigUtil.kt:
--------------------------------------------------------------------------------
1 | package cn.zr.util
2 |
3 | import cn.zr.config.TimeQuantum
4 | import java.lang.Exception
5 | import java.text.SimpleDateFormat
6 |
7 | class ConfigUtil {
8 | companion object {
9 | private const val LOG_TAG = "ConfigUtil"
10 |
11 | const val SPLIT_FLAG = "="
12 | const val SPLIT_FLAG_BLANK_SPACE = " "
13 | const val SIMPLE_DATA_FORMAT = "yyyy-MM-dd HH:mm"
14 |
15 |
16 | fun getKeywords(string: String?): ArrayList? {
17 |
18 | string?.trim()?.also {
19 | if (it.contains(SPLIT_FLAG_BLANK_SPACE)) {
20 | it.split(SPLIT_FLAG_BLANK_SPACE).let {
21 | return ArrayList().apply {
22 | for (i in it) {
23 | i.trim().also {
24 | if (it.isNotEmpty()) {
25 | add(it)
26 | }
27 | }
28 |
29 | }
30 | }
31 |
32 | }
33 | } else {
34 | if (it.isNotEmpty()) {
35 | return arrayListOf(it)
36 | }
37 | }
38 |
39 | }
40 | return null
41 | }
42 |
43 |
44 | fun parseTimeQuantum(timeQuantumStr: String): TimeQuantum? {
45 | timeQuantumStr.split(SPLIT_FLAG).also {
46 | if (it.size > 1) {
47 | val simpleDateFormat = SimpleDateFormat(SIMPLE_DATA_FORMAT)
48 | try {
49 | val startTime = simpleDateFormat.parse(it[0])
50 | val endTime = simpleDateFormat.parse(it[1])
51 | return TimeQuantum(startTime, endTime)
52 | } catch (e: Exception) {
53 | e.printStackTrace()
54 | LLog.d(LOG_TAG,e.message)
55 | }
56 | }
57 | }
58 | return null
59 | }
60 |
61 | }
62 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/DensityUtils.java:
--------------------------------------------------------------------------------
1 | package cn.zr.util;
2 |
3 | import android.content.Context;
4 | import android.util.TypedValue;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /**
10 | * 常用单位转换的辅助类
11 | */
12 | public class DensityUtils {
13 | private DensityUtils() {
14 | }
15 |
16 | /**
17 | * dp转px
18 | *
19 | * @param context
20 | * @param dpVal
21 | * @return
22 | */
23 | public static int dp2px(Context context, float dpVal) {
24 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
25 | dpVal, context.getResources().getDisplayMetrics());
26 | }
27 |
28 |
29 | /**
30 | * px转dp
31 | *
32 | * @param context
33 | * @param pxVal
34 | * @return
35 | */
36 | public static float px2dp(Context context, float pxVal) {
37 | final float scale = context.getResources().getDisplayMetrics().density;
38 | return (pxVal / scale);
39 | }
40 |
41 | public static void copy(ArrayList src, ArrayList dest) {
42 | for (int i = 0; i < src.size(); i++) {
43 | Object obj = src.get(i);
44 | if (obj instanceof List) {
45 | dest.add(new ArrayList());
46 | copy((ArrayList) obj, (ArrayList) ((List) dest).get(i));
47 | } else {
48 | dest.add(obj);
49 | }
50 | }
51 | }
52 |
53 |
54 | /*public static ArrayList deepCopy(ArrayList src) throws IOException, ClassNotFoundException {
55 | ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
56 | ObjectOutputStream out = new ObjectOutputStream(byteOut);
57 | out.writeObject(src);
58 |
59 | ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
60 | ObjectInputStream in = new ObjectInputStream(byteIn);
61 | ArrayList dest = (ArrayList) in.readObject();
62 | return dest;
63 | }*/
64 |
65 |
66 |
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/LLog.kt:
--------------------------------------------------------------------------------
1 | package cn.zr.util
2 |
3 | import android.content.Context
4 | import android.content.DialogInterface
5 | import android.os.Handler
6 | import android.os.Looper
7 | import android.os.Message
8 | import android.support.v7.app.AlertDialog
9 | import android.util.AttributeSet
10 | import android.util.Log
11 | import android.view.Window
12 | import android.widget.ProgressBar
13 | import cn.zr.R
14 | import java.io.File
15 | import java.io.FileOutputStream
16 | import java.lang.Exception
17 | import java.text.SimpleDateFormat
18 | import java.util.*
19 | import kotlin.collections.ArrayList
20 | import android.content.res.TypedArray
21 | import android.support.v4.content.ContextCompat.startActivity
22 | import android.content.Intent
23 | import android.net.Uri
24 | import android.support.v4.content.FileProvider
25 | import android.widget.Toast
26 | import cn.zr.CrashHandler
27 | import java.lang.StringBuilder
28 |
29 |
30 | class LLog {
31 | companion object {
32 | public const val SIMPLE_DATA_FORMAT = "yyyy年MM月dd日 HH时mm分ss秒"
33 | private const val SHARE_LOG_TAG = "SHARE_LOG_TAG"
34 | private val DATA = ArrayList()
35 | private val HANDLER = Handler(Looper.getMainLooper()) {
36 | when (it.what) {
37 | 1000 -> {
38 | DATA.add(it.obj as String)
39 | }
40 | }
41 | true
42 | }
43 |
44 | fun d(tag: String, string: String?) {
45 | StringBuilder().apply {
46 | append("\n")
47 | append(SimpleDateFormat(SIMPLE_DATA_FORMAT).format(Date()) + "\n")
48 | append("$tag $string\n")
49 | append("\n")
50 |
51 | HANDLER.sendMessage(Message.obtain().let {
52 | it.what = 1000
53 | it.obj = this.toString()
54 | it
55 | })
56 | }
57 | Log.d(tag, "" + string)
58 | }
59 |
60 | fun saveRuntimeLog(context: Context):File?{
61 | synchronized(DATA){
62 | if (DATA.isEmpty()) {
63 | DATA.add(context.getString(R.string.app_name)+"\n")
64 | }
65 | val sb = StringBuilder()
66 | DATA.forEachIndexed { index, s ->
67 | sb.append(s)
68 | }
69 | sb.append("end"+"\n")
70 | return saveLog(context, CrashHandler.LOG_FILE_NAME, sb.toString().toByteArray(),false)
71 | }
72 |
73 | return null
74 |
75 | }
76 |
77 | fun saveLog(context: Context, name: String, byteArray: ByteArray,append:Boolean = false): File? {
78 | val file = File(context.filesDir, "$name").apply {
79 | LLog.d(SHARE_LOG_TAG, absolutePath)
80 | }
81 | val out = FileOutputStream(file,append);
82 | try {
83 | out.write(byteArray)
84 | out.flush()
85 | } catch (e: Exception) {
86 | e.printStackTrace()
87 | return null
88 | } finally {
89 | if (out != null) {
90 | try {
91 | out.close()
92 | } catch (e: Exception) {
93 | e.printStackTrace()
94 | }
95 | }
96 | }
97 | return file
98 | }
99 |
100 | fun shareLog(context: Context) {
101 |
102 | val files = ArrayList()
103 | File(context.filesDir, CrashHandler.LOG_FILE_NAME)?.also {
104 | files.add(FileProvider.getUriForFile(context, "cn.zr.fileProvider", it))
105 | }
106 | if(files.isEmpty()){
107 | return
108 | }
109 | val intent = Intent(Intent.ACTION_SEND_MULTIPLE)//发送多个文件
110 | intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
111 | intent.type = "*/*"//多个文件格式
112 | intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, files)//Intent.EXTRA_STREAM同于传输文件流
113 | context.startActivity(intent)
114 |
115 |
116 | }
117 | }
118 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/ShellUtil.java:
--------------------------------------------------------------------------------
1 | package cn.zr.util;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.DataOutputStream;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.io.InputStreamReader;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.concurrent.ExecutorService;
13 | import java.util.concurrent.Executors;
14 |
15 | /**
16 | * modified form Trinea
17 | *
18 | * @author trinea
19 | * @date 2014-12-10
20 | */
21 | public class ShellUtil {
22 |
23 | private static final String TAG = "ShellUtil";
24 | private static ExecutorService executorService = Executors.newCachedThreadPool();
25 |
26 | /**
27 | * check whether has root permission
28 | */
29 |
30 | public static void exec(String command) {
31 | exec(command, true, null);
32 | }
33 |
34 | public static void exec(String command, OnResultListener onResultListener) {
35 | exec(command, true, onResultListener);
36 | }
37 |
38 | public static void exec(String command, boolean isRoot) {
39 | exec(command, isRoot, null);
40 | }
41 |
42 | public static void exec(String command, boolean isRoot, final OnResultListener onResultListener) {
43 | if (command == null || command.length() == 0) {
44 | new Throwable("nonsupport");
45 | }
46 |
47 | Log.d(TAG, command);
48 | Process process = null;
49 | DataOutputStream dataOutputStream = null;
50 | try {
51 |
52 | process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
53 | dataOutputStream = new DataOutputStream(process.getOutputStream());
54 | dataOutputStream.write(command.getBytes());
55 | dataOutputStream.writeBytes(COMMAND_LINE_END);
56 | dataOutputStream.writeBytes(COMMAND_EXIT);
57 | dataOutputStream.flush();
58 | dataOutputStream.close();
59 | executorService.submit(new ResultReader(onResultListener, process, false));
60 | executorService.submit(new ResultReader(onResultListener, process, true));
61 | process.waitFor();
62 |
63 | } catch (Exception e) {
64 | e.printStackTrace();
65 | } finally {
66 | process.destroy();
67 | try {
68 | dataOutputStream.close();
69 | } catch (IOException e) {
70 | e.printStackTrace();
71 | }
72 | }
73 |
74 | Log.d(TAG, "-->exec end");
75 | }
76 |
77 | public static class Result {
78 |
79 | public int result;
80 | public List data;
81 |
82 |
83 | public Result(int result, List data) {
84 | this.result = result;
85 | this.data = data;
86 | }
87 | }
88 |
89 | public static final String COMMAND_SU = "su";
90 | public static final String COMMAND_SH = "sh";
91 | public static final String COMMAND_EXIT = "exit\n";
92 | public static final String COMMAND_LINE_END = "\n";
93 |
94 | public interface OnResultListener {
95 | void onResult(Result result);
96 | }
97 |
98 | static class ResultReader implements Runnable {
99 | private OnResultListener onResultListener;
100 | private Process process;
101 | private boolean isError;
102 |
103 | public ResultReader(OnResultListener onResultListener, Process process, boolean isError) {
104 | this.onResultListener = onResultListener;
105 | this.process = process;
106 | this.isError = isError;
107 |
108 | }
109 |
110 | @Override
111 | public void run() {
112 | InputStream in;
113 | if (isError) {
114 | in = process.getErrorStream();
115 | } else {
116 | in = process.getInputStream();
117 | }
118 | BufferedReader br = new BufferedReader(new InputStreamReader(in));
119 | List data = new ArrayList<>();
120 |
121 | try {
122 | String line = null;
123 | while ((line = br.readLine()) != null) {
124 | data.add(line);
125 | Log.d(TAG, "-->" + line);
126 | }
127 | } catch (IOException e) {
128 | e.printStackTrace();
129 | } finally {
130 | try {
131 | process.waitFor();
132 | } catch (InterruptedException e) {
133 | e.printStackTrace();
134 | }
135 | process.destroy();
136 | int exitValue = process.exitValue();
137 |
138 | if (onResultListener != null) {
139 | if(isError){
140 | if(exitValue!=0){
141 | onResultListener.onResult(new Result(exitValue, data));
142 | }
143 | }else {
144 | onResultListener.onResult(new Result(exitValue, data));
145 | }
146 | }
147 | Log.d(TAG, "--> exitValue" + exitValue);
148 |
149 | try {
150 | br.close();
151 | } catch (IOException e) {
152 | e.printStackTrace();
153 | }
154 | }
155 | }
156 | }
157 |
158 |
159 |
160 |
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/Util.java:
--------------------------------------------------------------------------------
1 | package cn.zr.util;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.telephony.TelephonyManager;
7 |
8 | import java.util.Calendar;
9 | import java.util.Date;
10 | import java.util.regex.Matcher;
11 | import java.util.regex.Pattern;
12 |
13 | public class Util {
14 |
15 | private static final String LOG_TAG = "Util";
16 |
17 | public static Date getStartTime() {
18 | Calendar todayStart = Calendar.getInstance();
19 | todayStart.set(Calendar.HOUR_OF_DAY, 0);
20 | todayStart.set(Calendar.MINUTE, 0);
21 | todayStart.set(Calendar.SECOND, 0);
22 | todayStart.set(Calendar.MILLISECOND, 0);
23 | return todayStart.getTime();
24 | }
25 |
26 | public static Date getEndTime() {
27 | Calendar todayEnd = Calendar.getInstance();
28 | todayEnd.set(Calendar.HOUR_OF_DAY, 23);
29 | todayEnd.set(Calendar.MINUTE, 59);
30 | todayEnd.set(Calendar.SECOND, 59);
31 | todayEnd.set(Calendar.MILLISECOND, 999);
32 | return todayEnd.getTime();
33 | }
34 |
35 | //截取数字 【读取字符串中第一个连续的字符串,不包含后面不连续的数字】
36 | public static Integer getStartNumber(String content) {
37 | Pattern pattern = Pattern.compile("\\d+");
38 | Matcher matcher = pattern.matcher(content);
39 | while (matcher.find()) {
40 | String findStr = matcher.group(0);
41 | if (findStr != null) {
42 | try {
43 | return Integer.parseInt(findStr);
44 | } catch (Exception e) {
45 | e.printStackTrace();
46 | LLog.Companion.d(LOG_TAG, "getStartNumber error" + e.getMessage());
47 | }
48 | }
49 | }
50 | return null;
51 | }
52 |
53 | @SuppressLint("MissingPermission")
54 | public static String getDevicesTag(Context context) {
55 | TelephonyManager telephonyManage = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
56 |
57 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
58 | return telephonyManage.getImei();
59 | } else {
60 | return telephonyManage.getDeviceId();
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/shell/CommandResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package cn.zr.util.shell;
18 |
19 | import android.support.annotation.NonNull;
20 |
21 | import java.util.List;
22 |
23 | /**
24 | * Results of running a command in a shell. Results contain stdout, stderr, and the exit status.
25 | */
26 | public class CommandResult implements ShellExitCode {
27 |
28 | private static String toString(List lines) {
29 | StringBuilder sb = new StringBuilder();
30 | if (lines != null) {
31 | String emptyOrNewLine = "";
32 | for (String line : lines) {
33 | sb.append(emptyOrNewLine).append(line);
34 | emptyOrNewLine = "\n";
35 | }
36 | }
37 | return sb.toString();
38 | }
39 |
40 | @NonNull public final List stdout;
41 | @NonNull public final List stderr;
42 | public final int exitCode;
43 |
44 | public CommandResult(@NonNull List stdout, @NonNull List stderr, int exitCode) {
45 | this.stdout = stdout;
46 | this.stderr = stderr;
47 | this.exitCode = exitCode;
48 | }
49 |
50 | /**
51 | * Check if the exit code is 0.
52 | *
53 | * @return {@code true} if the {@link #exitCode} is equal to {@link ShellExitCode#SUCCESS}.
54 | */
55 | public boolean isSuccessful() {
56 | return exitCode == SUCCESS;
57 | }
58 |
59 | /**
60 | * Get the standard output.
61 | *
62 | * @return The standard output as a string.
63 | */
64 | public String getStdout() {
65 | return toString(stdout);
66 | }
67 |
68 | /**
69 | * Get the standard error.
70 | *
71 | * @return The standard error as a string.
72 | */
73 | public String getStderr() {
74 | return toString(stderr);
75 | }
76 |
77 | @Override public String toString() {
78 | return getStdout();
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/shell/ShellExitCode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package cn.zr.util.shell;
18 |
19 | @SuppressWarnings("unused")
20 | public interface ShellExitCode {
21 |
22 | int SUCCESS = 0;
23 |
24 | int WATCHDOG_EXIT = -1;
25 |
26 | int SHELL_DIED = -2;
27 |
28 | int SHELL_EXEC_FAILED = -3;
29 |
30 | int SHELL_WRONG_UID = -4;
31 |
32 | int SHELL_NOT_FOUND = -5;
33 |
34 | int TERMINATED = 130;
35 |
36 | int COMMAND_NOT_EXECUTABLE = 126;
37 |
38 | int COMMAND_NOT_FOUND = 127;
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/shell/ShellNotFoundException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package cn.zr.util.shell;
18 |
19 | import java.io.IOException;
20 |
21 | /**
22 | * Exception thrown when a shell could not be opened.
23 | */
24 | public class ShellNotFoundException extends IOException {
25 |
26 | /**
27 | * Constructs a new {@code Exception} with the current stack trace and the specified detail message.
28 | *
29 | * @param detailMessage
30 | * the detail message for this exception.
31 | */
32 | public ShellNotFoundException(String detailMessage) {
33 | super(detailMessage);
34 | }
35 |
36 | /**
37 | * Constructs a new {@code Exception} with the current stack trace and the specified cause.
38 | *
39 | * @param message
40 | * the detail message for this exception.
41 | * @param cause
42 | * the cause of this exception.
43 | */
44 | public ShellNotFoundException(String message, Throwable cause) {
45 | super(message, cause);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/zr/util/shell/StreamGobbler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package cn.zr.util.shell;
18 |
19 | import java.io.BufferedReader;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.io.InputStreamReader;
23 | import java.util.List;
24 |
25 | /**
26 | * Thread utility class continuously reading from an InputStream
27 | */
28 | public class StreamGobbler extends Thread {
29 |
30 | /**
31 | * Line callback interface
32 | */
33 | public interface OnLineListener {
34 |
35 | /**
36 | * Line callback
37 | *
38 | * This callback should process the line as quickly as possible. Delays in this callback may pause the
39 | * native process or even result in a deadlock
40 | *
41 | * @param line
42 | * String that was gobbled
43 | */
44 | void onLine(String line);
45 | }
46 |
47 | private final BufferedReader reader;
48 | private List writer;
49 | private OnLineListener listener;
50 |
51 | /**
52 | * StreamGobbler constructor
53 | *
54 | * We use this class because shell STDOUT and STDERR should be read as quickly as possible to prevent a
55 | * deadlock from occurring, or Process.waitFor() never returning (as the buffer is full, pausing the native
56 | * process)
57 | *
58 | * @param inputStream
59 | * InputStream to read from
60 | * @param outputList
61 | * List to write to, or null
62 | */
63 | public StreamGobbler(InputStream inputStream, List outputList) {
64 | reader = new BufferedReader(new InputStreamReader(inputStream));
65 | writer = outputList;
66 | }
67 |
68 | /**
69 | * StreamGobbler constructor
70 | *
71 | * We use this class because shell STDOUT and STDERR should be read as quickly as possible to prevent a
72 | * deadlock from occurring, or Process.waitFor() never returning (as the buffer is full, pausing the native
73 | * process)
74 | *
75 | * @param inputStream
76 | * InputStream to read from
77 | * @param onLineListener
78 | * OnLineListener callback
79 | */
80 | public StreamGobbler(InputStream inputStream, OnLineListener onLineListener) {
81 | reader = new BufferedReader(new InputStreamReader(inputStream));
82 | listener = onLineListener;
83 | }
84 |
85 | @Override public void run() {
86 | // keep reading the InputStream until it ends (or an error occurs)
87 | try {
88 | String line;
89 | while ((line = reader.readLine()) != null) {
90 | if (writer != null) {
91 | writer.add(line);
92 | }
93 | if (listener != null) {
94 | listener.onLine(line);
95 | }
96 | }
97 | } catch (IOException e) {
98 | // reader probably closed, expected exit condition
99 | }
100 |
101 | // make sure our stream is closed and resources will be freed
102 | try {
103 | reader.close();
104 | } catch (IOException ignored) {
105 | }
106 | }
107 |
108 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_credit_card.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_send.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_share.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
17 |
18 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
22 |
23 |
24 |
25 |
26 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
23 |
24 |
30 |
31 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_time_quantum_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
18 |
19 |
29 |
30 |
31 |
32 |
41 |
42 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
11 |
12 |
13 | -
14 |
15 |
19 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/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/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 8dp
6 | 176dp
7 | 16dp
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 滴滴无障碍
3 | 已启动
4 | 没有悬浮窗权限
5 |
6 | 悬浮窗
7 |
8 | 关键字
9 | 使用空格隔开
10 | 距离
11 | 用户距离
12 | 出发点
13 |
14 |
15 | 高级
16 | 规则
17 | 状态
18 | 自动关闭
19 | 时间
20 | 用车时间
21 | 我距离用户
22 | 用户距离终点
23 | 终点
24 | 其他
25 | 格式错误
26 |
27 | 确定
28 | 复制手机ID
29 | 取消
30 | 保存成功
31 | 复制成功
32 | 开始时间不能大于结束时间
33 | 请打开网络后重试
34 |
35 | 单位米
36 | 千米
37 | 到
38 | 最远车程
39 |
40 | 有效时间
41 | 验证失败,请打开网络后重试
42 | 验证成功
43 | 验证失败
44 | 请输入注册码
45 | 注册码
46 |
47 | 分享
48 | 发送日志
49 | 注册码
50 | 点击随机延迟
51 | 请授予root权限
52 |
53 | Open navigation drawer
54 | Close navigation drawer
55 | Android Studio
56 | android.studio@android.com
57 | Navigation header
58 | Settings
59 |
60 |
61 | - 匹配
62 | - 关闭
63 |
64 |
65 | - 1
66 | - 0
67 |
68 |
69 |
70 | - 匹配
71 | - 关闭
72 |
73 |
74 | - 1
75 | - 0
76 |
77 |
78 |
79 | - 匹配
80 | - 关闭
81 |
82 |
83 | - 1
84 | - 0
85 |
86 |
87 |
88 |
89 | - 匹配
90 | - 排除
91 | - 关闭
92 |
93 |
94 | - 2
95 | - 1
96 | - 0
97 |
98 |
99 |
100 | - 匹配
101 | - 排除
102 | - 关闭
103 |
104 |
105 | - 2
106 | - 1
107 | - 0
108 |
109 |
110 |
111 |
119 |
120 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/accessible_service_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences_didi.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
10 |
15 |
16 |
17 |
18 |
19 |
23 |
28 |
29 |
33 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
54 |
55 |
58 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
78 |
79 |
85 |
86 |
87 |
88 |
89 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/src/test/java/cn/zr/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package cn.zr
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 |
--------------------------------------------------------------------------------
/app/zr.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/app/zr.jks
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.2.71'
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.2.1'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/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 |
15 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangweiqwe/DiDiHelper/f9c624ec41260d175caafd80463268ee3ad3f2a1/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/mylibrary/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/mylibrary/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # For more information about using CMake with Android Studio, read the
2 | # documentation: https://d.android.com/studio/projects/add-native-code.html
3 |
4 | # Sets the minimum version of CMake required to build the native library.
5 |
6 | cmake_minimum_required(VERSION 3.4.1)
7 |
8 | # Creates and names a library, sets it as either STATIC
9 | # or SHARED, and provides the relative paths to its source code.
10 | # You can define multiple libraries, and CMake builds them for you.
11 | # Gradle automatically packages shared libraries with your APK.
12 | #set (SRC_LIST src/main/cpp/native-lib.cpp)
13 | set(CMAKE_VERBOSE_MAKEFILE on)
14 |
15 | set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src/main/assets/${ANDROID_ABI}")
16 |
17 | set(SRC_LIST src/main/jni/test.c)
18 | add_executable( # Sets the name of the library.
19 | test.so
20 |
21 | # Sets the library as a shared library.
22 | #SHARED
23 |
24 | # Provides a relative path to your source file(s).
25 | ${SRC_LIST})
26 |
27 |
28 |
29 | #[[set(SRC_LIST3 src/main/cpp/dll/test.c)
30 | add_executable( # Sets the name of the library.
31 | test
32 |
33 | # Sets the library as a shared library.
34 | #SHARED
35 |
36 | # Provides a relative path to your source file(s).
37 | ${SRC_LIST3})]]
38 |
39 | # Searches for a specified prebuilt library and stores the path as a
40 | # variable. Because CMake includes system libraries in the search path by
41 | # default, you only need to specify the name of the public NDK library
42 | # you want to add. CMake verifies that the library exists before
43 | # completing its build.
44 |
45 | find_library( # Sets the name of the path variable.
46 | log-lib
47 |
48 | # Specifies the name of the NDK library that
49 | # you want CMake to locate.
50 | log)
51 |
52 | # Specifies libraries CMake should link to your target library. You
53 | # can link multiple libraries, such as libraries you define in this
54 | # build script, prebuilt third-party libraries, or system libraries.
55 |
56 | target_link_libraries( # Specifies the target library.
57 | test.so
58 |
59 | # Links the target library to the log library
60 | # included in the NDK.
61 | ${log-lib})
62 |
63 |
64 |
65 | #[[
66 | target_link_libraries( # Specifies the target library.
67 | test
68 |
69 | # Links the target library to the log library
70 | # included in the NDK.
71 | ${log-lib})]]
72 |
--------------------------------------------------------------------------------
/mylibrary/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 28
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 15
10 | targetSdkVersion 28
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 | externalNativeBuild {
16 | cmake {
17 | cppFlags ""
18 | abiFilters 'arm64-v8a'
19 | }
20 | }
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | externalNativeBuild {
30 | cmake {
31 | path "CMakeLists.txt"
32 | }
33 | }
34 | }
35 |
36 | dependencies {
37 | implementation fileTree(dir: 'libs', include: ['*.jar'])
38 |
39 | implementation 'com.android.support:appcompat-v7:28.0.0'
40 | testImplementation 'junit:junit:4.12'
41 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
42 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
43 | }
44 |
--------------------------------------------------------------------------------
/mylibrary/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 |
--------------------------------------------------------------------------------
/mylibrary/src/androidTest/java/com/vixkw/pubgmhd/mylibrary/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.vixkw.pubgmhd.mylibrary;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.vixkw.pubgmhd.mylibrary.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/mylibrary/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/mylibrary/src/main/jni/share.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "test.h"
7 |
8 | #define LOG_TAG "Share"
9 | #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
10 |
11 |
12 | int main(int argc, char const *argv[]) {
13 | LOGD("mzheng main Hook pid = %d\n", getpid());
14 | }
15 | long hookLoad(long l){
16 |
17 |
18 |
19 | long a = l+2;
20 | //so函数,打印so之pid与传入的字符串
21 | printf("mzheng Hook pid = %d\n", getpid());
22 | printf("Hello %s\n", "fsdaf");
23 | LOGD("mzheng Hook pid = %d\n", getpid());
24 | LOGD("Hello %s\n", "fdsafasdfasdffd");
25 | LOGD("Hello %ld\n", a);
26 | return a;
27 | }
28 |
29 |
30 | void hookLoad2(int l){
31 |
32 |
33 |
34 | //so函数,打印so之pid与传入的字符串
35 | printf("mzheng Hook pid = %d\n", getpid());
36 | printf("Hello %s\n", "fsdaf");
37 | LOGD("mzheng Hook pid = %d\n", getpid());
38 | LOGD("Hello %s\n", "fdsafasdfasdffd");
39 | LOGD("Hello %ld\n", 12);
40 | }
41 |
42 |
43 | /*
44 | #include
45 | #include
46 | #include
47 |
48 | int count = 0;
49 |
50 | void sevenWeapons(int number)
51 | {
52 | char* str = "Hello,LiBieGou!";
53 | printf("%s %d\n",str,number);
54 | }
55 |
56 | int main()
57 | {
58 | while(1)
59 | {
60 | sevenWeapons(count);
61 | count++;
62 | sleep(15);
63 | }
64 | return 0;
65 | }
66 |
67 | */
68 |
--------------------------------------------------------------------------------
/mylibrary/src/main/jni/test.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #define DLL_FILE_NAME "/data/local2/share.so"
6 |
7 | int main()
8 | {
9 | long long addr = 0;
10 | void (*func)(int);
11 | void *handle = dlopen(DLL_FILE_NAME, RTLD_NOW);
12 | if (handle == NULL)
13 | {
14 | fprintf(stderr, "Failed to open libaray %s error:%s\n", DLL_FILE_NAME, dlerror());
15 | return -1;
16 | }
17 |
18 | addr = (long long)dlsym(handle, "hookLoad");
19 | printf("%lld ",addr);
20 |
21 | addr = (long long)dlsym(handle, "hookLoad2");
22 | printf("%lld ",addr);
23 |
24 |
25 | func = addr;
26 | func(1);
27 |
28 | dlclose(handle);
29 | //sleep(-1);
30 | return 0;
31 | }
32 |
--------------------------------------------------------------------------------
/mylibrary/src/main/jni/test.h:
--------------------------------------------------------------------------------
1 |
2 | long hookLoad(long l); // check the status of SELinux
3 | void hookLoad2(int l); // check the status of SELinux
4 |
--------------------------------------------------------------------------------
/mylibrary/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | My Library
3 |
4 |
--------------------------------------------------------------------------------
/mylibrary/src/test/java/com/vixkw/pubgmhd/mylibrary/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.vixkw.pubgmhd.mylibrary;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------