mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
Shamrock
: アンチシミュレータ検出
This commit is contained in:
parent
4a4507dfcd
commit
b7266e490f
@ -19,7 +19,7 @@
|
|||||||
android:theme="@style/Theme.Shamrock"
|
android:theme="@style/Theme.Shamrock"
|
||||||
android:zygotePreloadName="@string/app_name"
|
android:zygotePreloadName="@string/app_name"
|
||||||
android:multiArch="true"
|
android:multiArch="true"
|
||||||
android:extractNativeLibs="false"
|
android:extractNativeLibs="true"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
# Sets the minimum CMake version required for this project.
|
# Sets the minimum CMake version required for this project.
|
||||||
cmake_minimum_required(VERSION 3.22.1)
|
cmake_minimum_required(VERSION 3.22.1)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
|
# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
|
||||||
# Since this is the top level CMakeLists.txt, the project name is also accessible
|
# Since this is the top level CMakeLists.txt, the project name is also accessible
|
||||||
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
|
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
|
||||||
|
@ -1,19 +1,116 @@
|
|||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <vector>
|
||||||
#include <sys/auxv.h>
|
#include <sys/auxv.h>
|
||||||
|
#include <android/log.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <string_view>
|
||||||
#include "lsposed.h"
|
#include "lsposed.h"
|
||||||
|
#include "jnihelper.h"
|
||||||
|
|
||||||
|
static HookFunType hook_function = nullptr;
|
||||||
|
|
||||||
|
static std::vector<std::string> qemu_detect_props = {
|
||||||
|
"init.svc.qemu-props", "qemu.hw.mainkeys", "qemu.sf.fake_camera", "ro.kernel.android.qemud",
|
||||||
|
"qemu.sf.lcd_density", "init.svc.qemud", "ro.kernel.qemu",
|
||||||
|
"libc.debug.malloc"
|
||||||
|
};
|
||||||
|
|
||||||
|
int (*backup_system_property_get)(const char *name, char *value);
|
||||||
|
|
||||||
|
int fake_system_property_get(const char *name, char *value) {
|
||||||
|
for (auto &prop: qemu_detect_props) {
|
||||||
|
if (strstr(name, prop.c_str())) {
|
||||||
|
LOGI("[Shamrock] bypass qemu detection");
|
||||||
|
value[0] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(name, "ro.debuggable")
|
||||||
|
|| strstr(name, "ro.kernel.qemu.gles")
|
||||||
|
|| strstr(name, "debug.atrace.tags.enableflags")) {
|
||||||
|
strcpy(value, "0");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(name, "ro.product.cpu.abilist")) {
|
||||||
|
int len = backup_system_property_get(name, value);
|
||||||
|
if (len > 0) {
|
||||||
|
if (strstr(value, "x86")) {
|
||||||
|
strcpy(value, "arm64-v8a,armeabi-v7a,armeabi");
|
||||||
|
return 29;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(name, "ro.hardware")) {
|
||||||
|
int len = backup_system_property_get(name, value);
|
||||||
|
if (len > 0) {
|
||||||
|
if (strstr(value, "generic")
|
||||||
|
|| strstr(value, "unknown")
|
||||||
|
|| strstr(value, "emulator")
|
||||||
|
|| strstr(value, "vbox")
|
||||||
|
|| strstr(value, "genymotion")
|
||||||
|
|| strstr(value, "goldfish")) {
|
||||||
|
strcpy(value, "qcom");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
//LOGI("[Shamrock] fake_system_property_get(%s)", name);
|
||||||
|
return backup_system_property_get(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
void on_library_loaded(const char *name, void *handle) {
|
void on_library_loaded(const char *name, void *handle) {
|
||||||
if (std::string(name) == "libc.so") {
|
auto libraryName = std::string(name);
|
||||||
|
if (libraryName.ends_with("libc.so") || libraryName.ends_with("libfekit.so")) {
|
||||||
void *target = dlsym(handle, "__system_property_get");
|
void *target = dlsym(handle, "__system_property_get");
|
||||||
|
if (target != nullptr) {
|
||||||
|
hook_function(target, (void *)fake_system_property_get, (void **) &backup_system_property_get);
|
||||||
|
} else {
|
||||||
|
LOGE("[Shamrock] failed to hook __system_property_get");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" [[gnu::visibility("default")]] [[gnu::used]]
|
extern "C" [[gnu::visibility("default")]] [[gnu::used]]
|
||||||
NativeOnModuleLoaded native_init(const NativeAPIEntries *entries) {
|
jint JNI_OnLoad(JavaVM *jvm, void*) {
|
||||||
|
JNIHelper::initJavaVM(jvm);
|
||||||
|
int attach = 0;
|
||||||
|
JNIEnv *env = JNIHelper::getJNIEnv(&attach);
|
||||||
|
|
||||||
|
// do something
|
||||||
|
LOGI("[Shamrock] JNI_OnLoad NativeModule Init: %p", env);
|
||||||
|
|
||||||
|
if (attach == 1) {
|
||||||
|
JNIHelper::delJNIEnv();
|
||||||
|
}
|
||||||
|
|
||||||
|
//hook_function((void *)env->functions->FindClass, (void *)fake_FindClass, (void **)&backup_FindClass);
|
||||||
|
return JNI_VERSION_1_6;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" [[gnu::visibility("default")]] [[gnu::used]]
|
||||||
|
NativeOnModuleLoaded native_init(const NativeAPIEntries *entries) {
|
||||||
|
hook_function = entries->hook_func;
|
||||||
|
LOGI("[Shamrock] LSPosed NativeModule Init: %p", hook_function);
|
||||||
return on_library_loaded;
|
return on_library_loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_moe_fuqiuluo_shamrock_xposed_XposedEntry_00024Companion_injected(JNIEnv *env, jobject thiz) {
|
||||||
|
return hook_function != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_moe_fuqiuluo_shamrock_xposed_XposedEntry_00024Companion_hasEnv(JNIEnv *env, jobject thiz) {
|
||||||
|
return JNIHelper::global_jvm != nullptr;
|
||||||
|
}
|
40
xposed/src/main/cpp/jnihelper.h
Normal file
40
xposed/src/main/cpp/jnihelper.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef SHAMROCK_JNIHELPER_H
|
||||||
|
#define SHAMROCK_JNIHELPER_H
|
||||||
|
|
||||||
|
#include "android/log.h"
|
||||||
|
|
||||||
|
namespace JNIHelper {
|
||||||
|
static JavaVM *global_jvm = nullptr;
|
||||||
|
|
||||||
|
void initJavaVM(JavaVM *jvm) {
|
||||||
|
global_jvm = jvm;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEnv *getJNIEnv(int *attach) {
|
||||||
|
if (global_jvm == NULL) return NULL;
|
||||||
|
|
||||||
|
*attach = 0;
|
||||||
|
JNIEnv *jni_env = NULL;
|
||||||
|
|
||||||
|
int status = global_jvm->GetEnv((void **)&jni_env, JNI_VERSION_1_6);
|
||||||
|
|
||||||
|
if (status == JNI_EDETACHED || jni_env == NULL) {
|
||||||
|
status = global_jvm->AttachCurrentThread(&jni_env, NULL);
|
||||||
|
if (status < 0) {
|
||||||
|
jni_env = NULL;
|
||||||
|
} else {
|
||||||
|
*attach = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jni_env;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint delJNIEnv() {
|
||||||
|
if (global_jvm == nullptr) return 0;
|
||||||
|
return global_jvm->DetachCurrentThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SHAMROCK_JNIHELPER_H
|
@ -3,6 +3,13 @@
|
|||||||
|
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
|
|
||||||
|
#define TAG "LSPosed-Bridge"
|
||||||
|
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
|
||||||
|
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)
|
||||||
|
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)
|
||||||
|
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
|
||||||
|
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)
|
||||||
|
|
||||||
typedef int (*HookFunType)(void *func, void *replace, void **backup);
|
typedef int (*HookFunType)(void *func, void *replace, void **backup);
|
||||||
|
|
||||||
typedef int (*UnhookFunType)(void *func);
|
typedef int (*UnhookFunType)(void *func);
|
||||||
|
@ -51,8 +51,29 @@ internal object LogCenter {
|
|||||||
|
|
||||||
private val format = SimpleDateFormat("[HH:mm:ss] ")
|
private val format = SimpleDateFormat("[HH:mm:ss] ")
|
||||||
|
|
||||||
fun log(string: String, level: Level = Level.INFO, toast: Boolean = false) =
|
fun log(string: String, level: Level = Level.INFO, toast: Boolean = false) {
|
||||||
log({ string }, level, toast)
|
if (!ShamrockConfig.isDebug() && level == Level.DEBUG) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toast) {
|
||||||
|
MobileQQ.getContext().toast(string)
|
||||||
|
}
|
||||||
|
// 把日志广播到主进程
|
||||||
|
GlobalScope.launch(Dispatchers.Default) {
|
||||||
|
DataRequester.request("send_message", bodyBuilder = {
|
||||||
|
put("string", string)
|
||||||
|
put("level", level.id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!LogFile.exists()) {
|
||||||
|
LogFile.createNewFile()
|
||||||
|
}
|
||||||
|
val format = "%s%s %s\n".format(format.format(Date()), level.name, string)
|
||||||
|
|
||||||
|
LogFile.appendText(format)
|
||||||
|
}
|
||||||
|
|
||||||
fun log(
|
fun log(
|
||||||
string: () -> String,
|
string: () -> String,
|
||||||
|
@ -5,6 +5,8 @@ import de.robv.android.xposed.IXposedHookLoadPackage
|
|||||||
import de.robv.android.xposed.XposedBridge
|
import de.robv.android.xposed.XposedBridge
|
||||||
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
||||||
import de.robv.android.xposed.XposedBridge.log
|
import de.robv.android.xposed.XposedBridge.log
|
||||||
|
import moe.fuqiuluo.shamrock.helper.Level
|
||||||
|
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||||
import moe.fuqiuluo.shamrock.utils.MMKVFetcher
|
import moe.fuqiuluo.shamrock.utils.MMKVFetcher
|
||||||
import moe.fuqiuluo.shamrock.xposed.loader.ActionLoader
|
import moe.fuqiuluo.shamrock.xposed.loader.ActionLoader
|
||||||
import moe.fuqiuluo.shamrock.xposed.loader.FuckAMS
|
import moe.fuqiuluo.shamrock.xposed.loader.FuckAMS
|
||||||
@ -12,6 +14,7 @@ import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader
|
|||||||
import moe.fuqiuluo.shamrock.tools.FuzzySearchClass
|
import moe.fuqiuluo.shamrock.tools.FuzzySearchClass
|
||||||
import moe.fuqiuluo.shamrock.tools.afterHook
|
import moe.fuqiuluo.shamrock.tools.afterHook
|
||||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||||
|
import moe.fuqiuluo.shamrock.xposed.loader.NativeLoader
|
||||||
import mqq.app.MobileQQ
|
import mqq.app.MobileQQ
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
import java.lang.reflect.Modifier
|
import java.lang.reflect.Modifier
|
||||||
@ -26,6 +29,12 @@ internal class XposedEntry: IXposedHookLoadPackage {
|
|||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
var sec_static_stage_inited = false
|
var sec_static_stage_inited = false
|
||||||
|
@JvmStatic
|
||||||
|
var sec_static_nativehook_inited = false
|
||||||
|
|
||||||
|
external fun injected(): Boolean
|
||||||
|
|
||||||
|
external fun hasEnv(): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
private var firstStageInit = false
|
private var firstStageInit = false
|
||||||
@ -108,7 +117,6 @@ internal class XposedEntry: IXposedHookLoadPackage {
|
|||||||
if (sec_static_stage_inited) return
|
if (sec_static_stage_inited) return
|
||||||
|
|
||||||
val classLoader = ctx.classLoader.also { requireNotNull(it) }
|
val classLoader = ctx.classLoader.also { requireNotNull(it) }
|
||||||
|
|
||||||
LuoClassloader.hostClassLoader = classLoader
|
LuoClassloader.hostClassLoader = classLoader
|
||||||
|
|
||||||
if(injectClassloader(XposedEntry::class.java.classLoader)) {
|
if(injectClassloader(XposedEntry::class.java.classLoader)) {
|
||||||
@ -116,12 +124,7 @@ internal class XposedEntry: IXposedHookLoadPackage {
|
|||||||
System.setProperty("qxbot_flag", "1")
|
System.setProperty("qxbot_flag", "1")
|
||||||
} else return
|
} else return
|
||||||
|
|
||||||
log("Process Name = " + MobileQQ.getMobileQQ().qqProcessName.apply {
|
log("Process Name = " + MobileQQ.getMobileQQ().qqProcessName)
|
||||||
// if (!contains("msf", ignoreCase = true)) return // 非MSF进程 退出
|
|
||||||
//if (contains("peak")) {
|
|
||||||
// PlatformUtils.killProcess(ctx, this)
|
|
||||||
//}
|
|
||||||
})
|
|
||||||
|
|
||||||
PlatformUtils.isTim()
|
PlatformUtils.isTim()
|
||||||
|
|
||||||
|
@ -6,12 +6,15 @@ import android.content.pm.PackageManager
|
|||||||
import android.content.pm.VersionedPackage
|
import android.content.pm.VersionedPackage
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import de.robv.android.xposed.XC_MethodReplacement
|
import de.robv.android.xposed.XC_MethodReplacement
|
||||||
|
import de.robv.android.xposed.XposedBridge
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import de.robv.android.xposed.XposedHelpers
|
||||||
import moe.fuqiuluo.shamrock.helper.Level
|
import moe.fuqiuluo.shamrock.helper.Level
|
||||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||||
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
|
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
|
||||||
import moe.fuqiuluo.shamrock.tools.hookMethod
|
import moe.fuqiuluo.shamrock.tools.hookMethod
|
||||||
|
import moe.fuqiuluo.shamrock.xposed.XposedEntry
|
||||||
import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader
|
import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader
|
||||||
|
import moe.fuqiuluo.shamrock.xposed.loader.NativeLoader
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 反检测
|
* 反检测
|
||||||
@ -19,6 +22,7 @@ import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader
|
|||||||
class AntiDetection: IAction {
|
class AntiDetection: IAction {
|
||||||
override fun invoke(ctx: Context) {
|
override fun invoke(ctx: Context) {
|
||||||
antiFindPackage(ctx)
|
antiFindPackage(ctx)
|
||||||
|
antiNativeDetection()
|
||||||
if (ShamrockConfig.isAntiTrace())
|
if (ShamrockConfig.isAntiTrace())
|
||||||
antiTrace()
|
antiTrace()
|
||||||
antiMemoryWalking()
|
antiMemoryWalking()
|
||||||
@ -35,6 +39,23 @@ class AntiDetection: IAction {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun antiNativeDetection() {
|
||||||
|
try {
|
||||||
|
//System.loadLibrary("clover")
|
||||||
|
NativeLoader.load("clover")
|
||||||
|
val env = XposedEntry.hasEnv()
|
||||||
|
val injected = XposedEntry.injected()
|
||||||
|
if (!env || !injected) {
|
||||||
|
LogCenter.log("[Shamrock] Shamrock反检测启动失败(env=$env, injected=$injected)", Level.ERROR)
|
||||||
|
} else {
|
||||||
|
XposedEntry.sec_static_nativehook_inited = true
|
||||||
|
LogCenter.log("[Shamrock] Shamrock反检测启动成功", Level.INFO)
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
LogCenter.log("[Shamrock] Shamrock反检测启动失败,请检查LSPosed版本使用大于100: ${e.message}", Level.ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun antiFindPackage(context: Context) {
|
private fun antiFindPackage(context: Context) {
|
||||||
val packageManager = context.packageManager
|
val packageManager = context.packageManager
|
||||||
val applicationInfo = packageManager.getApplicationInfo("moe.fuqiuluo.shamrock", 0)
|
val applicationInfo = packageManager.getApplicationInfo("moe.fuqiuluo.shamrock", 0)
|
||||||
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
|||||||
import de.robv.android.xposed.XposedBridge
|
import de.robv.android.xposed.XposedBridge
|
||||||
import moe.fuqiuluo.shamrock.helper.Level
|
import moe.fuqiuluo.shamrock.helper.Level
|
||||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||||
|
import moe.fuqiuluo.shamrock.xposed.XposedEntry
|
||||||
import mqq.app.MobileQQ
|
import mqq.app.MobileQQ
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ internal object NativeLoader {
|
|||||||
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
||||||
fun load(name: String) {
|
fun load(name: String) {
|
||||||
try {
|
try {
|
||||||
if (name == "shamrock") {
|
if (name == "shamrock" || name == "clover") {
|
||||||
val context = MobileQQ.getContext()
|
val context = MobileQQ.getContext()
|
||||||
val packageManager = context.packageManager
|
val packageManager = context.packageManager
|
||||||
val applicationInfo = packageManager.getApplicationInfo("moe.fuqiuluo.shamrock.hided", 0)
|
val applicationInfo = packageManager.getApplicationInfo("moe.fuqiuluo.shamrock.hided", 0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user