Repository: qiang/Riru-ModuleFridaGadget
Branch: master
Commit: f1484a762d56
Files: 30
Total size: 41.1 KB
Directory structure:
gitextract_8ya0o3m1/
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── module/
│ ├── .gitignore
│ ├── build.gradle
│ ├── libs/
│ │ └── riru-10.aar
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ └── cpp/
│ ├── CMakeLists.txt
│ ├── logging.h
│ ├── main.cpp
│ └── main.h
├── module.example.gradle
├── module.gradle
├── settings.gradle
└── template/
└── magisk_module/
├── .gitattributes
├── META-INF/
│ └── com/
│ └── google/
│ └── android/
│ ├── update-binary
│ └── updater-script
├── README.md
├── customize.sh
├── post-fs-data.sh
├── riru.sh
├── uninstall.sh
└── verify.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.prop text eol=lf
*.sh text eol=lf
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
.idea
/.idea/caches/build_file_checksums.ser
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
.DS_Store
/build
/captures
/out
.externalNativeBuild
.cxx
git-email.sh
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 Rikka
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
#### 1、说明
firda gadget 模式支持如下四种模式:
- Listen(部分支持,不支持 `"on_load": "wait"`)
- Connect (?)
- Script (完整支持)
- ScriptDirectory(完整支持)
我没有全部测试,根据使用目的不同,我现在只需要最后一种,主要用于大规模手机部署hook功能,为了把 libgadget.so 注入到进程,所以选择了 magisk + riru 的模式,通过自定义riru模块在riru的回调里面加载 libgadget.so
[Riru-ModuleTemplate](https://github.com/RikkaApps/Riru-ModuleTemplate)
本项目使用的是 [API 10 (Riru v23)](https://github.com/RikkaApps/Riru-ModuleTemplate#api-10-riru-v23) 来编译的
#### 2、 目的 & 功能
- frida 持久化
- frida 代码能够hook同一个应用的不同进程
- 应用白名单(避免和其他hook框架冲突)
- 为了用于生产环境而不是调试环境
#### 3、适配Android版本
Android 9,Android 10 ,?
#### 4、安装
- 通过 twrp 刷入 magisk v21 - v22.1(或者官网推荐方式)
- 通过 magisk 刷入 riru ,目前测试过 v23.9 ~ v25.4.4
- 通过 magisk 刷入 riru-FridaGadgetRiruMoudle-v14.2.12.9.zip
- 记得重启手机
#### 5、编译
gradle assembleRelease
#### 6、配置
##### 6.1、白名单
`/data/local/tmp/_white_list.config`
我写的这个白名单是控制进程是不是需要加载 gadget 的so的,目的是为了在手机上同时兼容xposed,要不然一个进程启动的时候同时加载 xposed 的so和 gadget.so 这时候进程会卡死。
这个配置文件格式很简单,就是把app进程名(包名)用逗号隔开,比如:
```txt
com.twitter.twitter,com.github.testapp1,com.github.testapp2
```
##### 6.2、gadget scriptdirectory 配置
这个配置不同于上面的白名单配置,这个配置是用了控制当前已经加载了 gadget.so 的进程,是不是要加载和当前配置文件同名的js文件的。
https://frida.re/docs/gadget/#scriptdirectory
我把 gadget 的这个识别的目录硬编码指定在了 `/data/local/tmp/frida_scripts` 如果有需要,可以修改后自己编译当前项目。
那么以twitter 手机目录结构如下为例:
```
/data/local/tmp/_white_list.config
/data/local/tmp/frida_scripts/twitter.js
/data/local/tmp/frida_scripts/twitter.config
```
twitter.config 配置文件的目的是为了指定是否应该为某个 app 加载 twitter.js hook 脚本。twitter.js 就是普通的frida hook 脚本,twitter.config 文件格式大概如下:
```json
{
"filter": {
"executables": ["com.twitter.twitter"],
"bundles": [],
"objc_classes": []
}
}
```
#### 7、TODO
1、构建用于调试的工具
2、开发一个图形界面用于配置配置文件和传输js脚本
3、app 图形界面控制gadget的动态库可选
4、整理当前ts 脚本,分离改机和系统函数监控
================================================
FILE: build.gradle
================================================
apply plugin: 'idea'
idea.module {
excludeDirs += file('out')
resourceDirs += file('template')
resourceDirs += file('scripts')
}
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
ext {
minSdkVersion = 23
targetSdkVersion = 30
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Oct 09 23:12:33 CST 2020
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# https://github.com/google/prefab/issues/122
android.prefabVersion=1.1.2
================================================
FILE: gradlew
================================================
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: module/.gitignore
================================================
/.externalNativeBuild
/build
/release
================================================
FILE: module/build.gradle
================================================
apply plugin: 'com.android.library'
apply from: file(rootProject.file('module.gradle'))
android {
compileSdkVersion rootProject.ext.targetSdkVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
externalNativeBuild {
cmake {
arguments "-DMODULE_NAME:STRING=riru_$moduleId",
"-DRIRU_MODULE_API_VERSION=$moduleRiruApiVersion",
"-DRIRU_MODULE_VERSION=$moduleVersionCode",
"-DRIRU_MODULE_VERSION_NAME:STRING=\"$moduleVersion\""
}
}
}
buildFeatures {
prefab true
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
ndkVersion '22.0.6917172 rc1'
}
repositories {
mavenLocal()
jcenter()
maven { url 'https://dl.bintray.com/rikkaw/Libraries' }
flatDir { dirs 'libs' }
}
dependencies {
// This is prefab aar which contains "riru.h"
// If you want to use older versions of AGP,
// you can copy this file from https://github.com/RikkaApps/Riru/blob/master/riru/src/main/cpp/include_riru/riru.h
// The default version of prefab in AGP has problem to process header only package,
// you may have to add android.prefabVersion=1.1.2 in your gradle.properties.
// See https://github.com/google/prefab/issues/122
// implementation 'rikka.ndk:riru:10'
implementation (name:'riru-10', ext:'aar')
}
def outDir = file("$rootDir/out")
def magiskDir = file("$outDir/magisk_module")
def zipName = "${magiskModuleProp['id'].replace('_', '-')}-${magiskModuleProp['version']}.zip"
def riruDir = "$magiskDir/riru"
import org.apache.tools.ant.filters.FixCrLfFilter
import java.nio.file.Files
import java.security.MessageDigest
static def calcSha256(file) {
def md = MessageDigest.getInstance("SHA-256")
file.eachByte 4096, { bytes, size ->
md.update(bytes, 0, size);
}
return md.digest().encodeHex()
}
static def renameOrFail(File fromFile, File toFile) {
if (!fromFile.renameTo(toFile)) {
throw new IOException("Unable reanme file $fromFile to $toFile")
}
}
android.libraryVariants.all { variant ->
def task = variant.assembleProvider.get()
task.doLast {
// clear
delete { delete magiskDir }
// copy from template
copy {
from "$rootDir/template/magisk_module"
into magiskDir.path
exclude 'riru.sh'
}
// copy riru.sh
copy {
from "$rootDir/template/magisk_module"
into magiskDir.path
include 'riru.sh'
filter { line ->
line.replaceAll('%%%RIRU_MODULE_ID%%%', moduleId)
.replaceAll('%%%RIRU_MODULE_API_VERSION%%%', moduleRiruApiVersion.toString())
.replaceAll('%%%RIRU_MODULE_MIN_API_VERSION%%%', moduleMinRiruApiVersion.toString())
.replaceAll('%%%RIRU_MODULE_MIN_RIRU_VERSION_NAME%%%', moduleMinRiruVersionName)
}
filter(FixCrLfFilter.class,
eol: FixCrLfFilter.CrLf.newInstance("lf"))
}
// copy .git files manually since gradle exclude it by default
Files.copy(file("$rootDir/template/magisk_module/.gitattributes").toPath(), file("${magiskDir.path}/.gitattributes").toPath())
// generate module.prop
def modulePropText = ""
magiskModuleProp.each { k, v -> modulePropText += "$k=$v\n" }
modulePropText = modulePropText.trim()
file("$magiskDir/module.prop").text = modulePropText
// generate module.prop for Riru
def riruModulePropText = ""
moduleProp.each { k, v -> riruModulePropText += "$k=$v\n" }
riruModulePropText = riruModulePropText.trim()
file(riruDir).mkdirs()
// module.prop.new will be renamed to module.prop in post-fs-data.sh
file("$riruDir/module.prop.new").text = riruModulePropText
// copy native files
def nativeOutDir = file("build/intermediates/cmake/$variant.name/obj")
file("$magiskDir/system").mkdirs()
file("$magiskDir/system_x86").mkdirs()
if (file("$magiskDir/system/lib64").exists()) {
copy {
from "$nativeOutDir/arm64-v8a"
into "$magiskDir/system/lib64"
include '*.so'
include '*.sha256sum'
}
} else {
renameOrFail(file("$nativeOutDir/arm64-v8a"), file("$magiskDir/system/lib64"))
}
if (file("$magiskDir/system/lib").exists()) {
copy {
from "$nativeOutDir/armeabi-v7a"
into "$magiskDir/system/lib"
include '*.so'
}
} else {
renameOrFail(file("$nativeOutDir/armeabi-v7a"), file("$magiskDir/system/lib"))
}
renameOrFail(file("$nativeOutDir/x86_64"), file("$magiskDir/system_x86/lib64"))
renameOrFail(file("$nativeOutDir/x86"), file("$magiskDir/system_x86/lib"))
// generate sha1sum
fileTree("$magiskDir").matching {
exclude "README.md", "META-INF"
}.visit { f ->
if (f.directory) return
file(f.file.path + ".sha256sum").text = calcSha256(f.file)
}
}
task.finalizedBy zipMagiskMoudle
}
task zipMagiskMoudle(type: Zip) {
from magiskDir
archiveName zipName
destinationDir outDir
}
================================================
FILE: module/src/main/AndroidManifest.xml
================================================
================================================
FILE: module/src/main/cpp/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.4.1)
if (NOT DEFINED MODULE_NAME)
message(FATAL_ERROR "MODULE_NAME is not set")
endif ()
add_definitions(-DRIRU_MODULE)
add_definitions(-DRIRU_MODULE_API_VERSION=${RIRU_MODULE_API_VERSION})
add_definitions(-DRIRU_MODULE_VERSION=${RIRU_MODULE_VERSION})
add_definitions(-DRIRU_MODULE_VERSION_NAME=${RIRU_MODULE_VERSION_NAME})
message("Build type: ${CMAKE_BUILD_TYPE}")
set(CMAKE_CXX_STANDARD 11)
set(LINKER_FLAGS "-ffixed-x18 -Wl,--hash-style=both")
set(C_FLAGS "-Werror=format -fdata-sections -ffunction-sections")
if (CMAKE_BUILD_TYPE STREQUAL "Release")
set(C_FLAGS "${C_FLAGS} -O2 -fvisibility=hidden -fvisibility-inlines-hidden")
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,-exclude-libs,ALL -Wl,--gc-sections")
else ()
set(C_FLAGS "${C_FLAGS} -O0")
endif ()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
find_package(riru REQUIRED CONFIG)
add_library(${MODULE_NAME} SHARED main.cpp)
target_link_libraries(${MODULE_NAME} log riru::riru)
set_target_properties(${MODULE_NAME} PROPERTIES LINK_FLAGS_RELEASE -s)
================================================
FILE: module/src/main/cpp/logging.h
================================================
#ifndef _LOGGING_H
#define _LOGGING_H
#include
#include "android/log.h"
#ifndef LOG_TAG
#define LOG_TAG "Riru-ModuleFridaGadget"
#endif
#ifdef DEBUG
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#else
#define LOGD(...)
#endif
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno))
#endif // _LOGGING_H
================================================
FILE: module/src/main/cpp/main.cpp
================================================
#include
#include
#include
#include
#include
#include
#include
#include "logging.h"
#include "main.h"
static char nice_process_name[256] = {0};
static char package_name[256] = {0};
static jint my_uid = 0;
static bool isApp(int uid) {
if (uid < 0) {
return false;
}
int appId = uid % 100000;
// limit only regular app, or strange situation will happen, such as zygote process not start (dead for no reason and leave no clues?)
// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r8/core/java/android/os/UserHandle.java#151
return appId >= 10000 && appId <= 19999;
}
static void
my_forkAndSpecializePre(JNIEnv *env, jint *uid, jstring *niceName, jstring *appDataDir) {
//LOGI("Q_M xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx %s", "forkAndSpecializePre");
my_uid = *uid;
if (!isApp(my_uid)) {
return;
}
const char *tablePath = (env->GetStringUTFChars(*niceName, 0));
sprintf(nice_process_name, "%s", tablePath);
delete tablePath;
if (!appDataDir) {
LOGI("Q_M forkAndSpecializePre appDataDir null");
return;
}
const char *app_data_dir = env->GetStringUTFChars(*appDataDir, NULL);
if (app_data_dir == nullptr) {
return;
}
//LOGI("Q_M xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx app_data_dir %s",app_data_dir);
int user = 0;
if (sscanf(app_data_dir, "/data/%*[^/]/%d/%s", &user, package_name) != 2) {
if (sscanf(app_data_dir, "/data/%*[^/]/%s", package_name) != 1) {
package_name[0] = '\0';
LOGI("Q_M can't parse %s", app_data_dir);
}
}
env->ReleaseStringUTFChars(*appDataDir, app_data_dir);
}
static void my_forkAndSpecializePost(JNIEnv *env) {
if (!isApp(my_uid)) {
return;
}
// if (!strstr(nice_process_name, "com.smile.gifmaker")
// && !strstr(nice_process_name, "com.ss.android.ugc.aweme")
// && !strstr(nice_process_name, "com.xingin.xhs")
// ) {
// return;
// }
//http://www.cplusplus.com/reference/cstdio/fread/ 读取整个文件
char *white_list;
//白名单的pkgName 最好以逗号或者分好分割开来
const char *filepath = "/data/local/tmp/_white_list.config";
FILE *fp = nullptr;
fp = fopen(filepath, "r");
if (fp != nullptr) {
fseek(fp, 0, SEEK_END);
int fileLen = ftell(fp);
white_list = (char *) malloc(sizeof(char) * (fileLen + 1));
fseek(fp, 0, SEEK_SET);
// size_t count = fread(white_list, fileLen, sizeof(char), fp);
size_t count = fread(white_list, 1, fileLen, fp);
// LOGI("Q_M xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 白名单长度 %zu", count);
white_list[count] = '\0';
fclose(fp);
LOGI("Q_M xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 白名单:%s", white_list);
} else {
white_list = "";
}
if (!strstr(white_list, package_name)) {
return;
}
LOGI("Q_M xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx nice_process_name=%s, pkg=%s,uid=%d, isApp= %d",
nice_process_name, package_name, my_uid,
isApp(my_uid));
//添加这种机制,就可以提前设置进程名, 从而让frida 的gadget 能够识别到
jclass java_Process = env->FindClass("android/os/Process");
if (java_Process != nullptr && isApp(my_uid)) {
jmethodID mtd_setArgV0 = env->GetStaticMethodID(java_Process, "setArgV0",
"(Ljava/lang/String;)V");
jstring name = env->NewStringUTF(nice_process_name);
env->CallStaticVoidMethod(java_Process, mtd_setArgV0, name);
void *handle = dlopen(nextLoadSo, RTLD_LAZY);
if (!handle) {
// LOGE("%s",dlerror());
LOGE("Q_M %s loaded in libgadget 出错 %s", nice_process_name, dlerror());
} else {
LOGI("Q_M xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-> %s 加载 ' %s ' 成功 ", nice_process_name,
nextLoadSo);
}
}
}
static void forkAndSpecializePre(
JNIEnv *env, jclass clazz, jint *uid, jint *gid, jintArray *gids, jint *runtimeFlags,
jobjectArray *rlimits, jint *mountExternal, jstring *seInfo, jstring *niceName,
jintArray *fdsToClose, jintArray *fdsToIgnore, jboolean *is_child_zygote,
jstring *instructionSet, jstring *appDataDir, jboolean *isTopApp,
jobjectArray *pkgDataInfoList,
jobjectArray *whitelistedDataInfoList, jboolean *bindMountAppDataDirs,
jboolean *bindMountAppStorageDirs) {
my_forkAndSpecializePre(env, uid, niceName, appDataDir);
}
//很遗憾,执行这行代码的时候,还没有设置进程名字,导致,这个方法里面加载 frida gadget 的动态库获取不到进程名
// 只有执行完 Zygote.forkAndSpecialize 会在 handleChildProc 里面设置进程名,Process.setArgV0(parsedArgs.niceName);
// libandroid_runtime.so
//https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/jni/android_util_Process.cpp;l=593?q=setSwappiness&ss=android%2Fplatform%2Fsuperproject
static void forkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
if (res == 0) {
my_forkAndSpecializePost(env);
} else {
// in zygote process, res is child pid
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
}
}
static void specializeAppProcessPre(
JNIEnv *env, jclass clazz, jint *uid, jint *gid, jintArray *gids, jint *runtimeFlags,
jobjectArray *rlimits, jint *mountExternal, jstring *seInfo, jstring *niceName,
jboolean *startChildZygote, jstring *instructionSet, jstring *appDataDir,
jboolean *isTopApp, jobjectArray *pkgDataInfoList, jobjectArray *whitelistedDataInfoList,
jboolean *bindMountAppDataDirs, jboolean *bindMountAppStorageDirs) {
// added from Android 10, but disabled at least in Google Pixel devices
my_forkAndSpecializePre(env, uid, niceName, appDataDir);
}
static void specializeAppProcessPost(
JNIEnv *env, jclass clazz) {
// added from Android 10, but disabled at least in Google Pixel devices
my_forkAndSpecializePost(env);
}
static void forkSystemServerPre(
JNIEnv *env, jclass clazz, uid_t *uid, gid_t *gid, jintArray *gids, jint *runtimeFlags,
jobjectArray *rlimits, jlong *permittedCapabilities, jlong *effectiveCapabilities) {
}
static void forkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
if (res == 0) {
// in system server process
} else {
// in zygote process, res is child pid
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
}
}
static int shouldSkipUid(int uid) {
// By default (the module does not provide this function in init), Riru will only call
// module functions in "normal app processes" (10000 <= uid % 100000 <= 19999)
// Provide this function so that the module can control if a specific uid should be skipped
return false;
}
static void onModuleLoaded() {
// called when the shared library of Riru core is loaded
}
extern "C" {
int riru_api_version;
RiruApiV9 *riru_api_v9;
/*
* Init will be called three times.
*
* The first time:
* Returns the highest version number supported by both Riru and the module.
*
* arg: (int *) Riru's API version
* returns: (int *) the highest possible API version
*
* The second time:
* Returns the RiruModuleX struct created by the module.
* (X is the return of the first call)
*
* arg: (RiruApiVX *) RiruApi strcut, this pointer can be saved for further use
* returns: (RiruModuleX *) RiruModule strcut
*
* The third time:
* Let the module to cleanup (such as RiruModuleX struct created before).
*
* arg: null
* returns: (ignored)
*
*/
void *init(void *arg) {
static int step = 0;
step += 1;
LOGI("Q_M Riru-ModuleFridaGadget xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx %s", "init");
static void *_module;
switch (step) {
case 1: {
auto core_max_api_version = *(int *) arg;
riru_api_version =
core_max_api_version <= RIRU_MODULE_API_VERSION ? core_max_api_version
: RIRU_MODULE_API_VERSION;
return &riru_api_version;
}
case 2: {
switch (riru_api_version) {
// RiruApiV10 and RiruModuleInfoV10 are equal to V9
case 10:
case 9: {
riru_api_v9 = (RiruApiV9 *) arg;
auto module = (RiruModuleInfoV9 *) malloc(sizeof(RiruModuleInfoV9));
memset(module, 0, sizeof(RiruModuleInfoV9));
_module = module;
module->supportHide = true;
module->version = RIRU_MODULE_VERSION;
module->versionName = RIRU_MODULE_VERSION_NAME;
module->onModuleLoaded = onModuleLoaded;
module->shouldSkipUid = shouldSkipUid;
module->forkAndSpecializePre = forkAndSpecializePre;
module->forkAndSpecializePost = forkAndSpecializePost;
module->specializeAppProcessPre = specializeAppProcessPre;
module->specializeAppProcessPost = specializeAppProcessPost;
module->forkSystemServerPre = forkSystemServerPre;
module->forkSystemServerPost = forkSystemServerPost;
return module;
}
default: {
return nullptr;
}
}
}
case 3: {
free(_module);
return nullptr;
}
default: {
return nullptr;
}
}
}
}
================================================
FILE: module/src/main/cpp/main.h
================================================
//
// Created by canyie on 2020/8/12.
//
#ifndef NBINJECTION_MAIN_H
#define NBINJECTION_MAIN_H
#ifdef __LP64__
constexpr const char* kZygoteNiceName = "zygote64";
constexpr const char* nextLoadSo = "/system/lib64/libgadget.so";
#else
constexpr const char* kZygoteNiceName = "zygote";
constexpr const char* nextLoadSo = "/system/lib/libgadget.so";
#endif
#endif //NBINJECTION_MAIN_H
================================================
FILE: module.example.gradle
================================================
ext {
// FIXME replace with yours
moduleId = "template"
moduleName = "Template"
moduleAuthor = "Template"
moduleDescription = "Riru module template."
moduleVersion = "v1.1"
moduleVersionCode = 1
moduleMinRiruApiVersion = 9
moduleMinRiruVersionName = "v22.0"
moduleRiruApiVersion = 10
moduleProp = [
name : moduleName,
version : moduleVersion,
versionCode: moduleVersionCode.toString(),
author : moduleAuthor,
description: moduleDescription,
minApi : moduleMinRiruApiVersion
]
magiskModuleProp = [
id : "riru-${moduleId.replace('_', '-')}",
name : "Riru - ${moduleProp['name']}",
version : moduleProp['version'],
versionCode: moduleProp['versionCode'],
author : moduleProp['author'],
description: moduleProp['description']
]
}
================================================
FILE: module.gradle
================================================
ext {
moduleId = "FridaGadgetRiruMoudle"
moduleName = "Frida-Gadget-Riru-Module"
moduleAuthor = "BayBayMax"
moduleDescription = "一个加载 FridaGadget 动态库的magisk 插件,依赖riru 框架"
moduleVersion = "v14.2.12.9"
moduleVersionCode = 14_2_12_9
moduleMinRiruApiVersion = 9
moduleMinRiruVersionName = "v22.0"
moduleRiruApiVersion = 10
moduleProp = [
name : moduleName,
version : moduleVersion,
versionCode: moduleVersionCode.toString(),
author : moduleAuthor,
description: moduleDescription,
minApi : moduleMinRiruApiVersion
]
magiskModuleProp = [
id : "riru-${moduleId.replace('_', '-')}",
name : "Riru - ${moduleProp['name']}",
version : moduleProp['version'],
versionCode: moduleProp['versionCode'],
author : moduleProp['author'],
description: moduleProp['description']
]
}
================================================
FILE: settings.gradle
================================================
include ':module'
================================================
FILE: template/magisk_module/.gitattributes
================================================
# Declare files that will always have LF line endings on checkout.
META-INF/** text eol=lf
*.prop text eol=lf
*.sh text eol=lf
*.md text eol=lf
sepolicy.rule text eol=lf
# Denote all files that are truly binary and should not be modified.
system/** binary
system_x86/** binary
================================================
FILE: template/magisk_module/META-INF/com/google/android/update-binary
================================================
#!/sbin/sh
#################
# Initialization
#################
umask 022
# Global vars
TMPDIR=/dev/tmp
PERSISTDIR=/sbin/.magisk/mirror/persist
rm -rf $TMPDIR 2>/dev/null
mkdir -p $TMPDIR
# echo before loading util_functions
ui_print() { echo "$1"; }
require_new_magisk() {
ui_print "*******************************"
ui_print " Please install Magisk v19.0+! "
ui_print "*******************************"
exit 1
}
is_legacy_script() {
unzip -l "$ZIPFILE" install.sh | grep -q install.sh
return $?
}
print_modname() {
local len
len=`echo -n $MODNAME | wc -c`
len=$((len + 2))
local pounds=`printf "%${len}s" | tr ' ' '*'`
ui_print "$pounds"
ui_print " $MODNAME "
ui_print "$pounds"
ui_print "*******************"
ui_print " Powered by Magisk "
ui_print "*******************"
}
##############
# Environment
##############
OUTFD=$2
ZIPFILE=$3
mount /data 2>/dev/null
# Load utility functions
[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
. /data/adb/magisk/util_functions.sh
[ $MAGISK_VER_CODE -gt 18100 ] || require_new_magisk
# Preperation for flashable zips
setup_flashable
# Mount partitions
mount_partitions
# Detect version and architecture
api_level_arch_detect
# Setup busybox and binaries
$BOOTMODE && boot_actions || recovery_actions
##############
# Preparation
##############
# Extract prop file
unzip -o "$ZIPFILE" module.prop -d $TMPDIR >&2
[ ! -f $TMPDIR/module.prop ] && abort "! Unable to extract zip file!"
$BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules
MODULEROOT=$NVBASE/$MODDIRNAME
MODID=`grep_prop id $TMPDIR/module.prop`
MODPATH=$MODULEROOT/$MODID
MODNAME=`grep_prop name $TMPDIR/module.prop`
# Create mod paths
rm -rf $MODPATH 2>/dev/null
mkdir -p $MODPATH
##########
# Install
##########
if is_legacy_script; then
unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2
# Load install script
. $TMPDIR/install.sh
# Callbacks
print_modname
on_install
# Custom uninstaller
[ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh
# Skip mount
$SKIPMOUNT && touch $MODPATH/skip_mount
# prop file
$PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop
# Module info
cp -af $TMPDIR/module.prop $MODPATH/module.prop
# post-fs-data scripts
$POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh
# service scripts
$LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh
ui_print "- Setting permissions"
set_permissions
else
print_modname
unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2
if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then
ui_print "- Extracting module files"
unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2
# Default permissions
set_perm_recursive $MODPATH 0 0 0755 0644
fi
# Load customization script
[ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh
fi
# Handle replace folders
for TARGET in $REPLACE; do
ui_print "- Replace target: $TARGET"
mktouch $MODPATH$TARGET/.replace
done
if $BOOTMODE; then
# Update info for Magisk Manager
mktouch $NVBASE/modules/$MODID/update
cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop
fi
# Copy over custom sepolicy rules
if [ -f $MODPATH/sepolicy.rule -a -e $PERSISTDIR ]; then
ui_print "- Installing custom sepolicy patch"
PERSISTMOD=$PERSISTDIR/magisk/$MODID
mkdir -p $PERSISTMOD
cp -af $MODPATH/sepolicy.rule $PERSISTMOD/sepolicy.rule
fi
# Remove stuffs that don't belong to modules
rm -rf \
$MODPATH/system/placeholder $MODPATH/customize.sh \
$MODPATH/README.md $MODPATH/.git* 2>/dev/null
##############
# Finalizing
##############
cd /
$BOOTMODE || recovery_cleanup
rm -rf $TMPDIR
ui_print "- Done"
exit 0
================================================
FILE: template/magisk_module/META-INF/com/google/android/updater-script
================================================
#MAGISK
================================================
FILE: template/magisk_module/README.md
================================================
# Riru - Template
================================================
FILE: template/magisk_module/customize.sh
================================================
SKIPUNZIP=1
# check_architecture
if [ "$ARCH" != "arm" ] && [ "$ARCH" != "arm64" ] && [ "$ARCH" != "x86" ] && [ "$ARCH" != "x64" ]; then
abort "! Unsupported platform: $ARCH"
else
ui_print "- Device platform: $ARCH"
fi
# extract verify.sh
ui_print "- Extracting verify.sh"
unzip -o "$ZIPFILE" 'verify.sh' -d "$TMPDIR" >&2
if [ ! -f "$TMPDIR/verify.sh" ]; then
ui_print "*********************************************************"
ui_print "! Unable to extract verify.sh!"
ui_print "! This zip may be corrupted, please try downloading again"
abort "*********************************************************"
fi
. $TMPDIR/verify.sh
# extract riru.sh
extract "$ZIPFILE" 'riru.sh' "$MODPATH"
. $MODPATH/riru.sh
check_riru_version
# extract libs
ui_print "- Extracting module files"
extract "$ZIPFILE" 'module.prop' "$MODPATH"
extract "$ZIPFILE" 'post-fs-data.sh' "$MODPATH"
extract "$ZIPFILE" 'uninstall.sh' "$MODPATH"
if [ "$ARCH" = "x86" ] || [ "$ARCH" = "x64" ]; then
ui_print "- Extracting x86 libraries"
extract "$ZIPFILE" "system_x86/lib/libriru_$RIRU_MODULE_ID.so" "$MODPATH"
mv "$MODPATH/system_x86" "$MODPATH/system"
if [ "$IS64BIT" = true ]; then
ui_print "- Extracting x64 libraries"
extract "$ZIPFILE" "system_x86/lib64/libriru_$RIRU_MODULE_ID.so" "$MODPATH"
mv "$MODPATH/system_x86/lib64" "$MODPATH/system/lib64"
fi
else
ui_print "- Extracting arm libraries"
REPLACEMENT_DIR="system/*"
# 一劳永逸。完全提取。在某些一加手机上这个方法不能提取 system/lib/ 里面的数据,为啥?是unzip这个命令工具的问题。
# 注意加上引号
unzip -o "$ZIPFILE" "$REPLACEMENT_DIR" -d "$MODPATH" >&2 || abort "! Can't extract system/: $?"
# extract "$ZIPFILE" "system/lib/libgadget.so" "$MODPATH"
# extract "$ZIPFILE" "system/lib/libgadget.config.so" "$MODPATH"
# extract "$ZIPFILE" "system/lib/libriru_FridaGadgetRiruMoudle.so" "$MODPATH"
#
# extract "$ZIPFILE" "system/lib64/libgadget.so" "$MODPATH"
# extract "$ZIPFILE" "system/lib64/libgadget.config.so" "$MODPATH"
# extract "$ZIPFILE" "system/lib64/libriru_FridaGadgetRiruMoudle.so" "$MODPATH"
fi
set_perm_recursive "$MODPATH" 0 0 0755 0644
# extract Riru files
ui_print "- Extracting extra files"
[ -d "$RIRU_MODULE_PATH" ] || mkdir -p "$RIRU_MODULE_PATH" || abort "! Can't create $RIRU_MODULE_PATH"
rm -f "$RIRU_MODULE_PATH/module.prop.new"
extract "$ZIPFILE" 'riru/module.prop.new' "$RIRU_MODULE_PATH" true
set_perm "$RIRU_MODULE_PATH/module.prop.new" 0 0 0600 $RIRU_SECONTEXT
================================================
FILE: template/magisk_module/post-fs-data.sh
================================================
#!/system/bin/sh
MODDIR=${0%/*}
[ ! -f "$MODDIR/riru.sh" ] && exit 1
. $MODDIR/riru.sh
# Rename module.prop.new
if [ -f "$RIRU_MODULE_PATH/module.prop.new" ]; then
rm "$RIRU_MODULE_PATH/module.prop"
mv "$RIRU_MODULE_PATH/module.prop.new" "$RIRU_MODULE_PATH/module.prop"
fi
================================================
FILE: template/magisk_module/riru.sh
================================================
#!/sbin/sh
RIRU_PATH="/data/adb/riru"
RIRU_MODULE_ID="%%%RIRU_MODULE_ID%%%"
RIRU_MODULE_PATH="$RIRU_PATH/modules/$RIRU_MODULE_ID"
RIRU_SECONTEXT="u:object_r:magisk_file:s0"
# used by /data/adb/riru/util_functions.sh
RIRU_MODULE_API_VERSION=%%%RIRU_MODULE_API_VERSION%%%
RIRU_MODULE_MIN_API_VERSION=%%%RIRU_MODULE_MIN_API_VERSION%%%
RIRU_MODULE_MIN_RIRU_VERSION_NAME="%%%RIRU_MODULE_MIN_RIRU_VERSION_NAME%%%"
# this function will be used when /data/adb/riru/util_functions.sh not exits
check_riru_version() {
if [ ! -f "$RIRU_PATH/api_version" ] && [ ! -f "$RIRU_PATH/api_version.new" ]; then
ui_print "*********************************************************"
ui_print "! Riru $RIRU_MIN_VERSION_NAME or above is required"
ui_print "! Please install Riru from Magisk Manager or https://github.com/RikkaApps/Riru/releases"
abort "*********************************************************"
fi
local_api_version=$(cat "$RIRU_PATH/api_version.new") || local_api_version=$(cat "$RIRU_PATH/api_version") || local_api_version=0
[ "$local_api_version" -eq "$local_api_version" ] || local_api_version=0
ui_print "- Riru API version: $local_api_version"
if [ "$local_api_version" -lt $RIRU_MODULE_MIN_API_VERSION ]; then
ui_print "*********************************************************"
ui_print "! Riru $RIRU_MIN_VERSION_NAME or above is required"
ui_print "! Please upgrade Riru from Magisk Manager or https://github.com/RikkaApps/Riru/releases"
abort "*********************************************************"
fi
}
if [ -f /data/adb/riru/util_functions.sh ]; then
ui_print "- Load /data/adb/riru/util_functions.sh"
. /data/adb/riru/util_functions.sh
else
ui_print "- Can't find /data/adb/riru/util_functions.sh"
fi
================================================
FILE: template/magisk_module/uninstall.sh
================================================
#!/sbin/sh
MODDIR=${0%/*}
[ ! -f "$MODDIR/riru.sh" ] && exit 1
. $MODDIR/riru.sh
rm -rf "$RIRU_MODULE_PATH"
================================================
FILE: template/magisk_module/verify.sh
================================================
TMPDIR_FOR_VERIFY="$TMPDIR/.vunzip"
mkdir "$TMPDIR_FOR_VERIFY"
abort_verify() {
ui_print "*********************************************************"
ui_print "! $1"
ui_print "! This zip may be corrupted, please try downloading again"
abort "*********************************************************"
}
# extract
extract() {
zip=$1
file=$2
dir=$3
junk_paths=$4
[ -z "$junk_paths" ] && junk_paths=false
opts="-o"
[ $junk_paths = true ] && opts="-oj"
file_path=""
hash_path=""
if [ $junk_paths = true ]; then
file_path="$dir/$(basename "$file")"
hash_path="$TMPDIR_FOR_VERIFY/$(basename "$file").sha256sum"
else
file_path="$dir/$file"
hash_path="$TMPDIR_FOR_VERIFY/$file.sha256sum"
fi
unzip $opts "$zip" "$file" -d "$dir" >&2
[ -f "$file_path" ] || abort_verify "$file not exists"
unzip $opts "$zip" "$file.sha256sum" -d "$TMPDIR_FOR_VERIFY" >&2
[ -f "$hash_path" ] || abort_verify "$file.sha256sum not exists"
(echo "$(cat "$hash_path") $file_path" | sha256sum -c -s -) || abort_verify "Failed to verify $file"
ui_print "- Verified $file" >&1
}