├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── compiler.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── CMakeLists.txt
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── androidinject
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── cpp
│ │ ├── InjectModule
│ │ │ ├── CMakeLists.txt
│ │ │ ├── InjectModule.cpp
│ │ │ ├── PrintLog.h
│ │ │ ├── common.h
│ │ │ ├── fake_dlfcn.cpp
│ │ │ ├── fake_dlfcn.h
│ │ │ ├── load_dex.cpp
│ │ │ └── load_dex.h
│ │ ├── PtraceInject
│ │ │ ├── CMakeLists.txt
│ │ │ ├── PrintLog.h
│ │ │ ├── PtraceInject.cpp
│ │ │ ├── PtraceInject.h
│ │ │ ├── lib_name.cpp
│ │ │ ├── lib_name.h
│ │ │ ├── main.cpp
│ │ │ ├── module_utils.cpp
│ │ │ ├── module_utils.h
│ │ │ ├── ptrace_utils.cpp
│ │ │ └── ptrace_utils.h
│ │ └── native-lib
│ │ │ ├── CMakeLists.txt
│ │ │ ├── PrintLog.h
│ │ │ └── native-lib.cpp
│ ├── java
│ │ └── com
│ │ │ ├── app
│ │ │ ├── context
│ │ │ │ ├── ContextUtils.java
│ │ │ │ └── RunUiInterface.java
│ │ │ ├── logic
│ │ │ │ └── LogicEntry.java
│ │ │ ├── service
│ │ │ │ ├── AbstractEntry.java
│ │ │ │ └── Entry.java
│ │ │ ├── signal
│ │ │ │ └── IRecvListener.java
│ │ │ ├── socket
│ │ │ │ ├── JWebSocketClient.java
│ │ │ │ └── WebSocketMessage.java
│ │ │ ├── tools
│ │ │ │ └── ScreenShot.java
│ │ │ └── view
│ │ │ │ ├── ViewInfo.java
│ │ │ │ └── ViewManager.java
│ │ │ └── example
│ │ │ └── androidinject
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.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
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── androidinject
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── installcmd.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | xmlns:android
14 |
15 | ^$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | xmlns:.*
25 |
26 | ^$
27 |
28 |
29 | BY_NAME
30 |
31 |
32 |
33 |
34 |
35 |
36 | .*:id
37 |
38 | http://schemas.android.com/apk/res/android
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | .*:name
48 |
49 | http://schemas.android.com/apk/res/android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | name
59 |
60 | ^$
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | style
70 |
71 | ^$
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | .*
81 |
82 | ^$
83 |
84 |
85 | BY_NAME
86 |
87 |
88 |
89 |
90 |
91 |
92 | .*
93 |
94 | http://schemas.android.com/apk/res/android
95 |
96 |
97 | ANDROID_ATTRIBUTE_ORDER
98 |
99 |
100 |
101 |
102 |
103 |
104 | .*
105 |
106 | .*
107 |
108 |
109 | BY_NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.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 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 1.8
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SharkInject
2 | android8 arm64 注入方案
3 |
4 | -f:启动目标app
5 | -n:指定app包名
6 | -p:app pid
7 | -d:指定注入dex
8 | -so:指定注入so
9 |
10 | ```
11 | ./SharkInject -f -n com.ss.android.ugc.aweme
12 | ```
13 | `您也可以直接运行gradle的executeDevice Task`
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /libs
--------------------------------------------------------------------------------
/app/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.1)
2 |
3 | # LIB目录和BIN目录
4 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI})
5 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI})
6 |
7 | #设置头文件搜索路径(和此txt同个路径的头文件无需设置),可选
8 | #INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/common)
9 |
10 | #指定用到的系统库或者NDK库或者第三方库的搜索路径,可选。
11 | #LINK_DIRECTORIES(/usr/local/lib)
12 |
13 | #添加子目录,将自动找到子目录中的CMakeLists.txt
14 | ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/src/main/cpp/native-lib)
15 | ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/src/main/cpp/PtraceInject)
16 | ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/src/main/cpp/InjectModule)
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "29.0.3"
6 | defaultConfig {
7 | applicationId "com.example.androidinject"
8 | minSdkVersion 24
9 | targetSdkVersion 29
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | multiDexEnabled false
15 |
16 | externalNativeBuild {
17 | cmake {
18 | cppFlags ""
19 | // abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
20 | abiFilters "armeabi-v7a", "arm64-v8a"
21 | }
22 | }
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 |
32 | externalNativeBuild {
33 | cmake {
34 | path "CMakeLists.txt"
35 | version "3.10.2"
36 | }
37 | }
38 | compileOptions {
39 | sourceCompatibility JavaVersion.VERSION_1_8
40 | targetCompatibility JavaVersion.VERSION_1_8
41 | }
42 | }
43 |
44 | dependencies {
45 | implementation fileTree(dir: 'libs', include: ['*.jar'])
46 | implementation 'androidx.appcompat:appcompat:1.1.0'
47 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
48 | implementation 'com.swift.sandhook:hooklib:4.2.1'
49 | implementation "org.java-websocket:Java-WebSocket:1.5.1"
50 | implementation 'com.google.code.gson:gson:2.8.1'
51 |
52 | // 不使用 Xposed API 则不需要引入
53 | implementation 'com.swift.sandhook:xposedcompat:4.2.+'
54 | testImplementation 'junit:junit:4.12'
55 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
56 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
57 | }
58 |
59 | ext {
60 | //push的路径
61 | pushPath = "/data/local/tmp/"
62 | //可执行文件的名称
63 | elfName = "SharkInject"
64 | //部署的架构
65 | abi = 'armeabi-v7a'
66 | //so名称
67 | soName = "libLoadModule.so"
68 | //注入目标包名
69 | appName = "com.ss.android.ugc.aweme"
70 | }
71 |
72 | //将相关文件push到手机
73 | task pushDevice(dependsOn: 'assembleDebug') {
74 | group 'Online-Device'
75 | description 'Debug with online device without remote server'
76 |
77 | doLast {
78 | //push到手机上
79 | def info = "adb push ${new File(project.buildDir, "/intermediates/dex/debug/mergeDexDebug/classes.dex").canonicalPath} $pushPath".execute().text
80 | println "Push dex:$info"
81 |
82 | info = "adb push ${new File(project.buildDir, "/intermediates/cmake/debug/obj/$abi/$elfName").canonicalPath} $pushPath".execute().text
83 | println "Push SharkInject:$info"
84 |
85 | info = "adb push ${new File(project.buildDir, "/intermediates/cmake/debug/obj/$abi/$soName").canonicalPath} $pushPath".execute().text
86 | println "Push libLoadModule.so:$info"
87 | }
88 | }
89 |
90 | //修改执行文件的权限
91 | task chmodDevice(dependsOn: pushDevice) {
92 | group 'Online-Device'
93 | doLast {
94 | def info = "adb shell chmod 777 $pushPath/SharkInject".execute().text
95 | println "chmod:$info"
96 | }
97 | }
98 |
99 | //执行命令
100 | task executeDevice(dependsOn: chmodDevice) {
101 | group 'Online-Device'
102 | doLast {
103 | def exec_cmd = "adb shell \"cd $pushPath;su -c $pushPath$elfName -f -n $appName\""
104 | println exec_cmd
105 | def info = exec_cmd.execute().text
106 |
107 | println "executeDevice:$info"
108 | }
109 | }
110 |
111 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/androidinject/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.androidinject;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("com.example.androidinject", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/cpp/InjectModule/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 |
13 | add_library( # Sets the name of the library.
14 | LoadModule
15 |
16 | # Sets the library as a shared library.
17 | SHARED
18 |
19 | # Provides a relative path to your source file(s).
20 | InjectModule.cpp fake_dlfcn.cpp load_dex.cpp
21 | )
22 |
23 | # Searches for a specified prebuilt library and stores the path as a
24 | # variable. Because CMake includes system libraries in the search path by
25 | # default, you only need to specify the name of the public NDK library
26 | # you want to add. CMake verifies that the library exists before
27 | # completing its build.
28 |
29 | find_library( # Sets the name of the path variable.
30 | log-lib
31 |
32 | # Specifies the name of the NDK library that
33 | # you want CMake to locate.
34 | log android)
35 |
36 | # Specifies libraries CMake should link to your target library. You
37 | # can link multiple libraries, such as libraries you define in this
38 | # build script, prebuilt third-party libraries, or system libraries.
39 |
40 | target_link_libraries( # Specifies the target library.
41 | LoadModule
42 |
43 | # Links the target library to the log library
44 | # included in the NDK.
45 | ${log-lib})
--------------------------------------------------------------------------------
/app/src/main/cpp/InjectModule/InjectModule.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "PrintLog.h"
12 | #include "fake_dlfcn.h"
13 | #include "load_dex.h"
14 |
15 | pthread_t gThread;
16 |
17 | #if defined(__aarch64__) || defined(__x86_64__)
18 | const char *libandroid_runtime_path = "/system/lib64/libandroid_runtime.so";
19 | #else
20 | const char *libandroid_runtime_path = "/system/lib/libandroid_runtime.so";
21 | #endif
22 |
23 | /**
24 | * 这种方式是将我们的插件dex加载进内存后,在添加到app的ClassLoader中
25 | * 这样在app中是可以看到我们的代码的
26 | * @param env
27 | * @param jarpath
28 | */
29 | void load_dex_and_run2(JNIEnv *env, const char *jarpath) {
30 |
31 | //使用DexFile.loadDex加载dex
32 | const char *pkgName = "com.shark.nougat";
33 |
34 | jobject dexObject = LoadDex(env, jarpath, pkgName);
35 |
36 | //获得app的PathClassLoader
37 | jobject appPathClassLoader = getClassLoader(env);
38 | //将我们加载的dex 放入到app的PathClassLoader的pathList;的dexElements;中
39 | //如此在app中就能直接加载到我们的dex中的类了
40 | makeDexElements(env, appPathClassLoader, dexObject);
41 |
42 | //找到我们的入口类
43 | const char *targetClass = "com/app/service/Entry";
44 |
45 | jclass Inject = myFindClass(env, targetClass, dexObject);
46 |
47 | //下面这一段就是去调用我们的入口类了
48 | jmethodID main = env->GetStaticMethodID(Inject, "onLoad",
49 | "(Ldalvik/system/PathClassLoader;Ljava/lang/String;Z)V");
50 |
51 | if (ClearException(env)) {
52 | LOGE("find Inject class Entry jmethodId failed");
53 | return;
54 | }
55 |
56 | //inject_flag is only used for art
57 | jboolean inject_flag = false;
58 | env->CallStaticVoidMethod(Inject, main, appPathClassLoader, env->NewStringUTF(pkgName),
59 | inject_flag);
60 | if (ClearException(env)) {
61 | LOGE("call Entry method failed");
62 | return;
63 | }
64 | }
65 |
66 | /**
67 | *
68 | * 下面这种方式是直接自己创建一个ClassLoader 这样创建的ClassLoader在App的加载器中是找不到我们的注入代码的
69 | * @param env
70 | * @param jarpath
71 | */
72 | void load_dex_and_run(JNIEnv *env, const char *jarpath) {
73 | jobject appPathClassLoader = getClassLoader(env);
74 | //获取当前目录
75 | char current_absolute_path[4096] ="/data/local/tmp";
76 |
77 | jobject myClassLoader = createNewClassLoader(env, jarpath, current_absolute_path);
78 | LOGI("myClassLoader 0x%p\n", myClassLoader);
79 | if (NULL != myClassLoader) {
80 | jclass entry_class = findClassFromLoader(env, myClassLoader, "com.app.service.Entry");
81 |
82 | if (NULL != entry_class) {
83 | LOGI("Entry Class 0x%p\n", entry_class);
84 | //"(Ldalvik/system/PathClassLoader;Ljava/lang/String;Z)V"
85 |
86 | const char *entryName = "onLoad";
87 | jmethodID entry_method = env->GetStaticMethodID(entry_class, entryName,
88 | "(Ldalvik/system/PathClassLoader;Ljava/lang/String;Z)V");
89 |
90 | if (NULL != entry_method) {
91 | jboolean inject_flag = false;
92 | const char *pkgName = "com.shark.initapp";
93 |
94 | env->CallStaticVoidMethod(entry_class, entry_method, appPathClassLoader,
95 | env->NewStringUTF(pkgName), inject_flag);
96 | }
97 | }
98 | }
99 | }
100 |
101 | int _clientInit(const char *jarpath) {
102 | JNIEnv *testenv = NULL;
103 | void *handle;
104 | //依靠libandroid_runtime.so 找到JavaVM
105 | handle = dlopen_ex(libandroid_runtime_path, RTLD_NOW);
106 | LOGI("fake_dlopen for libandroid_runtime.so returned %p\n", handle);
107 | void *pVM = dlsym_ex(handle, "_ZN7android14AndroidRuntime7mJavaVME");
108 |
109 | JavaVM *javaVM = (JavaVM *) *(void **) pVM;
110 | LOGI("use mJavaVM returned %p\n", javaVM);
111 | if (javaVM) {
112 | jint result = javaVM->AttachCurrentThread(&testenv, 0);
113 | if ((result == JNI_OK) && (testenv != NULL)) {
114 | LOGI("attach ok. clientInit JavaVM : 0x%p, JNIEnv : 0x%p\n", javaVM, testenv);
115 | load_dex_and_run(testenv, jarpath);
116 | javaVM->DetachCurrentThread();
117 | LOGI("DetachCurrentThread all finished!");
118 | } else {
119 | LOGE("NOTE: attach of thread failed\n");
120 | return -1;
121 | }
122 | }
123 |
124 | return 0;
125 | }
126 |
127 | extern "C" __attribute__((visibility("default"))) int entry(char *so_parameter) {
128 | LOGE("[InjectModule] Inject_entry Func is called\n");
129 | pthread_create(&gThread, NULL, (void *(*)(void *)) _clientInit, (void *) so_parameter);
130 |
131 | return 0;
132 | }
--------------------------------------------------------------------------------
/app/src/main/cpp/InjectModule/PrintLog.h:
--------------------------------------------------------------------------------
1 | #ifndef _ANDROID_LOG_PRINT_H_
2 | #define _ANDROID_LOG_PRINT_H_
3 |
4 | #include
5 |
6 | #define IS_DEBUG
7 |
8 | #ifdef IS_DEBUG
9 |
10 | #define LOG_TAG ("InjectShark")
11 |
12 | #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
13 |
14 | #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__))
15 |
16 | #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__))
17 |
18 | #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__))
19 |
20 | #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__))
21 |
22 | #else
23 |
24 | #define LOGV(LOG_TAG, ...) NULL
25 |
26 | #define LOGD(LOG_TAG, ...) NULL
27 |
28 | #define LOGI(LOG_TAG, ...) NULL
29 |
30 | #define LOGW(LOG_TAG, ...) NULL
31 |
32 | #define LOGE(LOG_TAG, ...) NULL
33 |
34 | #endif
35 |
36 | #endif
--------------------------------------------------------------------------------
/app/src/main/cpp/InjectModule/common.h:
--------------------------------------------------------------------------------
1 | #ifndef __COMMON_H__
2 | #define __COMMON_H__
3 |
4 | #include
5 | #include
6 |
7 | #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
8 |
9 | #define TAG "InjectShark"
10 | #define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO, TAG, FORMAT, ##__VA_ARGS__);
11 | #define LOGD(FORMAT, ...) __android_log_print(ANDROID_LOG_DEBUG, TAG, FORMAT, ##__VA_ARGS__);
12 | #define LOGV(FORMAT, ...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, FORMAT, ##__VA_ARGS__);
13 | #define LOGW(FORMAT, ...) __android_log_print(ANDROID_LOG_WARN, TAG, FORMAT, ##__VA_ARGS__);
14 | #define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR, TAG, FORMAT, ##__VA_ARGS__);
15 |
16 | #endif //__COMMON_H__
17 |
--------------------------------------------------------------------------------
/app/src/main/cpp/InjectModule/fake_dlfcn.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 avs333
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include "common.h"
32 |
33 |
34 | #if defined(__LP64__) || defined(__aarch64__) || defined(__x86_64__) || defined(__x86_64)
35 | #define Elf_Ehdr Elf64_Ehdr
36 | #define Elf_Shdr Elf64_Shdr
37 | #define Elf_Sym Elf64_Sym
38 | #elif defined(__arm__) || defined(__i386__)
39 | #define Elf_Ehdr Elf32_Ehdr
40 | #define Elf_Shdr Elf32_Shdr
41 | #define Elf_Sym Elf32_Sym
42 | #else
43 | #error "Arch unknown, please port me"
44 | #endif
45 |
46 | struct ctx {
47 | // void *load_addr;
48 | // void *dynstr;
49 | // void *dynsym;
50 | char *load_addr;
51 | char *dynstr;
52 | char *dynsym;
53 | int nsyms;
54 | off_t bias;
55 | };
56 |
57 | extern "C" {
58 | static int fake_dlclose(void *handle) {
59 | LOGI("fake_dlclose");
60 | if (handle) {
61 | struct ctx *ctx = (struct ctx *) handle;
62 | if (ctx->dynsym) free(ctx->dynsym); /* we're saving dynsym and dynstr */
63 | if (ctx->dynstr) free(ctx->dynstr); /* from library file just in case */
64 | free(ctx);
65 | }
66 | return 0;
67 | }
68 |
69 | /* flags are ignored */
70 |
71 | static void *fake_dlopen_with_path(const char *libpath, int flags) {
72 | LOGI("fake_dlopen");
73 | FILE *maps;
74 | char buff[256];
75 | struct ctx *ctx = 0;
76 | off_t load_addr, size;
77 | int k, fd = -1, found = 0;
78 | char *shoff;
79 | Elf_Ehdr *elf = (Elf_Ehdr *) MAP_FAILED;
80 |
81 | #define fatal(fmt, args...) do { LOGE(fmt,##args); goto err_exit; } while(0)
82 |
83 | maps = fopen("/proc/self/maps", "r");
84 | if (!maps) LOGE("failed to open maps");
85 |
86 | while (!found && fgets(buff, sizeof(buff), maps)) {
87 | if (strstr(buff, libpath) && (strstr(buff, "r-xp") || strstr(buff, "r--p"))) found = 1;
88 | }
89 | fclose(maps);
90 |
91 | if (!found) fatal("%s not found in my userspace", libpath);
92 |
93 | if (sscanf(buff, "%lx", &load_addr) != 1)
94 | LOGE("failed to read load address for %s", libpath);
95 |
96 | LOGI("%s loaded in Android at 0x%08lx", libpath, load_addr);
97 |
98 | /* Now, mmap the same library once again */
99 |
100 | fd = open(libpath, O_RDONLY);
101 | if (fd < 0) fatal("failed to open %s", libpath);
102 |
103 | size = lseek(fd, 0, SEEK_END);
104 | if (size <= 0) fatal("lseek() failed for %s", libpath);
105 |
106 | elf = (Elf_Ehdr *) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
107 | close(fd);
108 | fd = -1;
109 |
110 | if (elf == MAP_FAILED) fatal("mmap() failed for %s", libpath);
111 |
112 | ctx = (struct ctx *) calloc(1, sizeof(struct ctx));
113 | if (!ctx) fatal("no memory for %s", libpath);
114 |
115 | ctx->load_addr = (char *) load_addr;
116 | shoff = ((char *) elf) + elf->e_shoff;
117 |
118 | for (k = 0; k < elf->e_shnum; k++, shoff += elf->e_shentsize) {
119 |
120 | Elf_Shdr *sh = (Elf_Shdr *) shoff;
121 | LOGI("%s: k=%d shdr=%p type=%x", __func__, k, sh, sh->sh_type);
122 |
123 | switch (sh->sh_type) {
124 |
125 | case SHT_DYNSYM:
126 | if (ctx->dynsym) fatal("%s: duplicate DYNSYM sections", libpath); /* .dynsym */
127 | ctx->dynsym = (char*) malloc(sh->sh_size);
128 | if (!ctx->dynsym) fatal("%s: no memory for .dynsym", libpath);
129 | memcpy(ctx->dynsym, ((char *) elf) + sh->sh_offset, sh->sh_size);
130 | ctx->nsyms = (sh->sh_size / sizeof(Elf_Sym));
131 | break;
132 |
133 | case SHT_STRTAB:
134 | if (ctx->dynstr) break; /* .dynstr is guaranteed to be the first STRTAB */
135 | ctx->dynstr = (char*) malloc(sh->sh_size);
136 | if (!ctx->dynstr) fatal("%s: no memory for .dynstr", libpath);
137 | memcpy(ctx->dynstr, ((char *) elf) + sh->sh_offset, sh->sh_size);
138 | break;
139 |
140 | case SHT_PROGBITS:
141 | if (!ctx->dynstr || !ctx->dynsym) break;
142 | /* won't even bother checking against the section name */
143 | ctx->bias = (off_t) sh->sh_addr - (off_t) sh->sh_offset;
144 | k = elf->e_shnum; /* exit for */
145 | break;
146 | }
147 | }
148 |
149 | munmap(elf, size);
150 | elf = 0;
151 |
152 | if (!ctx->dynstr || !ctx->dynsym) fatal("dynamic sections not found in %s", libpath);
153 |
154 | #undef fatal
155 |
156 | LOGI("%s: ok, dynsym = %p, dynstr = %p", libpath, ctx->dynsym, ctx->dynstr);
157 |
158 | return ctx;
159 |
160 | err_exit:
161 | if (fd >= 0) close(fd);
162 | if (elf != MAP_FAILED) munmap(elf, size);
163 | fake_dlclose(ctx);
164 | return 0;
165 | }
166 |
167 | #if defined(__LP64__)
168 | static const char *const kSystemLibDir = "/system/lib64/";
169 | static const char *const kOdmLibDir = "/odm/lib64/";
170 | static const char *const kVendorLibDir = "/vendor/lib64/";
171 | static const char *const kApexLibDir = "/apex/com.android.runtime/lib64/";
172 | #else
173 | static const char *const kSystemLibDir = "/system/lib/";
174 | static const char *const kOdmLibDir = "/odm/lib/";
175 | static const char *const kVendorLibDir = "/vendor/lib/";
176 | static const char *const kApexLibDir = "/apex/com.android.runtime/lib/";
177 | #endif
178 |
179 | static void *fake_dlopen(const char *filename, int flags) {
180 | LOGI("fake_dlopen filename=%s", filename);
181 | if (strlen(filename) > 0 && filename[0] == '/') {
182 | return fake_dlopen_with_path(filename, flags);
183 | } else {
184 | char buf[512] = {0};
185 | void *handle = NULL;
186 | //sysmtem
187 | strcpy(buf, kSystemLibDir);
188 | strcat(buf, filename);
189 | handle = fake_dlopen_with_path(buf, flags);
190 | if (handle) {
191 | return handle;
192 | }
193 | LOGI("fake_dlopen 1");
194 |
195 | // apex
196 | memset(buf, 0, sizeof(buf));
197 | strcpy(buf, kApexLibDir);
198 | strcat(buf, filename);
199 | handle = fake_dlopen_with_path(buf, flags);
200 | if (handle) {
201 | return handle;
202 | }
203 | LOGI("fake_dlopen 2");
204 |
205 | //odm
206 | memset(buf, 0, sizeof(buf));
207 | strcpy(buf, kOdmLibDir);
208 | strcat(buf, filename);
209 | handle = fake_dlopen_with_path(buf, flags);
210 | if (handle) {
211 | return handle;
212 | }
213 | LOGI("fake_dlopen 3");
214 |
215 | //vendor
216 | memset(buf, 0, sizeof(buf));
217 | strcpy(buf, kVendorLibDir);
218 | strcat(buf, filename);
219 | handle = fake_dlopen_with_path(buf, flags);
220 | if (handle) {
221 | return handle;
222 | }
223 | LOGI("fake_dlopen 4");
224 | return fake_dlopen_with_path(filename, flags);
225 | }
226 | }
227 |
228 | static void *fake_dlsym(void *handle, const char *name) {
229 | int k;
230 | struct ctx *ctx = (struct ctx *) handle;
231 | Elf_Sym *sym = (Elf_Sym *) ctx->dynsym;
232 | char *strings = (char *) ctx->dynstr;
233 |
234 | for (k = 0; k < ctx->nsyms; k++, sym++)
235 | if (strcmp(strings + sym->st_name, name) == 0) {
236 | /* NB: sym->st_value is an offset into the section for relocatables,
237 | but a VMA for shared libs or exe files, so we have to subtract the bias */
238 | void *ret = ctx->load_addr + sym->st_value - ctx->bias;
239 | LOGI("%s found at %p", name, ret);
240 | return ret;
241 | }
242 | return 0;
243 | }
244 |
245 |
246 | static const char *fake_dlerror() {
247 | return NULL;
248 | }
249 |
250 | // =============== implementation for compat ==========
251 | static int SDK_INT = -1;
252 | static int get_sdk_level() {
253 | if (SDK_INT > 0) {
254 | return SDK_INT;
255 | }
256 | char sdk[PROP_VALUE_MAX] = {0};;
257 | __system_property_get("ro.build.version.sdk", sdk);
258 | SDK_INT = atoi(sdk);
259 | return SDK_INT;
260 | }
261 |
262 | int dlclose_ex(void *handle) {
263 | if (get_sdk_level() >= 24) {
264 | return fake_dlclose(handle);
265 | } else {
266 | return dlclose(handle);
267 | }
268 | }
269 |
270 | void *dlopen_ex(const char *filename, int flags) {
271 | LOGI("dlopen: %s", filename);
272 | if (get_sdk_level() >= 24) {
273 | return fake_dlopen(filename, flags);
274 | } else {
275 | return dlopen(filename, flags);
276 | }
277 | }
278 |
279 | void *dlsym_ex(void *handle, const char *symbol) {
280 | if (get_sdk_level() >= 24) {
281 | return fake_dlsym(handle, symbol);
282 | } else {
283 | return dlsym(handle, symbol);
284 | }
285 | }
286 |
287 | const char *dlerror_ex() {
288 | if (get_sdk_level() >= 24) {
289 | return fake_dlerror();
290 | } else {
291 | return dlerror();
292 | }
293 | }
294 | }
295 |
--------------------------------------------------------------------------------
/app/src/main/cpp/InjectModule/fake_dlfcn.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 avs333
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 |
21 | #ifndef DEXPOSED_DLFCN_H
22 | #define DEXPOSED_DLFCN_H
23 |
24 | #include
25 | #include
26 | #include
27 |
28 | extern "C" {
29 |
30 | void *dlopen_ex(const char *filename, int flags);
31 |
32 | void *dlsym_ex(void *handle, const char *symbol);
33 |
34 | int dlclose_ex(void *handle);
35 |
36 | const char *dlerror_ex();
37 |
38 | };
39 | #endif //DEXPOSED_DLFCN_H
40 |
--------------------------------------------------------------------------------
/app/src/main/cpp/InjectModule/load_dex.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "android/log.h"
3 | #include "stdio.h"
4 | #include "stdlib.h"
5 | #include
6 | #include
7 | #define ANDROID_SMP 0
8 | #include
9 | #include
10 | #include "load_dex.h"
11 | #include "PrintLog.h"
12 |
13 | static jobject g_orignalDex;
14 | static jobject g_classLoader=0;
15 |
16 |
17 | int ClearException(JNIEnv *jenv){
18 | JNIEnv * test = NULL;
19 | jthrowable exception = jenv->ExceptionOccurred();
20 | if (exception != NULL) {
21 | jenv->ExceptionDescribe();
22 | jenv->ExceptionClear();
23 | return true;
24 | }
25 | return false;
26 | }
27 |
28 |
29 |
30 | int makeDexElements(JNIEnv* env, jobject classLoader, jobject dexFileobj)
31 | {
32 | jclass PathClassLoader = env->GetObjectClass(classLoader);
33 |
34 | jclass BaseDexClassLoader = env->GetSuperclass(PathClassLoader);
35 |
36 | //get pathList fieldid
37 | jfieldID pathListid = env->GetFieldID(BaseDexClassLoader, "pathList", "Ldalvik/system/DexPathList;");
38 | jobject pathList = env->GetObjectField(classLoader, pathListid);
39 |
40 | //get DexPathList Class
41 | jclass DexPathListClass = env->GetObjectClass(pathList);
42 | //get dexElements fieldid
43 | jfieldID dexElementsid = env->GetFieldID(DexPathListClass, "dexElements", "[Ldalvik/system/DexPathList$Element;");
44 |
45 | //获取elements数组 get dexElement array value
46 | jobjectArray dexElement = static_cast(env->GetObjectField(pathList, dexElementsid));
47 |
48 |
49 | //获取数组的个数 get DexPathList$Element Class construction method and get a new DexPathList$Element object
50 | jint len = env->GetArrayLength(dexElement);
51 | LOGI( "original Element size:%d", len);
52 |
53 |
54 | jclass ElementClass = env->FindClass("dalvik/system/DexPathList$Element");// dalvik/system/DexPathList$Element
55 | jmethodID Elementinit = env->GetMethodID(ElementClass, "", "(Ljava/io/File;ZLjava/io/File;Ldalvik/system/DexFile;)V");
56 | jboolean isDirectory = JNI_FALSE;
57 |
58 | /**
59 | * get origianl dex object
60 | */
61 | jobject originalDexElement=env->GetObjectArrayElement(dexElement,0);
62 | if(originalDexElement!=0)
63 | {
64 | jfieldID tmp=env->GetFieldID(ElementClass,"dexFile","Ldalvik/system/DexFile;");
65 | g_orignalDex=env->GetObjectField(originalDexElement,tmp);
66 | if(ClearException(env)){
67 | LOGI("get original DexObj faield");
68 | }
69 | }
70 |
71 | //创建一个新的dalvik/system/DexPathList$Element类 dexFileobj为新的dexFileobj
72 | jobject element_obj = env->NewObject(ElementClass, Elementinit, 0, isDirectory, 0, dexFileobj);
73 |
74 | //Get dexElement all values and add add each value to the new array
75 | jobjectArray new_dexElement = env->NewObjectArray(len + 1, ElementClass, 0);
76 | for (int i = 0; i < len; ++i)
77 | {
78 | //将以前的Elements添加到这个新的new_dexElement数组
79 | env->SetObjectArrayElement(new_dexElement, i, env->GetObjectArrayElement(dexElement, i));
80 | }
81 | //将要加载的element_obj放在新数组的最后一个成员里
82 | env->SetObjectArrayElement(new_dexElement, len, element_obj);
83 | env->SetObjectField(pathList, dexElementsid, new_dexElement);
84 | LOGI("make complete");
85 | env->DeleteLocalRef(element_obj);
86 | env->DeleteLocalRef(ElementClass);
87 | env->DeleteLocalRef(dexElement);
88 | env->DeleteLocalRef(DexPathListClass);
89 | env->DeleteLocalRef(pathList);
90 | env->DeleteLocalRef(BaseDexClassLoader);
91 | env->DeleteLocalRef(PathClassLoader);
92 | return 1;
93 | }
94 |
95 |
96 |
97 | jobject getClassLoader(JNIEnv *jenv){
98 | //获取Loaders
99 | jclass clazzApplicationLoaders = jenv->FindClass("android/app/ApplicationLoaders");
100 | jthrowable exception = jenv->ExceptionOccurred();
101 | if (ClearException(jenv)) {
102 | LOGI("Exception","No class : %s", "android/app/ApplicationLoaders");
103 | return NULL;
104 | }
105 | jfieldID fieldApplicationLoaders = jenv->GetStaticFieldID(clazzApplicationLoaders,"gApplicationLoaders","Landroid/app/ApplicationLoaders;");
106 | if (ClearException(jenv)) {
107 | LOGI("Exception","No Static Field :%s","gApplicationLoaders");
108 | return NULL;
109 | }
110 | jobject objApplicationLoaders = jenv->GetStaticObjectField(clazzApplicationLoaders,fieldApplicationLoaders);
111 | if (ClearException(jenv)) {
112 | LOGI("Exception","GetStaticObjectField is failed [%s","gApplicationLoaders");
113 | return NULL;
114 | }
115 | //
116 |
117 | jfieldID fieldLoaders = jenv->GetFieldID(clazzApplicationLoaders,"mLoaders","Ljava/util/Map;");
118 | if (ClearException(jenv)) {
119 | fieldLoaders = jenv->GetFieldID(clazzApplicationLoaders,"mLoaders","Landroid/util/ArrayMap;");
120 | if(ClearException(jenv)){
121 | LOGI("Exception","No Field :%s","mLoaders");
122 | return NULL;
123 | }
124 |
125 | }
126 |
127 | jobject objLoaders = jenv->GetObjectField(objApplicationLoaders,fieldLoaders);
128 | if (ClearException(jenv)) {
129 | LOGI("Exception","No object :%s","mLoaders");
130 | return NULL;
131 | }
132 | //提取map中的values
133 | jclass clazzHashMap = jenv->GetObjectClass(objLoaders);
134 | jmethodID methodValues = jenv->GetMethodID(clazzHashMap,"values","()Ljava/util/Collection;");
135 | jobject values = jenv->CallObjectMethod(objLoaders,methodValues);
136 |
137 | jclass clazzValues = jenv->GetObjectClass(values);
138 | jmethodID methodToArray = jenv->GetMethodID(clazzValues,"toArray","()[Ljava/lang/Object;");
139 | if (ClearException(jenv)) {
140 | LOGI("Exception","No Method:%s","toArray");
141 | return NULL;
142 | }
143 |
144 | jobjectArray classLoaders = (jobjectArray)jenv->CallObjectMethod(values,methodToArray);
145 | if (ClearException(jenv)) {
146 | LOGI("Exception","CallObjectMethod failed :%s","toArray");
147 | return NULL;
148 | }
149 |
150 | int size = jenv->GetArrayLength(classLoaders);
151 |
152 | //classLoaders size always is 1 ???
153 | LOGI("classLoaders size:%d",size);
154 |
155 | for(int i = 0 ; i < size ; i ++){
156 | jobject classLoader = jenv->GetObjectArrayElement(classLoaders,i);
157 | g_classLoader=jenv->NewGlobalRef(classLoader);
158 | if(g_classLoader==NULL){
159 | LOGI("classLoader NewGlobalRef failed");
160 | return NULL;
161 | }
162 | jenv->DeleteLocalRef(classLoader);
163 | return g_classLoader;
164 | }
165 |
166 | }
167 |
168 | jclass loadCLass_plan_one(JNIEnv *jenv,const char *name,jobject dexObject)
169 | {
170 | loadCLass_plan_one(jenv,name,dexObject);
171 | jclass DexFile=jenv->FindClass("dalvik/system/DexFile");
172 | jmethodID loadClass=jenv->GetMethodID(DexFile,"loadClass","(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/Class;");
173 | if(ClearException(jenv))
174 | {
175 | LOGI("find loadClass methodId failed");
176 | return 0;
177 | }
178 | //important dexObject.loadClass()
179 | jstring className=jenv->NewStringUTF(name);
180 | jclass tClazz = (jclass)jenv->CallObjectMethod(dexObject,loadClass,className,g_classLoader);
181 | if(ClearException(jenv))
182 | {
183 | LOGI("loadClass %s failed",name);
184 | return 0;
185 | }
186 | return tClazz;
187 |
188 | }
189 |
190 | //MultiDex
191 | jclass loadCLass_plan_two(JNIEnv *jenv,const char *name)
192 | {
193 | jstring className=jenv->NewStringUTF(name);
194 | jclass clazzCL = jenv->GetObjectClass(g_classLoader);
195 | jmethodID loadClass = jenv->GetMethodID(clazzCL,"loadClass","(Ljava/lang/String;)Ljava/lang/Class;");
196 | jclass tClazz = (jclass)jenv->CallObjectMethod(g_classLoader,loadClass,className);
197 |
198 | if(ClearException(jenv))
199 | {
200 | LOGI("loadClass %s failed",name);
201 | return 0;
202 | }
203 | return tClazz;
204 | }
205 |
206 | jclass findAppClass_test(JNIEnv *jenv,const char *name,jobject dexObject)
207 | {
208 | //there hava 2 plan to loadClass
209 | // plan 1
210 | //jclass TargetClazz=loadCLass_plan_one(jenv,name,dexObject);
211 |
212 | // plan 2
213 | jclass TargetClazz=loadCLass_plan_two(jenv,name);
214 | if(TargetClazz!=0)
215 | LOGI("loadClass %s successful clazz:0x%x",name,TargetClazz);
216 | return TargetClazz;
217 | }
218 |
219 |
220 | jobject LoadDex(JNIEnv* jenv,const char* dexPath,const char* pKgName)
221 | {
222 | jclass DexFile=jenv->FindClass("dalvik/system/DexFile");
223 | if(ClearException(jenv))
224 | {
225 | LOGI("find DexFile class failed");
226 | return 0;
227 | }
228 | jmethodID loadDex=jenv->GetStaticMethodID(DexFile,"loadDex","(Ljava/lang/String;Ljava/lang/String;I)Ldalvik/system/DexFile;");
229 | if(ClearException(jenv))
230 | {
231 | LOGI("find loadDex methodId failed");
232 | return 0;
233 | }
234 | //jstring inPath=jenv->NewStringUTF("/data/data/com.example.stromhooktest/legend.dex");
235 | jstring inPath=jenv->NewStringUTF(dexPath);
236 |
237 | char optPath[256]={0};
238 | strcat(optPath,"/data/data/");
239 | strcat(optPath,pKgName);
240 | strcat(optPath,"/hook.dat");
241 | LOGI("LoadDex optFile path:%s",optPath);
242 | jstring outPath=jenv->NewStringUTF(optPath);
243 | jobject dexObject=jenv->CallStaticObjectMethod(DexFile,loadDex,inPath,outPath,0);
244 | if(ClearException(jenv))
245 | {
246 | LOGI("call loadDex method failed");
247 | return 0;
248 | }
249 | return dexObject;
250 | }
251 |
252 |
253 | jclass myFindClass(JNIEnv* jenv,const char* targetClassName,jobject dexObj)
254 | {
255 | //char* targetClassName="com/legend/demo/Inject";
256 | jclass clazzTarget = jenv->FindClass(targetClassName);
257 | if (ClearException(jenv)) {
258 | LOGI("ClassMethodHook[Can't find class:%s in bootclassloader",targetClassName);
259 | clazzTarget = findAppClass_test(jenv,targetClassName,dexObj);
260 | if(clazzTarget == NULL){
261 | LOGI("found class %s failed",targetClassName);
262 | return NULL;
263 | }
264 | }
265 |
266 | return clazzTarget;
267 | }
268 |
269 | jobject createNewClassLoader(JNIEnv* env, const char *jarpath,char * nativepath){
270 | jclass clzPathClassLoader = env->FindClass("dalvik/system/PathClassLoader");
271 | // LOGI("java/lang/ClassLoader 0x%p\n", clzClassLoader);
272 | jmethodID mdinitPathCL = env->GetMethodID(clzPathClassLoader, "",
273 | "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
274 |
275 | LOGI("PathClassLoader loading jarpath[%s]\n", jarpath);
276 | LOGI("nativepath loading nativepath[%s]\n", nativepath);
277 |
278 | jstring jarpath_str = env->NewStringUTF(jarpath);
279 | jstring narivepath_str = env->NewStringUTF(nativepath);
280 |
281 | jobject myClassLoader = env->NewObject(clzPathClassLoader, mdinitPathCL, jarpath_str, narivepath_str,
282 | NULL);
283 | env->DeleteLocalRef(narivepath_str);
284 | env->DeleteLocalRef(jarpath_str);
285 | return myClassLoader;
286 | }
287 |
288 | jclass findClassFromLoader(JNIEnv *env, jobject class_loader, const char *class_name) {
289 | jclass clz = env->GetObjectClass(class_loader);
290 |
291 | jmethodID mid = env->GetMethodID(clz, "loadClass",
292 | "(Ljava/lang/String;)Ljava/lang/Class;");
293 | jclass ret = nullptr;
294 | if (!mid) {
295 | mid = env->GetMethodID(clz, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
296 | }
297 | jobject target = env->CallObjectMethod(class_loader, mid,
298 | env->NewStringUTF(class_name));
299 | if (target) {
300 | return (jclass) target;
301 | }
302 |
303 | LOGE("Class %s not found", class_name);
304 |
305 | return ret;
306 | }
--------------------------------------------------------------------------------
/app/src/main/cpp/InjectModule/load_dex.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Administrator on 2021/5/9.
3 | //
4 |
5 | #ifndef ANDROIDINJECT_LOAD_DEX_H
6 | #define ANDROIDINJECT_LOAD_DEX_H
7 |
8 |
9 | int ClearException(JNIEnv *jenv);
10 |
11 | int makeDexElements(JNIEnv *env, jobject classLoader, jobject dexFileobj);
12 |
13 | jobject getClassLoader(JNIEnv *jenv);
14 |
15 | jclass loadCLass_plan_one(JNIEnv *jenv, const char *name, jobject dexObject);
16 |
17 | jclass loadCLass_plan_two(JNIEnv *jenv, const char *name);
18 |
19 | jclass findAppClass_test(JNIEnv *jenv, const char *name, jobject dexObject);
20 |
21 | jobject LoadDex(JNIEnv *jenv, const char *dexPath, const char *pKgName);
22 |
23 | jclass myFindClass(JNIEnv *jenv, const char *targetClassName, jobject dexObj);
24 |
25 | jobject createNewClassLoader(JNIEnv *env, const char *jarpath, char *nativepath);
26 |
27 | jclass findClassFromLoader(JNIEnv *env, jobject class_loader, const char *class_name);
28 |
29 | #endif //ANDROIDINJECT_LOAD_DEX_H
30 |
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.1)
2 |
3 | enable_language(ASM) #支持汇编
4 | add_executable(SharkInject main.cpp PtraceInject.cpp ptrace_utils.cpp module_utils.cpp )
5 |
6 | find_library(log-lib log)
7 |
8 | target_link_libraries(SharkInject ${log-lib} )
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/PrintLog.h:
--------------------------------------------------------------------------------
1 | #ifndef _ANDROID_LOG_PRINT_H_
2 | #define _ANDROID_LOG_PRINT_H_
3 |
4 | #include
5 |
6 | //如果不想打印日志可以注释这行宏定义
7 | #define IS_DEBUG
8 | //如果宏定义了IS_DEBUG,那么下面就会宏定义下面这些日志打印函数
9 | #ifdef IS_DEBUG
10 |
11 | #define LOG_TAG ("InjectShark")
12 |
13 | #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
14 |
15 | #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__))
16 |
17 | #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__))
18 |
19 | #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__))
20 |
21 | #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__))
22 |
23 | #else
24 |
25 | #define LOGV(LOG_TAG, ...) NULL
26 |
27 | #define LOGD(LOG_TAG, ...) NULL
28 |
29 | #define LOGI(LOG_TAG, ...) NULL
30 |
31 | #define LOGW(LOG_TAG, ...) NULL
32 |
33 | #define LOGE(LOG_TAG, ...) NULL
34 |
35 | #endif
36 |
37 | #endif
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/PtraceInject.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include "PtraceInject.h"
14 | #include "PrintLog.h"
15 | #include "ptrace_utils.h"
16 | #include "module_utils.h"
17 |
18 | /*************************************************
19 | * 通过远程直接调用dlopen\dlsym的方法ptrace注入so模块到远程进程中
20 | * Input: pid表示远程进程的ID,LibPath为被远程注入的so模块路径,FunctionName为远程注入的模块后调用的函数
21 | * FuncParameter指向被远程调用函数的参数(若传递字符串,需要先将字符串写入到远程进程空间中),
22 | * NumParameter为参数的个数
23 | * Return: 返回0表示注入成功,返回-1表示失败
24 | * ***********************************************/
25 | int inject_remote_process(pid_t pid, char *LibPath, char *FunctionName,
26 | char *parameter, long NumParameter) {
27 | int iRet = -1;
28 | long parameters[6];
29 | //attach到目标进程
30 | if (ptrace_attach(pid) != 0) {
31 | return iRet;
32 | }
33 |
34 | do {
35 | //CurrentRegs 当前寄存器
36 | //OriginalRegs 保存注入前寄存器
37 | struct pt_regs CurrentRegs, OriginalRegs;
38 |
39 | if (ptrace_getregs(pid, &CurrentRegs) != 0) {
40 | break;
41 | }
42 |
43 | memcpy(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs));
44 |
45 | void *mmap_addr = get_mmap_address(pid);
46 | printf("mmap RemoteFuncAddr:0x%lx\n", (uintptr_t) mmap_addr);
47 |
48 | // mmap映射
49 | parameters[0] = 0; // 设置为NULL表示让系统自动选择分配内存的地址
50 | parameters[1] = 0x3000; // 映射内存的大小
51 | parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC; // 表示映射内存区域可读可写可执行
52 | parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; // 建立匿名映射
53 | parameters[4] = 0; // 若需要映射文件到内存中,则为文件的fd
54 | parameters[5] = 0; //文件映射偏移量
55 |
56 | if (ptrace_call(pid, (uintptr_t) mmap_addr, parameters, 6, &CurrentRegs) == -1) {
57 | printf("Call Remote mmap Func Failed, err:%s\n", strerror(errno));
58 | break;
59 | }
60 |
61 | printf("ptrace_call mmap success, return value=%lX, pc=%lX\n", ptrace_getret(&CurrentRegs),
62 | ptrace_getpc(&CurrentRegs));
63 |
64 | // 获取mmap函数执行后的返回值,也就是内存映射的起始地址
65 | void *RemoteMapMemoryAddr = (void *) ptrace_getret(&CurrentRegs);
66 | printf("Remote Process Map Memory Addr:0x%lx\n", (uintptr_t) RemoteMapMemoryAddr);
67 |
68 |
69 | // 分别获取dlopen、dlsym、dlclose等函数的地址
70 | void *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;
71 | dlopen_addr = get_dlopen_address(pid);
72 | dlsym_addr = get_dlsym_address(pid);
73 | dlclose_addr = get_dlclose_address(pid);
74 | dlerror_addr = get_dlerror_address(pid);
75 | // 将要加载的so库路径写入到远程进程内存空间中
76 | if (ptrace_writedata(pid, (uint8_t *) RemoteMapMemoryAddr, (uint8_t *) LibPath,
77 | strlen(LibPath) + 1) == -1) {
78 | printf("Write LibPath:%s to RemoteProcess error\n", LibPath);
79 | break;
80 | }
81 |
82 | // 设置dlopen的参数,返回值为模块加载的地址
83 | // void *dlopen(const char *filename, int flag);
84 | parameters[0] = (uintptr_t) RemoteMapMemoryAddr;
85 | parameters[1] = RTLD_NOW | RTLD_GLOBAL;
86 |
87 | if (ptrace_call(pid, (uintptr_t) dlopen_addr, parameters, 2, &CurrentRegs) == -1) {
88 | printf("Call Remote dlopen Func Failed\n");
89 | break;
90 | }
91 |
92 | // RemoteModuleAddr为远程进程加载注入模块的地址
93 | void *RemoteModuleAddr = (void *) ptrace_getret(&CurrentRegs);
94 | printf("ptrace_call dlopen success, Remote Process load module Addr:0x%lx\n",
95 | (long) RemoteModuleAddr);
96 |
97 | if ((long) RemoteModuleAddr == 0x0) // dlopen 错误
98 | {
99 | printf("dlopen error\n");
100 | if (ptrace_call(pid, (uintptr_t) dlerror_addr, parameters, 0, &CurrentRegs) == -1) {
101 | printf("Call Remote dlerror Func Failed\n");
102 | break;
103 | }
104 | char *Error = (char *) ptrace_getret(&CurrentRegs);
105 | char LocalErrorInfo[1024] = {0};
106 | ptrace_readdata(pid, (uint8_t *) Error, (uint8_t *) LocalErrorInfo, 1024);
107 | printf("dlopen error:%s\n", LocalErrorInfo);
108 | break;
109 | }
110 |
111 | // 将so库中需要调用的函数名称写入到远程进程内存空间中
112 | if (ptrace_writedata(pid, (uint8_t *) RemoteMapMemoryAddr + strlen(LibPath) + 2,
113 | (uint8_t *) FunctionName, strlen(FunctionName) + 1) == -1) {
114 | printf("Write FunctionName:%s to RemoteProcess error\n", FunctionName);
115 | break;
116 | }
117 |
118 | // 设置dlsym的参数,返回值为远程进程内函数的地址
119 | // void *dlsym(void *handle, const char *symbol);
120 | parameters[0] = (uintptr_t) RemoteModuleAddr;
121 | parameters[1] = (uintptr_t) ((uint8_t *) RemoteMapMemoryAddr + strlen(LibPath) + 2);
122 |
123 | if (ptrace_call(pid, (uintptr_t) dlsym_addr, parameters, 2, &CurrentRegs) == -1) {
124 | printf("Call Remote dlsym Func Failed\n");
125 | break;
126 | }
127 |
128 | // RemoteModuleFuncAddr为远程进程空间内获取的函数地址
129 | void *RemoteModuleFuncAddr = (void *) ptrace_getret(&CurrentRegs);
130 | printf("ptrace_call dlsym success, Remote Process ModuleFunc Addr:0x%lx\n",
131 | (uintptr_t) RemoteModuleFuncAddr);
132 |
133 | //为调用的函数参数,拷贝字符串 (这里分配到0x200后面 一般上面的字符串不会超过)
134 | if (ptrace_writedata(pid, (uint8_t *) RemoteMapMemoryAddr + strlen(LibPath) + 2 +
135 | strlen(parameter) + 2,
136 | (uint8_t *) parameter, strlen(parameter) + 1) == -1) {
137 | printf("Write param error\n");
138 | break;
139 | }
140 | parameters[0] = (uintptr_t) ((uint8_t *) RemoteMapMemoryAddr + strlen(LibPath) + 2 +
141 | strlen(parameter) + 2);
142 |
143 | //这里其实应该计算参数的大小 然后在分配内存空间
144 | //暂时传一个参数吧
145 | if (ptrace_call(pid, (uintptr_t) RemoteModuleFuncAddr, parameters, NumParameter,
146 | &CurrentRegs) == -1) {
147 | printf("Call Remote injected Func Failed\n");
148 | break;
149 | }
150 |
151 | if (ptrace_setregs(pid, &OriginalRegs) == -1) {
152 | printf("Recover reges failed\n");
153 | break;
154 | }
155 | printf("Recover Regs Success\n");
156 | ptrace_getregs(pid, &CurrentRegs);
157 | if (memcmp(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs)) != 0) {
158 | printf("Set Regs Error\n");
159 | }
160 | iRet = 0;
161 | } while (false);
162 |
163 | ptrace_detach(pid);
164 | return iRet;
165 | }
166 |
167 | struct process_inject {
168 | pid_t pid;
169 | char lib_name[1024];
170 | char dex_name[1024];
171 | char *entry_fun;
172 | } process_inject = {0, "", "", "entry"};
173 |
174 |
175 | void init_lib() {
176 | //获取当前目录
177 | char current_absolute_path[4096] = {0};
178 | if (realpath("./", current_absolute_path) == NULL) {
179 | perror("realpath");
180 | exit(-1);
181 | }
182 | strcat(process_inject.lib_name, current_absolute_path);
183 | strcat(process_inject.lib_name, "/libLoadModule.so");
184 |
185 | strcat(process_inject.dex_name, current_absolute_path);
186 | strcat(process_inject.dex_name, "/classes.dex");
187 |
188 | //修改为默认从加载so的路径读取
189 | // cp_lib(pkgName,"libsandhook.so");
190 | }
191 |
192 | void handle_parameter(int argc, char *argv[]) {
193 | pid_t pid = 0;
194 | int index = 0;
195 | char *pkg_name = NULL;
196 | char *file_name = NULL;
197 | char *dex_name = NULL;
198 | bool start_app_flag = false;
199 |
200 | while (index < argc) {
201 | if (strcmp("-p", argv[index]) == 0) {
202 | if (index + 1 >= argc) {
203 | printf("Missing parameter -p\n");
204 | exit(-1);
205 | }
206 | index++;
207 | pid = atoi(argv[index]);
208 | }
209 |
210 | if (strcmp("-n", argv[index]) == 0) {
211 | if (index + 1 >= argc) {
212 | printf("Missing parameter -n\n");
213 | exit(-1);
214 | }
215 | index++;
216 | pkg_name = argv[index];
217 |
218 | if (start_app_flag) {
219 | start_app(pkg_name);
220 | sleep(1);
221 | }
222 | }
223 |
224 | if (strcmp("-so", argv[index]) == 0) {
225 | if (index + 1 >= argc) {
226 | printf("Missing parameter -f\n");
227 | exit(-1);
228 | }
229 | index++;
230 | file_name = argv[index];
231 | }
232 |
233 | if (strcmp("-f", argv[index]) == 0) { start_app_flag = true; }
234 |
235 | if (strcmp("-d", argv[index]) == 0) {
236 | if (index + 1 >= argc) {
237 | printf("Missing parameter -d\n");
238 | exit(-1);
239 | }
240 | index++;
241 | dex_name = argv[index];
242 | }
243 | index++;
244 | }
245 |
246 | if (pkg_name != NULL) {
247 | printf("pkg_name is %s\n", pkg_name);
248 | if (get_pid_by_name(&pid, pkg_name)) {
249 | printf("getPidByName pid is %d\n", pid);
250 | }
251 | }
252 |
253 | if (pid == 0) {
254 | printf("not found target\n");
255 | exit(0);
256 | }
257 |
258 | process_inject.pid = pid;
259 |
260 | if (dex_name != NULL) {
261 | printf("dex_name is %s\n", dex_name);
262 | strcpy(process_inject.dex_name, strdup(dex_name));
263 | }
264 |
265 |
266 | if (file_name != NULL) {
267 | printf("file_name is %s\n", file_name);
268 | strcpy(process_inject.lib_name, strdup(file_name));
269 | }
270 | }
271 |
272 | int test(int argc, char *argv[]) {
273 | //初始化dex so
274 | init_lib();
275 | //处理参数
276 | handle_parameter(argc, argv);
277 |
278 | return inject_remote_process(process_inject.pid, process_inject.lib_name,
279 | process_inject.entry_fun, process_inject.dex_name, 1);
280 | }
281 |
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/PtraceInject.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Rose on 2020/2/18.
3 | //
4 |
5 | #ifndef INJECT_PTRACEINJECT_H
6 | #define INJECT_PTRACEINJECT_H
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | int inject_remote_process(pid_t pid, char *LibPath, char *FunctionName,
15 | char * parameter, long NumParameter);
16 | int test(int argc, char *argv[]);
17 |
18 | #endif //INJECT_PTRACEINJECT_H
19 |
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/lib_name.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Administrator on 2021/5/3.
3 | //
4 | #include "lib_name.h"
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/lib_name.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Administrator on 2021/5/3.
3 | //
4 | #pragma once
5 |
6 | #ifndef ANDROIDINJECT_LIB_NAME_H
7 |
8 | #define ANDROIDINJECT_LIB_NAME_H
9 |
10 | #if defined(__aarch64__) || defined(__x86_64__)
11 | const char *libc_path = "/system/lib64/libc.so";
12 | const char *linker_path = "/system/bin/linker64";
13 | const char *libdl_path = "/system/lib64/libdl.so";
14 |
15 | #else
16 | const char *libc_path = "/system/lib/libc.so";
17 | const char *linker_path = "/system/bin/linker";
18 | const char *libdl_path = "/system/lib/libdl.so";
19 | #endif
20 |
21 | #endif //ANDROIDINJECT_LIB_NAME_H
22 |
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/main.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by haoyuanli on 2020-3-24.
3 | //
4 | #include
5 | #include
6 | #include "PrintLog.h"
7 | #include "PtraceInject.h"
8 |
9 | int main(int argc, char *argv[]) {
10 | LOGI("[+] start main\n");
11 | test(argc,argv);
12 | return 0;
13 | }
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/module_utils.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include "PrintLog.h"
18 |
19 | #define MAX_PATH 0x100
20 |
21 |
22 | /*************************************************
23 | * Description: 在指定进程中搜索对应模块的基址
24 | * Input: pid表示远程进程的ID,若为-1表示自身进程,ModuleName表示要搜索的模块的名称
25 | * Return: 返回0表示获取模块基址失败,返回非0为要搜索的模块基址
26 | * **********************************************/
27 | void *get_module_base_addr(pid_t pid, const char *ModuleName) {
28 | FILE *fp = NULL;
29 | long ModuleBaseAddr = 0;
30 | char szFileName[50] = {0};
31 | char szMapFileLine[1024] = {0};
32 |
33 | // 读取"/proc/pid/maps"可以获得该进程加载的模块
34 | if (pid < 0) {
35 | // 枚举自身进程模块
36 | snprintf(szFileName, sizeof(szFileName), "/proc/self/maps");
37 | } else {
38 | snprintf(szFileName, sizeof(szFileName), "/proc/%d/maps", pid);
39 | }
40 |
41 | fp = fopen(szFileName, "r");
42 |
43 | if (fp != NULL) {
44 | while (fgets(szMapFileLine, sizeof(szMapFileLine), fp)) {
45 | if (strstr(szMapFileLine, ModuleName)) {
46 | char *Addr = strtok(szMapFileLine, "-");
47 | ModuleBaseAddr = strtoul(Addr, NULL, 16);
48 |
49 | if (ModuleBaseAddr == 0x8000)
50 | ModuleBaseAddr = 0;
51 |
52 | break;
53 | }
54 | }
55 |
56 | fclose(fp);
57 | }
58 |
59 | return (void *) ModuleBaseAddr;
60 | }
61 |
62 |
63 | /*************************************************
64 | * Description: 获取远程进程与本进程都加载的模块中函数的地址
65 | * Input: pid表示远程进程的ID,ModuleName表示模块名称,LocalFuncAddr表示本地进程中该函数的地址
66 | * Return: 返回远程进程中对应函数的地址
67 | * ***********************************************/
68 | void *get_remote_func_addr(pid_t pid, const char *ModuleName, void *LocalFuncAddr) {
69 | void *LocalModuleAddr, *RemoteModuleAddr, *RemoteFuncAddr;
70 |
71 | LocalModuleAddr = get_module_base_addr(-1, ModuleName);
72 | RemoteModuleAddr = get_module_base_addr(pid, ModuleName);
73 |
74 | RemoteFuncAddr = (void *) ((uintptr_t) LocalFuncAddr - (uintptr_t) LocalModuleAddr +
75 | (uintptr_t) RemoteModuleAddr);
76 | //[get_remote_func_addr] lmod=0x752805B000, rmod=0x0, lfunc=0x752805C0C0, rfunc=0x10C0
77 | //[get_remote_func_addr] lmod=0x7CBB472000, rmod=0x0, lfunc=0x7CBB4730EC, rfunc=0x10EC
78 | //[get_remote_func_addr] lmod=0x72921C6000, rmod=0x748CD89000, lfunc=0x72921C70C0, rfunc=0x748CD8A0C0
79 | LOGI("[get_remote_func_addr] lmod=0x%lX, rmod=0x%lX, lfunc=0x%lX, rfunc=0x%lX",
80 | LocalModuleAddr, RemoteModuleAddr, LocalFuncAddr, RemoteFuncAddr);
81 | return RemoteFuncAddr;
82 | }
83 |
84 | /*************************************************
85 | Description: 通过进程名称定位到进程的PID
86 | Input: process_name为要定位的进程名称
87 | Output: 无
88 | Return: 返回定位到的进程PID,若为-1,表示定位失败
89 | Others: 无
90 | *************************************************/
91 | pid_t find_pid_by_name(const char *process_name) {
92 | int dirid = 0;
93 | pid_t pid = -1;
94 | FILE *fp = NULL;
95 | char filename[MAX_PATH] = {0};
96 | char cmdline[MAX_PATH] = {0};
97 |
98 | struct dirent *entry = NULL;
99 |
100 | if (process_name == NULL)
101 | return -1;
102 |
103 | DIR *dir = opendir("/proc");
104 | if (dir == NULL)
105 | return -1;
106 |
107 | while ((entry = readdir(dir)) != NULL) {
108 | dirid = atoi(entry->d_name);
109 | if (dirid != 0) {
110 | snprintf(filename, MAX_PATH, "/proc/%d/cmdline", dirid);
111 | fp = fopen(filename, "r");
112 | if (fp) {
113 | fgets(cmdline, sizeof(cmdline), fp);
114 | fclose(fp);
115 | if (strncmp(process_name, cmdline, strlen(process_name)) == 0) {
116 | pid = dirid;
117 | LOGI("find cmdline: %s", cmdline);
118 | break;
119 | }
120 | }
121 | }
122 | }
123 |
124 | closedir(dir);
125 | return pid;
126 | }
127 |
128 | long freespaceaddr(pid_t pid) {
129 | FILE *fp;
130 | char filename[50];
131 | char line[850];
132 | long addr;
133 | char str[20];
134 | char perms[5];
135 | sprintf(filename, "/proc/%d/maps", pid);
136 | fp = fopen(filename, "r");
137 | if (fp == NULL) {
138 | LOGE("open file %s failed, err:%s", filename, strerror(errno));
139 | exit(1);
140 | }
141 |
142 | while (fgets(line, 850, fp) != NULL) {
143 | sscanf(line, "%lx-%*lx %s %*s %s %*d", &addr, perms, str);
144 |
145 | if (strstr(perms, "x") != NULL) {
146 | break;
147 | }
148 | }
149 | fclose(fp);
150 | return addr;
151 | }
152 |
153 |
154 | #define INTEL_RET_INSTRUCTION 0xc3
155 |
156 | unsigned char *findRet(void *endAddr) {
157 | unsigned char *retInstAddr = (unsigned char *) endAddr;
158 | while (*retInstAddr != INTEL_RET_INSTRUCTION) {
159 | retInstAddr--;
160 | }
161 | return retInstAddr;
162 | }
163 |
164 | bool get_pid_by_name(pid_t *pid, char *task_name) {
165 | DIR *dir;
166 | struct dirent *ptr;
167 | FILE *fp;
168 | char filepath[50];
169 | char cur_task_name[50];
170 | char buf[1024];
171 |
172 | dir = opendir("/proc");
173 | if (NULL != dir) {
174 | while ((ptr = readdir(dir)) != NULL) //循环读取/proc下的每一个文件/文件夹
175 | {
176 | //如果读取到的是"."或者".."则跳过,读取到的不是文件夹名字也跳过
177 | if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0))
178 | continue;
179 | if (DT_DIR != ptr->d_type)
180 | continue;
181 |
182 | sprintf(filepath, "/proc/%s/cmdline", ptr->d_name);//生成要读取的文件的路径
183 | fp = fopen(filepath, "r");
184 | if (NULL != fp) {
185 | if (fgets(buf, 1024 - 1, fp) == NULL) {
186 | fclose(fp);
187 | continue;
188 | }
189 | sscanf(buf, "%s", cur_task_name);
190 | //如果文件内容满足要求则打印路径的名字(即进程的PID)
191 | if (strstr(task_name, cur_task_name)) {
192 | // sscanf(ptr->d_name, "%d", pid);
193 | printf("d_name %s\n", ptr->d_name);
194 | *pid = atoi(ptr->d_name);
195 | return true;
196 |
197 | }
198 | fclose(fp);
199 | }
200 | }
201 | closedir(dir);
202 | }
203 |
204 | return false;
205 | }
206 |
207 |
208 | void copy_file(char *source_path, char *destination_path) {
209 | char buffer[1024];
210 | FILE *in, *out;
211 | if ((in = fopen(source_path, "r")) == NULL) {
212 | printf("源文件打开失败!\n");
213 | perror("fopen");
214 | exit(1);
215 | }
216 | if ((out = fopen(destination_path, "w")) == NULL) {
217 | printf("目标文件创建失败!\n");
218 | perror("fopen");
219 | exit(1);
220 | }
221 | int len;
222 | while ((len = fread(buffer, 1, 1024, in)) > 0) {
223 | fwrite(buffer, 1, len, out);
224 | }
225 | fclose(out);
226 | fclose(in);
227 | }
228 |
229 | void find_pkg_lib_path(char *pkgName, char *pkgLibPath) {
230 | DIR *pDir;
231 | struct dirent *ent;
232 | int i = 0;
233 | char childpath[256];
234 | pDir = opendir("/data/app");
235 | memset(childpath, 0, sizeof(childpath));
236 |
237 | while ((ent = readdir(pDir)) != NULL) {
238 | if (ent->d_type & DT_DIR) {
239 | if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
240 | continue;
241 | if (strstr(ent->d_name, pkgName) != NULL) {
242 | strcat(pkgLibPath, "/data/app/");
243 | strcat(pkgLibPath, ent->d_name);
244 | strcat(pkgLibPath, "/lib");
245 | break;
246 | }
247 |
248 | }
249 | }
250 | }
251 |
252 | void cp_lib(char *pkgName, char *libName) {
253 | //获取目标lib目录
254 | char pkgLibPath[256] = {0};
255 | find_pkg_lib_path(pkgName, pkgLibPath);
256 | //如果没有arm64则创建
257 | strcat(pkgLibPath, "/arm/");
258 | printf("pkgLibPath %s \n", pkgLibPath);
259 |
260 | if ((access(pkgLibPath, F_OK)) == -1) {
261 | if (mkdir(pkgLibPath, 0755) == -1) {
262 | perror("mkdir");
263 | exit(-1);
264 | }
265 | }
266 | strcat(pkgLibPath, libName);
267 | //获取当前目录
268 | char current_absolute_path[4096] = {0};
269 | if (realpath("./", current_absolute_path) == NULL) {
270 | perror("realpath");
271 | exit(-1);
272 | }
273 | //得到lib的路径
274 | char libPath[500] = {};
275 | strcat(current_absolute_path, "/");
276 | strcat(libPath, current_absolute_path);
277 | strcat(libPath, libName);
278 | printf("pkgLibPath %s \n", pkgLibPath);
279 | printf("libPath %s \n", libPath);
280 | copy_file(libPath, pkgLibPath);
281 | }
282 |
283 | /**
284 | * 获取应用的android.intent.action.MAIN
285 | * @param pkg_name 获取的应用包名
286 | * @param start_activity_name out 存放启动的main activity
287 | */
288 | void get_app_start_activity(char *pkg_name, char *start_activity_name) {
289 | char cmdstring[1024] = "dumpsys package ";
290 | char cmd_string[1024] = {0};
291 | char temp_file[] = "tmp_XXXXXX";
292 |
293 | strcat(cmdstring, pkg_name);
294 | int fd;
295 |
296 | if ((fd = mkstemp(temp_file)) == -1) {
297 | printf("create tmp file failed.\n");
298 | }
299 |
300 | sprintf(cmd_string, "%s > %s", cmdstring, temp_file);
301 | system(cmd_string);
302 |
303 | FILE *fp = fdopen(fd, "r");
304 | if (fp == NULL) {
305 | printf("can not load file!");
306 | return;
307 | }
308 | char line[1024];
309 | while (!feof(fp)) {
310 | fgets(line, 1024, fp);
311 | if (strstr(line, "android.intent.action.MAIN")) {
312 | fgets(line, 1024, fp);
313 | char *p;
314 | //选取第二个
315 | int index = 1;
316 | p = strtok(line, " ");
317 | while (p) {
318 | if (index == 2) {
319 | strcpy(start_activity_name, p);
320 | }
321 | index++;
322 | p = strtok(NULL, " ");
323 | }
324 | break;
325 | }
326 | }
327 | fclose(fp);
328 | unlink(temp_file);
329 | return;
330 | }
331 |
332 | /**
333 | * 启动app
334 | * @param pkg_name
335 | */
336 | void start_app(char *pkg_name) {
337 | char start_activity_name[1024] = {0};
338 | get_app_start_activity(pkg_name, start_activity_name);
339 | printf("%s\n", start_activity_name);
340 |
341 | char start_cmd[1024] = "am start ";
342 | strcat(start_cmd, start_activity_name);
343 | printf("%s\n",start_cmd);
344 | system(start_cmd);
345 | }
346 |
347 | // SeLinux的强制实施,使得dlopen()外部的so动态库有可能会失败返回。
348 | // 关闭SeLinux setenforce 0; getenforce
349 | // SeLinux会检测so动态库的label标签与权限是否满足可加载的要求,不满足就会无情的拒绝!
350 | // 为了解决这个问题,需要调用setxattr()修改so的属性信息。
351 | // chcon -v u:object_r:system_file:s0 /data/local/tmp/libInjectModule.so
352 | // setxattr(process_inject.libname, "u:object_r:system_file:s0");
353 |
354 | /*int setxattr(const char *path, const char *value) {
355 | if ((access("/sys/fs/selinux", F_OK)) != -1) {
356 | return 0;
357 | }
358 | return syscall(__NR_setxattr, path, "security.selinux", value, strlen(value), 0);
359 | }*/
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/module_utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Administrator on 2021/5/3.
3 | //
4 |
5 | #ifndef ANDROIDINJECT_MODULE_UTILS_H
6 | #define ANDROIDINJECT_MODULE_UTILS_H
7 | void *get_module_base_addr(pid_t pid, const char *ModuleName);
8 | pid_t find_pid_by_name(const char *process_name);
9 | void *get_remote_func_addr(pid_t pid, const char *ModuleName, void *LocalFuncAddr);
10 | long freespaceaddr(pid_t pid);
11 | unsigned char *findRet(void *endAddr);
12 | int setxattr(const char *path, const char *value);
13 | bool get_pid_by_name(pid_t *pid, char *task_name);
14 | void copy_file(char *source_path, char *destination_path);
15 | void find_pkg_lib_path(char *pkgName, char *pkgLibPath);
16 | void cp_lib(char * pkgName,char * libName);
17 | void get_app_start_activity(char * pkg_name, char *start_activity_name);
18 | void start_app(char * pkg_name);
19 | #endif //ANDROIDINJECT_MODULE_UTILS_H
20 |
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/ptrace_utils.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Administrator on 2021/5/3.
3 | //
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include "PrintLog.h"
18 | #include "ptrace_utils.h"
19 | #include "lib_name.h"
20 | #include "module_utils.h"
21 |
22 |
23 | void *get_mmap_address(pid_t pid) {
24 | return get_remote_func_addr(pid, libc_path, (void *) mmap);
25 | }
26 |
27 | void *get_dlopen_address(pid_t pid) {
28 | void *dlopen_addr;
29 | char sdk_ver[32];
30 | memset(sdk_ver, 0, sizeof(sdk_ver));
31 | __system_property_get("ro.build.version.sdk", sdk_ver);
32 |
33 | printf("linker_path value:%s\n",linker_path);
34 | if (atoi(sdk_ver) <= 23) {
35 | dlopen_addr = get_remote_func_addr(pid, linker_path, (void *) dlopen);
36 | } else {
37 | dlopen_addr = get_remote_func_addr(pid, libdl_path, (void *) dlopen);
38 | }
39 | printf("dlopen RemoteFuncAddr:0x%lx\n", (uintptr_t) dlopen_addr);
40 | return dlopen_addr;
41 | }
42 |
43 | void *get_dlclose_address(pid_t pid) {
44 | void *dlclose_addr;
45 | char sdk_ver[32];
46 | memset(sdk_ver, 0, sizeof(sdk_ver));
47 | __system_property_get("ro.build.version.sdk", sdk_ver);
48 |
49 | if (atoi(sdk_ver) <= 23) {
50 | dlclose_addr = get_remote_func_addr(pid, linker_path, (void *) dlclose);
51 | } else {
52 | dlclose_addr = get_remote_func_addr(pid, libdl_path, (void *) dlclose);
53 | }
54 | printf("dlclose RemoteFuncAddr:0x%lx\n", (uintptr_t) dlclose_addr);
55 | return dlclose_addr;
56 | }
57 |
58 | void *get_dlsym_address(pid_t pid) {
59 | void *dlsym_addr;
60 | char sdk_ver[32];
61 | memset(sdk_ver, 0, sizeof(sdk_ver));
62 | __system_property_get("ro.build.version.sdk", sdk_ver);
63 |
64 | if (atoi(sdk_ver) <= 23) {
65 | dlsym_addr = get_remote_func_addr(pid, linker_path, (void *) dlsym);
66 | } else {
67 | dlsym_addr = get_remote_func_addr(pid, libdl_path, (void *) dlsym);
68 | }
69 | printf("dlsym RemoteFuncAddr:0x%lx\n", (uintptr_t) dlsym_addr);
70 | return dlsym_addr;
71 | }
72 |
73 |
74 | void *get_dlerror_address(pid_t pid) {
75 | void *dlerror_addr;
76 | char sdk_ver[32];
77 | memset(sdk_ver, 0, sizeof(sdk_ver));
78 | __system_property_get("ro.build.version.sdk", sdk_ver);
79 |
80 | if (atoi(sdk_ver) <= 23) {
81 | dlerror_addr = get_remote_func_addr(pid, linker_path, (void *) dlerror);
82 | } else {
83 | dlerror_addr = get_remote_func_addr(pid, libdl_path, (void *) dlerror);
84 | }
85 | printf("dlerror RemoteFuncAddr:0x%lx\n", (uintptr_t) dlerror_addr);
86 | return dlerror_addr;
87 | }
88 |
89 | /***************************
90 | * Description: 使用ptrace Attach附加到指定进程,发送SIGSTOP信号给指定进程让其停止下来并对其进行跟踪。
91 | * 但是被跟踪进程(tracee)不一定会停下来,因为同时attach和传递SIGSTOP可能会将SIGSTOP丢失。
92 | * 所以需要waitpid(2)等待被跟踪进程被停下
93 | * Input: pid表示远程进程的ID
94 | * Output: 无
95 | * Return: 返回0表示attach成功,返回-1表示失败
96 | * Others: 无
97 | * ************************/
98 | int ptrace_attach(pid_t pid) {
99 | int status = 0;
100 | if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
101 | printf("ptrace attach process error, pid:%d, err:%s\n", pid, strerror(errno));
102 | return -1;
103 | }
104 |
105 | printf("attach porcess success, pid:%d\n", pid);
106 | waitpid(pid, &status, WUNTRACED);
107 |
108 | return 0;
109 | }
110 |
111 | /*************************************************
112 | * Description: 使用ptrace detach指定进程,完成对指定进程的跟踪操作后,使用该参数即可解除附加
113 | * Input: pid表示远程进程的ID
114 | * Output: 无
115 | * Return: 返回0表示detach成功,返回-1表示失败
116 | * Others: 无
117 | * ***********************************************/
118 | int ptrace_detach(pid_t pid) {
119 | if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) {
120 | printf("detach process error, pid:%d, err:%s\n", pid, strerror(errno));
121 | return -1;
122 | }
123 |
124 | printf("detach process success, pid:%d\n", pid);
125 | return 0;
126 | }
127 |
128 | /*************************************************
129 | * Description: ptrace使远程进程继续运行
130 | * Input: pid表示远程进程的ID
131 | * Output: 无
132 | * Return: 返回0表示continue成功,返回-1表示失败
133 | * Others: 无
134 | * ***********************************************/
135 | int ptrace_continue(pid_t pid) {
136 | if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
137 | printf("ptrace continue process error, pid:%d, err:%ss\n", pid, strerror(errno));
138 | return -1;
139 | }
140 |
141 | printf("ptrace continue process success, pid:%d\n", pid);
142 | return 0;
143 | }
144 |
145 |
146 | /*************************************************
147 | * Description: 使用ptrace获取远程进程的寄存器值
148 | * Input: pid表示远程进程的ID,regs为pt_regs结构,存储了寄存器值
149 | * Output: 无
150 | * Return: 返回0表示获取寄存器成功,返回-1表示失败
151 | * Others: 无
152 | * ***********************************************/
153 | int ptrace_getregs(pid_t pid, struct pt_regs *regs) {
154 | #if defined(__aarch64__)
155 | int regset = NT_PRSTATUS;
156 | struct iovec ioVec;
157 |
158 | ioVec.iov_base = regs;
159 | ioVec.iov_len = sizeof(*regs);
160 | if (ptrace(PTRACE_GETREGSET, pid, (void *) regset, &ioVec) < 0) {
161 | printf("ptrace_getregs: Can not get register values, io %llx, %d\n", ioVec.iov_base,
162 | ioVec.iov_len);
163 | return -1;
164 | }
165 |
166 | return 0;
167 | #else
168 | if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) {
169 | printf("Get Regs error, pid:%d, err:%s\n", pid, strerror(errno));
170 | return -1;
171 | }
172 | #endif
173 | return 0;
174 | }
175 |
176 |
177 | /*************************************************
178 | * Description: 使用ptrace设置远程进程的寄存器值
179 | * Input: pid表示远程进程的ID,regs为pt_regs结构,存储需要修改的寄存器值
180 | * Output: 无
181 | * Return: 返回0表示设置寄存器成功,返回-1表示失败
182 | * ***********************************************/
183 | int ptrace_setregs(pid_t pid, struct pt_regs *regs) {
184 | #if defined(__aarch64__)
185 | int regset = NT_PRSTATUS;
186 | struct iovec ioVec;
187 |
188 | ioVec.iov_base = regs;
189 | ioVec.iov_len = sizeof(*regs);
190 | if (ptrace(PTRACE_SETREGSET, pid, (void *) regset, &ioVec) < 0) {
191 | perror("ptrace_setregs: Can not get register values");
192 | return -1;
193 | }
194 |
195 | return 0;
196 | #else
197 | if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) {
198 | printf("Set Regs error, pid:%d, err:%s\n", pid, strerror(errno));
199 | return -1;
200 | }
201 | #endif
202 | return 0;
203 | }
204 |
205 | /*************************************************
206 | * Description: 获取返回值,ARM处理器中返回值存放在ARM_r0寄存器中
207 | * Input: regs存储远程进程当前的寄存器值
208 | * Return: 在ARM处理器下返回r0寄存器值
209 | * ***********************************************/
210 | long ptrace_getret(struct pt_regs *regs) {
211 | #if defined(__i386__) || defined(__x86_64__)
212 | return regs->eax;
213 | #elif defined(__arm__) || defined(__aarch64__)
214 | return regs->ARM_r0;
215 | #else
216 | printf("Not supported Environment %s\n", __FUNCTION__);
217 | #endif
218 | }
219 |
220 | /*************************************************
221 | * Description: 获取当前执行代码的地址,ARM处理器下存放在ARM_pc中
222 | * Input: regs存储远程进程当前的寄存器值
223 | * Return: 在ARM处理器下返回pc寄存器值
224 | * **********************************************/
225 | long ptrace_getpc(struct pt_regs *regs) {
226 | #if defined(__i386__) || defined(__x86_64__)
227 | return regs->eip;
228 | #elif defined(__arm__) || defined(__aarch64__)
229 | return regs->ARM_pc;
230 | #else
231 | printf("Not supported Environment %s\n", __FUNCTION__);
232 | #endif
233 | }
234 |
235 | /*************************************************
236 | * Description: 使用ptrace从远程进程内存中读取数据
237 | * Input: pid表示远程进程的ID,pSrcBuf表示从远程进程读取数据的内存地址
238 | * pDestBuf表示用于存储读取出数据的地址,size表示读取数据的大小
239 | * Return: 返回0表示读取数据成功
240 | * other: 这里的*_t类型是typedef定义一些基本类型的别名,用于跨平台。例如
241 | * uint8_t表示无符号8位也就是无符号的char类型
242 | * **********************************************/
243 | int ptrace_readdata(pid_t pid, uint8_t *pSrcBuf, uint8_t *pDestBuf, size_t size) {
244 | long nReadCount = 0;
245 | long nRemainCount = 0;
246 | uint8_t *pCurSrcBuf = pSrcBuf;
247 | uint8_t *pCurDestBuf = pDestBuf;
248 | long lTmpBuf = 0;
249 | long i = 0;
250 |
251 | nReadCount = size / sizeof(long);
252 | nRemainCount = size % sizeof(long);
253 |
254 | for (i = 0; i < nReadCount; i++) {
255 | lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurSrcBuf, 0);
256 | memcpy(pCurDestBuf, (char *) (&lTmpBuf), sizeof(long));
257 | pCurSrcBuf += sizeof(long);
258 | pCurDestBuf += sizeof(long);
259 | }
260 |
261 | if (nRemainCount > 0) {
262 | lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurSrcBuf, 0);
263 | memcpy(pCurDestBuf, (char *) (&lTmpBuf), nRemainCount);
264 | }
265 |
266 | return 0;
267 | }
268 |
269 | /*************************************************
270 | * Description: 使用ptrace将数据写入到远程进程空间中
271 | * Input: pid表示远程进程的ID,pWriteAddr表示写入数据到远程进程的内存地址
272 | * pWriteData用于存储写入数据的地址,size表示写入数据的大小
273 | * Return: 返回0表示写入数据成功,返回-1表示写入数据失败
274 | * ***********************************************/
275 | int ptrace_writedata(pid_t pid, uint8_t *pWriteAddr, uint8_t *pWriteData,
276 | size_t size) {
277 |
278 | long nWriteCount = 0;
279 | long nRemainCount = 0;
280 | uint8_t *pCurSrcBuf = pWriteData;
281 | uint8_t *pCurDestBuf = pWriteAddr;
282 | long lTmpBuf = 0;
283 | long i = 0;
284 |
285 | nWriteCount = size / sizeof(long);
286 | nRemainCount = size % sizeof(long);
287 |
288 | // 先讲数据以sizeof(long)字节大小为单位写入到远程进程内存空间中
289 | for (i = 0; i < nWriteCount; i++) {
290 | memcpy((void *) (&lTmpBuf), pCurSrcBuf, sizeof(long));
291 | if (ptrace(PTRACE_POKETEXT, pid, (void *) pCurDestBuf, (void *) lTmpBuf) <
292 | 0) // PTRACE_POKETEXT表示从远程内存空间写入一个sizeof(long)大小的数据
293 | {
294 | printf("Write Remote Memory error, MemoryAddr:0x%lx, err:%s\n", (uintptr_t) pCurDestBuf,
295 | strerror(errno));
296 | return -1;
297 | }
298 | pCurSrcBuf += sizeof(long);
299 | pCurDestBuf += sizeof(long);
300 | }
301 |
302 | // 将剩下的数据写入到远程进程内存空间中
303 | if (nRemainCount > 0) {
304 | lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurDestBuf,
305 | NULL); //先取出原内存中的数据,然后将要写入的数据以单字节形式填充到低字节处
306 | memcpy((void *) (&lTmpBuf), pCurSrcBuf, nRemainCount);
307 | if (ptrace(PTRACE_POKETEXT, pid, pCurDestBuf, lTmpBuf) < 0) {
308 | printf("Write Remote Memory error, MemoryAddr:0x%lx, err:%s\n", (uintptr_t) pCurDestBuf,
309 | strerror(errno));
310 | return -1;
311 | }
312 | }
313 |
314 | return 0;
315 | }
316 |
317 | /*************************************************
318 | * Description: 使用ptrace远程call函数
319 | * Input: pid表示远程进程的ID,ExecuteAddr为远程进程函数的地址
320 | * parameters为函数参数的地址,regs为远程进程call函数前的寄存器环境
321 | * Return: 返回0表示call函数成功,返回-1表示失败
322 | * **********************************************/
323 | int ptrace_call(pid_t pid, uintptr_t ExecuteAddr, long *parameters, long num_params,
324 | struct pt_regs *regs) {
325 | #if defined(__i386__)
326 | // 写入参数到堆栈
327 | regs->esp -= (num_params) * sizeof(long); // 分配栈空间,栈的方向是从高地址到低地址
328 | if (0 != ptrace_writedata(pid, (uint8_t *) regs->esp, (uint8_t *) parameters,
329 | (num_params) * sizeof(long))) {
330 | return -1;
331 | }
332 |
333 | long tmp_addr = 0x0;
334 | regs->esp -= sizeof(long);
335 | if (0 !=
336 | ptrace_writedata(pid, (uint8_t *) regs->esp, (uint8_t *) &tmp_addr, sizeof(tmp_addr))) {
337 | return -1;
338 | }
339 |
340 | //设置eip寄存器为需要调用的函数地址
341 | regs->eip = ExecuteAddr;
342 |
343 | // 开始执行
344 | if (-1 == ptrace_setregs(pid, regs) || -1 == ptrace_continue(pid)) {
345 | printf("ptrace set regs or continue error, pid:%d\n", pid);
346 | return -1;
347 | }
348 |
349 | int stat = 0;
350 | // 对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:①下一次系统调用;②子进程退出;③子进程的执行发生错误。
351 | // 参数WUNTRACED表示当进程进入暂停状态后,立即返回
352 | waitpid(pid, &stat, WUNTRACED);
353 |
354 | // 判断是否成功执行函数
355 | printf("ptrace call ret status is %d\n", stat);
356 | while (stat != 0xb7f) {
357 | if (ptrace_continue(pid) == -1) {
358 | printf("ptrace call error");
359 | return -1;
360 | }
361 | waitpid(pid, &stat, WUNTRACED);
362 | }
363 |
364 | // 获取远程进程的寄存器值,方便获取返回值
365 | if (ptrace_getregs(pid, regs) == -1) {
366 | printf("After call getregs error");
367 | return -1;
368 | }
369 | #elif defined(__x86_64__)
370 | int num_param_registers = 6;
371 | // x64处理器,函数传递参数,将整数和指针参数前6个参数从左到右保存在寄存器rdi,rsi,rdx,rcx,r8和r9
372 | // 更多的参数则按照从右到左的顺序依次压入堆栈。
373 | if (num_params > 0) regs->rdi = parameters[0];
374 | if (num_params > 1) regs->rsi = parameters[1];
375 | if (num_params > 2) regs->rdx = parameters[2];
376 | if (num_params > 3) regs->rcx = parameters[3];
377 | if (num_params > 4) regs->r8 = parameters[4];
378 | if (num_params > 5) regs->r9 = parameters[5];
379 |
380 | if (num_param_registers < num_params) {
381 | regs->esp -= (num_params - num_param_registers) * sizeof(long); // 分配栈空间,栈的方向是从高地址到低地址
382 | if (0 != ptrace_writedata(pid, (uint8_t *) regs->esp,
383 | (uint8_t *) ¶meters[num_param_registers],
384 | (num_params - num_param_registers) * sizeof(long))) {
385 | return -1;
386 | }
387 | }
388 |
389 | long tmp_addr = 0x0;
390 | regs->esp -= sizeof(long);
391 | if (0 !=
392 | ptrace_writedata(pid, (uint8_t *) regs->esp, (uint8_t *) &tmp_addr, sizeof(tmp_addr))) {
393 | return -1;
394 | }
395 |
396 | //设置eip寄存器为需要调用的函数地址
397 | regs->eip = ExecuteAddr;
398 |
399 | // 开始执行
400 | if (-1 == ptrace_setregs(pid, regs) || -1 == ptrace_continue(pid)) {
401 | printf("ptrace set regs or continue error, pid:%d", pid);
402 | return -1;
403 | }
404 |
405 | int stat = 0;
406 | // 对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:①下一次系统调用;②子进程退出;③子进程的执行发生错误。
407 | // 参数WUNTRACED表示当进程进入暂停状态后,立即返回
408 | waitpid(pid, &stat, WUNTRACED);
409 |
410 | // 判断是否成功执行函数
411 | printf("ptrace call ret status is %lX\n", stat);
412 | while (stat != 0xb7f) {
413 | if (ptrace_continue(pid) == -1) {
414 | printf("ptrace call error");
415 | return -1;
416 | }
417 | waitpid(pid, &stat, WUNTRACED);
418 | }
419 |
420 | #elif defined(__arm__) || defined(__aarch64__)
421 | #if defined(__arm__)
422 | int num_param_registers = 4;
423 | #elif defined(__aarch64__)
424 | int num_param_registers = 8;
425 | #endif
426 | int i = 0;
427 | // ARM处理器,函数传递参数,将前四个参数放到r0-r3,剩下的参数压入栈中
428 | for (i = 0; i < num_params && i < num_param_registers; i++) {
429 | regs->uregs[i] = parameters[i];
430 | }
431 |
432 | if (i < num_params) {
433 | regs->ARM_sp -= (num_params - i) * sizeof(long); // 分配栈空间,栈的方向是从高地址到低地址
434 | if (ptrace_writedata(pid, (uint8_t *) (regs->ARM_sp), (uint8_t *) ¶meters[i],
435 | (num_params - i) * sizeof(long)) == -1)
436 | return -1;
437 | }
438 |
439 | regs->ARM_pc = ExecuteAddr; //设置ARM_pc寄存器为需要调用的函数地址
440 | // 与BX跳转指令类似,判断跳转的地址位[0]是否为1,如果为1,则将CPST寄存器的标志T置位,解释为Thumb代码
441 | // 若为0,则将CPSR寄存器的标志T复位,解释为ARM代码
442 | if (regs->ARM_pc & 1) {
443 | /* thumb */
444 | regs->ARM_pc &= (~1u);
445 | regs->ARM_cpsr |= CPSR_T_MASK;
446 | } else {
447 | /* arm */
448 | regs->ARM_cpsr &= ~CPSR_T_MASK;
449 | }
450 |
451 | regs->ARM_lr = 0;
452 |
453 | // Android 7.0以上修正lr为libc.so的起始地址 getprop获取ro.build.version.sdk
454 | long lr_val = 0;
455 | char sdk_ver[32];
456 | memset(sdk_ver, 0, sizeof(sdk_ver));
457 | __system_property_get("ro.build.version.sdk", sdk_ver);
458 | // printf("ro.build.version.sdk: %s", sdk_ver);
459 | if (atoi(sdk_ver) <= 23) {
460 | lr_val = 0;
461 | } else { // Android 7.0
462 | static long start_ptr = 0;
463 | if (start_ptr == 0) {
464 | start_ptr = (long) get_module_base_addr(pid, libc_path);
465 | }
466 | lr_val = start_ptr;
467 | }
468 | regs->ARM_lr = lr_val;
469 |
470 | if (ptrace_setregs(pid, regs) == -1 || ptrace_continue(pid) == -1) {
471 | printf("ptrace set regs or continue error, pid:%d\n", pid);
472 | return -1;
473 | }
474 |
475 | int stat = 0;
476 | // 对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:①下一次系统调用;②子进程退出;③子进程的执行发生错误。
477 | // 参数WUNTRACED表示当进程进入暂停状态后,立即返回
478 | // 将ARM_lr(存放返回地址)设置为0,会导致子进程执行发生错误,则子进程进入暂停状态
479 | waitpid(pid, &stat, WUNTRACED);
480 |
481 | // 判断是否成功执行函数
482 | printf("ptrace call ret status is %d\n", stat);
483 | while ((stat & 0xFF) != 0x7f) {
484 | if (ptrace_continue(pid) == -1) {
485 | printf("ptrace call error\n");
486 | return -1;
487 | }
488 | waitpid(pid, &stat, WUNTRACED);
489 | }
490 |
491 | // 获取远程进程的寄存器值,方便获取返回值
492 | if (ptrace_getregs(pid, regs) == -1) {
493 | printf("After call getregs error\n");
494 | return -1;
495 | }
496 | #else
497 | printf("Not supported Environment %s\n", __FUNCTION__);
498 | #endif
499 | return 0;
500 | }
501 |
502 | void dump_registers(struct pt_regs *regs) {
503 | #if defined(__i386__)
504 | printf("X86 eax:%08x, ebx:%08x, ecx:%08x, edx:%08x, esi:%08x, edi:%08x, ebp:%08x, xds:%08x, xes:%08x, xfs:%08x, xgs:%08x, orig_eax:%08x, eip:%08x, xcs:%08x, eflags:%08x, esp:%08x, xss:%08x,",
505 | regs->eax, regs->ebx, regs->ecx, regs->edx, regs->esi, regs->edi, regs->ebp, regs->xds,
506 | regs->xes, regs->xfs, regs->xgs, regs->orig_eax, regs->eip, regs->xcs, regs->eflags,
507 | regs->esp, regs->xss);
508 | #elif defined(__arm__)
509 | printf("ARM_r0:0x%08X, ARM_r1:0x%08X, ARM_r2:0x%08X, ARM_r3:0x%08X, ARM_r4:0x%08X, ARM_r5:0x%08X, ARM_r6:0x%08X, ARM_r7:0x%08X, ARM_r8:0x%08X, ARM_r9:0x%08X, ARM_r10:0x%08X, ARM_fp:0x%08X, ARM_ip:0x%08X, ARM_sp:0x%08X, ARM_lr:0x%08X, ARM_pc:0x%08X, ARM_cpsr:0x%08X, ARM_ORIG_r0:0x%08X",
510 | regs->ARM_r0 ,regs->ARM_r1 ,regs->ARM_r2 ,regs->ARM_r3 ,regs->ARM_r4 ,regs->ARM_r5 ,regs->ARM_r6 ,regs->ARM_r7 ,regs->ARM_r8 ,regs->ARM_r9 ,regs->ARM_r10 ,regs->ARM_fp ,regs->ARM_ip ,regs->ARM_sp ,regs->ARM_lr ,regs->ARM_pc ,regs->ARM_cpsr ,regs->ARM_ORIG_r0);
511 | #elif defined(__aarch64__)
512 | printf("x0:%016lx, x1:%016lx, x2:%016lx, x3:%016lx, x4:%016lx, x5:%016lx, x6:%016lx, x7:%016lx, x8:%016lx, x9:%016lx, x10:%016lx, x11:%016lx, x12:%016lx, x13:%016lx, x14:%016lx, x15:%016lx, x16:%016lx, x17:%016lx, x18:%016lx, x19:%016lx, x20:%016lx, x21:%016lx, x22:%016lx, x23:%016lx, x24:%016lx, x25:%016lx, x26:%016lx, x27:%016lx, x28:%016lx, x29:%016lx, x30:%016lx, sp:%016lx, pc:%016lx, pstate:%016lx\n",
513 | regs->regs[0], regs->regs[1], regs->regs[2], regs->regs[3], regs->regs[4], regs->regs[5],
514 | regs->regs[6], regs->regs[7], regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11],
515 | regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15], regs->regs[16],
516 | regs->regs[17], regs->regs[18], regs->regs[19], regs->regs[20], regs->regs[21],
517 | regs->regs[22], regs->regs[23], regs->regs[24], regs->regs[25], regs->regs[26],
518 | regs->regs[27], regs->regs[28], regs->regs[29], regs->regs[30], regs->sp, regs->pc,
519 | regs->pstate);
520 | #elif defined(__x86_64__)
521 | printf("rax:0x%lX, rbx:0x%lX, rcx:0x%lX, rdx:0x%lX, rbp:0x%lX, rdi:0x%lX, rip:0x%lX, rsi:0x%lX, rsp:0x%lX, ss:0x%lX, cs:0x%lX, eflags:0x%lX, orig_rax:0x%lX, r8:0x%lX, r9:0x%lX, r10:0x%lX, r11:0x%lX, r12:0x%lX, r13:0x%lX, r14:0x%lX, r15:0x%lX",
522 | regs->rax, regs->rbx, regs->rcx, regs->rdx, regs->rbp, regs->rdi, regs->rip, regs->rsi,
523 | regs->rsp, regs->ss, regs->cs, regs->eflags, regs->orig_rax, regs->r8, regs->r9, regs->r10,
524 | regs->r11, regs->r12, regs->r13, regs->r14, regs->r15);
525 | #else
526 | printf("Not supported Environment %s\n", __FUNCTION__);
527 | #endif
528 | }
--------------------------------------------------------------------------------
/app/src/main/cpp/PtraceInject/ptrace_utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Administrator on 2021/5/3.
3 | //
4 | #pragma once
5 |
6 | #ifndef ANDROIDINJECT_PTRACE_UTILS_H
7 | #define ANDROIDINJECT_PTRACE_UTILS_H
8 |
9 | #define CPSR_T_MASK ( 1u << 5 )
10 | #define REMOTE_ADDR(addr, local_base, remote_base) ( (uint32_t)(addr) + (uint32_t)(remote_base) - (uint32_t)(local_base) )
11 |
12 | #if defined(__aarch64__)
13 | #define pt_regs user_pt_regs
14 | #define uregs regs
15 | #define ARM_pc pc
16 | #define ARM_sp sp
17 | #define ARM_cpsr pstate
18 | #define ARM_lr regs[30]
19 | #define ARM_r0 regs[0]
20 | #define PTRACE_GETREGS PTRACE_GETREGSET
21 | #define PTRACE_SETREGS PTRACE_SETREGSET
22 | #elif defined(__x86_64__)
23 | #define pt_regs user_regs_struct
24 | #define eax rax
25 | #define esp rsp
26 | #define eip rip
27 | #endif
28 |
29 | #if defined(__aarch64__)
30 | #define pt_regs user_pt_regs
31 | #elif defined(__x86_64__)
32 | #define pt_regs user_regs_struct
33 | #endif
34 |
35 | int ptrace_attach(pid_t pid);
36 |
37 | int ptrace_detach(pid_t pid);
38 |
39 | int ptrace_continue(pid_t pid);
40 |
41 | int ptrace_getregs(pid_t pid, struct pt_regs *regs);
42 |
43 | int ptrace_setregs(pid_t pid, struct pt_regs *regs);
44 |
45 | long ptrace_getret(struct pt_regs *regs);
46 |
47 | long ptrace_getpc(struct pt_regs *regs);
48 |
49 | int ptrace_readdata(pid_t pid, uint8_t *pSrcBuf, uint8_t *pDestBuf, size_t size);
50 |
51 | int ptrace_writedata(pid_t pid, uint8_t *pWriteAddr, uint8_t *pWriteData,
52 | size_t size);
53 |
54 | int ptrace_call(pid_t pid, uintptr_t ExecuteAddr, long *parameters, long num_params,
55 | struct pt_regs *regs);
56 |
57 | void dump_registers(struct pt_regs *regs);
58 |
59 | void *get_mmap_address(pid_t pid);
60 |
61 | void *get_dlopen_address(pid_t pid);
62 |
63 | void *get_dlclose_address(pid_t pid);
64 |
65 | void *get_dlsym_address(pid_t pid);
66 |
67 | void *get_dlerror_address(pid_t pid);
68 |
69 |
70 | #endif //ANDROIDINJECT_PTRACE_UTILS_H
71 |
--------------------------------------------------------------------------------
/app/src/main/cpp/native-lib/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 |
13 | add_library( # Sets the name of the library.
14 | native-lib
15 |
16 | # Sets the library as a shared library.
17 | SHARED
18 |
19 | # Provides a relative path to your source file(s).
20 | native-lib.cpp )
21 |
22 | # Searches for a specified prebuilt library and stores the path as a
23 | # variable. Because CMake includes system libraries in the search path by
24 | # default, you only need to specify the name of the public NDK library
25 | # you want to add. CMake verifies that the library exists before
26 | # completing its build.
27 |
28 | find_library( # Sets the name of the path variable.
29 | log-lib
30 |
31 | # Specifies the name of the NDK library that
32 | # you want CMake to locate.
33 | log )
34 |
35 | # Specifies libraries CMake should link to your target library. You
36 | # can link multiple libraries, such as libraries you define in this
37 | # build script, prebuilt third-party libraries, or system libraries.
38 |
39 | target_link_libraries( # Specifies the target library.
40 | native-lib
41 |
42 | # Links the target library to the log library
43 | # included in the NDK.
44 | ${log-lib} )
--------------------------------------------------------------------------------
/app/src/main/cpp/native-lib/PrintLog.h:
--------------------------------------------------------------------------------
1 | #ifndef _ANDROID_LOG_PRINT_H_
2 | #define _ANDROID_LOG_PRINT_H_
3 |
4 | #include
5 |
6 | #define IS_DEBUG
7 |
8 | #ifdef IS_DEBUG
9 |
10 | #define LOG_TAG ("SharkChilli")
11 |
12 | #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
13 |
14 | #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__))
15 |
16 | #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__))
17 |
18 | #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__))
19 |
20 | #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__))
21 |
22 | #else
23 |
24 | #define LOGV(LOG_TAG, ...) NULL
25 |
26 | #define LOGD(LOG_TAG, ...) NULL
27 |
28 | #define LOGI(LOG_TAG, ...) NULL
29 |
30 | #define LOGW(LOG_TAG, ...) NULL
31 |
32 | #define LOGE(LOG_TAG, ...) NULL
33 |
34 | #endif
35 |
36 | #endif
--------------------------------------------------------------------------------
/app/src/main/cpp/native-lib/native-lib.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "PrintLog.h"
5 |
6 | typedef int (*FUNC_INJECT_ENTRY)();
7 |
8 | int test_load_library() {
9 | char InjectModuleName[] = "/data/app/com.example.androidinject-waaMZzkROOdkpeuvRzkKAQ==/lib/arm64/libInjectModule.so"; // 注入模块全路径
10 | void *handle = dlopen(InjectModuleName, RTLD_LAZY);
11 | if (!handle) {
12 | LOGE("[%s](%d) dlopen %s error:%s", __FILE__, __LINE__, InjectModuleName, dlerror());
13 | return 0;
14 | }
15 |
16 | do {
17 | FUNC_INJECT_ENTRY entry_func = (FUNC_INJECT_ENTRY) dlsym(handle, "Inject_entry");
18 | if (NULL == entry_func) {
19 | LOGE("[%s](%d) dlsym %s error:%s", __FILE__, __LINE__, "Inject_entry", dlerror());
20 | break;
21 | }
22 | entry_func();
23 | } while (false);
24 |
25 | dlclose(handle);
26 | return 1;
27 | }
28 |
29 | extern "C" JNIEXPORT jstring JNICALL
30 | Java_com_example_androidinject_MainActivity_stringFromJNI(
31 | JNIEnv *env,
32 | jobject /* this */) {
33 | std::string hello = "Hello from C++";
34 | return env->NewStringUTF(hello.c_str());
35 | }
36 |
37 | extern "C" JNIEXPORT jint JNICALL
38 | Java_com_example_androidinject_MainActivity_testload(
39 | JNIEnv *env,
40 | jobject /* this */) {
41 | return test_load_library();
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/app/context/ContextUtils.java:
--------------------------------------------------------------------------------
1 | package com.app.context;
2 |
3 | import android.app.Activity;
4 | import android.app.ActivityManager;
5 | import android.app.Application;
6 | import android.content.Context;
7 | import android.content.pm.ActivityInfo;
8 | import android.content.pm.PackageInfo;
9 | import android.content.pm.PackageManager;
10 | import android.util.Log;
11 |
12 | import java.lang.reflect.Field;
13 | import java.lang.reflect.InvocationTargetException;
14 | import java.util.ArrayList;
15 | import java.util.List;
16 | import java.util.Map;
17 |
18 | public class ContextUtils {
19 | private static ContextUtils mContextUtils;
20 | private ClassLoader mClassLoader;
21 |
22 | private ContextUtils() {
23 | }
24 |
25 | private ContextUtils(ClassLoader classLoader) {
26 | this.mClassLoader = classLoader;
27 | }
28 |
29 | public static synchronized ContextUtils getInstance(ClassLoader classLoader) {
30 | if (mContextUtils == null) {
31 | mContextUtils = new ContextUtils(classLoader);
32 | }
33 | return mContextUtils;
34 | }
35 |
36 | public static synchronized ContextUtils getInstance() {
37 | if (mContextUtils == null) {
38 | throw new RuntimeException("mContextUtils is null");
39 | }
40 | return mContextUtils;
41 | }
42 |
43 | public void runOnUiThread(RunUiInterface runUiInterface) {
44 | Activity topActivity = getTopActivity();
45 | topActivity.runOnUiThread(() -> {
46 | runUiInterface.fun();
47 | });
48 | }
49 |
50 | public Application geApplication() {
51 | try {
52 | Application application =
53 | (Application) mClassLoader.loadClass("android.app.ActivityThread")
54 | .getMethod("currentApplication")
55 | .invoke(null, (Object[]) null);
56 | return application;
57 | } catch (Exception e) {
58 | throw new RuntimeException(e);
59 | }
60 | }
61 |
62 | public PackageManager getPackageManager() {
63 | PackageManager packageManager = geApplication().getPackageManager();
64 | return packageManager;
65 | }
66 |
67 | public List getAllActivityClass() {
68 | PackageManager packageManager = getPackageManager();
69 | ArrayList list = new ArrayList<>();
70 |
71 | Context context = geApplication();
72 | try {
73 | PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
74 |
75 | for (ActivityInfo activityInfo : packageInfo.activities) {
76 | Class aClass = Class.forName(activityInfo.name);
77 | list.add(aClass);
78 | }
79 | } catch (Exception exception) {
80 | throw new RuntimeException(exception);
81 | }
82 | return list;
83 | }
84 |
85 | public String getTopActivityName() {
86 | Application application = geApplication();
87 | ActivityManager activityManager = (ActivityManager) application.getSystemService(Application.ACTIVITY_SERVICE);
88 | List runningTasks = activityManager.getRunningTasks(1);
89 | ActivityManager.RunningTaskInfo runningTaskInfo = runningTasks.get(0);
90 | return runningTaskInfo.topActivity.getClassName();
91 | }
92 |
93 | public Activity getTopActivity() {
94 | List runningActivitys = getRunningActivitys();
95 | String topActivityName = getTopActivityName();
96 | // Log.i("SharkChilli", "getTopActivity: " + topActivityName);
97 |
98 | if (runningActivitys.size() == 1) {
99 | return runningActivitys.get(0);
100 | }
101 |
102 | for (Activity activityRun : runningActivitys) {
103 | if (topActivityName.equals(activityRun.getClass().getName())) {
104 | return activityRun;
105 | }
106 | // Log.i("SharkChilli", "activityRun: " + activityRun);
107 | }
108 | return null;
109 | }
110 |
111 | public List getRunningActivitys() {
112 | List list = new ArrayList<>();
113 | try {
114 | Class applicationClass = Application.class;
115 | Field mLoadedApkField = applicationClass.getDeclaredField("mLoadedApk");
116 | mLoadedApkField.setAccessible(true);
117 |
118 | Application application = geApplication();
119 | Object mLoadedApk = mLoadedApkField.get(application);
120 | Class> mLoadedApkClass = mLoadedApk.getClass();
121 | Field mActivityThreadField = mLoadedApkClass.getDeclaredField("mActivityThread");
122 |
123 | mActivityThreadField.setAccessible(true);
124 | Object mActivityThread = mActivityThreadField.get(mLoadedApk);
125 | Class> mActivityThreadClass = mActivityThread.getClass();
126 | Field mActivitiesField = mActivityThreadClass.getDeclaredField("mActivities");
127 | mActivitiesField.setAccessible(true);
128 | // ActivityThread.ActivityClientRecord
129 | Object mActivities = mActivitiesField.get(mActivityThread);
130 | // 注意这里一定写成Map,低版本这里用的是HashMap,高版本用的是ArrayMap
131 | if (mActivities instanceof Map) {
132 | @SuppressWarnings("unchecked")
133 | Map