├── .gitignore
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── inject
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── cpp
│ ├── CMakeLists.txt
│ ├── elfutil.cpp
│ ├── elfutil.h
│ ├── gotutil.cpp
│ ├── include
│ └── gotutil.h
│ ├── inject.cpp
│ └── mylog.h
├── settings.gradle
├── victim
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── cpp
│ ├── CMakeLists.txt
│ └── victim.c
├── victim_app
├── .gitignore
├── build.gradle
├── nativelib
│ ├── .gitignore
│ ├── build.gradle
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── cpp
│ │ ├── CMakeLists.txt
│ │ └── nativelib.cpp
│ │ └── java
│ │ └── com
│ │ └── xhy
│ │ └── nativelib
│ │ └── NativeLib.java
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── xhy
│ │ └── androidgothook
│ │ └── 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
└── workdir
├── arm
├── 0-patch-victim-arm.bat
└── 1-run-victim-patch-arm.bat
├── arm64
├── 0-patch-victim-arm64.bat
└── 1-run-victim-patch-arm64.bat
└── edit-victim.py
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/
2 | *.iml
3 | .gradle
4 | /local.properties
5 | /.idea/caches
6 | /.idea/libraries
7 | /.idea/modules.xml
8 | /.idea/workspace.xml
9 | /.idea/navEditor.xml
10 | /.idea/assetWizardSettings.xml
11 | .DS_Store
12 | /build
13 | /captures
14 | .externalNativeBuild
15 | .cxx
16 | local.properties
17 | /workdir/victim-patch-arm*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Simple Android ARM&ARM64 GOT Hook
2 | 基于链接视图和执行视图,解析ELF,查找导入函数偏移值,替换函数地址。
3 |
4 | 详见:
5 |
6 | [简易Android ARM&ARM64 GOT Hook (一)](https://blog.xhyeax.com/2021/08/23/android-arm-got-hook/)
7 |
8 | [简易Android ARM&ARM64 GOT Hook (二)](https://blog.xhyeax.com/2021/08/30/android-arm-plt-hook/)
9 |
10 | ## 编译
11 | 使用`Android Studio`打开项目,点击`Make Project`
12 |
13 | 编译完成后,在`模块名/build/intermediates/cmake/debug/obj/CPU架构/`目录下,
14 |
15 | 可以找到生成的可执行文件(`victim`)和动态库(`libinject.so`)
16 |
17 | ## 测试
18 | ### 注入可执行文件
19 | `workdir`文件中包含补丁脚本、adb测试脚本。编译完成后按顺序运行即可
20 |
21 | ### 作为动态链接库使用
22 | `victim_app`模块是一个例子。
23 |
24 | 通过配置`CMakeLists.txt`将`libinject.so`作为动态库链接。
25 |
26 | 在`nativelib.cpp`的`JNI_OnLoad`中调用`hackBySegment`替换`getpid`函数。
27 |
28 | Java层调用`stringFromJNI`函数通过JNI获取pid并显示。
29 |
30 | 注释`inject.cpp`的`hack`函数体后,编译生成apk,运行即可。(不注释将查找一次`victim-patch`,不影响运行)
31 |
32 | ### 通过JNI加载
33 | 在Java层通过`System.loadLibrary`加载。最终调用到Native层的`LoadNativeLibrary`函数。
34 |
35 | 其中首先调用`dlopen`加载so(`linker`调用构造函数)。成功后查找`JNI_OnLoad`并调用。
36 |
37 | 原理见[andorid linker 解读1----从loadLibrary到dlopen](https://bbs.pediy.com/thread-264852.htm)
38 |
39 | ## 存在的问题
40 | 1. 未绕过`dlopen`命名空间限制,在`Android 7`以上无法打开非公共库
41 | 2. 未hook`dlopen`,无法实时修改加载模块的GOT表
42 | 3. 基于maps解析,兼容性可能存在一定问题
43 | 4. 基于静态注入,无法绕过完整性检测
44 | 5. 未提供卸载函数,无法恢复GOT表
45 | 6. ...
46 |
47 | ## 总结
48 | 通过本项目,学习了`GOT Hook`原理,ELF文件结构和导入符号的查找方式,目的基本达到。虽然功能还不够完善,但短期内应该不会再改动了(这次是真的了)。
49 |
50 | 实际应用可以考虑使用字节的[bhook](https://github.com/bytedance/bhook)
51 |
52 | ## 参考
53 | [android中基于plt/got的hook实现原理](https://blog.csdn.net/byhook/article/details/103500524)
54 |
55 | [聊聊Linux动态链接中的PLT和GOT(2)——延迟重定位](https://linyt.blog.csdn.net/article/details/51636753)
56 |
57 | [constructor属性函数在动态库加载中的执行顺序](https://zhuanlan.zhihu.com/p/108274829)
58 |
59 | [Android7.0以上命名空间详解(dlopen限制)](https://www.52pojie.cn/thread-948942-1-1.html)
60 |
61 | [Android中GOT表HOOK手动实现](https://blog.csdn.net/u011247544/article/details/78564564)
62 |
63 | [Android GOT Hook](https://www.cnblogs.com/mmmmar/p/8228391.html)
64 |
65 | [基于Android的ELF PLT/GOT符号和重定向过程ELF Hook实现](https://blog.csdn.net/L173864930/article/details/40507359)
66 |
67 | [ELF文件格式与got表hook简单实现](https://bbs.pediy.com/thread-267842.htm)
68 |
69 | [重定位节 - 链接程序和库指南](https://docs.oracle.com/cd/E26926_01/html/E25910/chapter6-54839.html)
70 |
71 | [符号表节 - 链接程序和库指南](https://docs.oracle.com/cd/E26926_01/html/E25910/chapter6-79797.html)
72 |
73 | [散列表节 - 链接程序和库指南](https://docs.oracle.com/cd/E26926_01/html/E25910/chapter6-48031.html)
74 |
75 | [动态节 - 链接程序和库指南](https://docs.oracle.com/cd/E26926_01/html/E25910/chapter6-42444.html)
76 |
77 | [ELF文件结构详解](https://bbs.pediy.com/thread-255670.htm)
78 |
79 | [PLT HOOK](https://zhuanlan.zhihu.com/p/269441842)
80 |
81 | [bhook](https://github.com/bytedance/bhook)
82 |
83 | [xhook](https://github.com/iqiyi/xhook)
84 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:7.1.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
25 |
26 | ext {
27 | minSdkVersion = 21
28 | compileSdkVersion = 31
29 | targetSdkVersion = 31
30 | buildToolsVersion = "31.0.0"
31 | ndkVersion = "24.0.8215888"
32 | cmakeVersion = "3.18.1"
33 | abiFilters = "armeabi-v7a,arm64-v8a"
34 | javaVersion = JavaVersion.VERSION_1_8
35 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Aug 22 20:52:31 CST 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/inject/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/inject/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | }
4 |
5 | android {
6 | compileSdkVersion rootProject.ext.compileSdkVersion
7 | buildToolsVersion rootProject.ext.buildToolsVersion
8 | ndkVersion rootProject.ext.ndkVersion
9 |
10 | defaultConfig {
11 | minSdkVersion rootProject.ext.minSdkVersion
12 | targetSdkVersion rootProject.ext.targetSdkVersion
13 | consumerProguardFiles "consumer-rules.pro"
14 | externalNativeBuild {
15 | cmake {
16 | abiFilters rootProject.ext.abiFilters.split(",")
17 | }
18 | }
19 | }
20 |
21 | externalNativeBuild {
22 | cmake {
23 | path file('src/main/cpp/CMakeLists.txt')
24 | version rootProject.ext.cmakeVersion
25 | }
26 | }
27 |
28 | buildTypes {
29 | release {
30 | minifyEnabled false
31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
32 | }
33 | }
34 | compileOptions {
35 | sourceCompatibility rootProject.ext.javaVersion
36 | targetCompatibility rootProject.ext.javaVersion
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/inject/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/inject/consumer-rules.pro
--------------------------------------------------------------------------------
/inject/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
--------------------------------------------------------------------------------
/inject/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/inject/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18.1)
2 | project(inject)
3 |
4 | set(CMAKE_CXX_STANDARD 11)
5 | include_directories(include/)
6 | add_library(inject SHARED inject.cpp elfutil.cpp gotutil.cpp)
7 | find_library(log-lib log)
8 |
9 | target_link_libraries(inject ${log-lib})
--------------------------------------------------------------------------------
/inject/src/main/cpp/elfutil.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Xhy on 2021/8/23.
3 | //
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "elfutil.h"
15 | #include "mylog.h"
16 |
17 | void getFullPath(const char *src, char *dest) {
18 | while (*src != '/') {
19 | *src++;
20 | }
21 | strncpy(dest, src, strlen(src) - 1);
22 | }
23 |
24 | uintptr_t getModuleBase(const char *module_name, char *moduleFullPath) {
25 | uintptr_t addr = 0;
26 | char buff[256] = "\n";
27 |
28 | FILE *fp = fopen("/proc/self/maps", "r");
29 | while (fgets(buff, sizeof(buff), fp)) {
30 | if (strstr(buff, "r-xp") && strstr(buff, module_name) &&
31 | sscanf(buff, "%" SCNxPTR, &addr) == 1) {
32 | getFullPath(buff, moduleFullPath);
33 | LOGE("[%s] moduleBase: %" SCNxPTR, moduleFullPath, addr);
34 | return addr;
35 | }
36 | }
37 | // LOGE("buff: %s", buff);
38 | LOGE("[%s] moduleBase not found!\n", module_name);
39 | fclose(fp);
40 | return 0;
41 | }
42 |
43 | // 解析Section
44 | int getGOTOffsetAndSize(const char *modulePath, int &GOTSize) {
45 | int GOTOffset = 0;
46 | FILE *fp = fopen(modulePath, "r");
47 | if (!fp) {
48 | LOGE("[%s] open failed!", modulePath);
49 | return 0;
50 | }
51 | ELFW(Ehdr) elf_header;
52 | ELFW(Shdr) elf_section_header;
53 | memset(&elf_header, 0, sizeof(elf_header));
54 | memset(&elf_section_header, 0, sizeof(elf_section_header));
55 | // 解析elf_header
56 | fseek(fp, 0, SEEK_SET);
57 | fread(&elf_header, sizeof(elf_header), 1, fp);
58 | // LOGE("elf_header e_shoff: %" SCNxPTR ", e_shstrndx: %d", elf_header.e_shoff, elf_header.e_shstrndx);
59 | // LOGE("elf_header e_shnum: %d", elf_header.e_shnum);
60 | // 获取字符串表在section header中的偏移
61 | fseek(fp, elf_header.e_shoff + elf_header.e_shstrndx * elf_header.e_shentsize, SEEK_SET);
62 | fread(&elf_section_header, sizeof(elf_section_header), 1, fp);
63 | int string_table_size = elf_section_header.sh_size;
64 | char *string_table = (char *) (malloc(string_table_size));
65 | // 获取字符串表
66 | fseek(fp, elf_section_header.sh_offset, SEEK_SET);
67 | fread(string_table, string_table_size, 1, fp);
68 | // 遍历section header table, 查找.got
69 | fseek(fp, elf_header.e_shoff, SEEK_SET);
70 | for (int i = 0; i < elf_header.e_shnum; ++i) {
71 | fread(&elf_section_header, elf_header.e_shentsize, 1, fp);
72 | if (elf_section_header.sh_type == SHT_PROGBITS
73 | && 0 == strcmp(".got", string_table + elf_section_header.sh_name)) {
74 | GOTOffset = elf_section_header.sh_addr;
75 | GOTSize = elf_section_header.sh_size;
76 | break;
77 | }
78 | }
79 | free(string_table);
80 | fclose(fp);
81 | return GOTOffset;
82 | }
83 |
84 | static uint32_t elf_sysv_hash(const uint8_t *name) {
85 | uint32_t h = 0, g;
86 |
87 | while (*name) {
88 | h = (h << 4) + *name++;
89 | g = h & 0xf0000000;
90 | h ^= g;
91 | h ^= g >> 24;
92 | }
93 | return h;
94 | }
95 |
96 | // 解析Segment
97 | int getSymAddrDynamic(const char *module_name, const char *symName, uintptr_t *addrArray) {
98 | char moduleFullPath[256] = {0};
99 | uintptr_t moduleBase = getModuleBase(module_name, moduleFullPath);
100 | if (moduleBase == 0) {
101 | return 0;
102 | }
103 | ELFW(Ehdr) elf_header;
104 | ELFW(Phdr) elf_program_header;
105 | memset(&elf_header, 0, sizeof(elf_header));
106 | memset(&elf_program_header, 0, sizeof(elf_program_header));
107 | // 解析elf_header
108 | memcpy(&elf_header, (const void *) moduleBase, sizeof(elf_header));
109 | // LOGE("elf_header e_phoff: %" SCNxPTR ", e_phentsize: %d", elf_header.e_phoff, elf_header.e_phentsize);
110 | // LOGE("elf_header e_phnum: %d", elf_header.e_phnum);
111 | // 遍历program header table, 查找.dynamic
112 | int DYNOffset = 0;
113 | int DYNSize = 0;
114 | for (int i = 0; i < elf_header.e_phnum; ++i) {
115 | memcpy(&elf_program_header,
116 | (const void *) (moduleBase + elf_header.e_phoff + i * elf_header.e_phentsize),
117 | elf_header.e_phentsize);
118 | if (elf_program_header.p_type == PT_DYNAMIC) {
119 | DYNOffset = elf_program_header.p_vaddr;
120 | DYNSize = elf_program_header.p_memsz;
121 | break;
122 | }
123 | }
124 | if (DYNOffset == 0 || DYNSize == 0) {
125 | LOGE(".dynamic not found!");
126 | return 0;
127 | }
128 | uintptr_t DYNBase = moduleBase + DYNOffset;
129 | // LOGE("DYNOffset: %" SCNxPTR " DYNSize: %" SCNxPTR "", DYNOffset, DYNSize);
130 |
131 | int addrArraySize = 0;
132 | // 保存各表
133 | ELFW(Sym) *dynsym;
134 | const char *dynstr;
135 | ELFW(Rel) *rel_dyn;
136 | ELFW(Rel) *rel_plt;
137 | ELFW(Rela) *rela_dyn;
138 | ELFW(Rela) *rela_plt;
139 | int rel_dyn_cnt, rel_plt_cnt;
140 | //.hash
141 | const uint32_t *buckets;
142 | uint32_t buckets_cnt;
143 | const uint32_t *chains;
144 | uint32_t chains_cnt;
145 | //遍历.dynamic 解析需要的表 (.rel.plt .rel.dyn .dynsym .dynstr和.hash)
146 | ELFW(Dyn) dyn;
147 | int dyn_entsize = sizeof(ELFW(Dyn));
148 | for (int i = 0; i < DYNSize / dyn_entsize; ++i) {
149 | memcpy(&dyn, (const void *) (DYNBase + i * dyn_entsize), dyn_entsize);
150 | switch (dyn.d_tag) {
151 | // .rel.plt / .rela.plt
152 | case DT_JMPREL:
153 | #if defined(__LP64__)
154 | rela_plt = (ELFW(Rela) *) (moduleBase + dyn.d_un.d_ptr);
155 | #else
156 | rel_plt = (ELFW(Rel) *) (moduleBase + dyn.d_un.d_ptr);
157 | #endif
158 | break;
159 | case DT_PLTRELSZ:
160 | #if defined(__LP64__)
161 | rel_plt_cnt = dyn.d_un.d_val / sizeof(ELFW(Rela));
162 | #else
163 | rel_plt_cnt = dyn.d_un.d_val / sizeof(ELFW(Rel));
164 | #endif
165 | break;
166 | // .rel.dyn / .rela.dyn
167 | case DT_REL:
168 | case DT_RELA:
169 | #if defined(__LP64__)
170 | rela_dyn = (ELFW(Rela) *) (moduleBase + dyn.d_un.d_ptr);
171 | #else
172 | rel_dyn = (ELFW(Rel) *) (moduleBase + dyn.d_un.d_ptr);
173 | #endif
174 | break;
175 | case DT_RELSZ:
176 | case DT_RELASZ:
177 | rel_dyn_cnt = dyn.d_un.d_val / sizeof(ELFW(Rel));
178 | break;
179 | // .dynsym
180 | case DT_SYMTAB:
181 | dynsym = (ELFW(Sym) *) (moduleBase + dyn.d_un.d_ptr);
182 | break;
183 | // .dynstr
184 | case DT_STRTAB:
185 | dynstr = (const char *) (moduleBase + dyn.d_un.d_ptr);
186 | break;
187 | // .hash
188 | case DT_HASH:
189 | auto rawdata = (const uint32_t *) (moduleBase + dyn.d_un.d_ptr);
190 | buckets_cnt = rawdata[0];
191 | chains_cnt = rawdata[1];
192 | buckets = &(rawdata[2]);
193 | chains = &(buckets[buckets_cnt]);
194 | break;
195 | }
196 | }
197 | //查找符号 .hash -> .dynsym -> .dynstr O(x) + O(1) + O(1)
198 | ELFW(Sym) *target = nullptr;
199 | uint32_t hash = elf_sysv_hash((const uint8_t *) symName);
200 | for (uint32_t i = buckets[hash % buckets_cnt];
201 | 0 != i; i = chains[i]) {
202 | ELFW(Sym) *sym = dynsym + i;
203 | unsigned char type = ELF_ST_TYPE(sym->st_info);
204 | if (STT_FUNC != type && STT_GNU_IFUNC != type && STT_NOTYPE != type)
205 | continue; // find function only, allow no-type
206 | if (0 == strcmp(dynstr + sym->st_name, symName)) {
207 | target = sym;
208 | break;
209 | }
210 | }
211 | if (!target) {
212 | LOGE("target sym not found!");
213 | return 0;
214 | }
215 | //遍历 .rel.plt / .rela.plt 和 .rel.dyn / .rela.dyn,获取偏移,计算内存地址
216 | for (int i = 0; i < rel_plt_cnt; i++) {
217 | #if defined(__LP64__)
218 | ELFW(Rela) &rel = rela_plt[i];
219 | #else
220 | ELFW(Rel) &rel = rel_plt[i];
221 | #endif
222 | if (&(dynsym[ELF_R_SYM(rel.r_info)]) == target &&
223 | ELF_R_TYPE(rel.r_info) == ELF_R_JUMP_SLOT) {
224 | // LOGE("target r_offset: %" SCNxPTR "", rel.r_offset);
225 | addrArray[addrArraySize++] = moduleBase + rel.r_offset;
226 | }
227 | }
228 | for (int i = 0; i < rel_dyn_cnt; i++) {
229 | #if defined(__LP64__)
230 | ELFW(Rela) &rel = rela_dyn[i];
231 | #else
232 | ELFW(Rel) &rel = rel_dyn[i];
233 | #endif
234 | if (&(dynsym[ELF_R_SYM(rel.r_info)]) == target &&
235 | (ELF_R_TYPE(rel.r_info) == ELF_R_ABS
236 | || ELF_R_TYPE(rel.r_info) == ELF_R_GLOB_DAT)) {
237 | // LOGE("target r_offset: %" SCNxPTR "", rel.r_offset);
238 | addrArray[addrArraySize++] = moduleBase + rel.r_offset;
239 | }
240 | }
241 | return addrArraySize;
242 | }
--------------------------------------------------------------------------------
/inject/src/main/cpp/elfutil.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Xhy on 2021/8/23.
3 | //
4 |
5 | #ifndef ANDROIDGOTHOOK_ELFUTIL_H
6 | #define ANDROIDGOTHOOK_ELFUTIL_H
7 |
8 | #if defined(__LP64__)
9 | #define ELFW(what) Elf64_ ## what
10 | #define ELF_R_TYPE(what) ELF64_R_TYPE(what)
11 | #define ELF_R_SYM(what) ELF64_R_SYM(what)
12 | #else
13 | #define ELFW(what) Elf32_ ## what
14 | #define ELF_R_TYPE(what) ELF32_R_TYPE(what)
15 | #define ELF_R_SYM(what) ELF32_R_SYM(what)
16 | #endif
17 |
18 | #if defined(__arm__)
19 | #define ELF_R_JUMP_SLOT R_ARM_JUMP_SLOT //.rel.plt
20 | #define ELF_R_GLOB_DAT R_ARM_GLOB_DAT //.rel.dyn
21 | #define ELF_R_ABS R_ARM_ABS32 //.rel.dyn
22 | #elif defined(__aarch64__)
23 | #define ELF_R_JUMP_SLOT R_AARCH64_JUMP_SLOT
24 | #define ELF_R_GLOB_DAT R_AARCH64_GLOB_DAT
25 | #define ELF_R_ABS R_AARCH64_ABS64
26 | #endif
27 |
28 | uintptr_t getModuleBase(const char *modulePath, char *moduleFullPath);
29 |
30 | int getGOTOffsetAndSize(const char *modulePath, int &GOTSize);
31 |
32 | int getSymAddrDynamic(const char *moduleBase, const char *symName, uintptr_t *addrArray);
33 |
34 | #endif //ANDROIDGOTHOOK_ELFUTIL_H
35 |
--------------------------------------------------------------------------------
/inject/src/main/cpp/gotutil.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Xhy on 2021/8/23.
3 | //
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include "gotutil.h"
14 | #include "elfutil.h"
15 | #include "mylog.h"
16 |
17 | #define PAGE_START(addr) ((addr) & PAGE_MASK)
18 | #define PAGE_END(addr) (PAGE_START(addr) + PAGE_SIZE)
19 |
20 | #define MAX_ADDRARRAY_SIZE 32
21 |
22 | uintptr_t getGOTBase(int &GOTSize, const char *module_name) {
23 | uintptr_t GOTBase = 0;
24 | char moduleFullPath[256] = {0};
25 | uintptr_t moduleBase = getModuleBase(module_name, moduleFullPath);
26 | if (moduleBase == 0) {
27 | return GOTBase;
28 | }
29 | int GOTOffset = getGOTOffsetAndSize(moduleFullPath, GOTSize);
30 | if (GOTOffset == 0) {
31 | LOGE("GOTOffset not found!\n");
32 | return GOTBase;
33 | }
34 |
35 | GOTBase = moduleBase + GOTOffset;
36 |
37 | LOGE("GOTOffset: %" SCNxPTR " GOTBase: %" SCNxPTR " GOTSize: %d\n", GOTOffset, GOTBase,
38 | GOTSize);
39 | return GOTBase;
40 | }
41 |
42 | int getSymAddrInGOT(uintptr_t GOTBase, int GOTSize, uintptr_t ori, uintptr_t *addrArray) {
43 | if (GOTBase == 0) {
44 | LOGE("getSymAddrInGOT failed! addr [%" SCNxPTR "] is wrong\n", GOTBase);
45 | return 0;
46 | }
47 |
48 | int addrArraySize = 0;
49 |
50 | for (int i = 0; i < GOTSize; ++i) {
51 | uintptr_t addr = GOTBase + i * 4;
52 | uintptr_t item = *(uintptr_t *) (addr);
53 | if (item == ori) {
54 | // LOGE("GOT [%d]: %" SCNxPTR "\n", i, item);
55 | addrArray[addrArraySize++] = addr;
56 | }
57 | }
58 | if (addrArraySize == 0) {
59 | LOGE("getSymAddrInGOT %" SCNxPTR " not found!\n", ori);
60 | }
61 |
62 | return addrArraySize;
63 | }
64 |
65 | void replaceFunction(uintptr_t addr, uintptr_t replace, uintptr_t ori) {
66 | if (addr == 0) {
67 | LOGE("replace failed! addr [%" SCNxPTR "] is wrong\n", addr);
68 | return;
69 | }
70 | // 比对函数地址
71 | uintptr_t item = *(uintptr_t *) (addr);
72 | if (item == replace) {
73 | LOGE("[%" SCNxPTR "] function has been replaced.\n", addr);
74 | return;
75 | }
76 | if (item != ori) {
77 | LOGE("replace failed! unexpected function address [%" SCNxPTR "]=%" SCNxPTR "\n", addr,
78 | item);
79 | return;
80 | }
81 | //修改权限、替换地址、清空指令缓存
82 | LOGE("replace [%" SCNxPTR "]=%" SCNxPTR " with %" SCNxPTR "\n", addr, item, replace);
83 | mprotect((void *) PAGE_START(addr), PAGE_SIZE, PROT_READ | PROT_WRITE);
84 | *(uintptr_t *) addr = replace;
85 | __builtin___clear_cache((char *) PAGE_START(addr), (char *) PAGE_END(addr));
86 | }
87 |
88 | uintptr_t hackGOT(const char *module_name, const char *target_lib, const char *target_func,
89 | uintptr_t replace) {
90 | // hackBySection or hackBySegment
91 | return hackBySegment(module_name, target_lib, target_func, replace);
92 | }
93 |
94 | // 基于链接视图解析ELF
95 | uintptr_t hackBySection(const char *module_name, const char *target_lib, const char *target_func,
96 | uintptr_t replace) {
97 | LOGE("hackBySection start.\n");
98 | // 获取目标函数地址
99 | void *handle = dlopen(target_lib, RTLD_LAZY);
100 | auto ori = (uintptr_t) dlsym(handle, target_func);
101 | // LOGE("ori addr: %" SCNxPTR "\n", ori);
102 | int GOTSize = 0;
103 | // 获取GOT表地址及大小 (解析Section)
104 | uintptr_t GOTBase = getGOTBase(GOTSize, module_name);
105 | // 遍历GOT表,查找符号地址
106 | uintptr_t addrArray[MAX_ADDRARRAY_SIZE];
107 | int addrArraySize = getSymAddrInGOT(GOTBase, GOTSize, ori, addrArray);
108 | // 替换地址
109 | for (int i = 0; i < addrArraySize; i++) {
110 | uintptr_t replaceAddr = addrArray[i];
111 | replaceFunction(replaceAddr, replace, ori);
112 | }
113 | return ori;
114 | }
115 |
116 | // 基于执行视图解析ELF
117 | uintptr_t hackBySegment(const char *module_name, const char *target_lib, const char *target_func,
118 | uintptr_t replace) {
119 | LOGE("hackBySegment start.\n");
120 | // 获取目标函数地址
121 | void *handle = dlopen(target_lib, RTLD_LAZY);
122 | auto ori = (uintptr_t) dlsym(handle, target_func);
123 | // LOGE("ori addr: %" SCNxPTR "\n", ori);
124 | // 获取符号地址 (解析Segment)
125 | uintptr_t addrArray[MAX_ADDRARRAY_SIZE];
126 | int addrArraySize = getSymAddrDynamic(module_name, target_func, addrArray);
127 | // 替换地址
128 | for (int i = 0; i < addrArraySize; i++) {
129 | uintptr_t replaceAddr = addrArray[i];
130 | replaceFunction(replaceAddr, replace, ori);
131 | }
132 | return ori;
133 | }
134 |
--------------------------------------------------------------------------------
/inject/src/main/cpp/include/gotutil.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Xhy on 2021/8/23.
3 | //
4 |
5 | #ifndef ANDROIDGOTHOOK_GOTUTIL_H
6 | #define ANDROIDGOTHOOK_GOTUTIL_H
7 |
8 | uintptr_t getGOTBase(int &GOTSize, const char *modulePath);
9 |
10 | int getSymAddrInGOT(uintptr_t GOTBase, int GOTSize, uintptr_t ori, uintptr_t *addrArray);
11 |
12 | void replaceFunction(uintptr_t addr, uintptr_t replace, uintptr_t ori);
13 |
14 | uintptr_t hackGOT(const char *module_name, const char *target_lib, const char *target_func,
15 | uintptr_t replace);
16 |
17 | uintptr_t hackBySection(const char *module_name, const char *target_lib, const char *target_func,
18 | uintptr_t replace);
19 |
20 | uintptr_t hackBySegment(const char *module_name, const char *target_lib, const char *target_func,
21 | uintptr_t replace);
22 |
23 | #endif //ANDROIDGOTHOOK_GOTUTIL_H
24 |
--------------------------------------------------------------------------------
/inject/src/main/cpp/inject.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "gotutil.h"
8 | #include "mylog.h"
9 | #include "gotutil.h"
10 |
11 | #if defined(__LP64__)
12 | #define MODULE_NAME "victim-patch-arm64"
13 | #else
14 | #define MODULE_NAME "victim-patch-arm"
15 | #endif
16 |
17 | typedef int (*getpid_fun)();
18 |
19 | // 原方法的备份
20 | getpid_fun getpidOri;
21 |
22 | // 替换方法
23 | int getpidReplace() {
24 | LOGE("before hook getpid\n");
25 | //调用原方法
26 | int pid = getpidOri();
27 | LOGE("after hook getpid: %d\n", pid);
28 | return 233333;
29 | }
30 |
31 | void hack() {
32 | uintptr_t ori = hackGOT(MODULE_NAME, "libc.so", "getpid",
33 | (uintptr_t) getpidReplace);
34 | getpidOri = (getpid_fun) ori;
35 | }
36 |
37 | //so加载时由linker调用
38 | void __attribute__((constructor)) init() {
39 | LOGE("call from constructor\n");
40 | hack();
41 | LOGE("constructor finish.\n");
42 | }
43 |
44 | // JNI LoadNativeLibrary中调用
45 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
46 | if (nullptr == vm) return JNI_ERR;
47 | LOGE("call from JNI_OnLoad\n");
48 | hack();
49 | return JNI_VERSION_1_6;
50 | }
--------------------------------------------------------------------------------
/inject/src/main/cpp/mylog.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Xhy on 2021/8/31.
3 | //
4 |
5 | #ifndef ANDROIDGOTHOOK_MYLOG_H
6 | #define ANDROIDGOTHOOK_MYLOG_H
7 |
8 | #include
9 |
10 | #if defined(__LP64__)
11 | #define LOG_TAG "NInject-64"
12 | #else
13 | #define LOG_TAG "NInject"
14 | #endif
15 |
16 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
17 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
18 |
19 | #endif //ANDROIDGOTHOOK_MYLOG_H
20 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = "AndroidGotHook"
2 | include ':victim'
3 | include ':inject'
4 | include ':victim_app'
5 | include ':victim_app:nativelib'
--------------------------------------------------------------------------------
/victim/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/victim/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | }
4 |
5 | android {
6 | compileSdkVersion rootProject.ext.compileSdkVersion
7 | buildToolsVersion rootProject.ext.buildToolsVersion
8 | ndkVersion rootProject.ext.ndkVersion
9 |
10 | defaultConfig {
11 | minSdkVersion rootProject.ext.minSdkVersion
12 | targetSdkVersion rootProject.ext.targetSdkVersion
13 | consumerProguardFiles "consumer-rules.pro"
14 | externalNativeBuild {
15 | cmake {
16 | abiFilters rootProject.ext.abiFilters.split(",")
17 | }
18 | }
19 | }
20 |
21 | externalNativeBuild {
22 | cmake {
23 | path file('src/main/cpp/CMakeLists.txt')
24 | version rootProject.ext.cmakeVersion
25 | }
26 | }
27 |
28 | buildTypes {
29 | release {
30 | minifyEnabled false
31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
32 | }
33 | }
34 | compileOptions {
35 | sourceCompatibility rootProject.ext.javaVersion
36 | targetCompatibility rootProject.ext.javaVersion
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/victim/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim/consumer-rules.pro
--------------------------------------------------------------------------------
/victim/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
--------------------------------------------------------------------------------
/victim/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/victim/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18.1)
2 | project(victim)
3 |
4 | add_executable(victim victim.c)
5 |
--------------------------------------------------------------------------------
/victim/src/main/cpp/victim.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | typedef int (*getpid_fun)();
5 |
6 | getpid_fun global_getpid = (getpid_fun) getpid;
7 |
8 | int main() {
9 | getpid_fun local_getpid = (getpid_fun) getpid;
10 | int pid = getpid();
11 | int local_pid = local_getpid();
12 | int global_pid = global_getpid();
13 |
14 | printf("direct call: %d, local call: %d, global call: %d\n",
15 | pid, local_pid, global_pid);
16 |
17 | // getchar();
18 | return 0;
19 | }
--------------------------------------------------------------------------------
/victim_app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/victim_app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 |
5 | android {
6 | compileSdkVersion rootProject.ext.compileSdkVersion
7 | buildToolsVersion rootProject.ext.buildToolsVersion
8 |
9 | defaultConfig {
10 | applicationId "com.xhy.androidgothook"
11 | minSdkVersion rootProject.ext.minSdkVersion
12 | targetSdkVersion rootProject.ext.targetSdkVersion
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | android {
17 | defaultConfig {
18 | ndk {
19 | abiFilters rootProject.ext.abiFilters.split(",")
20 | }
21 | }
22 | }
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 | compileOptions {
32 | sourceCompatibility rootProject.ext.javaVersion
33 | targetCompatibility rootProject.ext.javaVersion
34 | }
35 |
36 | buildFeatures {
37 | viewBinding true
38 | }
39 | packagingOptions {
40 | jniLibs {
41 | pickFirsts += ['**/libinject.so']
42 | }
43 | }
44 | }
45 |
46 | dependencies {
47 | implementation project(path: ':victim_app:nativelib')
48 | }
49 |
--------------------------------------------------------------------------------
/victim_app/nativelib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/victim_app/nativelib/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | }
4 |
5 | android {
6 | compileSdk rootProject.ext.compileSdkVersion
7 | buildToolsVersion rootProject.ext.buildToolsVersion
8 | ndkVersion rootProject.ext.ndkVersion
9 |
10 | defaultConfig {
11 | minSdk rootProject.ext.minSdkVersion
12 | targetSdk rootProject.ext.targetSdkVersion
13 |
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | consumerProguardFiles "consumer-rules.pro"
16 |
17 | externalNativeBuild {
18 | cmake {
19 | abiFilters rootProject.ext.abiFilters.split(",")
20 | }
21 | }
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | externalNativeBuild {
31 | cmake {
32 | path "src/main/cpp/CMakeLists.txt"
33 | version rootProject.ext.cmakeVersion
34 | }
35 | }
36 | compileOptions {
37 | sourceCompatibility rootProject.ext.javaVersion
38 | targetCompatibility rootProject.ext.javaVersion
39 | }
40 | }
41 |
42 | dependencies {
43 | implementation project(':inject')
44 | }
45 |
--------------------------------------------------------------------------------
/victim_app/nativelib/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/nativelib/consumer-rules.pro
--------------------------------------------------------------------------------
/victim_app/nativelib/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
--------------------------------------------------------------------------------
/victim_app/nativelib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/victim_app/nativelib/src/main/cpp/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.18.1)
7 |
8 | # Declares and names the project.
9 |
10 | project("nativelib")
11 |
12 | # Creates and names a library, sets it as either STATIC
13 | # or SHARED, and provides the relative paths to its source code.
14 | # You can define multiple libraries, and CMake builds them for you.
15 | # Gradle automatically packages shared libraries with your APK.
16 |
17 | add_library( # Sets the name of the library.
18 | nativelib
19 |
20 | # Sets the library as a shared library.
21 | SHARED
22 |
23 | # Provides a relative path to your source file(s).
24 | nativelib.cpp )
25 |
26 | # Searches for a specified prebuilt library and stores the path as a
27 | # variable. Because CMake includes system libraries in the search path by
28 | # default, you only need to specify the name of the public NDK library
29 | # you want to add. CMake verifies that the library exists before
30 | # completing its build.
31 |
32 | find_library( # Sets the name of the path variable.
33 | log-lib
34 |
35 | # Specifies the name of the NDK library that
36 | # you want CMake to locate.
37 | log )
38 |
39 | # Specifies libraries CMake should link to your target library. You
40 | # can link multiple libraries, such as libraries you define in this
41 | # build script, prebuilt third-party libraries, or system libraries.
42 |
43 | set(INJECT_BASE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../inject)
44 | add_library(inject SHARED IMPORTED)
45 | set_target_properties(inject PROPERTIES
46 | IMPORTED_LOCATION ${INJECT_BASE}/build/intermediates/merged_native_libs/debug/out/lib/${ANDROID_ABI}/libinject.so
47 | INTERFACE_INCLUDE_DIRECTORIES ${INJECT_BASE}/src/main/cpp/include)
48 |
49 | include_directories(${INJECT_BASE}/src/main/cpp/include)
50 |
51 | target_link_libraries( # Specifies the target library.
52 | nativelib
53 | inject
54 | # Links the target library to the log library
55 | # included in the NDK.
56 | ${log-lib} )
--------------------------------------------------------------------------------
/victim_app/nativelib/src/main/cpp/nativelib.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 |
7 | #define LOG_TAG "NInject-Native"
8 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
9 |
10 | #include "gotutil.h"
11 |
12 | typedef int (*getpid_fun)();
13 |
14 | // 全局函数指针
15 | getpid_fun global_getpid = (getpid_fun) getpid;
16 |
17 | // 原方法的备份
18 | getpid_fun getpidOri;
19 |
20 | // 替换方法
21 | int getpidReplace() {
22 | LOGI("before hook getpid\n");
23 | //调用原方法
24 | int pid = getpidOri();
25 | LOGI("after hook getpid: %d\n", pid);
26 | return 23333;
27 | }
28 |
29 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
30 | uintptr_t ori = hackGOT("libnativelib.so", "libc.so", "getpid",
31 | (uintptr_t) getpidReplace);
32 | getpidOri = (getpid_fun) ori;
33 | return JNI_VERSION_1_6;
34 | }
35 |
36 | extern "C" JNIEXPORT jstring JNICALL
37 | Java_com_xhy_nativelib_NativeLib_stringFromJNI(
38 | JNIEnv *env,
39 | jclass clazz) {
40 | auto local_getpid = getpid;
41 | int pid = getpid();
42 | int local_pid = local_getpid();
43 | int global_pid = global_getpid();
44 |
45 | char buff[256];
46 | sprintf(buff, "direct call: %d, local call: %d, global call: %d\n",
47 | pid, local_pid, global_pid);
48 | LOGI("%s", buff);
49 |
50 | return env->NewStringUTF(buff);
51 | }
--------------------------------------------------------------------------------
/victim_app/nativelib/src/main/java/com/xhy/nativelib/NativeLib.java:
--------------------------------------------------------------------------------
1 | package com.xhy.nativelib;
2 |
3 | public class NativeLib {
4 |
5 | // Used to load the 'nativelib' library on application startup.
6 | static {
7 | System.loadLibrary("nativelib");
8 | }
9 |
10 | /**
11 | * A native method that is implemented by the 'nativelib' native library,
12 | * which is packaged with this application.
13 | */
14 | public static native String stringFromJNI();
15 | }
--------------------------------------------------------------------------------
/victim_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
--------------------------------------------------------------------------------
/victim_app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/victim_app/src/main/java/com/xhy/androidgothook/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.xhy.androidgothook;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.widget.TextView;
6 |
7 | import com.xhy.nativelib.NativeLib;
8 |
9 | public class MainActivity extends Activity {
10 |
11 | @Override
12 | protected void onCreate(Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_main);
15 | TextView sample = findViewById(R.id.sample_text);
16 | sample.setText(NativeLib.stringFromJNI());
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/victim_app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/victim_app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/victim_app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XhyEax/AndroidGotHook/8df7afebb12bb7d14d467f81a393f859b6adfdb1/victim_app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/victim_app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/victim_app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidGotHook
3 |
--------------------------------------------------------------------------------
/workdir/arm/0-patch-victim-arm.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd ..
3 | python edit-victim.py armeabi-v7a
4 | pause
--------------------------------------------------------------------------------
/workdir/arm/1-run-victim-patch-arm.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd ..
3 | :Loop
4 | adb push ../inject/build/intermediates/cmake/debug/obj/armeabi-v7a/libinject.so /data/local/tmp/libinject-arm.so
5 | adb push victim-patch-arm /data/local/tmp/
6 | adb shell chmod +x /data/local/tmp/victim-patch-arm
7 | adb shell /data/local/tmp/victim-patch-arm
8 | pause
9 | goto :Loop
--------------------------------------------------------------------------------
/workdir/arm64/0-patch-victim-arm64.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd ..
3 | python edit-victim.py arm64-v8a
4 | pause
--------------------------------------------------------------------------------
/workdir/arm64/1-run-victim-patch-arm64.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd ..
3 | :Loop
4 | adb push ../inject/build/intermediates/cmake/debug/obj/arm64-v8a/libinject.so /data/local/tmp/libinject-arm64.so
5 | adb push victim-patch-arm64 /data/local/tmp/
6 | adb shell chmod +x /data/local/tmp/victim-patch-arm64
7 | adb shell /data/local/tmp/victim-patch-arm64
8 | pause
9 | goto :Loop
--------------------------------------------------------------------------------
/workdir/edit-victim.py:
--------------------------------------------------------------------------------
1 | import lief,sys
2 |
3 | abi = "armeabi-v7a"
4 | tail = "-arm"
5 | if(len(sys.argv) > 1 and sys.argv[1] == "arm64-v8a"):
6 | abi = sys.argv[1]
7 | tail = "-arm64"
8 |
9 | path = "../victim/build/intermediates/cmake/debug/obj/"+abi+"/victim"
10 | elf = lief.parse(path)
11 | elf.add_library("/data/local/tmp/libinject"+tail+".so")
12 | elf.write("victim-patch"+tail)
13 | print("patch success")
--------------------------------------------------------------------------------