mirror of
https://github.com/kdrag0n/safetynet-fix.git
synced 2024-10-06 06:39:49 +00:00
riru: Initial module implementation
This commit is contained in:
parent
1282960dbf
commit
8d50d8fe3c
@ -4,12 +4,12 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 31
|
||||
compileSdk 30
|
||||
|
||||
defaultConfig {
|
||||
applicationId "dev.kdrag0n.safetynetriru"
|
||||
minSdk 24
|
||||
targetSdk 31
|
||||
targetSdk 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
|
27
java_module/app/proguard-rules.pro
vendored
27
java_module/app/proguard-rules.pro
vendored
@ -27,3 +27,30 @@
|
||||
-keepclassmembers class dev.kdrag0n.safetynetriru.proxy.ProxyKeyStoreSpi {
|
||||
public <init>(...);
|
||||
}
|
||||
|
||||
# Remove @DebugMetadata annotations to avoid leaking info
|
||||
# Source: https://proandroiddev.com/kotlin-cleaning-java-bytecode-before-release-9567d4c63911
|
||||
-checkdiscard @interface kotlin.coroutines.jvm.internal.DebugMetadata
|
||||
-assumenosideeffects public class kotlin.coroutines.jvm.internal.BaseContinuationImpl {
|
||||
private kotlin.coroutines.jvm.internal.DebugMetadata getDebugMetadataAnnotation() return null;
|
||||
public java.lang.StackTraceElement getStackTraceElement() return null;
|
||||
public java.lang.String[] getSpilledVariableFieldMapping() return null;
|
||||
}
|
||||
|
||||
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
|
||||
# Remove verbose NPE intrinsics to reduce code size and avoid leaking info
|
||||
# Source: https://issuetracker.google.com/issues/190489514
|
||||
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
|
||||
static void checkNotNullParameter(java.lang.Object, java.lang.String);
|
||||
static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
|
||||
static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
|
||||
static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
|
||||
static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
|
||||
static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
|
||||
static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
|
||||
static void checkNotNull(java.lang.Object);
|
||||
static void checkNotNull(java.lang.Object, java.lang.String);
|
||||
|
||||
# Remove remaining stray calls to stringPlus
|
||||
static java.lang.String stringPlus(java.lang.String, java.lang.Object);
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
ext {
|
||||
/*
|
||||
This name will be used in the name of the so file ("lib${moduleLibraryName}.so").
|
||||
*/
|
||||
moduleLibraryName = "template"
|
||||
|
||||
/* Minimal supported Riru API version, used in the version check of riru.sh */
|
||||
moduleMinRiruApiVersion = 24
|
||||
|
||||
/* The version name of minimal supported Riru, used in the version check of riru.sh */
|
||||
moduleMinRiruVersionName = "v24.0.0"
|
||||
|
||||
/* Maximum supported Riru API version, used in the version check of riru.sh */
|
||||
moduleRiruApiVersion = 26
|
||||
|
||||
/*
|
||||
Magisk module ID
|
||||
Since Magisk use it to distinguish different modules, you should never change it.
|
||||
|
||||
Note, the older version of the template uses '-' instead of '_', if your are upgrading from
|
||||
the older version, please pay attention.
|
||||
*/
|
||||
magiskModuleId = "riru_template"
|
||||
|
||||
moduleName = "Template"
|
||||
moduleAuthor = "Template"
|
||||
moduleDescription = "Riru module template. Requires Riru $moduleMinRiruVersionName or above."
|
||||
moduleVersion = "v26.0.0"
|
||||
moduleVersionCode = 26
|
||||
}
|
@ -4,6 +4,115 @@
|
||||
#include <malloc.h>
|
||||
#include <cstring>
|
||||
#include <config.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <android/log.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define DEBUG(...) __android_log_write(ANDROID_LOG_DEBUG, "SafetyNetJNI/SARU", __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG(...)
|
||||
#endif
|
||||
|
||||
static constexpr bool DEBUG = true;
|
||||
|
||||
static void *moduleDex;
|
||||
static size_t moduleDexSize;
|
||||
|
||||
static constexpr size_t APP_DATA_DIR_SIZE = 128;
|
||||
static char lastAppDataDir[APP_DATA_DIR_SIZE];
|
||||
|
||||
static void updateAppDataDir(JNIEnv *env, jstring appDataDir) {
|
||||
DEBUG("updateAppDataDir");
|
||||
if (appDataDir == nullptr) {
|
||||
DEBUG("dir is null");
|
||||
memset(lastAppDataDir, 0, APP_DATA_DIR_SIZE);
|
||||
} else {
|
||||
DEBUG("copy dir");
|
||||
const char *copy = env->GetStringUTFChars(appDataDir, NULL);
|
||||
strncpy(lastAppDataDir, copy, APP_DATA_DIR_SIZE);
|
||||
env->ReleaseStringUTFChars(appDataDir, copy);
|
||||
DEBUG(lastAppDataDir);
|
||||
}
|
||||
}
|
||||
|
||||
static void specializeCommon(JNIEnv *env) {
|
||||
DEBUG("specializeCommon");
|
||||
DEBUG(lastAppDataDir);
|
||||
if (moduleDex == nullptr) {
|
||||
DEBUG("dex null");
|
||||
}
|
||||
if (moduleDex == nullptr || strstr(lastAppDataDir, "com.google.android.gms") == nullptr) {
|
||||
DEBUG("pkg doesn't match");
|
||||
riru_set_unload_allowed(true);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("get system classloader");
|
||||
// First, get the system classloader
|
||||
jclass clClass = env->FindClass("java/lang/ClassLoader");
|
||||
jmethodID getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
jobject systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader);
|
||||
|
||||
DEBUG("create buf");
|
||||
// Assuming we have a valid mapped module, load it. This is similar to the approach used for
|
||||
// Dynamite modules in GmsCompat, except we can use InMemoryDexClassLoader directly instead of
|
||||
// tampering with DelegateLastClassLoader's DexPathList.
|
||||
jobject buf = env->NewDirectByteBuffer(moduleDex, moduleDexSize);
|
||||
DEBUG("construct dex cl");
|
||||
jclass dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
|
||||
jmethodID dexClInit = env->GetMethodID(dexClClass, "<init>", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
||||
jobject dexCl = env->NewObject(dexClClass, dexClInit, buf, systemClassLoader);
|
||||
|
||||
// Run it
|
||||
DEBUG("load class method lookup");
|
||||
jmethodID loadClass = env->GetMethodID(clClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
DEBUG("call load class");
|
||||
// Create a Java string. VM crashes with a C string.
|
||||
jstring entryClassName = env->NewStringUTF("dev.kdrag0n.safetynetriru.EntryPoint");
|
||||
jobject entryClassObj = env->CallObjectMethod(dexCl, loadClass, entryClassName);
|
||||
|
||||
// Call init
|
||||
DEBUG("call init");
|
||||
auto entryClass = (jclass) entryClassObj;
|
||||
jmethodID entryInit = env->GetStaticMethodID(entryClass, "init", "()V");
|
||||
env->CallStaticVoidMethod(entryClass, entryInit);
|
||||
DEBUG("specializeCommon end");
|
||||
}
|
||||
|
||||
static void *readFile(char *path, size_t *fileSize) {
|
||||
int fd = open(path, O_RDONLY, 0);
|
||||
if (fd < 0) {
|
||||
DEBUG("open fail");
|
||||
return nullptr;
|
||||
}
|
||||
// Get size
|
||||
DEBUG("get size");
|
||||
*fileSize = lseek(fd, 0, SEEK_END);
|
||||
if (*fileSize < 0) {
|
||||
DEBUG("seek fail");
|
||||
return nullptr;
|
||||
}
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
// Map
|
||||
/*
|
||||
DEBUG("mmap");
|
||||
moduleDex = mmap(nullptr, *fileSize, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (moduleDex == MAP_FAILED) {
|
||||
DEBUG("mmap fail");
|
||||
}*/
|
||||
// Close the fd. This doesn't destroy the mapping.
|
||||
//DEBUG("close");
|
||||
char *data = (char *) malloc(*fileSize);
|
||||
int bytes = 0;
|
||||
while (bytes < *fileSize) {
|
||||
bytes += read(fd, data + bytes, *fileSize - bytes);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void forkAndSpecializePre(
|
||||
JNIEnv *env, jclass clazz, jint *uid, jint *gid, jintArray *gids, jint *runtimeFlags,
|
||||
@ -11,25 +120,7 @@ static void forkAndSpecializePre(
|
||||
jintArray *fdsToClose, jintArray *fdsToIgnore, jboolean *is_child_zygote,
|
||||
jstring *instructionSet, jstring *appDataDir, jboolean *isTopApp, jobjectArray *pkgDataInfoList,
|
||||
jobjectArray *whitelistedDataInfoList, jboolean *bindMountAppDataDirs, jboolean *bindMountAppStorageDirs) {
|
||||
// Called "before" com_android_internal_os_Zygote_nativeForkAndSpecialize in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
||||
// Parameters are pointers, you can change the value of them if you want
|
||||
// Some parameters are not exist is older Android versions, in this case, they are null or 0
|
||||
}
|
||||
|
||||
static void forkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
|
||||
// Called "after" com_android_internal_os_Zygote_nativeForkAndSpecialize in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
||||
// "res" is the return value of com_android_internal_os_Zygote_nativeForkAndSpecialize
|
||||
|
||||
if (res == 0) {
|
||||
// In app process
|
||||
|
||||
// When unload allowed is true, the module will be unloaded (dlclose) by Riru
|
||||
// If this modules has hooks installed, DONOT set it to true, or there will be SIGSEGV
|
||||
// This value will be automatically reset to false before the "pre" function is called
|
||||
riru_set_unload_allowed(true);
|
||||
} else {
|
||||
// In zygote process
|
||||
}
|
||||
updateAppDataDir(env, *appDataDir);
|
||||
}
|
||||
|
||||
static void specializeAppProcessPre(
|
||||
@ -38,37 +129,23 @@ static void specializeAppProcessPre(
|
||||
jboolean *startChildZygote, jstring *instructionSet, jstring *appDataDir,
|
||||
jboolean *isTopApp, jobjectArray *pkgDataInfoList, jobjectArray *whitelistedDataInfoList,
|
||||
jboolean *bindMountAppDataDirs, jboolean *bindMountAppStorageDirs) {
|
||||
// Called "before" com_android_internal_os_Zygote_nativeSpecializeAppProcess in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
||||
// Parameters are pointers, you can change the value of them if you want
|
||||
// Some parameters are not exist is older Android versions, in this case, they are null or 0
|
||||
updateAppDataDir(env, *appDataDir);
|
||||
}
|
||||
|
||||
static void forkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
|
||||
// Called "after" com_android_internal_os_Zygote_nativeForkAndSpecialize in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
||||
// "res" is the return value of com_android_internal_os_Zygote_nativeForkAndSpecialize
|
||||
|
||||
if (res == 0) {
|
||||
// In app process
|
||||
specializeCommon(env);
|
||||
}
|
||||
}
|
||||
|
||||
static void specializeAppProcessPost(
|
||||
JNIEnv *env, jclass clazz) {
|
||||
// Called "after" com_android_internal_os_Zygote_nativeSpecializeAppProcess in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
||||
|
||||
// When unload allowed is true, the module will be unloaded (dlclose) by Riru
|
||||
// If this modules has hooks installed, DONOT set it to true, or there will be SIGSEGV
|
||||
// This value will be automatically reset to false before the "pre" function is called
|
||||
riru_set_unload_allowed(true);
|
||||
}
|
||||
|
||||
static void forkSystemServerPre(
|
||||
JNIEnv *env, jclass clazz, uid_t *uid, gid_t *gid, jintArray *gids, jint *runtimeFlags,
|
||||
jobjectArray *rlimits, jlong *permittedCapabilities, jlong *effectiveCapabilities) {
|
||||
// Called "before" com_android_internal_os_Zygote_forkSystemServer in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
||||
// Parameters are pointers, you can change the value of them if you want
|
||||
// Some parameters are not exist is older Android versions, in this case, they are null or 0
|
||||
}
|
||||
|
||||
static void forkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
|
||||
// Called "after" com_android_internal_os_Zygote_forkSystemServer in frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
|
||||
|
||||
if (res == 0) {
|
||||
// In system server process
|
||||
} else {
|
||||
// In zygote process
|
||||
}
|
||||
specializeCommon(env);
|
||||
}
|
||||
|
||||
static void onModuleLoaded() {
|
||||
@ -77,6 +154,21 @@ static void onModuleLoaded() {
|
||||
// If you want to use threads, start them here rather than the constructors
|
||||
// __attribute__((constructor)) or constructors of static variables,
|
||||
// or the "hide" will cause SIGSEGV
|
||||
|
||||
|
||||
// Load
|
||||
DEBUG("onModuleLoaded, loading file");
|
||||
char pathBuf[128];
|
||||
snprintf(pathBuf, 128, "%s/%s", riru_magisk_module_path, "classes.dex");
|
||||
DEBUG((char*)riru_magisk_module_path);
|
||||
DEBUG(pathBuf);
|
||||
|
||||
moduleDex = readFile(pathBuf, &moduleDexSize);
|
||||
if (!moduleDex) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("module loaded");
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@ -86,19 +178,19 @@ const char *riru_magisk_module_path = nullptr;
|
||||
int *riru_allow_unload = nullptr;
|
||||
|
||||
static auto module = RiruVersionedModuleInfo{
|
||||
.moduleApiVersion = riru::moduleApiVersion,
|
||||
.moduleInfo= RiruModuleInfo{
|
||||
.supportHide = true,
|
||||
.version = riru::moduleVersionCode,
|
||||
.versionName = riru::moduleVersionName,
|
||||
.onModuleLoaded = onModuleLoaded,
|
||||
.forkAndSpecializePre = forkAndSpecializePre,
|
||||
.forkAndSpecializePost = forkAndSpecializePost,
|
||||
.forkSystemServerPre = forkSystemServerPre,
|
||||
.forkSystemServerPost = forkSystemServerPost,
|
||||
.specializeAppProcessPre = specializeAppProcessPre,
|
||||
.specializeAppProcessPost = specializeAppProcessPost
|
||||
}
|
||||
.moduleApiVersion = riru::moduleApiVersion,
|
||||
.moduleInfo = RiruModuleInfo{
|
||||
.supportHide = true,
|
||||
.version = riru::moduleVersionCode,
|
||||
.versionName = riru::moduleVersionName,
|
||||
.onModuleLoaded = onModuleLoaded,
|
||||
.forkAndSpecializePre = forkAndSpecializePre,
|
||||
.forkAndSpecializePost = forkAndSpecializePost,
|
||||
.forkSystemServerPre = NULL,
|
||||
.forkSystemServerPost = NULL,
|
||||
.specializeAppProcessPre = specializeAppProcessPre,
|
||||
.specializeAppProcessPost = specializeAppProcessPost,
|
||||
},
|
||||
};
|
||||
|
||||
RiruVersionedModuleInfo *init(Riru *riru) {
|
||||
|
21
riru/template/magisk_module/LICENSE
Normal file
21
riru/template/magisk_module/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021 Danny Lin <danny@kdrag0n.dev>
|
||||
|
||||
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.
|
@ -1 +0,0 @@
|
||||
# Riru - Template
|
@ -1,7 +1,6 @@
|
||||
SKIPUNZIP=1
|
||||
|
||||
# Extract verify.sh
|
||||
ui_print "- Extracting verify.sh"
|
||||
unzip -o "$ZIPFILE" 'verify.sh' -d "$TMPDIR" >&2
|
||||
if [ ! -f "$TMPDIR/verify.sh" ]; then
|
||||
ui_print "*********************************************************"
|
||||
@ -38,7 +37,7 @@ fi
|
||||
ui_print "- Extracting module files"
|
||||
|
||||
extract "$ZIPFILE" 'module.prop' "$MODPATH"
|
||||
extract "$ZIPFILE" 'uninstall.sh' "$MODPATH"
|
||||
extract "$ZIPFILE" 'classes.dex' "$MODPATH"
|
||||
|
||||
# Riru v24+ load files from the "riru" folder in the Magisk module folder
|
||||
# This "riru" folder is also used to determine if a Magisk module is a Riru module
|
||||
|
@ -1,2 +0,0 @@
|
||||
#!/sbin/sh
|
||||
MODDIR=${0%/*}
|
@ -35,5 +35,4 @@ extract() {
|
||||
[ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user