feat(sigbypass): SVC Bypass (ARM64) and OpenAt I/O Redirection

導入 ARM64 專用的 SVC/Seccomp 內核級簽名繞過 (Level 3),並全面強化檔案 I/O 重定向機制。
移除非 ARM64 架構的支持
This commit is contained in:
NkBe 2025-12-22 21:57:33 +08:00
parent 01071283c6
commit 271eb7bd82
No known key found for this signature in database
GPG Key ID: 13CC1FC09F3AE10B
21 changed files with 469 additions and 36 deletions

View File

@ -60,7 +60,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'adopt'
distribution: 'zulu'
- name: 設定 Gradle
uses: gradle/actions/setup-gradle@v5
@ -76,7 +76,7 @@ jobs:
- name: 設定 CMake
uses: jwlawson/actions-setup-cmake@v2
with:
cmake-version: '4.0.3'
cmake-version: '4.1.1'
- name: 移除 Android 的 cmake
shell: bash

View File

@ -108,7 +108,7 @@ fun Project.configureBaseExtension() {
arguments += "-DEXTERNAL_ROOT=${File(rootDir.absolutePath, "core/external")}"
arguments += "-DCORE_ROOT=${File(rootDir.absolutePath,
"core/core/src/main/jni")}"
abiFilters("arm64-v8a", "armeabi-v7a", "x86", "x86_64")
abiFilters("arm64-v8a")
val flags = arrayOf(
"-Wall",
"-Qunused-arguments",

View File

@ -3,6 +3,8 @@
-keep class org.lsposed.npatch.Patcher$Options { *; }
-keep class org.lsposed.npatch.share.LSPConfig { *; }
-keep class org.lsposed.npatch.share.PatchConfig { *; }
-keep class org.lsposed.lspd.nativebridge.** { *; }
-keep class org.lsposed.npatch.loader.SigBypass { *; }
-keepclassmembers class org.lsposed.patch.NPatch {
private <fields>;
}

View File

@ -19,6 +19,8 @@
-keep class org.lsposed.npatch.Patcher$Options { *; }
-keep class org.lsposed.npatch.share.LSPConfig { *; }
-keep class org.lsposed.npatch.share.PatchConfig { *; }
-keep class org.lsposed.lspd.nativebridge.** { *; }
-keep class org.lsposed.npatch.loader.SigBypass { *; }
-dontwarn com.google.auto.value.AutoValue$Builder
-dontwarn com.google.auto.value.AutoValue
-dontwarn com.squareup.moshi.**

View File

@ -281,6 +281,7 @@ private fun sigBypassLvStr(level: Int) = when (level) {
0 -> stringResource(R.string.patch_sigbypasslv0)
1 -> stringResource(R.string.patch_sigbypasslv1)
2 -> stringResource(R.string.patch_sigbypasslv2)
3 -> stringResource(R.string.patch_sigbypasslv3)
else -> throw IllegalArgumentException("Invalid sigBypassLv: $level")
}
@ -384,7 +385,7 @@ private fun PatchOptionsBody(modifier: Modifier, onAddEmbed: () -> Unit) {
)
}
) {
repeat(3) {
repeat(4) {
DropdownMenuItem(
text = {
Row(verticalAlignment = Alignment.CenterVertically) {

View File

@ -64,6 +64,7 @@
<string name="patch_sigbypasslv0">lv0: 关闭</string>
<string name="patch_sigbypasslv1">lv1: 绕过 PM</string>
<string name="patch_sigbypasslv2">lv2: 绕过 PM + openat (libc)</string>
<string name="patch_sigbypasslv3">lv3: 绕过 PM + openat (libc) + SVC (仅 arm64) (测试版)</string>
<string name="patch_override_version_code">覆写版本号</string>
<string name="patch_override_version_code_desc">将修补的 App 版本号重写为 1\n这将允许后续降级安装并且通常来说这不会影响应用实际感知到的版本号</string>
<string name="patch_new_package">修补新包名</string>

View File

@ -64,6 +64,7 @@
<string name="patch_sigbypasslv0">lv0: 關閉</string>
<string name="patch_sigbypasslv1">lv1: 繞過 PM</string>
<string name="patch_sigbypasslv2">lv2: 繞過 PM + openat (libc)</string>
<string name="patch_sigbypasslv3">lv3: 繞過 PM + openat (libc) + SVC (僅 arm64) (測試用)</string>
<string name="patch_override_version_code">覆蓋版本編號</string>
<string name="patch_override_version_code_desc">將打包應用程式的版本編號改成 1\n允許以後降級安裝一般來說這不會影響應用程式實際感知的版本編號。</string>
<string name="patch_new_package">修補新套件名</string>

View File

@ -66,6 +66,7 @@
<string name="patch_sigbypasslv0">lv0: Off</string>
<string name="patch_sigbypasslv1">lv1: Bypass PM</string>
<string name="patch_sigbypasslv2">lv2: Bypass PM + openat (libc)</string>
<string name="patch_sigbypasslv3">lv3: Bypass PM + openat(libc) + SVC (v8a only) (testing)</string>
<string name="patch_new_package">Patch New PackageName</string>
<string name="hint_patch_new_package">Input a new package for app</string>
<string name="patch_override_version_code">Override version code</string>

View File

@ -45,9 +45,7 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory {
private static void bootstrap() {
try {
archToLib.put("arm", "armeabi-v7a");
archToLib.put("arm64", "arm64-v8a");
archToLib.put("x86", "x86");
archToLib.put("x86_64", "x86_64");
var cl = Objects.requireNonNull(LSPAppComponentFactoryStub.class.getClassLoader());

View File

@ -1,5 +1,6 @@
package org.lsposed.lspd.nativebridge;
public class SigBypass {
public static native void enableOpenatHook(String origApkPath, String cacheApkPath);
public static native void enableOpenatHook(String patchedApkPath, String originalApkPath, String packageName);
public static native void disableOpenatHook();
}

View File

@ -0,0 +1,31 @@
package org.lsposed.lspd.nativebridge;
public class SvcBypass {
// 核心功能方法
public static native boolean initSvcHook();
public static native void enableSvcRedirect(String path, String orig, String pkg);
public static native void disableSvcRedirect();
// 狀態檢查與除錯方法
public static native boolean isSvcHookActive();
public static native void logSvcHookStats();
public static native String getDebugInfo();
// 進程與檔案描述符 (FD) 相關方法
public static native int getCurrentPid();
public static native int getInitialPid();
public static native boolean isChildProcess();
public static native String checkFd(int fd);
public static native int dupFd(int fd);
public static native long getFdInode(int fd);
public static native boolean isSystemFile(int fd);
// 系統 APK 與證書相關方法
public static native int findSystemApkFd(String path);
public static native String[][] getSystemApkFds();
public static native void refreshSystemFds();
public static native byte[] readCertificateFromFd(int fd);
public static native byte[] readCertificateFromPath(String path);
}

View File

@ -15,15 +15,21 @@ import android.util.Log;
import com.google.gson.JsonSyntaxException;
import org.lsposed.npatch.loader.util.XLog;
import org.lsposed.npatch.share.Constants;
import org.json.JSONException;
import org.json.JSONObject;
import org.lsposed.lspd.nativebridge.SvcBypass;
import org.lsposed.npatch.loader.util.XLog;
import org.lsposed.npatch.share.Constants;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import de.robv.android.xposed.XC_MethodHook;
@ -34,6 +40,7 @@ public class SigBypass {
private static final String TAG = "NPatch-SigBypass";
private static final Map<String, String> signatures = new HashMap<>();
private static String cachedOriginalApkPath;
private static void replaceSignature(Context context, PackageInfo packageInfo) {
boolean hasSignature = (packageInfo.signatures != null && packageInfo.signatures.length != 0) || packageInfo.signingInfo != null;
@ -145,17 +152,96 @@ public class SigBypass {
}
}
private static String extractOriginalApk(Context context) {
File cacheDir = new File(context.getCacheDir(), "npatch/origin");
if (!cacheDir.exists()) cacheDir.mkdirs();
try (ZipFile sourceFile = new ZipFile(context.getPackageResourcePath())) {
ZipEntry entry = sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH);
if (entry == null) {
Log.e(TAG, "Original APK not found in assets!");
return null;
}
File targetFile = new File(cacheDir, entry.getCrc() + ".apk");
if (targetFile.exists() && targetFile.length() == entry.getSize()) {
return targetFile.getAbsolutePath();
}
try (InputStream is = sourceFile.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(targetFile)) {
byte[] buffer = new byte[8192];
int length;
while ((length = is.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
}
return targetFile.getAbsolutePath();
} catch (IOException e) {
Log.e(TAG, "Failed to extract original APK", e);
return null;
}
}
private static void hookJavaIO(String currentApkPath, String originalApkPath) {
XC_MethodHook redirectHook = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
if (param.args.length > 0) {
if (param.args[0] instanceof String) {
String path = (String) param.args[0];
if (path.equals(currentApkPath)) {
param.args[0] = originalApkPath;
}
} else if (param.args[0] instanceof File) {
File file = (File) param.args[0];
if (file.getPath().equals(currentApkPath)) {
param.args[0] = new File(originalApkPath);
}
}
}
}
};
XposedBridge.hookAllConstructors(ZipFile.class, redirectHook);
try {
XposedBridge.hookAllConstructors(FileInputStream.class, redirectHook);
} catch (Throwable ignored) {}
}
static void doSigBypass(Context context, int sigBypassLevel) throws IOException {
// Level 1: Java PMS Hook
if (sigBypassLevel >= Constants.SIGBYPASS_LV_PM) {
hookPackageParser(context);
proxyPackageInfoCreator(context);
}
if (sigBypassLevel >= Constants.SIGBYPASS_LV_PM_OPENAT) {
String cacheApkPath;
try (ZipFile sourceFile = new ZipFile(context.getPackageResourcePath())) {
cacheApkPath = context.getCacheDir() + "/npatch/origin/" + sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc() + ".apk";
String currentApkPath = context.getPackageResourcePath();
cachedOriginalApkPath = extractOriginalApk(context);
if (cachedOriginalApkPath != null) {
// 1. Java Core stability
hookJavaIO(currentApkPath, cachedOriginalApkPath);
// 2. Native OpenAt Hook
org.lsposed.lspd.nativebridge.SigBypass.enableOpenatHook(
currentApkPath,
cachedOriginalApkPath,
context.getPackageName()
);
// Level 3: SVC (Seccomp) Hook
if (sigBypassLevel >= Constants.SIGBYPASS_LV_SVC) {
if (SvcBypass.initSvcHook()) {
SvcBypass.enableSvcRedirect(
currentApkPath,
cachedOriginalApkPath,
context.getPackageName()
);
XLog.i(TAG, "SVC Hook enabled");
} else {
XLog.w(TAG, "SVC Hook failed to init");
}
}
}
org.lsposed.lspd.nativebridge.SigBypass.enableOpenatHook(context.getPackageResourcePath(), cacheApkPath);
}
}
}

View File

@ -7,6 +7,8 @@ add_subdirectory(${CORE_ROOT} core)
aux_source_directory(src SRC_LIST)
aux_source_directory(src/jni SRC_LIST)
set(SRC_LIST ${SRC_LIST} api/patch_main.cpp)
set(SRC_LIST ${SRC_LIST} src/jni/bypass_sig.cpp)
set(SRC_LIST ${SRC_LIST} src/jni/bypass_svc.cpp)
add_library(${PROJECT_NAME} SHARED ${SRC_LIST})

View File

@ -1,6 +1,6 @@
//
// Created by VIP on 2021/4/25.
// Update by HSSkyBoy on 2025/9/11
// Modified by HSSkyBoy on 2025/12/15
//
#include "bypass_sig.h"
@ -13,17 +13,22 @@
#include "utils/hook_helper.hpp"
#include "utils/jni_helper.hpp"
#include <unistd.h>
#include <string>
#include <cstring>
#include <memory>
using lsplant::operator""_sym;
namespace lspd {
std::string apkPath;
std::string redirectPath;
static std::string targetApkPath;
static std::string redirectApkPath;
static std::string currentPackageName;
static void *openat_backup = nullptr;
inline static constexpr const char* kLibCName = "libc.so";
// 修改回傳型別以匹配 kImg 的實際型別
// 修改回傳型別以匹配 kImg 的實際型別
std::unique_ptr<SandHook::ElfImg> &GetC(bool release = false) {
static auto kImg = std::make_unique<SandHook::ElfImg>(kLibCName);
if (release) {
@ -33,38 +38,49 @@ namespace lspd {
return kImg;
}
// OpenAt Hook 邏輯
inline static auto __openat_ =
"__openat"_sym.hook->*[]<lsplant::Backup auto backup>(int fd, const char *pathname, int flag,
int mode) static -> int {
if (pathname && strcmp(pathname, apkPath.c_str()) == 0) {
return backup(fd, redirectPath.c_str(), flag, mode);
if (pathname && !targetApkPath.empty() && strcmp(pathname, targetApkPath.c_str()) == 0) {
return backup(fd, redirectApkPath.c_str(), flag, mode);
}
return backup(fd, pathname, flag, mode);
};
static bool HookOpenat(const lsplant::HookHandler &handler) { return handler(__openat_); }
LSP_DEF_NATIVE_METHOD(void, SigBypass, enableOpenatHook, jstring origApkPath,
jstring cacheApkPath) {
if (origApkPath == nullptr || cacheApkPath == nullptr) {
LOGE("Invalid arguments: original or cache path is null.");
LSP_DEF_NATIVE_METHOD(void, SigBypass, enableOpenatHook,
jstring jOrigApkPath,
jstring jCacheApkPath,
jstring jPkgName) {
if (jOrigApkPath == nullptr || jCacheApkPath == nullptr) {
LOGE("Invalid arguments: paths cannot be null.");
return;
}
lsplant::JUTFString str1(env, origApkPath);
lsplant::JUTFString str2(env, cacheApkPath);
lsplant::JUTFString strOrig(env, jOrigApkPath);
lsplant::JUTFString strRedirect(env, jCacheApkPath);
apkPath = str1.get();
redirectPath = str2.get();
targetApkPath = strOrig.get();
redirectApkPath = strRedirect.get();
LOGI("Attempting to hook __openat (libc). Original: %s, Redirect: %s",
apkPath.c_str(), redirectPath.c_str());
if (jPkgName != nullptr) {
lsplant::JUTFString strPkg(env, jPkgName);
currentPackageName = strPkg.get();
}
LOGI("Enable OpenAt Hook: %s -> %s (Pkg: %s)",
targetApkPath.c_str(), redirectApkPath.c_str(), currentPackageName.c_str());
auto r = HookOpenat(lsplant::InitInfo{
.inline_hooker =
[](auto t, auto r) {
void *bk = nullptr;
return HookInline(t, r, &bk) == 0 ? bk : nullptr;
int ret = HookInline(t, r, &bk);
if (ret == 0) openat_backup = bk;
return ret == 0 ? bk : nullptr;
},
.art_symbol_resolver = [](auto symbol) {
return GetC()->getSymbAddress(symbol);
@ -77,8 +93,17 @@ namespace lspd {
GetC(true);
}
LSP_DEF_NATIVE_METHOD(void, SigBypass, disableOpenatHook) {
LOGI("Disable OpenAt Hook requested");
targetApkPath.clear();
redirectApkPath.clear();
}
// 註冊 JNI 方法
static JNINativeMethod gMethods[] = {
LSP_NATIVE_METHOD(SigBypass, enableOpenatHook, "(Ljava/lang/String;Ljava/lang/String;)V")};
LSP_NATIVE_METHOD(SigBypass, enableOpenatHook, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
LSP_NATIVE_METHOD(SigBypass, disableOpenatHook, "()V")
};
void RegisterBypass(JNIEnv *env) { REGISTER_LSP_NATIVE_METHODS(SigBypass); }

View File

@ -1,5 +1,4 @@
#pragma once
#include <jni.h>
namespace lspd {

View File

@ -0,0 +1,255 @@
#include "bypass_svc.h"
#include "logging.h"
#include "native_util.h"
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/prctl.h>
#include <signal.h>
#include <ucontext.h>
#include <pthread.h>
#include <cstddef>
#include <cstring>
#include <cstdlib>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/audit.h>
#include <queue>
#include <mutex>
#include <condition_variable>
namespace lspd {
// --- 共用結構與變數 ---
struct SyscallRequest {
long sys_no;
long args[6];
long result;
bool completed;
std::mutex mtx;
std::condition_variable cv;
};
static pthread_t g_trusted_thread;
static bool g_is_hook_active = false;
static std::queue<SyscallRequest*> g_request_queue;
static std::mutex g_queue_mtx;
static std::condition_variable g_queue_cv;
// --- 核心功能實作 (ARM64 Only) ---
// 1. 影子線程循環
static void* trusted_thread_loop(void* arg) {
LOGD("SvcBypass: Trusted thread started (TID: %d)", gettid());
while (true) {
SyscallRequest* req = nullptr;
{
std::unique_lock<std::mutex> lock(g_queue_mtx);
g_queue_cv.wait(lock, [] { return !g_request_queue.empty(); });
req = g_request_queue.front();
g_request_queue.pop();
}
if (req) {
// 執行真正的 syscall
req->result = syscall(req->sys_no,
req->args[0], req->args[1], req->args[2],
req->args[3], req->args[4], req->args[5]);
{
std::lock_guard<std::mutex> lock(req->mtx);
req->completed = true;
}
req->cv.notify_one();
}
}
return nullptr;
}
// 2. SIGSYS 信號處理器
static void sigsys_handler(int signo, siginfo_t* info, void* context) {
if (signo != SIGSYS) return;
ucontext_t* ctx = (ucontext_t*)context;
SyscallRequest req;
// ARM64: 從 regs 讀取 (x8=sys_no, x0-x5=args)
// 直接存取 ARM64 特有的 regs 結構
req.sys_no = ctx->uc_mcontext.regs[8];
for (int i = 0; i < 6; ++i) {
req.args[i] = ctx->uc_mcontext.regs[i];
}
req.completed = false;
LOGD("SvcBypass: Trapped syscall %ld (PID: %d)", req.sys_no, getpid());
{
std::lock_guard<std::mutex> lock(g_queue_mtx);
g_request_queue.push(&req);
}
g_queue_cv.notify_one();
{
std::unique_lock<std::mutex> lock(req.mtx);
req.cv.wait(lock, [&req] { return req.completed; });
}
// 將結果寫回 x0
ctx->uc_mcontext.regs[0] = req.result;
}
// --- JNI 接口層 ---
LSP_DEF_NATIVE_METHOD(jboolean, SvcBypass, initSvcHook) {
// 如果已經激活,直接返回成功
if (g_is_hook_active) return JNI_TRUE;
int ret = pthread_create(&g_trusted_thread, nullptr, trusted_thread_loop, nullptr);
if (ret != 0) {
LOGE("SvcBypass: Failed to create trusted thread");
return JNI_FALSE;
}
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = sigsys_handler;
sa.sa_flags = SA_SIGINFO | SA_NODEFER;
if (sigaction(SIGSYS, &sa, nullptr) < 0) {
LOGE("SvcBypass: Failed to register SIGSYS handler");
return JNI_FALSE;
}
g_is_hook_active = true;
LOGI("SvcBypass: Initialized successfully (ARM64)");
return JNI_TRUE;
}
LSP_DEF_NATIVE_METHOD(void, SvcBypass, enableSvcRedirect,
jstring path, jstring orig, jstring pkg) {
if (!g_is_hook_active) {
LOGW("SvcBypass: Hook not initialized.");
return;
}
// ARM64 BPF 規則
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, nr))),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_openat, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRAP),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
LOGE("SvcBypass: prctl(NO_NEW_PRIVS) failed");
return;
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
LOGE("SvcBypass: prctl(SECCOMP) failed");
} else {
LOGI("SvcBypass: Seccomp filter applied (ARM64)");
}
}
LSP_DEF_NATIVE_METHOD(void, SvcBypass, disableSvcRedirect) {
LOGW("SvcBypass: Cannot disable Seccomp filters once applied.");
}
LSP_DEF_NATIVE_METHOD(jboolean, SvcBypass, isSvcHookActive) {
return g_is_hook_active ? JNI_TRUE : JNI_FALSE;
}
LSP_DEF_NATIVE_METHOD(jstring, SvcBypass, getDebugInfo) {
return env->NewStringUTF("SvcBypass: Active (ARM64)");
}
LSP_DEF_NATIVE_METHOD(jint, SvcBypass, getCurrentPid) {
return getpid();
}
LSP_DEF_NATIVE_METHOD(jint, SvcBypass, getInitialPid) {
return getpid();
}
LSP_DEF_NATIVE_METHOD(void, SvcBypass, logSvcHookStats) {
}
LSP_DEF_NATIVE_METHOD(jboolean, SvcBypass, isChildProcess) {
return JNI_FALSE;
}
LSP_DEF_NATIVE_METHOD(jstring, SvcBypass, checkFd, jint fd) {
char path[512];
char link[64];
snprintf(link, sizeof(link), "/proc/self/fd/%d", fd);
ssize_t len = readlink(link, path, sizeof(path) - 1);
if (len != -1) {
path[len] = '\0';
return env->NewStringUTF(path);
}
return nullptr;
}
LSP_DEF_NATIVE_METHOD(jint, SvcBypass, dupFd, jint fd) {
return dup(fd);
}
LSP_DEF_NATIVE_METHOD(jlong, SvcBypass, getFdInode, jint fd) {
struct stat st;
if (fstat(fd, &st) == 0) return (jlong)st.st_ino;
return -1;
}
LSP_DEF_NATIVE_METHOD(jboolean, SvcBypass, isSystemFile, jint fd) {
return JNI_FALSE;
}
LSP_DEF_NATIVE_METHOD(jint, SvcBypass, findSystemApkFd, jstring path) {
return -1;
}
LSP_DEF_NATIVE_METHOD(jobjectArray, SvcBypass, getSystemApkFds) {
return nullptr;
}
LSP_DEF_NATIVE_METHOD(void, SvcBypass, refreshSystemFds) {
}
LSP_DEF_NATIVE_METHOD(jbyteArray, SvcBypass, readCertificateFromFd, jint fd) {
return nullptr;
}
LSP_DEF_NATIVE_METHOD(jbyteArray, SvcBypass, readCertificateFromPath, jstring path) {
return nullptr;
}
static JNINativeMethod gMethods[] = {
LSP_NATIVE_METHOD(SvcBypass, initSvcHook, "()Z"),
LSP_NATIVE_METHOD(SvcBypass, enableSvcRedirect, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
LSP_NATIVE_METHOD(SvcBypass, disableSvcRedirect, "()V"),
LSP_NATIVE_METHOD(SvcBypass, isSvcHookActive, "()Z"),
LSP_NATIVE_METHOD(SvcBypass, logSvcHookStats, "()V"),
LSP_NATIVE_METHOD(SvcBypass, getDebugInfo, "()Ljava/lang/String;"),
LSP_NATIVE_METHOD(SvcBypass, getCurrentPid, "()I"),
LSP_NATIVE_METHOD(SvcBypass, getInitialPid, "()I"),
LSP_NATIVE_METHOD(SvcBypass, isChildProcess, "()Z"),
LSP_NATIVE_METHOD(SvcBypass, checkFd, "(I)Ljava/lang/String;"),
LSP_NATIVE_METHOD(SvcBypass, dupFd, "(I)I"),
LSP_NATIVE_METHOD(SvcBypass, getFdInode, "(I)J"),
LSP_NATIVE_METHOD(SvcBypass, isSystemFile, "(I)Z"),
LSP_NATIVE_METHOD(SvcBypass, findSystemApkFd, "(Ljava/lang/String;)I"),
LSP_NATIVE_METHOD(SvcBypass, getSystemApkFds, "()[[Ljava/lang/String;"),
LSP_NATIVE_METHOD(SvcBypass, refreshSystemFds, "()V"),
LSP_NATIVE_METHOD(SvcBypass, readCertificateFromFd, "(I)[B"),
LSP_NATIVE_METHOD(SvcBypass, readCertificateFromPath, "(Ljava/lang/String;)[B"),
};
void RegisterSvcBypass(JNIEnv *env) {
REGISTER_LSP_NATIVE_METHODS(SvcBypass);
}
}

View File

@ -0,0 +1,8 @@
#pragma once
#include <jni.h>
namespace lspd {
void RegisterSvcBypass(JNIEnv* env);
} // namespace lspd

View File

@ -27,6 +27,7 @@
#include "art/runtime/oat_file_manager.h"
#include "elf_util.h"
#include "jni/bypass_sig.h"
#include "jni/bypass_svc.h"
#include "native_util.h"
#include "symbol_cache.h"
#include "utils/jni_helper.hpp"
@ -78,6 +79,7 @@ namespace lspd {
void PatchLoader::InitHooks(JNIEnv* env) {
Context::InitHooks(env);
RegisterBypass(env);
RegisterSvcBypass(env);
}
void PatchLoader::SetupEntryClass(JNIEnv* env) {

View File

@ -313,6 +313,14 @@ public class NPatch {
} catch (Throwable e) {
throw new PatchError("Error when adding dex", e);
}
if (sigbypassLevel >= Constants.SIGBYPASS_LV_PM_OPENAT) {
logger.i("Embedding original apk for SigBypass...");
try (var is = new FileInputStream(srcApkFile)) {
dstZFile.add(Constants.ORIGINAL_APK_ASSET_PATH, is);
} catch (Throwable e) {
throw new PatchError("Error when embedding original apk", e);
}
}
if (isInjectProvider){
try (var is = getClass().getClassLoader().getResourceAsStream("assets/mtprovider.dex")) {
@ -360,7 +368,16 @@ public class NPatch {
if (!injectDex && name.startsWith("classes") && name.endsWith(".dex")) continue;
if (name.equals("AndroidManifest.xml")) continue;
if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA"))) continue;
srcZFile.addFileLink(name, name);
try (InputStream is = entry.open()) {
if (name.endsWith(".so")) {
dstZFile.add(name, is, false);
} else {
dstZFile.add(name, is);
}
} catch (IOException e) {
throw new PatchError("Failed to copy entry: " + name, e);
}
}
dstZFile.realign();

View File

@ -17,5 +17,5 @@ public class Constants {
final static public int SIGBYPASS_LV_DISABLE = 0;
final static public int SIGBYPASS_LV_PM = 1;
final static public int SIGBYPASS_LV_PM_OPENAT = 2;
final static public int SIGBYPASS_LV_MAX = 3;
final static public int SIGBYPASS_LV_SVC = 3;
}

View File

@ -9,6 +9,7 @@ public class LSPConfig {
public String VERSION_NAME;
public int CORE_VERSION_CODE;
public String CORE_VERSION_NAME;
public int sigBypassLevel;
private LSPConfig() {
}