feat: Enhance core framework with improved service faking, package management, and build system updates.

intigrated disable flag secure

remove comments cleanup codes
This commit is contained in:
ArtRuntime
2026-02-04 22:09:34 +05:30
parent e770372144
commit 9c744770f8
389 changed files with 4621 additions and 7834 deletions
+6 -8
View File
@@ -16,12 +16,10 @@ android {
}
defaultConfig {
minSdkVersion rootProject.ext.minSdk
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
consumerProguardFiles "consumer-rules.pro"
ndk {
// 设置支持的SO库架构
abiFilters 'arm64-v8a' , 'armeabi-v7a'
}
}
@@ -41,11 +39,11 @@ android {
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
// Enable incremental annotation processing for faster builds
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:-deprecation" << "-Xlint:-unchecked" << "-Xlint:-rawtypes"
options.fork = true
@@ -89,8 +87,8 @@ dependencies {
implementation 'com.moandjiezana.toml:toml4j:0.7.2'
implementation 'com.github.tiann:FreeReflection:3.2.2'
// implementation "com.github.CodingGay.BlackReflection:core:$rootProject.ext.blackReflection"
// Pine dependency removed
}
+70 -70
View File
@@ -3,21 +3,21 @@
<!-- Internet permission for apps that need network access -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Permissions for RockerManager (floating GPS joystick) -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- Additional permissions for better location spoofing -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- Permissions for WebView functionality -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -26,16 +26,16 @@
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- Audio + Foreground service (Android 14+) -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<!-- Optional: silence WebView bluetooth media warnings -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- unknown -->
<uses-permission android:name="android.permission.WRITE_SOCIAL_STREAM" />
<uses-permission android:name="android.permission.READ_SOCIAL_STREAM" />
<uses-permission android:name="android.permission.READ_PROFILE" />
@@ -45,7 +45,7 @@
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<!-- samsung start -->
<uses-permission android:name="com.samsung.svoice.sync.READ_DATABASE" />
<uses-permission android:name="com.samsung.svoice.sync.ACCESS_SERVICE" />
<uses-permission android:name="com.samsung.svoice.sync.WRITE_DATABASE" />
@@ -59,21 +59,21 @@
<uses-permission android:name="sec.android.permission.READ_MSG_PREF" />
<uses-permission android:name="com.samsung.android.scloud.backup.lib.read" />
<uses-permission android:name="com.samsung.android.scloud.backup.lib.write" />
<!-- samsung end -->
<!-- other app start -->
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
<uses-permission android:name="com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL" />
<uses-permission android:name="com.huawei.authentication.HW_ACCESS_AUTH_SERVICE" />
<!-- other app end -->
<!-- google play store start -->
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="com.android.vending.CHECK_LICENSE" />
<!-- google play store end -->
<!-- google services framework start -->
<uses-permission android:name="com.google.android.providers.talk.permission.READ_ONLY" />
<uses-permission android:name="com.google.android.providers.talk.permission.WRITE_ONLY" />
@@ -132,9 +132,9 @@
<uses-permission android:name="com.google.android.gms.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<uses-permission android:name="com.google.android.gms.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
<uses-permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE" />
<!-- google services framework end -->
<!-- shortcut and badge start -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.READ_APP_BADGE" />
@@ -174,131 +174,131 @@
<uses-permission android:name="cn.nubia.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.huawei.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE" />
<!-- shortcut and badge end -->
<!-- 常用 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<!-- 相机 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<!-- 位置服务 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!-- 网络 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- sdcard -->
<uses-permission
android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 电量 -->
<uses-permission
android:name="android.permission.BATTERY_STATS"
tools:ignore="ProtectedPermissions" />
<!-- 身体传感器 -->
<uses-permission android:name="android.permission.BODY_SENSORS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<!-- 锁屏-->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<!-- 允许应用程序展开或折叠状态栏 -->
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<!-- 账号相关 -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<!-- 通话状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 修改当前配置-->
<uses-permission
android:name="android.permission.CHANGE_CONFIGURATION"
tools:ignore="ProtectedPermissions" />
<!-- 设置 -->
<uses-permission
android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<!-- 最近任务/进程 -->
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.REORDER_TASKS" />
<uses-permission android:name="android.permission.PERSISTENT_ACTIVITY" />
<!-- 录音 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- bluetooth -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- nfc -->
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- 震动 -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- 指纹 -->
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<!-- 下面自己按需保留 -->
<!-- browser history start -->
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />
<uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS" />
<!-- browser history end -->
<!-- 清空应用缓存-->
<uses-permission
android:name="android.permission.CLEAR_APP_CACHE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
<!-- 同步设置 -->
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.READ_SYNC_STATS" />
<!-- rss -->
<uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_READ" />
<uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE" />
<!-- 日历 -->
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<!-- 通讯录 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<!-- 系统日志 -->
<uses-permission
android:name="android.permission.READ_LOGS"
tools:ignore="ProtectedPermissions" />
<!-- 重启应用 -->
<uses-permission android:name="android.permission.RESTART_PACKAGES" />
<!-- 时间/时区 -->
<uses-permission
android:name="android.permission.SET_TIME"
tools:ignore="ProtectedPermissions" />
<uses-permission
android:name="android.permission.SET_TIME_ZONE"
tools:ignore="ProtectedPermissions" />
<!-- 墙纸 -->
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
<!-- 红外线 -->
<uses-permission android:name="android.permission.TRANSMIT_IR" />
<!-- SIP服务 -->
<uses-permission android:name="android.permission.USE_SIP" />
<!-- 唤醒屏幕 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- float window -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
<!-- boot -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- system app start -->
<uses-permission
android:name="android.permission.GET_INTENT_SENDER_INTENT"
tools:ignore="ProtectedPermissions" />
@@ -326,14 +326,14 @@
<uses-permission
android:name="android.permission.DEVICE_POWER"
tools:ignore="ProtectedPermissions" />
<!-- <uses-permission-->
<!-- android:name="android.permission.WRITE_APN_SETTINGS"-->
<!-- tools:ignore="ProtectedPermissions" />-->
<!-- xdja -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<!-- xdja -->
<uses-permission
android:name="android.permission.BIND_APPWIDGET"
@@ -344,8 +344,8 @@
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
<!-- system app end -->
<!-- not found -->
<uses-permission android:name="android.permission.READ_INSTALL_SESSIONS" />
<uses-permission android:name="android.permission.READ_OWNER_DATA" />
<uses-permission android:name="android.permission.READ_CELL_BROADCASTS" />
@@ -359,20 +359,20 @@
<uses-permission android:name="android.permission.CHANGE_WIMAX_STATE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<!-- xdja -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<!-- 安全接入 -->
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<!-- xdja -->
<!-- 通话记录 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<!-- call phone -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
@@ -410,10 +410,10 @@
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<!--android11-->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- Android 15 (API 35) Permissions -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<uses-permission android:name="android.permission.READ_MEDIA_AURAL_USER_SELECTED" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES_USER_SELECTED" />
@@ -453,7 +453,7 @@
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO_USER_SELECTED" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO_USER_SELECTED" />
<!-- POST_NOTIFICATIONS and other permissions continue below -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
@@ -493,7 +493,7 @@
android:exported="false"
android:process="@string/black_box_service_name" />
<!--file provider-->
<provider
android:name=".fake.provider.FileProvider"
android:authorities="${applicationId}.blackbox.FileProvider"
+5 -12
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 4/9/21.
//
#include "BoxCore.h"
#include "Log.h"
@@ -15,14 +15,7 @@
#include <Hook/RuntimeHook.h>
#include "Utils/HexDump.h"
#include "hidden_api.h"
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
struct {
JavaVM *vm;
jclass NativeCoreClass;
@@ -82,7 +75,7 @@ void nativeHook(JNIEnv *env) {
UnixFileSystemHook::init(env);
FileSystemHook::init();
VMClassLoaderHook::init(env);
// RuntimeHook::init(env);
BinderHook::init(env);
DexFileHook::init(env);
}
+4 -4
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 4/9/21.
//
#ifndef VIRTUALM_VMCORE_H
#define VIRTUALM_VMCORE_H
@@ -20,4 +20,4 @@ public:
};
#endif //VIRTUALM_VMCORE_H
#endif
+21 -21
View File
@@ -1,7 +1,7 @@
#ifndef dobby_h
#define dobby_h
// obfuscated interface
#if 0
#define DobbyBuildVersion c343f74888dffad84d9ad08d9c433456
#define DobbyHook c8dc3ffa44f22dbd10ccae213dd8b1f8
@@ -38,7 +38,7 @@ typedef uint64_t addr64_t;
#define ARM64_TMP_REG_NDX_0 17
// float register
typedef union _FPReg {
__int128_t q;
struct {
@@ -53,12 +53,12 @@ typedef union _FPReg {
} f;
} FPReg;
// register context
typedef struct _RegisterContext {
uint64_t dmmpy_0; // dummy placeholder
uint64_t dmmpy_0;
uint64_t sp;
uint64_t dmmpy_1; // dummy placeholder
uint64_t dmmpy_1;
union {
uint64_t x[29];
struct {
@@ -74,8 +74,8 @@ typedef struct _RegisterContext {
FPReg q[32];
struct {
FPReg q0, q1, q2, q3, q4, q5, q6, q7;
// [!!! READ ME !!!]
// for Arm64, can't access q8 - q31, unless you enable full floating-point register pack
FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29,
q30, q31;
} regs;
@@ -142,44 +142,44 @@ typedef struct _HookEntryInfo {
};
} HookEntryInfo;
// DobbyWrap <==> DobbyInstrument, so use DobbyInstrument instead of DobbyWrap
#if 0
// wrap function with pre_call and post_call
typedef void (*PreCallTy)(RegisterContext *ctx, const HookEntryInfo *info);
typedef void (*PostCallTy)(RegisterContext *ctx, const HookEntryInfo *info);
int DobbyWrap(void *function_address, PreCallTy pre_call, PostCallTy post_call);
#endif
// return dobby build date
const char *DobbyBuildVersion();
// replace function
int DobbyHook(void *address, void *replace_call, void **origin_call);
// dynamic binary instrument for instruction
// [!!! READ ME !!!]
// for Arm64, can't access q8 - q31, unless you enable full floating-point register pack
typedef void (*DBICallTy)(RegisterContext *ctx, const HookEntryInfo *info);
int DobbyInstrument(void *address, DBICallTy dbi_call);
// destory and restore hook
int DobbyDestroy(void *address);
// iterate symbol table and find symbol
void *DobbySymbolResolver(const char *image_name, const char *symbol_name);
// global offset table
int DobbyGlobalOffsetTableReplace(char *image_name, char *symbol_name, void *fake_func, void **orig_func);
// [!!! READ ME !!!]
// for arm, Arm64, dobby will use b xxx instead of ldr absolute indirect branch
// for x64, dobby always use absolute indirect jump
#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__)
void dobby_enable_near_branch_trampoline();
void dobby_disable_near_branch_trampoline();
#endif
// register linker load image callback
typedef void (*linker_load_callback_t)(const char *image_name, void *handle);
void dobby_register_image_load_callback(linker_load_callback_t func);
-4
View File
@@ -1,7 +1,3 @@
//
// updated by alex5402 on 4/10/21.
//
#include "BaseHook.h"
+1 -5
View File
@@ -1,7 +1,3 @@
//
// updated by alex5402 on 4/9/21.
//
#ifndef VIRTUALM_BASEHOOK_H
#define VIRTUALM_BASEHOOK_H
@@ -14,4 +10,4 @@ public:
};
#endif //VIRTUALM_BASEHOOK_H
#endif
+3 -3
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 4/25/21.
//
#include "BinderHook.h"
#include <IO.h>
+4 -4
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 4/25/21.
//
#ifndef BLACKBOX_BINDERHOOK_H
#define BLACKBOX_BINDERHOOK_H
@@ -13,4 +13,4 @@ public:
static void init(JNIEnv *env);
};
#endif //BLACKBOX_BINDERHOOK_H
#endif
+7 -7
View File
@@ -9,10 +9,10 @@ HOOK_JNI(jobject, openDexFileNative, JNIEnv *env, jobject obj,jstring sourceName
const char *sourceNameC = env->GetStringUTFChars(sourceName, JNI_FALSE);
ALOGD("openDexFileNative: %s", sourceNameC);
if(strstr(sourceNameC,"/blackbox/") != nullptr){
// const char *file_ext = strrchr(sourceNameC,'.');
// if(strcmp(file_ext,".dex") == 0 || strcmp(file_ext,".apk") == 0 || strcmp(file_ext,".jar") == 0){
//
// }
DexFileHook::setFileReadonly(sourceNameC);
}
jobject orig = orig_openDexFileNative(env, obj,sourceName,outputName,flags,loader,elements);
@@ -32,14 +32,14 @@ void DexFileHook::init(JNIEnv *env) {
void DexFileHook::setFileReadonly(const char* filePath) {
struct stat fileStat;
// 检查文件是否存在
if (stat(filePath, &fileStat) != 0) {
ALOGD("DexFileHook::setFileReadonly: %s 不存在",filePath);
return;
}
// 设置文件为只读(权限 0444)
//if (chmod(filePath, S_IRUSR | S_IRGRP | S_IROTH) != 0) {
if (chmod(filePath, S_IRUSR) != 0) {
ALOGD("DexFileHook::setFileReadonly: 设置文件 %s 为只读时出错",filePath);
} else {
+1 -1
View File
@@ -11,4 +11,4 @@ public:
};
#endif //BLACKBOX2_DEXFILEHOOK_H
#endif
+17 -17
View File
@@ -1,6 +1,6 @@
//
// Created for blocking problematic resource files
//
#include "FileSystemHook.h"
#include "Log.h"
@@ -11,13 +11,13 @@
#include <cstring>
#include <errno.h>
// Original function pointers
static int (*orig_open)(const char *pathname, int flags, ...) = nullptr;
static int (*orig_open64)(const char *pathname, int flags, ...) = nullptr;
// Hook for open system call
int new_open(const char *pathname, int flags, ...) {
// Block problematic resource paths
if (pathname != nullptr) {
if (strstr(pathname, "resource-cache") ||
strstr(pathname, "@idmap") ||
@@ -25,12 +25,12 @@ int new_open(const char *pathname, int flags, ...) {
strstr(pathname, "systemui") ||
strstr(pathname, "data@resource-cache@")) {
ALOGD("FileSystemHook: Blocking problematic file access: %s", pathname);
errno = ENOENT; // No such file or directory
errno = ENOENT;
return -1;
}
}
// For non-problematic paths, proceed normally
va_list args;
va_start(args, flags);
mode_t mode = va_arg(args, mode_t);
@@ -39,9 +39,9 @@ int new_open(const char *pathname, int flags, ...) {
return orig_open(pathname, flags, mode);
}
// Hook for open64 system call
int new_open64(const char *pathname, int flags, ...) {
// Block problematic resource paths
if (pathname != nullptr) {
if (strstr(pathname, "resource-cache") ||
strstr(pathname, "@idmap") ||
@@ -49,12 +49,12 @@ int new_open64(const char *pathname, int flags, ...) {
strstr(pathname, "systemui") ||
strstr(pathname, "data@resource-cache@")) {
ALOGD("FileSystemHook: Blocking problematic file access (64): %s", pathname);
errno = ENOENT; // No such file or directory
errno = ENOENT;
return -1;
}
}
// For non-problematic paths, proceed normally
va_list args;
va_start(args, flags);
mode_t mode = va_arg(args, mode_t);
@@ -66,24 +66,24 @@ int new_open64(const char *pathname, int flags, ...) {
void FileSystemHook::init() {
ALOGD("FileSystemHook: Initializing file system hooks");
// Load libc.so
void* handle = xdl_open("libc.so", XDL_DEFAULT);
if (!handle) {
ALOGE("FileSystemHook: Failed to open libc.so");
return;
}
// Hook open function
orig_open = (int (*)(const char*, int, ...))xdl_sym(handle, "open", nullptr);
if (orig_open) {
// Note: In a real implementation, you would use a proper hooking library
// like PLT hook or similar to replace the function pointer
ALOGD("FileSystemHook: Found open function at %p", orig_open);
} else {
ALOGE("FileSystemHook: Failed to find open function");
}
// Hook open64 function
orig_open64 = (int (*)(const char*, int, ...))xdl_sym(handle, "open64", nullptr);
if (orig_open64) {
ALOGD("FileSystemHook: Found open64 function at %p", orig_open64);
+4 -4
View File
@@ -1,6 +1,6 @@
//
// Created for blocking problematic resource files
//
#ifndef VIRTUALM_FILESYSTEMHOOK_H
#define VIRTUALM_FILESYSTEMHOOK_H
@@ -10,4 +10,4 @@ public:
static void init();
};
#endif //VIRTUALM_FILESYSTEMHOOK_H
#endif
+3 -3
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 5/5/21.
//
#include "RuntimeHook.h"
#import "JniHook/JniHook.h"
+4 -4
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 5/5/21.
//
#ifndef BLACKBOX_RUNTIMEHOOK_H
#define BLACKBOX_RUNTIMEHOOK_H
@@ -15,4 +15,4 @@ public:
};
#endif //BLACKBOX_RUNTIMEHOOK_H
#endif
+18 -58
View File
@@ -1,108 +1,68 @@
//
// updated by alex5402 on 4/9/21.
//
#include <IO.h>
#include "UnixFileSystemHook.h"
#import "JniHook/JniHook.h"
#include "BaseHook.h"
/*
* Class: java_io_UnixFileSystem
* Method: canonicalize0
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
HOOK_JNI(jstring, canonicalize0, JNIEnv *env, jobject obj, jstring path) {
jstring redirect = IO::redirectPath(env, path);
return orig_canonicalize0(env, obj, redirect);
}
/*
* Class: java_io_UnixFileSystem
* Method: getBooleanAttributes0
* Signature: (Ljava/lang/String;)I
*/
HOOK_JNI(jint, getBooleanAttributes0, JNIEnv *env, jobject obj, jstring abspath) {
jstring redirect = IO::redirectPath(env, abspath);
return orig_getBooleanAttributes0(env, obj, redirect);
}
/*
* Class: java_io_UnixFileSystem
* Method: getLastModifiedTime0
* Signature: (Ljava/io/File;)J
*/
HOOK_JNI(jlong, getLastModifiedTime0, JNIEnv *env, jobject obj, jobject path) {
jobject redirect = IO::redirectPath(env, path);
return orig_getLastModifiedTime0(env, obj, redirect);
}
/*
* Class: java_io_UnixFileSystem
* Method: setPermission0
* Signature: (Ljava/io/File;IZZ)Z
*/
HOOK_JNI(jboolean, setPermission0, JNIEnv *env, jobject obj, jobject file, jint access,
jboolean enable, jboolean owneronly) {
jobject redirect = IO::redirectPath(env, file);
return orig_setPermission0(env, obj, redirect, access, enable, owneronly);
}
/*
* Class: java_io_UnixFileSystem
* Method: createFileExclusively0
* Signature: (Ljava/lang/String;)Z
*/
HOOK_JNI(jboolean, createFileExclusively0, JNIEnv *env, jobject obj, jstring path) {
jstring redirect = IO::redirectPath(env, path);
return orig_createFileExclusively0(env, obj, redirect);
}
/*
* Class: java_io_UnixFileSystem
* Method: list0
* Signature: (Ljava/io/File;)[Ljava/lang/String;
*/
HOOK_JNI(jobjectArray, list0, JNIEnv *env, jobject obj, jobject file) {
jobject redirect = IO::redirectPath(env, file);
return orig_list0(env, obj, redirect);
}
/*
* Class: java_io_UnixFileSystem
* Method: createDirectory0
* Signature: (Ljava/io/File;)Z
*/
HOOK_JNI(jboolean, createDirectory0, JNIEnv *env, jobject obj, jobject path) {
jobject redirect = IO::redirectPath(env, path);
return orig_createDirectory0(env, obj, redirect);
}
/*
* Class: java_io_UnixFileSystem
* Method: setLastModifiedTime0
* Signature: (Ljava/io/File;J)Z
*/
HOOK_JNI(jboolean, setLastModifiedTime0, JNIEnv *env, jobject obj, jobject file, jobject time) {
jobject redirect = IO::redirectPath(env, file);
return orig_setLastModifiedTime0(env, obj, redirect, time);
}
/*
* Class: java_io_UnixFileSystem
* Method: setReadOnly0
* Signature: (Ljava/io/File;)Z
*/
HOOK_JNI(jboolean, setReadOnly0, JNIEnv *env, jobject obj, jobject file) {
jobject redirect = IO::redirectPath(env, file);
return orig_setReadOnly0(env, obj, redirect);
}
/*
* Class: java_io_UnixFileSystem
* Method: getSpace0
* Signature: (Ljava/io/File;I)J
*/
HOOK_JNI(jboolean, getSpace0, JNIEnv *env, jobject obj, jobject file, jint t) {
jobject redirect = IO::redirectPath(env, file);
return orig_getSpace0(env, obj, redirect, t);
@@ -111,7 +71,7 @@ HOOK_JNI(jboolean, getSpace0, JNIEnv *env, jobject obj, jobject file, jint t) {
void UnixFileSystemHook::init(JNIEnv *env) {
const char *className = "java/io/UnixFileSystem";
// Add error handling for canonicalize0 hook
try {
JniHook::HookJniFun(env, className, "canonicalize0", "(Ljava/lang/String;)Ljava/lang/String;",
(void *) new_canonicalize0, (void **) (&orig_canonicalize0), false);
@@ -119,11 +79,11 @@ void UnixFileSystemHook::init(JNIEnv *env) {
ALOGD("UnixFileSystemHook: Failed to hook canonicalize0, continuing without it");
}
// JniHook::HookJniFun(env, className, "getBooleanAttributes0", "(Ljava/lang/String;)I",
// (void *) new_getBooleanAttributes0,
// (void **) (&orig_getBooleanAttributes0), false);
// Add error handling for other hooks
try {
JniHook::HookJniFun(env, className, "getLastModifiedTime0", "(Ljava/io/File;)J",
(void *) new_getLastModifiedTime0, (void **) (&orig_getLastModifiedTime0),
+4 -4
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 4/9/21.
//
#ifndef VIRTUALM_UNIXFILESYSTEMHOOK_H
#define VIRTUALM_UNIXFILESYSTEMHOOK_H
@@ -14,4 +14,4 @@ public:
};
#endif //VIRTUALM_UNIXFILESYSTEMHOOK_H
#endif
@@ -1,10 +1,10 @@
//
// updated by alex5402 on 2021/5/5.
//
//
// updated by alex5402 on 5/5/21.
//
#include <cstring>
#include "VMClassLoaderHook.h"
@@ -13,7 +13,7 @@ static bool hideXposedClass = false;
HOOK_JNI(jobject, findLoadedClass, JNIEnv *env, jobject obj, jobject class_loader, jstring name) {
const char * nameC = env->GetStringUTFChars(name, JNI_FALSE);
// ALOGD("findLoadedClass: %s", nameC);
if (hideXposedClass) {
if (strstr(nameC, "de/robv/android/xposed/") ||
strstr(nameC, "me/weishu/epic") ||
+4 -4
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 2021/5/5.
//
#ifndef BLACKBOX_VMCLASSLOADERHOOK_H
#define BLACKBOX_VMCLASSLOADERHOOK_H
@@ -16,4 +16,4 @@ public:
};
#endif //BLACKBOX_VMCLASSLOADERHOOK_H
#endif
+21 -28
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 4/10/21.
//
#include "IO.h"
#include "Log.h"
@@ -8,14 +8,7 @@
jmethodID getAbsolutePathMethodId;
list<IO::RelocateInfo> relocate_rule;
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
char *replace(const char *str, const char *src, const char *dst) {
const char *pos = str;
int count = 0;
@@ -42,37 +35,37 @@ char *replace(const char *str, const char *src, const char *dst) {
}
const char *IO::redirectPath(const char *__path) {
// Block ALL resource-cache related paths that cause issues
if (strstr(__path, "resource-cache")) {
ALOGD("Blocking resource-cache path: %s", __path);
return "/dev/null";
}
// Block any path containing @idmap
if (strstr(__path, "@idmap")) {
ALOGD("Blocking idmap path: %s", __path);
return "/dev/null";
}
// Block any path containing systemui with problematic extensions
if (strstr(__path, "systemui") && (strstr(__path, ".frro") || strstr(__path, "-accent-") || strstr(__path, "-dynamic-") || strstr(__path, "-neutral-"))) {
ALOGD("Blocking systemui problematic path: %s", __path);
return "/dev/null";
}
// Block any path containing the specific problematic patterns
if (strstr(__path, "data@resource-cache@")) {
ALOGD("Blocking data@resource-cache@ pattern: %s", __path);
return "/dev/null";
}
// Block any path containing .frro files
if (strstr(__path, ".frro")) {
ALOGD("Blocking .frro file: %s", __path);
return "/dev/null";
}
// Block any path containing systemui
if (strstr(__path, "systemui")) {
ALOGD("Blocking systemui path: %s", __path);
return "/dev/null";
@@ -83,7 +76,7 @@ const char *IO::redirectPath(const char *__path) {
IO::RelocateInfo info = *iterator;
if (strstr(__path, info.targetPath) && !strstr(__path, "/blackbox/")) {
char *ret = replace(__path, info.targetPath, info.relocatePath);
// ALOGD("redirectPath %s => %s", __path, ret);
return ret;
}
}
@@ -91,20 +84,20 @@ const char *IO::redirectPath(const char *__path) {
}
jstring IO::redirectPath(JNIEnv *env, jstring path) {
// const char * pathC = env->GetStringUTFChars(path, JNI_FALSE);
// const char *redirect = redirectPath(pathC);
// env->ReleaseStringUTFChars(path, pathC);
// return env->NewStringUTF(redirect);
return BoxCore::redirectPathString(env, path);
}
jobject IO::redirectPath(JNIEnv *env, jobject path) {
// auto pathStr =
// reinterpret_cast<jstring>(env->CallObjectMethod(path, getAbsolutePathMethodId));
// jstring redirect = redirectPath(env, pathStr);
// jobject file = env->NewObject(fileClazz, fileNew, redirect);
// env->DeleteLocalRef(pathStr);
// env->DeleteLocalRef(redirect);
return BoxCore::redirectPathFile(env, path);
}
+4 -4
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 4/10/21.
//
#ifndef VIRTUALM_IO_H
#define VIRTUALM_IO_H
@@ -32,4 +32,4 @@ public:
};
#endif //VIRTUALM_IO_H
#endif
+30 -30
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 3/7/21.
//
#include <stdio.h>
#ifndef ARTHOOK_ART_METHOD_H
@@ -10,34 +10,34 @@
#define __ANDROID_API_Q__ 29
#define __ANDROID_API_P__ 28
static constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic
static constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic
static constexpr uint32_t kAccProtected = 0x0004; // field, method, ic
static constexpr uint32_t kAccStatic = 0x0008; // field, method, ic
static constexpr uint32_t kAccFinal = 0x0010; // class, field, method, ic
static constexpr uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives)
static constexpr uint32_t kAccSuper = 0x0020; // class (not used in dex)
static constexpr uint32_t kAccVolatile = 0x0040; // field
static constexpr uint32_t kAccBridge = 0x0040; // method (1.5)
static constexpr uint32_t kAccTransient = 0x0080; // field
static constexpr uint32_t kAccVarargs = 0x0080; // method (1.5)
static constexpr uint32_t kAccNative = 0x0100; // method
static constexpr uint32_t kAccInterface = 0x0200; // class, ic
static constexpr uint32_t kAccAbstract = 0x0400; // class, method, ic
static constexpr uint32_t kAccStrict = 0x0800; // method
static constexpr uint32_t kAccSynthetic = 0x1000; // class, field, method, ic
static constexpr uint32_t kAccAnnotation = 0x2000; // class, ic (1.5)
static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5)
static constexpr uint32_t kAccPublic = 0x0001;
static constexpr uint32_t kAccPrivate = 0x0002;
static constexpr uint32_t kAccProtected = 0x0004;
static constexpr uint32_t kAccStatic = 0x0008;
static constexpr uint32_t kAccFinal = 0x0010;
static constexpr uint32_t kAccSynchronized = 0x0020;
static constexpr uint32_t kAccSuper = 0x0020;
static constexpr uint32_t kAccVolatile = 0x0040;
static constexpr uint32_t kAccBridge = 0x0040;
static constexpr uint32_t kAccTransient = 0x0080;
static constexpr uint32_t kAccVarargs = 0x0080;
static constexpr uint32_t kAccNative = 0x0100;
static constexpr uint32_t kAccInterface = 0x0200;
static constexpr uint32_t kAccAbstract = 0x0400;
static constexpr uint32_t kAccStrict = 0x0800;
static constexpr uint32_t kAccSynthetic = 0x1000;
static constexpr uint32_t kAccAnnotation = 0x2000;
static constexpr uint32_t kAccEnum = 0x4000;
static constexpr uint32_t kAccPublicApi = 0x10000000; // field, method
static constexpr uint32_t kAccCorePlatformApi = 0x20000000; // field, method
static constexpr uint32_t kAccPublicApi = 0x10000000;
static constexpr uint32_t kAccCorePlatformApi = 0x20000000;
// Native method flags are set when linking the methods based on the presence of the
// @dalvik.annotation.optimization.{Fast,Critical}Native annotations with build visibility.
// Reuse the values of kAccSkipAccessChecks and kAccMiranda which are not used for native methods.
static constexpr uint32_t kAccFastNative = 0x00080000; // method (runtime; native only)
static constexpr uint32_t kAccCriticalNative = 0x00100000; // method (runtime; native only)
static constexpr uint32_t kAccNterpInvokeFastPathFlag = 0x00200000; // method (runtime)
#endif //ARTHOOK_ART_METHOD_H
static constexpr uint32_t kAccFastNative = 0x00080000;
static constexpr uint32_t kAccCriticalNative = 0x00100000;
static constexpr uint32_t kAccNterpInvokeFastPathFlag = 0x00200000;
#endif
+11 -11
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 3/8/21.
//
#include <jni.h>
#include "JniHook.h"
@@ -73,7 +73,7 @@ inline static bool HasAccessFlag(char *art_method, uint32_t flag) {
return (flags & flag) == flag;
}
// Add error handling for method flag checking
inline static bool IsNativeMethod(char *art_method) {
try {
return HasAccessFlag(art_method, kAccNative);
@@ -84,7 +84,7 @@ inline static bool IsNativeMethod(char *art_method) {
}
inline static bool ClearFastNativeFlag(char *art_method) {
// FastNative
return HookEnv.api_level < __ANDROID_API_P__ && ClearAccessFlag(art_method, kAccFastNative);
}
@@ -112,7 +112,7 @@ static void *GetFieldMethod(JNIEnv *env, jobject field) {
bool CheckFlags(void *artMethod) {
char *method = static_cast<char *>(artMethod);
// Add error handling for flag checking
try {
if (!HasAccessFlag(method, kAccNative)) {
ALOGD("Method is not native, skipping hook");
@@ -171,7 +171,7 @@ JniHook::HookJniFun(JNIEnv *env, const char *class_name, const char *method_name
ALOGE("jni hook error. class:%s, method:%s", class_name, method_name);
return;
}
// FastNative
if (HookEnv.api_level == __ANDROID_API_O__ || HookEnv.api_level == __ANDROID_API_O_MR1__) {
AddAccessFlag((char *) artMethod, kAccFastNative);
}
@@ -241,7 +241,7 @@ void JniHook::InitJniHook(JNIEnv *env, int api_level) {
HookEnv.art_method_size = (size_t) nativeOffset2 - (size_t) nativeOffset;
int i = 0;
// calc native offset
auto artMethod = reinterpret_cast<uintptr_t *>(nativeOffset);
for (i = 0; i < HookEnv.art_method_size; ++i) {
if (reinterpret_cast<void *>(artMethod[i]) == native_offset) {
@@ -259,17 +259,17 @@ void JniHook::InitJniHook(JNIEnv *env, int api_level) {
flags = flags | kAccStatic;
flags = flags | kAccNative;
flags = flags | kAccFinal;
if (api_level >= __ANDROID_API_Q__) {//android 10
if (api_level >= __ANDROID_API_Q__) {
flags = flags | kAccPublicApi;
}
if (api_level >= __ANDROID_API_S__) {//android 12
if (api_level >= __ANDROID_API_S__) {
flags = flags | kAccNterpInvokeFastPathFlag;
}
char *start = reinterpret_cast<char *>(artMethod);
for (i = 1; i < HookEnv.art_method_size; ++i) {
auto value = *(uint32_t *) (start + i * sizeof(uint32_t));
// ALOGD("art_method_size search:0x%x",value);
if (value == flags) {
HookEnv.art_method_flags_offset = i * sizeof(uint32_t);
break;
+4 -4
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 3/8/21.
//
#ifndef VIRTUAL_APP_JNIHOOK_H
#define VIRTUAL_APP_JNIHOOK_H
@@ -19,4 +19,4 @@ public:
static void HookJniFun(JNIEnv *env, jobject java_method, void *new_fun, void **orig_fun, bool is_static);
};
#endif //VIRTUAL_APP_JNIHOOK_H
#endif
+13 -27
View File
@@ -11,14 +11,7 @@
#define LOG_TAG "AntiDetection"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
/**
* created by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
struct SpoofedProp {
const char* key;
const char* value;
@@ -27,19 +20,12 @@ struct SpoofedProp {
static int (*orig_system_property_get)(const char *name, char *value) = nullptr;
// =============================================================================
// FILE SYSTEM HIDING
// =============================================================================
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
static const char* blocked_files[] = {
// Root detection files
"/system/xbin/su",
"/system/bin/su",
"/sbin/su",
@@ -58,7 +44,7 @@ static const char* blocked_files[] = {
"/sbin/magisk",
"/data/adb/magisk",
// Virtual environment detection
"/data/virtual",
"/data/data/com.benny.openlauncher",
"/data/data/io.va.exposed",
@@ -71,7 +57,7 @@ static const char* blocked_files[] = {
"/blackbox",
"/virtual",
// Emulator detection files
"/dev/vboxguest",
"/dev/vboxuser",
"/dev/qemu_pipe",
@@ -93,7 +79,7 @@ static const char* blocked_files[] = {
"/system/lib/libmemu.so",
"/system/lib/libbluelog.so",
// Xposed detection
"/system/xposed.prop",
"/system/framework/XposedBridge.jar",
"/data/data/de.robv.android.xposed.installer",
@@ -155,7 +141,7 @@ static bool is_blocked_package(const char* path) {
return false;
}
// Hook function pointers
static int (*orig_access)(const char *pathname, int mode) = nullptr;
static int (*orig_stat)(const char *pathname, struct stat *buf) = nullptr;
static int (*orig_lstat)(const char *pathname, struct stat *buf) = nullptr;
@@ -164,8 +150,8 @@ static int (*orig_open)(const char *pathname, int flags, ...) = nullptr;
static ssize_t (*orig_readlink)(const char *pathname, char *buf, size_t bufsiz) = nullptr;
static DIR* (*orig_opendir)(const char *name) = nullptr;
// Hook implementations
// Safe whitelist for network and critical paths
static bool is_safe_path(const char* path) {
if (!path) return false;
if (strstr(path, "/proc/net/")) return true;
@@ -253,7 +239,7 @@ static void install_file_hooks() {
LOGD("File system hooks installed");
}
// Main installer function - call this once at startup
__attribute__((constructor)) void install_antidetection_hooks() {
LOGD("Installing anti-detection hooks...");
install_file_hooks();
+3 -3
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 2020/8/18.
//
#include <jni.h>
#include <stdio.h>
+4 -4
View File
@@ -1,6 +1,6 @@
//
// updated by alex5402 on 2020/8/18.
//
#ifndef SPEED_HEXDUMP_H
#define SPEED_HEXDUMP_H
@@ -11,4 +11,4 @@ class HexDump {
};
void HexDump(char *buf, int len, int addr);
#endif //SPEED_HEXDUMP_H
#endif
+3 -10
View File
@@ -5,14 +5,7 @@
#include <dlfcn.h>
#include "Dobby/dobby.h"
/**
* created by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
#define LOG_TAG "VirtualSpoof"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
@@ -40,7 +33,7 @@ SpoofedProp spoofed_props[] = {
{"ro.kernel.android.qemud", ""},
{"ro.hardware.egl", "adreno"},
{"ro.boot.qemu", "0"},
{nullptr, nullptr} // Sentinel
{nullptr, nullptr}
};
@@ -78,7 +71,7 @@ void install_property_get_hook() {
}
// Initialization function to ensure our hook is loaded
__attribute__((constructor)) void init_virtual_spoof()
{
install_property_get_hook();
+9 -27
View File
@@ -1,22 +1,4 @@
/*
* This file is part of LSPosed.
*
* LSPosed is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LSPosed is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2019 Swift Gan
* Copyright (C) 2021 LSPosed Contributors
*/
#include <malloc.h>
#include <cstring>
#include <sys/mman.h>
@@ -43,7 +25,7 @@ ElfImg::ElfImg(std::string_view base_name) : elf(base_name) {
return;
}
//load elf
int fd = open(elf.data(), O_RDONLY);
if (fd < 0) {
LOGE("open(%s) failed: %s", elf.c_str(), strerror(errno));
@@ -210,20 +192,20 @@ ElfW(Addr) ElfImg::LinearLookupShort(std::string_view name) const {
}
}
return 0;
// if (auto i = symtabs_.find(name); i != symtabs_.end()) {
// return i->second->st_value;
// } else {
// return 0;
// }
}
ElfImg::~ElfImg() {
//open elf file local
if (buffer) {
free(buffer);
buffer = nullptr;
}
//use mmap
if (header) {
munmap(header, size);
}
+6 -24
View File
@@ -1,22 +1,4 @@
/*
* This file is part of LSPosed.
*
* LSPosed is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LSPosed is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2019 Swift Gan
* Copyright (C) 2021 LSPosed Contributors
*/
#ifndef SANDHOOK_ELF_UTIL_H
#define SANDHOOK_ELF_UTIL_H
@@ -48,10 +30,10 @@ namespace SandHook {
}
}
// template<typename T> requires(std::is_pointer_v<T>)
// constexpr T getSymbAddress(std::string_view name) const {
// return reinterpret_cast<T>(getSymbAddress(name));
// }
bool isValid() const {
return base != nullptr;
@@ -135,4 +117,4 @@ namespace SandHook {
}
}
#endif //SANDHOOK_ELF_UTIL_H
#endif
+13 -20
View File
@@ -5,14 +5,7 @@
#include "hidden_api.h"
#include "Utils/elf_util.h"
#include "Log.h"
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
bool disable_hidden_api(JNIEnv *env) {
char version_str[PROP_VALUE_MAX];
if (!__system_property_get("ro.build.version.sdk", version_str)) {
@@ -21,7 +14,7 @@ bool disable_hidden_api(JNIEnv *env) {
}
long android_version = std::strtol(version_str, nullptr, 10);
// Hidden api introduced in sdk 29
if (android_version < 29) {
ALOGD("HiddenAPI: Android version < 29, no need to disable");
return true;
@@ -34,7 +27,7 @@ bool disable_hidden_api(JNIEnv *env) {
return false;
}
// Try multiple possible symbol names for different Android versions
void *addr = nullptr;
const char* symbol_names[] = {
"_ZN3artL32VMRuntime_setHiddenApiExemptionsEP7_JNIEnvP7_jclassP13_jobjectArray",
@@ -64,7 +57,7 @@ bool disable_hidden_api(JNIEnv *env) {
return false;
}
// L is basically wildcard for everything
jstring wildcard = env->NewStringUTF("L");
if (!wildcard) {
ALOGE("HiddenAPI: Failed to create wildcard string");
@@ -78,23 +71,23 @@ bool disable_hidden_api(JNIEnv *env) {
}
auto func = reinterpret_cast<void (*)(JNIEnv *, jclass, jobjectArray)>(addr);
// jclass arg is not used so pass string class for the memes
func(env, stringClass, args);
ALOGD("HiddenAPI: Successfully disabled hidden API restrictions");
return true;
}
bool disable_resource_loading() {
// Try to hook the ApkAssets.nativeLoad method directly (safer than system properties)
try {
// Load the framework library
void* handle = xdl_open("libandroid_runtime.so", XDL_DEFAULT);
if (handle) {
// Try to find and hook the nativeLoad method
void* nativeLoadAddr = xdl_sym(handle, "_ZN7android8ApkAssets9nativeLoadEPKc", nullptr);
if (nativeLoadAddr) {
ALOGD("ResourceLoading: Found ApkAssets.nativeLoad at %p", nativeLoadAddr);
// Here we would implement the actual hook, but for now we'll just log it
} else {
ALOGD("ResourceLoading: Could not find ApkAssets.nativeLoad symbol");
}
@@ -106,16 +99,16 @@ bool disable_resource_loading() {
ALOGD("ResourceLoading: Exception while trying to hook ApkAssets.nativeLoad");
}
// Try to hook the file system calls directly
try {
// Load the libc library
void* handle = xdl_open("libc.so", XDL_DEFAULT);
if (handle) {
// Try to find and hook the open function
void* openAddr = xdl_sym(handle, "open", nullptr);
if (openAddr) {
ALOGD("ResourceLoading: Found open function at %p", openAddr);
// Here we would implement the actual hook, but for now we'll just log it
} else {
ALOGD("ResourceLoading: Could not find open function symbol");
}
+1 -1
View File
@@ -7,4 +7,4 @@
bool disable_hidden_api(JNIEnv*);
bool disable_resource_loading();
#endif //BLACKBOX2_HIDDEN_API_H
#endif
+53 -53
View File
@@ -1,33 +1,33 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2020-10-04.
//
// xDL version: 2.1.1
//
// xDL is an enhanced implementation of the Android DL series functions.
// For more information, documentation, and the latest version please check:
// https://github.com/hexhacking/xDL
//
#ifndef IO_GITHUB_HEXHACKING_XDL
#define IO_GITHUB_HEXHACKING_XDL
@@ -41,25 +41,25 @@ extern "C" {
#endif
typedef struct {
// same as Dl_info:
const char *dli_fname; // Pathname of shared object that contains address.
void *dli_fbase; // Address at which shared object is loaded.
const char *dli_sname; // Name of nearest symbol with address lower than addr.
void *dli_saddr; // Exact address of symbol named in dli_sname.
// added by xDL:
size_t dli_ssize; // Symbol size of nearest symbol with address lower than addr.
const ElfW(Phdr) *dlpi_phdr; // Pointer to array of ELF program headers for this object.
size_t dlpi_phnum; // Number of items in dlpi_phdr.
const char *dli_fname;
void *dli_fbase;
const char *dli_sname;
void *dli_saddr;
size_t dli_ssize;
const ElfW(Phdr) *dlpi_phdr;
size_t dlpi_phnum;
} xdl_info_t;
//
// Default value for flags in both xdl_open() and xdl_iterate_phdr().
//
#define XDL_DEFAULT 0x00
//
// Enhanced dlopen() / dlclose() / dlsym().
//
#define XDL_TRY_FORCE_LOAD 0x01
#define XDL_ALWAYS_FORCE_LOAD 0x02
void *xdl_open(const char *filename, int flags);
@@ -67,22 +67,22 @@ void *xdl_close(void *handle);
void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size);
void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size);
//
// Enhanced dladdr().
//
int xdl_addr(void *addr, xdl_info_t *info, void **cache);
void xdl_addr_clean(void **cache);
//
// Enhanced dl_iterate_phdr().
//
#define XDL_FULL_PATHNAME 0x01
int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags);
//
// Custom dlinfo().
//
#define XDL_DI_DLINFO 1 // type of info: xdl_info_t
#define XDL_DI_DLINFO 1
int xdl_info(void *handle, int request, void *info);
#ifdef __cplusplus
+113 -138
View File
@@ -1,25 +1,25 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2020-10-04.
#include "xdl.h"
@@ -67,18 +67,18 @@ typedef struct xdl {
const ElfW(Phdr) *dlpi_phdr;
ElfW(Half) dlpi_phnum;
struct xdl *next; // to next xdl obj for cache in xdl_addr()
void *linker_handle; // hold handle returned by xdl_linker_force_dlopen()
struct xdl *next;
void *linker_handle;
//
// (1) for searching symbols from .dynsym
//
bool dynsym_try_load;
ElfW(Sym) *dynsym; // .dynsym
const char *dynstr; // .dynstr
ElfW(Sym) *dynsym;
const char *dynstr;
// .hash (SYSV hash for .dynstr)
struct {
const uint32_t *buckets;
uint32_t buckets_cnt;
@@ -86,7 +86,7 @@ typedef struct xdl {
uint32_t chains_cnt;
} sysv_hash;
// .gnu.hash (GNU hash for .dynstr)
struct {
const uint32_t *buckets;
uint32_t buckets_cnt;
@@ -97,24 +97,24 @@ typedef struct xdl {
uint32_t bloom_shift;
} gnu_hash;
//
// (2) for searching symbols from .symtab
//
bool symtab_try_load;
uintptr_t base;
ElfW(Sym) *symtab; // .symtab
ElfW(Sym) *symtab;
size_t symtab_cnt;
char *strtab; // .strtab
char *strtab;
size_t strtab_sz;
} xdl_t;
#pragma clang diagnostic pop
// load from memory
static int xdl_dynsym_load(xdl_t *self) {
// find the dynamic segment
ElfW(Dyn) *dynamic = NULL;
for (size_t i = 0; i < self->dlpi_phnum; i++) {
const ElfW(Phdr) *phdr = &(self->dlpi_phdr[i]);
@@ -125,22 +125,22 @@ static int xdl_dynsym_load(xdl_t *self) {
}
if (NULL == dynamic) return -1;
// iterate the dynamic segment
for (ElfW(Dyn) *entry = dynamic; entry && entry->d_tag != DT_NULL; entry++) {
switch (entry->d_tag) {
case DT_SYMTAB: //.dynsym
case DT_SYMTAB:
self->dynsym = (ElfW(Sym) *)(self->load_bias + entry->d_un.d_ptr);
break;
case DT_STRTAB: //.dynstr
case DT_STRTAB:
self->dynstr = (const char *)(self->load_bias + entry->d_un.d_ptr);
break;
case DT_HASH: //.hash
case DT_HASH:
self->sysv_hash.buckets_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[0];
self->sysv_hash.chains_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[1];
self->sysv_hash.buckets = &(((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[2]);
self->sysv_hash.chains = &(self->sysv_hash.buckets[self->sysv_hash.buckets_cnt]);
break;
case DT_GNU_HASH: //.gnu.hash
case DT_GNU_HASH:
self->gnu_hash.buckets_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[0];
self->gnu_hash.symoffset = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[1];
self->gnu_hash.bloom_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[2];
@@ -220,47 +220,47 @@ static void *xdl_get_memory_by_section(void *mem, size_t mem_sz, ElfW(Shdr) *shd
return xdl_get_memory(mem, mem_sz, (size_t)shdr->sh_offset, shdr->sh_size);
}
// load from disk and memory
static int xdl_symtab_load_from_debugdata(xdl_t *self, int file_fd, size_t file_sz,
ElfW(Shdr) *shdr_debugdata) {
void *debugdata = NULL;
ElfW(Shdr) *shdrs = NULL;
int r = -1;
// get zipped .gnu_debugdata
uint8_t *debugdata_zip = (uint8_t *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr_debugdata);
if (NULL == debugdata_zip) return -1;
// get unzipped .gnu_debugdata
size_t debugdata_sz;
if (0 != xdl_lzma_decompress(debugdata_zip, shdr_debugdata->sh_size, (uint8_t **)&debugdata, &debugdata_sz))
goto end;
// get ELF header
ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)debugdata;
if (0 == ehdr->e_shnum || ehdr->e_shentsize != sizeof(ElfW(Shdr))) goto end;
// get section headers
shdrs = (ElfW(Shdr) *)xdl_read_memory_to_heap(debugdata, debugdata_sz, (size_t)ehdr->e_shoff,
ehdr->e_shentsize * ehdr->e_shnum);
if (NULL == shdrs) goto end;
// get .shstrtab
if (SHN_UNDEF == ehdr->e_shstrndx || ehdr->e_shstrndx >= ehdr->e_shnum) goto end;
char *shstrtab = (char *)xdl_get_memory_by_section(debugdata, debugdata_sz, shdrs + ehdr->e_shstrndx);
if (NULL == shstrtab) goto end;
// find .symtab & .strtab
for (ElfW(Shdr) *shdr = shdrs; shdr < shdrs + ehdr->e_shnum; shdr++) {
char *shdr_name = shstrtab + shdr->sh_name;
if (SHT_SYMTAB == shdr->sh_type && 0 == strcmp(".symtab", shdr_name)) {
// get & check associated .strtab section
if (shdr->sh_link >= ehdr->e_shnum) continue;
ElfW(Shdr) *shdr_strtab = shdrs + shdr->sh_link;
if (SHT_STRTAB != shdr_strtab->sh_type) continue;
// get .symtab & .strtab
ElfW(Sym) *symtab = (ElfW(Sym) *)xdl_read_memory_to_heap_by_section(debugdata, debugdata_sz, shdr);
if (NULL == symtab) continue;
char *strtab = (char *)xdl_read_memory_to_heap_by_section(debugdata, debugdata_sz, shdr_strtab);
@@ -269,7 +269,7 @@ static int xdl_symtab_load_from_debugdata(xdl_t *self, int file_fd, size_t file_
continue;
}
// OK
self->symtab = symtab;
self->symtab_cnt = shdr->sh_size / shdr->sh_entsize;
self->strtab = strtab;
@@ -286,7 +286,7 @@ end:
return r;
}
// load from disk and memory
static int xdl_symtab_load(xdl_t *self) {
if ('[' == self->pathname[0]) return -1;
@@ -294,7 +294,7 @@ static int xdl_symtab_load(xdl_t *self) {
ElfW(Shdr) *shdrs = NULL;
char *shstrtab = NULL;
// get base address
uintptr_t vaddr_min = UINTPTR_MAX;
for (size_t i = 0; i < self->dlpi_phnum; i++) {
const ElfW(Phdr) *phdr = &(self->dlpi_phdr[i]);
@@ -305,18 +305,18 @@ static int xdl_symtab_load(xdl_t *self) {
if (UINTPTR_MAX == vaddr_min) return -1;
self->base = self->load_bias + vaddr_min;
// open file
int flags = O_RDONLY | O_CLOEXEC;
int file_fd;
if ('/' == self->pathname[0]) {
file_fd = open(self->pathname, flags);
} else {
char full_pathname[1024];
// try the fast method
snprintf(full_pathname, sizeof(full_pathname), "%s/%s", XDL_LIB_PATH, self->pathname);
file_fd = open(full_pathname, flags);
if (file_fd < 0) {
// try the slow method
if (0 != xdl_iterate_get_full_pathname(self->base, full_pathname, sizeof(full_pathname))) return -1;
file_fd = open(full_pathname, flags);
}
@@ -326,31 +326,31 @@ static int xdl_symtab_load(xdl_t *self) {
if (0 != fstat(file_fd, &st)) goto end;
size_t file_sz = (size_t)st.st_size;
// get ELF header
ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)self->base;
if (0 == ehdr->e_shnum || ehdr->e_shentsize != sizeof(ElfW(Shdr))) goto end;
// get section headers
shdrs = (ElfW(Shdr) *)xdl_read_file_to_heap(file_fd, file_sz, (size_t)ehdr->e_shoff,
ehdr->e_shentsize * ehdr->e_shnum);
if (NULL == shdrs) goto end;
// get .shstrtab
if (SHN_UNDEF == ehdr->e_shstrndx || ehdr->e_shstrndx >= ehdr->e_shnum) goto end;
shstrtab = (char *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdrs + ehdr->e_shstrndx);
if (NULL == shstrtab) goto end;
// find .symtab & .strtab
for (ElfW(Shdr) *shdr = shdrs; shdr < shdrs + ehdr->e_shnum; shdr++) {
char *shdr_name = shstrtab + shdr->sh_name;
if (SHT_SYMTAB == shdr->sh_type && 0 == strcmp(".symtab", shdr_name)) {
// get & check associated .strtab section
if (shdr->sh_link >= ehdr->e_shnum) continue;
ElfW(Shdr) *shdr_strtab = shdrs + shdr->sh_link;
if (SHT_STRTAB != shdr_strtab->sh_type) continue;
// get .symtab & .strtab
ElfW(Sym) *symtab = (ElfW(Sym) *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr);
if (NULL == symtab) continue;
char *strtab = (char *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr_strtab);
@@ -359,7 +359,7 @@ static int xdl_symtab_load(xdl_t *self) {
continue;
}
// OK
self->symtab = symtab;
self->symtab_cnt = shdr->sh_size / shdr->sh_entsize;
self->strtab = strtab;
@@ -368,7 +368,7 @@ static int xdl_symtab_load(xdl_t *self) {
break;
} else if (SHT_PROGBITS == shdr->sh_type && 0 == strcmp(".gnu_debugdata", shdr_name)) {
if (0 == xdl_symtab_load_from_debugdata(self, file_fd, file_sz, shdr)) {
// OK
r = 0;
break;
}
@@ -383,21 +383,21 @@ end:
}
static xdl_t *xdl_find_from_auxv(unsigned long type, const char *pathname) {
if (NULL == getauxval) return NULL; // API level < 18
if (NULL == getauxval) return NULL;
uintptr_t val = (uintptr_t)getauxval(type);
if (0 == val) return NULL;
// get base
uintptr_t base = (AT_PHDR == type ? (val & (~0xffful)) : val);
if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) return NULL;
// ELF info
ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base;
const ElfW(Phdr) *dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff);
ElfW(Half) dlpi_phnum = ehdr->e_phnum;
// get bias
uintptr_t min_vaddr = UINTPTR_MAX;
for (size_t i = 0; i < dlpi_phnum; i++) {
const ElfW(Phdr) *phdr = &(dlpi_phdr[i]);
@@ -408,7 +408,7 @@ static xdl_t *xdl_find_from_auxv(unsigned long type, const char *pathname) {
if (UINTPTR_MAX == min_vaddr || base < min_vaddr) return NULL;
uintptr_t load_bias = base - min_vaddr;
// create xDL object
xdl_t *self;
if (NULL == (self = calloc(1, sizeof(xdl_t)))) return NULL;
if (NULL == (self->pathname = strdup(pathname))) {
@@ -430,10 +430,10 @@ static int xdl_find_iterate_cb(struct dl_phdr_info *info, size_t size, void *arg
xdl_t **self = (xdl_t **)*pkg++;
const char *filename = (const char *)*pkg;
// check load_bias
if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0;
// check pathname
if ('[' == filename[0]) {
if (0 != strcmp(info->dlpi_name, filename)) return 0;
} else if ('/' == filename[0]) {
@@ -450,30 +450,30 @@ static int xdl_find_iterate_cb(struct dl_phdr_info *info, size_t size, void *arg
}
}
// found the target ELF
if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; // return failed
if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1;
if (NULL == ((*self)->pathname = strdup((const char *)info->dlpi_name))) {
free(*self);
*self = NULL;
return 1; // return failed
return 1;
}
(*self)->load_bias = info->dlpi_addr;
(*self)->dlpi_phdr = info->dlpi_phdr;
(*self)->dlpi_phnum = info->dlpi_phnum;
(*self)->dynsym_try_load = false;
(*self)->symtab_try_load = false;
return 1; // return OK
return 1;
}
static xdl_t *xdl_find(const char *filename) {
// from auxv (linker, vDSO)
xdl_t *self = NULL;
if (xdl_util_ends_with(filename, XDL_UTIL_LINKER_BASENAME))
self = xdl_find_from_auxv(AT_BASE, XDL_UTIL_LINKER_PATHNAME);
else if (xdl_util_ends_with(filename, XDL_UTIL_VDSO_BASENAME))
self = xdl_find_from_auxv(AT_SYSINFO_EHDR, XDL_UTIL_VDSO_BASENAME);
// from auxv (app_process)
const char *basename, *pathname;
#if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__
if (xdl_util_get_api_level() < __ANDROID_API_L__) {
@@ -489,18 +489,18 @@ static xdl_t *xdl_find(const char *filename) {
if (NULL != self) return self;
// from dl_iterate_phdr
uintptr_t pkg[2] = {(uintptr_t)&self, (uintptr_t)filename};
xdl_iterate_phdr(xdl_find_iterate_cb, pkg, XDL_DEFAULT);
return self;
}
static void *xdl_open_always_force(const char *filename) {
// always force dlopen()
void *linker_handle = xdl_linker_force_dlopen(filename);
if (NULL == linker_handle) return NULL;
// find
xdl_t *self = xdl_find(filename);
if (NULL == self)
dlclose(linker_handle);
@@ -511,15 +511,15 @@ static void *xdl_open_always_force(const char *filename) {
}
static void *xdl_open_try_force(const char *filename) {
// find
xdl_t *self = xdl_find(filename);
if (NULL != self) return (void *)self;
// try force dlopen()
void *linker_handle = xdl_linker_force_dlopen(filename);
if (NULL == linker_handle) return NULL;
// find again
self = xdl_find(filename);
if (NULL == self)
dlclose(linker_handle);
@@ -595,14 +595,14 @@ static ElfW(Sym) *xdl_dynsym_find_symbol_use_gnu_hash(xdl_t *self, const char *s
size_t mask = 0 | (size_t)1 << (hash % elfclass_bits) |
(size_t)1 << ((hash >> self->gnu_hash.bloom_shift) % elfclass_bits);
// if at least one bit is not set, this symbol is surely missing
if ((word & mask) != mask) return NULL;
// ignore STN_UNDEF
uint32_t i = self->gnu_hash.buckets[hash % self->gnu_hash.buckets_cnt];
if (i < self->gnu_hash.symoffset) return NULL;
// loop through the chain
while (1) {
ElfW(Sym) *sym = self->dynsym + i;
uint32_t sym_hash = self->gnu_hash.chains[i - self->gnu_hash.symoffset];
@@ -613,7 +613,7 @@ static ElfW(Sym) *xdl_dynsym_find_symbol_use_gnu_hash(xdl_t *self, const char *s
}
}
// chain ends with an element with the lowest bit set to 1
if (sym_hash & (uint32_t)1) break;
i++;
@@ -628,21 +628,21 @@ void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size) {
xdl_t *self = (xdl_t *)handle;
// load .dynsym only once
if (!self->dynsym_try_load) {
self->dynsym_try_load = true;
if (0 != xdl_dynsym_load(self)) return NULL;
}
// find symbol
if (NULL == self->dynsym) return NULL;
ElfW(Sym) *sym = NULL;
if (self->gnu_hash.buckets_cnt > 0) {
// use GNU hash (.gnu.hash -> .dynsym -> .dynstr), O(x) + O(1) + O(1)
sym = xdl_dynsym_find_symbol_use_gnu_hash(self, symbol);
}
if (NULL == sym && self->sysv_hash.buckets_cnt > 0) {
// use SYSV hash (.hash -> .dynsym -> .dynstr), O(x) + O(1) + O(1)
sym = xdl_dynsym_find_symbol_use_sysv_hash(self, symbol);
}
if (NULL == sym || !XDL_DYNSYM_IS_EXPORT_SYM(sym->st_shndx)) return NULL;
@@ -651,34 +651,9 @@ void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size) {
return (void *)(self->load_bias + sym->st_value);
}
// clang-format off
/*
* For internal symbols in .symtab, LLVM may add some suffixes (for example for thinLTO).
* The format of the suffix is: ".xxxx.[hash]". LLVM may add multiple suffixes at once.
* The symbol name after removing these all suffixes is called canonical name.
*
* Because the hash part in the suffix may change when recompiled, so here we only match
* the canonical name.
*
* IN ADDITION: According to C/C++ syntax, it is illegal for a function name to contain
* dot character('.'), either in the middle or at the end.
*
* samples:
*
* symbol name in .symtab lookup is match
* ---------------------- ---------------- --------
* abcd abc N
* abcd abcde N
* abcd abcd Y
* abcd.llvm.10190306339727611508 abc N
* abcd.llvm.10190306339727611508 abcd Y
* abcd.llvm.10190306339727611508 abcd. N
* abcd.llvm.10190306339727611508 abcd.llvm Y
* abcd.llvm.10190306339727611508 abcd.llvm. N
* abcd.__uniq.513291356003753 abcd.__uniq.51329 N
* abcd.__uniq.513291356003753 abcd.__uniq.513291356003753 Y
*/
// clang-format on
static inline bool xdl_dsym_is_match(const char *str, const char *sym, size_t sym_len) {
size_t str_len = strlen(str);
if (0 == str_len) return false;
@@ -689,7 +664,7 @@ static inline bool xdl_dsym_is_match(const char *str, const char *sym, size_t sy
bool sym_len_match = (0 == memcmp(str, sym, sym_len));
if (str_len == sym_len)
return sym_len_match;
else // str_len > sym_len
else
return sym_len_match && (str[sym_len] == '.');
}
}
@@ -700,20 +675,20 @@ void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size) {
xdl_t *self = (xdl_t *)handle;
// load .symtab only once
if (!self->symtab_try_load) {
self->symtab_try_load = true;
if (0 != xdl_symtab_load(self)) return NULL;
}
// find symbol
if (NULL == self->symtab) return NULL;
size_t symbol_len = strlen(symbol);
for (size_t i = 0; i < self->symtab_cnt; i++) {
ElfW(Sym) *sym = self->symtab + i;
if (!XDL_SYMTAB_IS_EXPORT_SYM(sym->st_shndx)) continue;
// if (0 != strncmp(self->strtab + sym->st_name, symbol, self->strtab_sz - sym->st_name)) continue;
if (!xdl_dsym_is_match(self->strtab + sym->st_name, symbol, symbol_len)) continue;
if (NULL != symbol_size) *symbol_size = sym->st_size;
@@ -745,25 +720,25 @@ static int xdl_open_by_addr_iterate_cb(struct dl_phdr_info *info, size_t size, v
xdl_t **self = (xdl_t **)*pkg++;
uintptr_t addr = *pkg;
if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; // continue
if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0;
if (xdl_elf_is_match(info->dlpi_addr, info->dlpi_phdr, info->dlpi_phnum, addr)) {
// found the target ELF
if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; // failed
if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1;
if (NULL == ((*self)->pathname = strdup((const char *)info->dlpi_name))) {
free(*self);
*self = NULL;
return 1; // failed
return 1;
}
(*self)->load_bias = info->dlpi_addr;
(*self)->dlpi_phdr = info->dlpi_phdr;
(*self)->dlpi_phnum = info->dlpi_phnum;
(*self)->dynsym_try_load = false;
(*self)->symtab_try_load = false;
return 1; // OK
return 1;
}
return 0; // continue
return 0;
}
static void *xdl_open_by_addr(void *addr) {
@@ -790,13 +765,13 @@ static bool xdl_sym_is_match(ElfW(Sym) *sym, uintptr_t offset, bool is_symtab) {
static ElfW(Sym) *xdl_sym_by_addr(void *handle, void *addr) {
xdl_t *self = (xdl_t *)handle;
// load .dynsym only once
if (!self->dynsym_try_load) {
self->dynsym_try_load = true;
if (0 != xdl_dynsym_load(self)) return NULL;
}
// find symbol
if (NULL == self->dynsym) return NULL;
uintptr_t offset = (uintptr_t)addr - self->load_bias;
if (self->gnu_hash.buckets_cnt > 0) {
@@ -822,13 +797,13 @@ static ElfW(Sym) *xdl_sym_by_addr(void *handle, void *addr) {
static ElfW(Sym) *xdl_dsym_by_addr(void *handle, void *addr) {
xdl_t *self = (xdl_t *)handle;
// load .symtab only once
if (!self->symtab_try_load) {
self->symtab_try_load = true;
if (0 != xdl_symtab_load(self)) return NULL;
}
// find symbol
if (NULL == self->symtab) return NULL;
uintptr_t offset = (uintptr_t)addr - self->load_bias;
for (size_t i = 0; i < self->symtab_cnt; i++) {
@@ -844,12 +819,12 @@ int xdl_addr(void *addr, xdl_info_t *info, void **cache) {
memset(info, 0, sizeof(Dl_info));
// find handle from cache
xdl_t *handle = NULL;
for (handle = *((xdl_t **)cache); NULL != handle; handle = handle->next)
if (xdl_elf_is_match(handle->load_bias, handle->dlpi_phdr, handle->dlpi_phnum, (uintptr_t)addr)) break;
// create new handle, save handle to cache
if (NULL == handle) {
handle = (xdl_t *)xdl_open_by_addr(addr);
if (NULL == handle) return 0;
@@ -857,7 +832,7 @@ int xdl_addr(void *addr, xdl_info_t *info, void **cache) {
*(xdl_t **)cache = handle;
}
// we have at least: load_bias, pathname, dlpi_phdr, dlpi_phnum
info->dli_fbase = (void *)handle->load_bias;
info->dli_fname = handle->pathname;
info->dli_sname = NULL;
@@ -866,7 +841,7 @@ int xdl_addr(void *addr, xdl_info_t *info, void **cache) {
info->dlpi_phdr = handle->dlpi_phdr;
info->dlpi_phnum = (size_t)handle->dlpi_phnum;
// keep looking for: symbol name, symbol offset, symbol size
ElfW(Sym) *sym;
if (NULL != (sym = xdl_sym_by_addr((void *)handle, addr))) {
info->dli_sname = handle->dynstr + sym->st_name;
+52 -67
View File
@@ -1,25 +1,25 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2020-10-04.
#include "xdl_iterate.h"
@@ -40,22 +40,7 @@
#include "xdl_linker.h"
#include "xdl_util.h"
/*
* =========================================================================================================
* API-LEVEL ANDROID-VERSION SOLUTION
* =========================================================================================================
* 16 4.1 /proc/self/maps
* 17 4.2 /proc/self/maps
* 18 4.3 /proc/self/maps
* 19 4.4 /proc/self/maps
* 20 4.4W /proc/self/maps
* ---------------------------------------------------------------------------------------------------------
* 21 5.0 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3)
* 22 5.1 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3)
* ---------------------------------------------------------------------------------------------------------
* 23 >= 6.0 dl_iterate_phdr() + linker/linker64 from getauxval(3)
* =========================================================================================================
*/
extern __attribute((weak)) int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *);
extern __attribute((weak)) unsigned long int getauxval(unsigned long int);
@@ -82,28 +67,28 @@ static int xdl_iterate_open_or_rewind_maps(FILE **maps) {
}
static int xdl_iterate_get_pathname_from_maps(uintptr_t base, char *buf, size_t buf_len, FILE **maps) {
// open or rewind maps-file
if (0 != xdl_iterate_open_or_rewind_maps(maps)) return -1; // failed
if (0 != xdl_iterate_open_or_rewind_maps(maps)) return -1;
char line[1024];
while (fgets(line, sizeof(line), *maps)) {
// check base address
uintptr_t start, end;
if (2 != sscanf(line, "%" SCNxPTR "-%" SCNxPTR " r", &start, &end)) continue;
if (base < start) break; // failed
if (base < start) break;
if (base >= end) continue;
// get pathname
char *pathname = strchr(line, '/');
if (NULL == pathname) break; // failed
if (NULL == pathname) break;
xdl_util_trim_ending(pathname);
// found it
strlcpy(buf, pathname, buf_len);
return 0; // OK
return 0;
}
return -1; // failed
return -1;
}
static int xdl_iterate_by_linker_cb(struct dl_phdr_info *info, size_t size, void *arg) {
@@ -114,10 +99,10 @@ static int xdl_iterate_by_linker_cb(struct dl_phdr_info *info, size_t size, void
uintptr_t linker_load_bias = *pkg++;
int flags = (int)*pkg;
// ignore invalid ELF
if (0 == info->dlpi_addr || NULL == info->dlpi_name || '\0' == info->dlpi_name[0]) return 0;
// ignore linker if we have returned it already
if (linker_load_bias == info->dlpi_addr) return 0;
struct dl_phdr_info info_fixed;
@@ -127,27 +112,27 @@ static int xdl_iterate_by_linker_cb(struct dl_phdr_info *info, size_t size, void
info_fixed.dlpi_phnum = info->dlpi_phnum;
info = &info_fixed;
// fix dlpi_phdr & dlpi_phnum (from memory)
if (NULL == info->dlpi_phdr || 0 == info->dlpi_phnum) {
ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)info->dlpi_addr;
info->dlpi_phdr = (ElfW(Phdr) *)(info->dlpi_addr + ehdr->e_phoff);
info->dlpi_phnum = ehdr->e_phnum;
}
// fix dlpi_name (from /proc/self/maps)
if ('/' != info->dlpi_name[0] && '[' != info->dlpi_name[0] && (0 != (flags & XDL_FULL_PATHNAME))) {
// get base address
uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(info);
if (UINTPTR_MAX == min_vaddr) return 0; // ignore this ELF
if (UINTPTR_MAX == min_vaddr) return 0;
uintptr_t base = (uintptr_t)(info->dlpi_addr + min_vaddr);
char buf[1024];
if (0 != xdl_iterate_get_pathname_from_maps(base, buf, sizeof(buf), maps)) return 0; // ignore this ELF
if (0 != xdl_iterate_get_pathname_from_maps(base, buf, sizeof(buf), maps)) return 0;
info->dlpi_name = (const char *)buf;
}
// callback
return cb(info, size, cb_arg);
}
@@ -170,9 +155,9 @@ static int xdl_iterate_do_callback(xdl_iterate_phdr_cb_t cb, void *cb_arg, uintp
info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff);
info.dlpi_phnum = ehdr->e_phnum;
// get load bias
uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(&info);
if (UINTPTR_MAX == min_vaddr) return 0; // ignore invalid ELF
if (UINTPTR_MAX == min_vaddr) return 0;
info.dlpi_addr = (ElfW(Addr))(base - min_vaddr);
if (NULL != load_bias) *load_bias = info.dlpi_addr;
@@ -186,8 +171,8 @@ static int xdl_iterate_by_linker(xdl_iterate_phdr_cb_t cb, void *cb_arg, int fla
FILE *maps = NULL;
int r;
// dl_iterate_phdr(3) does NOT contain linker/linker64 when Android version < 8.1 (API level 27).
// Here we always try to get linker base address from auxv.
uintptr_t linker_load_bias = 0;
uintptr_t linker_base = xdl_iterate_get_linker_base();
if (0 != linker_base) {
@@ -196,7 +181,7 @@ static int xdl_iterate_by_linker(xdl_iterate_phdr_cb_t cb, void *cb_arg, int fla
return r;
}
// for other ELF
uintptr_t pkg[5] = {(uintptr_t)cb, (uintptr_t)cb_arg, (uintptr_t)&maps, linker_load_bias, (uintptr_t)flags};
if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) xdl_linker_lock();
r = dl_iterate_phdr(xdl_iterate_by_linker_cb, pkg);
@@ -218,20 +203,20 @@ static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) {
bool try_next_line = false;
while (fgets(line, sizeof(buf1), maps)) {
// Try to find an ELF which loaded by linker.
uintptr_t base, offset;
char exec;
if (3 != sscanf(line, "%" SCNxPTR "-%*" SCNxPTR " r%*c%cp %" SCNxPTR " ", &base, &exec, &offset))
goto clean;
if ('-' == exec && 0 == offset) {
// r--p
prev_base = base;
line = (line == buf1 ? buf2 : buf1);
try_next_line = true;
continue;
} else if (exec == 'x') {
// r-xp
char *pathname = NULL;
if (try_next_line && 0 != offset) {
char *prev = (line == buf1 ? buf2 : buf1);
@@ -245,14 +230,14 @@ static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) {
xdl_util_trim_ending(pathname);
if (0 != strcmp(prev_pathname, pathname)) goto clean;
// we found the line with r-xp in the next line
base = prev_base;
offset = 0;
}
if (0 != offset) goto clean;
// get pathname
if (NULL == pathname) {
pathname = strchr(line, '/');
if (NULL == pathname) goto clean;
@@ -266,7 +251,7 @@ static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) {
info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff);
info.dlpi_phnum = ehdr->e_phnum;
// callback
if (0 != (r = xdl_iterate_do_callback(cb, cb_arg, base, pathname, NULL))) break;
}
@@ -280,12 +265,12 @@ static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) {
#endif
int xdl_iterate_phdr_impl(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags) {
// iterate by /proc/self/maps in Android 4.x (Android 4.x only supports arm32 and x86)
#if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__
if (xdl_util_get_api_level() < __ANDROID_API_L__) return xdl_iterate_by_maps(cb, cb_arg);
#endif
// iterate by dl_iterate_phdr()
return xdl_iterate_by_linker(cb, cb_arg, flags);
}
+21 -21
View File
@@ -1,25 +1,25 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2020-10-04.
#ifndef IO_GITHUB_HEXHACKING_XDL_ITERATE
#define IO_GITHUB_HEXHACKING_XDL_ITERATE
+34 -34
View File
@@ -1,25 +1,25 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2021-02-21.
#include "xdl_linker.h"
@@ -66,8 +66,8 @@ typedef struct {
size_t matches_cursor;
} xdl_linker_caller_t;
// https://source.android.com/docs/core/architecture/vndk/linker-namespace
// The following rules are loose and incomplete, you can add more according to your needs.
static xdl_linker_match_t xdl_linker_match_default[] = {{MATCH_SUFFIX, "/libc.so"}};
static xdl_linker_match_t xdl_linker_match_art[] = {{MATCH_SUFFIX, "/libart.so"}};
static xdl_linker_match_t xdl_linker_match_sphal[] = {{MATCH_PREFIX, "/vendor/" LIB "/egl/"},
@@ -84,26 +84,26 @@ static xdl_linker_caller_t xdl_linker_callers[] = {
{NULL, xdl_linker_match_vndk, sizeof(xdl_linker_match_vndk) / sizeof(xdl_linker_match_t)}};
static void xdl_linker_init_symbols_impl(void) {
// find linker from: /proc/self/maps (API level < 18) or getauxval (API level >= 18)
void *handle = xdl_open(XDL_UTIL_LINKER_BASENAME, XDL_DEFAULT);
if (NULL == handle) return;
int api_level = xdl_util_get_api_level();
if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) {
// == Android 5.x
xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL);
} else if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) {
// == Android 7.x
xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_EXT_N, NULL);
if (NULL == xdl_linker_dlopen) {
xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DO_DLOPEN_N, NULL);
xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL);
}
} else if (__ANDROID_API_O__ == api_level || __ANDROID_API_O_MR1__ == api_level) {
// == Android 8.x
xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_O, NULL);
} else if (api_level >= __ANDROID_API_P__) {
// >= Android 9.0
xdl_linker_dlopen = xdl_sym(handle, XDL_LINKER_SYM_LOADER_DLOPEN_P, NULL);
}
@@ -154,9 +154,9 @@ static void xdl_linker_save_caller_addr(struct dl_phdr_info *info, xdl_linker_ca
static int xdl_linker_get_caller_addr_cb(struct dl_phdr_info *info, size_t size, void *arg) {
(void)size, (void)arg;
if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; // continue
if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0;
int ret = 1; // OK
int ret = 1;
for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) {
xdl_linker_caller_t *caller = &xdl_linker_callers[i];
for (size_t j = 0; j < caller->matches_cursor; j++) {
@@ -174,7 +174,7 @@ static int xdl_linker_get_caller_addr_cb(struct dl_phdr_info *info, size_t size,
break;
}
}
if (NULL == caller->addr || 0 != caller->matches_cursor) ret = 0; // continue
if (NULL == caller->addr || 0 != caller->matches_cursor) ret = 0;
}
return ret;
}
@@ -200,7 +200,7 @@ void *xdl_linker_force_dlopen(const char *filename) {
int api_level = xdl_util_get_api_level();
if (api_level <= __ANDROID_API_M__) {
// <= Android 6.0
return dlopen(filename, RTLD_NOW);
} else {
xdl_linker_init_symbols();
@@ -209,7 +209,7 @@ void *xdl_linker_force_dlopen(const char *filename) {
void *handle = NULL;
if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) {
// == Android 7.x
xdl_linker_lock();
for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) {
xdl_linker_caller_t *caller = &xdl_linker_callers[i];
@@ -220,7 +220,7 @@ void *xdl_linker_force_dlopen(const char *filename) {
}
xdl_linker_unlock();
} else {
// >= Android 8.0
for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) {
xdl_linker_caller_t *caller = &xdl_linker_callers[i];
if (NULL != caller->addr) {
+21 -21
View File
@@ -1,25 +1,25 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2021-02-21.
#ifndef IO_GITHUB_HEXHACKING_XDL_LINKER
#define IO_GITHUB_HEXHACKING_XDL_LINKER
+36 -36
View File
@@ -1,25 +1,25 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2020-11-08.
#include "xdl_lzma.h"
@@ -36,7 +36,7 @@
#include "xdl.h"
#include "xdl_util.h"
// LZMA library pathname & symbol names
#ifndef __LP64__
#define XDL_LZMA_PATHNAME "/system/lib/liblzma.so"
#else
@@ -49,26 +49,26 @@
#define XDL_LZMA_SYM_FREE "XzUnpacker_Free"
#define XDL_LZMA_SYM_CODE "XzUnpacker_Code"
// LZMA data type definition
#define SZ_OK 0
typedef struct ISzAlloc ISzAlloc;
typedef const ISzAlloc *ISzAllocPtr;
struct ISzAlloc {
void *(*Alloc)(ISzAllocPtr p, size_t size);
void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
void (*Free)(ISzAllocPtr p, void *address);
};
typedef enum {
CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
CODER_STATUS_NOT_FINISHED, /* stream was not finished */
CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
CODER_STATUS_NOT_SPECIFIED,
CODER_STATUS_FINISHED_WITH_MARK,
CODER_STATUS_NOT_FINISHED,
CODER_STATUS_NEEDS_MORE_INPUT
} ECoderStatus;
typedef enum {
CODER_FINISH_ANY, /* finish at any point */
CODER_FINISH_END /* block must be finished at the end */
CODER_FINISH_ANY,
CODER_FINISH_END
} ECoderFinishMode;
// LZMA function type definition
typedef void (*xdl_lzma_crcgen_t)(void);
typedef void (*xdl_lzma_crc64gen_t)(void);
typedef void (*xdl_lzma_construct_t)(void *, ISzAllocPtr);
@@ -79,13 +79,13 @@ typedef int (*xdl_lzma_code_t)(void *, uint8_t *, size_t *, const uint8_t *, siz
typedef int (*xdl_lzma_code_q_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, int,
ECoderFinishMode, ECoderStatus *);
// LZMA function pointor
static xdl_lzma_construct_t xdl_lzma_construct = NULL;
static xdl_lzma_isfinished_t xdl_lzma_isfinished = NULL;
static xdl_lzma_free_t xdl_lzma_free = NULL;
static void *xdl_lzma_code = NULL;
// LZMA init
static void xdl_lzma_init(void) {
void *lzma = xdl_open(XDL_LZMA_PATHNAME, XDL_TRY_FORCE_LOAD);
if (NULL == lzma) return;
@@ -107,7 +107,7 @@ end:
xdl_close(lzma);
}
// LZMA internal alloc / free
static void *xdl_lzma_internal_alloc(ISzAllocPtr p, size_t size) {
(void)p;
return malloc(size);
@@ -123,11 +123,11 @@ int xdl_lzma_decompress(uint8_t *src, size_t src_size, uint8_t **dst, size_t *ds
size_t src_remaining;
size_t dst_remaining;
ISzAlloc alloc = {.Alloc = xdl_lzma_internal_alloc, .Free = xdl_lzma_internal_free};
long long state[4096 / sizeof(long long)]; // must be enough, 8-bit aligned
long long state[4096 / sizeof(long long)];
ECoderStatus status;
int api_level = xdl_util_get_api_level();
// init and check
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static bool inited = false;
if (!inited) {
+21 -21
View File
@@ -1,25 +1,25 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2020-11-08.
#ifndef IO_GITHUB_HEXHACKING_XDL_LZMA
#define IO_GITHUB_HEXHACKING_XDL_LZMA
+22 -22
View File
@@ -1,25 +1,25 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2020-10-04.
#include "xdl_util.h"
@@ -92,7 +92,7 @@ int xdl_util_get_api_level(void) {
if (xdl_util_api_level < 0) {
int api_level = GetAndroidApiLevel();
if (api_level < 0)
api_level = xdl_util_get_api_level_from_build_prop(); // compatible with unusual models
api_level = xdl_util_get_api_level_from_build_prop();
if (api_level < __ANDROID_API_J__) api_level = __ANDROID_API_J__;
__atomic_store_n(&xdl_util_api_level, api_level, __ATOMIC_SEQ_CST);
+21 -21
View File
@@ -1,25 +1,25 @@
// Copyright (c) 2020-2023 HexHacking Team
//
// 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.
//
// Created by caikelun on 2020-10-04.
#ifndef IO_GITHUB_HEXHACKING_XDL_UTIL
#define IO_GITHUB_HEXHACKING_XDL_UTIL
@@ -12,14 +12,7 @@ import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.Objects;
/**
* updated by alex5402 on 2021/5/7.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class ActivityThread {
public H mH = null;
public AppBindData mBoundApplication;
@@ -4,14 +4,7 @@ import android.content.IContentProvider;
import android.content.pm.ProviderInfo;
import android.os.IBinder;
/**
* updated by alex5402 on 2021/5/7.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class ContentProviderHolder {
public final ProviderInfo info = null;
public IContentProvider provider;
@@ -2,13 +2,6 @@ package android.content;
import android.os.IInterface;
/**
* updated by alex5402 on 2021/5/7.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public interface IContentProvider extends IInterface {
}
@@ -1,18 +1,4 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content;
@@ -20,64 +6,45 @@ import android.accounts.Account;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Information about the sync operation that is currently underway.
*/
public class SyncInfo implements Parcelable {
/**
* Used when the caller receiving this object doesn't have permission to access the accounts
* on device.
* @See Manifest.permission.GET_ACCOUNTS
*/
private static final Account REDACTED_ACCOUNT = new Account("*****", "*****");
/** @hide */
public final int authorityId;
/**
* The {@link Account} that is currently being synced.
*/
public final Account account;
/**
* The authority of the provider that is currently being synced.
*/
public final String authority;
/**
* The start time of the current sync operation in milliseconds since boot.
* This is represented in elapsed real time.
* See {@link android.os.SystemClock#elapsedRealtime()}.
*/
public final long startTime;
/**
* Creates a SyncInfo object with an unusable Account. Used when the caller receiving this
* object doesn't have access to the accounts on the device.
* @See Manifest.permission.GET_ACCOUNTS
* @hide
*/
public static SyncInfo createAccountRedacted(
int authorityId, String authority, long startTime) {
throw new RuntimeException("Stub!");
}
/** @hide */
public SyncInfo(int authorityId, Account account, String authority, long startTime) {
throw new RuntimeException("Stub!");
}
/** @hide */
public SyncInfo(SyncInfo other) {
throw new RuntimeException("Stub!");
}
/** @hide */
public int describeContents() {
return 0;
}
/** @hide */
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(authorityId);
parcel.writeParcelable(account, flags);
@@ -26,8 +26,8 @@ public class SyncStatusInfo implements Parcelable {
public boolean pending;
public boolean initialize;
// Warning: It is up to the external caller to ensure there are
// no race conditions when accessing this list
private ArrayList<Long> periodicSyncTimes;
private static final String TAG = "Sync";
@@ -129,8 +129,8 @@ public class SyncStatusInfo implements Parcelable {
}
public void setPeriodicSyncTime(int index, long when) {
// The list is initialized lazily when scheduling occurs so we need to make sure
// we initialize elements < index to zero (zero is ignore for scheduling purposes)
ensurePeriodicSyncTimeSize(index);
periodicSyncTimes.set(index, when);
}
@@ -5,14 +5,7 @@ import android.os.Parcelable;
import java.util.jar.Attributes;
/**
* updated by alex5402 on 2021/5/7.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class ManifestDigest implements Parcelable {
ManifestDigest(final byte[] digest) {
@@ -90,24 +90,20 @@ public class PackageParser {
public final int installLocation;
public final VerifierInfo[] verifiers;
/** Names of any split APKs, ordered by parsed splitName */
public final String[] splitNames;
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
public final String codePath;
/** Path of base APK */
public final String baseCodePath;
/** Paths of any split APKs, ordered by parsed splitName */
public final String[] splitCodePaths;
/** Revision code of base APK */
public final int baseRevisionCode;
/** Revision codes of any split APKs, ordered by parsed splitName */
public final int[] splitRevisionCodes;
public final boolean coreApp;
@@ -141,9 +137,7 @@ public class PackageParser {
}
}
/**
* For Android 5.0+
*/
public PackageParser() {
throw new RuntimeException("Stub!");
}
@@ -180,49 +174,17 @@ public class PackageParser {
throw new RuntimeException("Stub!");
}
/**
* Parse only lightweight details about the package at the given location.
* Automatically detects if the package is a monolithic style (single APK
* file) or cluster style (directory of APKs).
* <p>
* This performs sanity checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
*
* @see PackageParser#parsePackage(File, int)
*/
public static PackageLite parsePackageLite(final File packageFile, final int flags) throws PackageParserException {
throw new RuntimeException("Stub!");
}
/**
* Parse the package at the given location. Automatically detects if the
* package is a monolithic style (single APK file) or cluster style
* (directory of APKs).
* <p>
* This performs sanity checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in {@link #collectCertificates(Package, int)}.
*
* @see #parsePackageLite(File, int)
* @since Android 5.0+
*/
public Package parsePackage(final File packageFile, final int flags) throws PackageParserException {
throw new RuntimeException("Stub!");
}
/**
*
* @param sourceFile
* @param destCodePath
* @param metrics
* @param flags
* @return
* @since Android 2.3+
*/
public Package parsePackage(final File sourceFile, final String destCodePath, final DisplayMetrics metrics, final int flags) {
throw new RuntimeException("Stub!");
}
@@ -235,63 +197,45 @@ public class PackageParser {
throw new RuntimeException("Stub!");
}
/**
* Utility method that retrieves lightweight details about a single APK
* file, including package name, split name, and install location.
*
* @param apkFile path to a single APK
* @param flags optional parse flags, such as
* {@link #PARSE_COLLECT_CERTIFICATES}
*/
public static ApkLite parseApkLite(final File apkFile, final int flags) throws PackageParserException {
throw new RuntimeException("Stub!");
}
/**
* Representation of a full package parsed from APK files on disk. A package
* consists of a single base APK, and zero or more split APKs.
*/
public final static class Package {
public String packageName;
/** Names of any split APKs, ordered by parsed splitName */
public String[] splitNames;
// TODO: work towards making these paths invariant
public String volumeUuid;
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
public String codePath;
/** Path of base APK */
public String baseCodePath;
/** Paths of any split APKs, ordered by parsed splitName */
public String[] splitCodePaths;
/** Revision code of base APK */
public int baseRevisionCode;
/** Revision codes of any split APKs, ordered by parsed splitName */
public int[] splitRevisionCodes;
/** Flags of any split APKs; ordered by parsed splitName */
public int[] splitFlags;
/**
* Private flags of any split APKs; ordered by parsed splitName.
*
* {@hide}
*/
public int[] splitPrivateFlags;
public boolean baseHardwareAccelerated;
// For now we only support one application per package.
public ApplicationInfo applicationInfo = new ApplicationInfo();
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
@@ -317,92 +261,80 @@ public class PackageParser {
public String mRealPackage = null;
public ArrayList<String> mAdoptPermissions = null;
// We store the application meta-data independently to avoid multiple unwanted references
public Bundle mAppMetaData = null;
// The version code declared for this package.
public int mVersionCode;
// The version name declared for this package.
public String mVersionName;
// The shared user id that this package wants to use.
public String mSharedUserId;
// The shared user label that this package wants to use.
public int mSharedUserLabel;
// Signatures that were read from the package.
public Signature[] mSignatures;
public SigningDetails mSigningDetails;
public Certificate[][] mCertificates;
// For use by package manager service for quick lookup of
// preferred up order.
public int mPreferredOrder = 0;
// For use by package manager to keep track of where it needs to do dexopt.
// public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);
// For use by package manager to keep track of when a package was last used.
public long mLastPackageUsageTimeInMills;
// // User set enabled state.
// public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
//
// // Whether the package has been stopped.
// public boolean mSetStopped = false;
// Additional data supplied by callers.
public Object mExtras;
// Applications hardware preferences
public ArrayList<ConfigurationInfo> configPreferences = null;
// Applications requested features
public ArrayList<FeatureInfo> reqFeatures = null;
// Applications requested feature groups
public ArrayList<FeatureGroupInfo> featureGroups = null;
public int installLocation;
public boolean coreApp;
/* An app that's required for all users and cannot be uninstalled for a user */
public boolean mRequiredForAllUsers;
/* The restricted account authenticator type that is used by this application */
public String mRestrictedAccountType;
/* The required account type without which this application will not function */
public String mRequiredAccountType;
/**
* Digest suitable for comparing whether this package's manifest is the
* same as another.
*/
public ManifestDigest manifestDigest;
public String mOverlayTarget;
public int mOverlayPriority;
public boolean mTrustedOverlay;
/**
* Data used to feed the KeySetManagerService
*/
public ArraySet<PublicKey> mSigningKeys;
public ArraySet<String> mUpgradeKeySets;
public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
/**
* The install time abi override for this package, if any.
*
* TODO: This seems like a horrible place to put the abiOverride because
* this isn't something the packageParser parsers. However, this fits in with
* the rest of the PackageManager where package scanning randomly pushes
* and prods fields out of {@code this.applicationInfo}.
*/
public String cpuAbiOverride;
public Package(String packageName) {
@@ -413,10 +345,7 @@ public class PackageParser {
throw new RuntimeException("Stub!");
}
/**
* Filtered set of {@link #getAllCodePaths()} that excludes
* resource-only APKs.
*/
public List<String> getAllCodePathsExcludingResourceOnly() {
throw new RuntimeException("Stub!");
}
@@ -2,20 +2,13 @@ package android.content.pm;
import android.util.ArraySet;
/**
* updated by alex5402 on 2021/5/7.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class PackageUserState {
public boolean stopped;
public boolean notLaunched;
public boolean installed;
public boolean hidden; // Is the app restricted by owner / admin
public boolean hidden;
public int enabled;
public boolean blockUninstall;
@@ -5,14 +5,7 @@ import android.os.Parcelable;
import java.security.PublicKey;
/**
* updated by alex5402 on 2021/5/7.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class VerifierInfo implements Parcelable {
public static final Parcelable.Creator<VerifierInfo> CREATOR = new Parcelable.Creator<VerifierInfo>() {
@@ -4,20 +4,7 @@ import android.annotation.TargetApi;
import java.io.IOException;
/**
* Wrapper class that offers to transport typical {@link Throwable} across a
* {@link Binder} call. This class is typically used to transport exceptions
* that cannot be modified to add {@link Parcelable} behavior, such as
* {@link IOException}.
* <ul>
* <li>The wrapped throwable must be defined as system class (that is, it must
* be in the same {@link ClassLoader} as {@link Parcelable}).
* <li>The wrapped throwable must support the
* {@link Throwable#Throwable(String)} constructor.
* <li>The receiver side must catch any thrown {@link ParcelableException} and
* call {@link #maybeRethrow(Class)} for all expected exception types.
* </ul>
*/
@TargetApi(Build.VERSION_CODES.O)
public final class ParcelableException extends RuntimeException implements Parcelable {
public ParcelableException(Throwable t) {
@@ -6,9 +6,7 @@ import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BField;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
/**
* Created by BlackBox on 2022/2/22.
*/
@BClassName("android.app.ActivityClient")
public interface ActivityClient {
@BField
@@ -4,9 +4,7 @@ import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BField;
import top.niunaijun.blackreflection.annotation.BMethod;
/**
* Created by BlackBox on 2022/2/20.
*/
@BClassName("android.content.AttributionSource")
public interface AttributionSource {
@BField
@@ -3,9 +3,7 @@ package black.android.content;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BField;
/**
* Created by BlackBox on 2022/2/20.
*/
@BClassName("android.content.AttributionSourceState")
public interface AttributionSourceState {
@BField
@@ -23,20 +23,20 @@ public interface PackageParser {
@BConstructor
android.content.pm.PackageParser _new(String String0);
// @BStaticMethod
// ActivityInfo generateActivityInfo();
//
// @BStaticMethod
// ApplicationInfo generateApplicationInfo();
//
// @BStaticMethod
// PackageInfo generatePackageInfo();
//
// @BStaticMethod
// ProviderInfo generateProviderInfo();
//
// @BStaticMethod
// ServiceInfo generateServiceInfo();
@BMethod
void collectCertificates(android.content.pm.PackageParser.Package p, int flags);
@@ -13,20 +13,20 @@ public interface PackageParserLollipop {
@BConstructor
android.content.pm.PackageParser _new();
// @BStaticMethod
// ActivityInfo generateActivityInfo(PackageParser.Activity service, int flag, PackageUserState state, int userId);
//
// @BStaticMethod
// ApplicationInfo generateApplicationInfo(Package p, int flags, PackageUserState state);
//
// @BStaticMethod
// PackageInfo generatePackageInfo(Package p, int[] ints, int int1, long long1, long );
//
// @BStaticMethod
// ProviderInfo generateProviderInfo(PackageParser.Provider service, int flag, PackageUserState state, int userId);
//
// @BStaticMethod
// ServiceInfo generateServiceInfo(PackageParser.Service service, int flag, PackageUserState state, int userId);
@BMethod
void collectCertificates(Package p, int flags);
@@ -13,20 +13,20 @@ public interface PackageParserLollipop22 {
@BConstructor
android.content.pm.PackageParser _new();
// @BStaticMethod
// ActivityInfo generateActivityInfo();
//
// @BStaticMethod
// ApplicationInfo generateApplicationInfo();
//
// @BStaticMethod
// PackageInfo generatePackageInfo();
//
// @BStaticMethod
// ProviderInfo generateProviderInfo();
//
// @BStaticMethod
// ServiceInfo generateServiceInfo();
@BMethod
void collectCertificates(Package p, int flags);
@@ -14,20 +14,20 @@ public interface PackageParserMarshmallow {
@BConstructor
PackageParser _new();
// @BStaticMethod
// ActivityInfo generateActivityInfo();
//
// @BStaticMethod
// ApplicationInfo generateApplicationInfo();
//
// @BStaticMethod
// PackageInfo generatePackageInfo();
//
// @BStaticMethod
// ProviderInfo generateProviderInfo();
//
// @BStaticMethod
// ServiceInfo generateServiceInfo();
@BMethod
void collectCertificates(Package p, int flags);
@@ -3,9 +3,7 @@ package black.android.graphics;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
/**
* Created by BlackBox on 2022/2/24.
*/
@BClassName("android.graphics.Compatibility")
public interface Compatibility {
@BStaticMethod
@@ -6,9 +6,7 @@ import android.os.IInterface;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
/**
* Created by BlackBox on 2022/3/2.
*/
@BClassName("android.hardware.location.IContextHubService")
public interface IContextHubService {
@@ -63,14 +63,14 @@ public interface LocationManager {
@BClassName("android.location.LocationManager$GpsStatusListenerTransport")
interface GpsStatusListenerTransportSumsungS5 {
// @BMethod
// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4, int int5, int int6, int int7, [I int[]8);
}
@BClassName("android.location.LocationManager$GpsStatusListenerTransport")
interface GpsStatusListenerTransportOPPO_R815T {
// @BMethod
// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4, [I int[]5, [I int[]6, [I int[]7, int int8);
}
@BClassName("android.location.LocationManager$GpsStatusListenerTransport")
@@ -93,14 +93,14 @@ public interface LocationManager {
@BMethod
void onNmeaReceived(long long0, String String1);
// @BMethod
// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4, int int5, int int6, int int7);
}
@BClassName("android.location.LocationManager$GnssStatusListenerTransport")
interface GnssStatusListenerTransportO {
// @BMethod
// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4, [F float[]5);
}
@BClassName("android.location.LocationManager$GnssStatusListenerTransport")
@@ -123,7 +123,7 @@ public interface LocationManager {
@BMethod
void onNmeaReceived(long long0, String String1);
// @BMethod
// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4);
}
}
@@ -6,9 +6,7 @@ import android.os.IInterface;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
/**
* Created by BlackBox on 2022/2/26.
*/
@BClassName("android.net.IVpnManager")
public interface IVpnManager {
@@ -6,9 +6,7 @@ import android.os.IInterface;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
/**
* Created by BlackBox on 2022/3/19.
*/
@BClassName("android.os.IVibratorManagerService")
public interface IVibratorManagerService {
@@ -6,9 +6,7 @@ import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticField;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
/**
* Created by BlackBox on 2022/2/26.
*/
@BClassName("android.telephony.TelephonyManager")
public interface TelephonyManager {
@@ -5,9 +5,7 @@ import java.util.List;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BField;
/**
* Created by BlackBox on 2022/2/25.
*/
@BClassName("com.android.internal.net.VpnConfig")
public interface VpnConfig {
@BField
File diff suppressed because it is too large Load Diff
@@ -86,14 +86,7 @@ import top.niunaijun.blackbox.utils.compat.ContextCompat;
import top.niunaijun.blackbox.utils.compat.StrictModeCompat;
import top.niunaijun.blackbox.core.system.JarManager;
/**
* updated by alex5402 on 3/31/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class BActivityThread extends IBActivityThread.Stub {
public static final String TAG = "BActivityThread";
@@ -181,7 +174,7 @@ public class BActivityThread extends IBActivityThread.Stub {
public void initProcess(AppConfig appConfig) {
synchronized (mConfigLock) {
if (this.mAppConfig != null && !this.mAppConfig.packageName.equals(appConfig.packageName)) {
// 该进程已被attach
throw new RuntimeException("reject init process: " + appConfig.processName + ", this process is : " + this.mAppConfig.processName);
}
this.mAppConfig = appConfig;
@@ -218,7 +211,7 @@ public class BActivityThread extends IBActivityThread.Stub {
try {
service = (Service) classLoader.loadClass(serviceInfo.name).newInstance();
} catch (ClassNotFoundException e) {
// Handle missing Google Play Services classes gracefully
if (serviceInfo.name.contains("google.android.gms") ||
serviceInfo.name.contains("google.android.location")) {
Slog.w(TAG, "Google Play Services class not found, skipping: " + serviceInfo.name);
@@ -253,7 +246,7 @@ public class BActivityThread extends IBActivityThread.Stub {
service.onCreate();
return service;
} catch (Exception e) {
// Handle service creation errors gracefully
if (serviceInfo.name.contains("google.android.gms") ||
serviceInfo.name.contains("google.android.location")) {
Slog.w(TAG, "Google Play Services service creation failed, skipping: " + serviceInfo.name);
@@ -273,7 +266,7 @@ public class BActivityThread extends IBActivityThread.Stub {
try {
service = (JobService) classLoader.loadClass(serviceInfo.name).newInstance();
} catch (ClassNotFoundException e) {
// Handle missing Google Play Services classes gracefully
if (serviceInfo.name.contains("google.android.gms") ||
serviceInfo.name.contains("google.android.location")) {
Slog.w(TAG, "Google Play Services JobService class not found, skipping: " + serviceInfo.name);
@@ -309,7 +302,7 @@ public class BActivityThread extends IBActivityThread.Stub {
service.onBind(null);
return service;
} catch (Exception e) {
// Handle JobService creation errors gracefully
if (serviceInfo.name.contains("google.android.gms") ||
serviceInfo.name.contains("google.android.location")) {
Slog.w(TAG, "Google Play Services JobService creation failed, skipping: " + serviceInfo.name);
@@ -324,30 +317,28 @@ public class BActivityThread extends IBActivityThread.Stub {
if (Looper.myLooper() != Looper.getMainLooper()) {
final ConditionVariable conditionVariable = new ConditionVariable();
BlackBoxCore.get().getHandler().post(() -> {
// Create a minimal data object for the new handleBindApplication method
Object bindData = createBindApplicationData(packageName, processName);
handleBindApplication(packageName, processName);
conditionVariable.open();
});
conditionVariable.block();
} else {
// Create a minimal data object for the new handleBindApplication method
Object bindData = createBindApplicationData(packageName, processName);
handleBindApplication(packageName, processName);
}
}
/**
* Create a minimal bind application data object
*/
private Object createBindApplicationData(String packageName, String processName) {
try {
// Get package info to create application info
PackageInfo packageInfo = BlackBoxCore.getBPackageManager().getPackageInfo(packageName, PackageManager.GET_PROVIDERS, getUserId());
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
// Create a simple data object that can be used by the new handleBindApplication method
// This is a simplified approach - in a real implementation you'd create the proper data structure
return new Object() {
public ApplicationInfo getInfo() { return applicationInfo; }
public List<ProviderInfo> getProviders() {
@@ -356,7 +347,7 @@ public class BActivityThread extends IBActivityThread.Stub {
};
} catch (Exception e) {
Slog.e(TAG, "Error creating bind application data", e);
// Return a minimal fallback object
return new Object() {
public ApplicationInfo getInfo() { return null; }
public List<ProviderInfo> getProviders() { return new ArrayList<>(); }
@@ -384,7 +375,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Context packageContext = createPackageContext(applicationInfo);
Object loadedApk = BRContextImpl.get(packageContext).mPackageInfo();
BRLoadedApk.get(loadedApk)._set_mSecurityViolation(false);
// fix applicationInfo
BRLoadedApk.get(loadedApk)._set_mApplicationInfo(applicationInfo);
int targetSdkVersion = applicationInfo.targetSdkVersion;
@@ -427,7 +418,7 @@ public class BActivityThread extends IBActivityThread.Stub {
mBoundApplication = bindData;
//ssl适配
if (BRNetworkSecurityConfigProvider.getRealClass() != null) {
Security.removeProvider("AndroidNSSP");
BRNetworkSecurityConfigProvider.get().install(packageContext);
@@ -436,7 +427,7 @@ public class BActivityThread extends IBActivityThread.Stub {
try {
onBeforeCreateApplication(packageName, processName, packageContext);
// Try to create the application with better error handling
try {
application = BRLoadedApk.get(loadedApk).makeApplication(false, null);
} catch (Exception makeAppException) {
@@ -444,22 +435,22 @@ public class BActivityThread extends IBActivityThread.Stub {
application = null;
}
// If application is still null, try alternative approaches
if (application == null) {
Slog.w(TAG, "makeApplication returned null, attempting fallback creation");
// Try with different parameters
try {
application = BRLoadedApk.get(loadedApk).makeApplication(true, null);
} catch (Exception e) {
Slog.e(TAG, "Fallback makeApplication also failed", e);
}
// If still null, try to create a minimal application context
if (application == null) {
Slog.w(TAG, "Creating minimal application context as fallback");
try {
// Create a minimal application object or use the package context
application = (Application) packageContext;
if (application == null) {
Slog.e(TAG, "Even package context is null, this is critical");
@@ -494,21 +485,19 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Initialize JAR environment for DEX loading
*/
private void initializeJarEnvironment() {
try {
Slog.d(TAG, "Initializing JAR environment for DEX loading");
// Initialize JarManager
JarManager jarManager = JarManager.getInstance();
if (!jarManager.isReady()) {
Slog.d(TAG, "JarManager not ready, initializing synchronously");
jarManager.initializeSync();
}
// Verify empty.jar is available
File emptyJar = jarManager.getEmptyJar();
if (emptyJar == null || !emptyJar.exists()) {
Slog.w(TAG, "Empty JAR not available, attempting to recreate");
@@ -528,12 +517,10 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Create application with enhanced error handling and fallback mechanisms
*/
private Application createApplicationWithFallback(android.content.pm.ApplicationInfo appInfo) {
try {
// First attempt: Try to create application normally
Application application = createApplication(appInfo);
if (application != null) {
Slog.d(TAG, "Application created successfully: " + appInfo.className);
@@ -544,7 +531,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
try {
// Second attempt: Try with different class loader
Slog.d(TAG, "Attempting fallback application creation");
ClassLoader classLoader = getClassLoader(appInfo);
if (classLoader == null) {
@@ -555,7 +542,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Class<?> appClass = classLoader.loadClass(appInfo.className);
Application application = (Application) appClass.newInstance();
// Ensure the application has a proper base context
ensureApplicationBaseContext(application, appInfo);
Slog.d(TAG, "Fallback application creation successful");
@@ -564,7 +551,7 @@ public class BActivityThread extends IBActivityThread.Stub {
} catch (Exception e) {
Slog.e(TAG, "Fallback application creation failed: " + e.getMessage());
// Third attempt: Create a minimal application wrapper
try {
Slog.d(TAG, "Creating minimal application wrapper");
Application wrapper = new Application() {
@@ -575,7 +562,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
};
// Ensure the minimal application has a proper base context
ensureApplicationBaseContext(wrapper, appInfo);
return wrapper;
@@ -586,9 +573,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Install content providers with enhanced error handling
*/
private void installContentProvidersWithFallback(Application application, Object data) {
try {
List<android.content.pm.ProviderInfo> providers = getProviderInfoList(data);
@@ -605,7 +590,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.d(TAG, "Successfully installed provider: " + providerInfo.name);
} catch (Exception e) {
Slog.w(TAG, "Failed to install provider " + providerInfo.name + ": " + e.getMessage());
// Continue with other providers
}
}
@@ -614,15 +599,13 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Get application info from bind application data
*/
private android.content.pm.ApplicationInfo getApplicationInfo(Object data) {
try {
// Try to get application info from our custom data object
if (data != null) {
try {
// Use reflection to call getInfo() method
Method getInfoMethod = data.getClass().getMethod("getInfo");
ApplicationInfo appInfo = (ApplicationInfo) getInfoMethod.invoke(data);
if (appInfo != null) {
@@ -633,7 +616,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
// Fallback: try to get from package manager
String packageName = BlackBoxCore.getAppPackageName();
if (packageName != null) {
PackageInfo packageInfo = BlackBoxCore.getBPackageManager().getPackageInfo(packageName, 0, getUserId());
@@ -647,18 +630,16 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Get class loader for application
*/
private ClassLoader getClassLoader(android.content.pm.ApplicationInfo appInfo) {
try {
// ApplicationInfo doesn't have a classLoader field, so we need to create one
String sourceDir = appInfo.sourceDir;
if (sourceDir != null) {
return new dalvik.system.PathClassLoader(sourceDir, ClassLoader.getSystemClassLoader());
}
// Fallback to system class loader
return ClassLoader.getSystemClassLoader();
} catch (Exception e) {
Slog.w(TAG, "Error getting class loader: " + e.getMessage());
@@ -666,17 +647,15 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Create application from application info
*/
private Application createApplication(android.content.pm.ApplicationInfo appInfo) {
try {
// Create a basic application instance
ClassLoader classLoader = getClassLoader(appInfo);
Class<?> appClass = classLoader.loadClass(appInfo.className);
Application application = (Application) appClass.newInstance();
// Ensure the application has a proper base context
ensureApplicationBaseContext(application, appInfo);
return application;
@@ -686,32 +665,30 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Ensure application has a proper base context
*/
private void ensureApplicationBaseContext(Application application, android.content.pm.ApplicationInfo appInfo) {
try {
// Check if application already has a base context
if (application.getBaseContext() != null) {
Slog.d(TAG, "Application already has base context: " + appInfo.className);
return;
}
// Create a package context for the application
Context packageContext = createPackageContext(appInfo);
if (packageContext == null) {
Slog.w(TAG, "Could not create package context for application: " + appInfo.className + ", using fallback");
// Use a fallback context that will never be null
packageContext = createFallbackContext(appInfo.packageName);
}
// Ensure the package context is not null
if (packageContext == null) {
Slog.e(TAG, "Failed to create any context for application: " + appInfo.className);
return;
}
// Attach the base context to the application
try {
Method attachBaseContext = Application.class.getDeclaredMethod("attachBaseContext", Context.class);
attachBaseContext.setAccessible(true);
@@ -726,9 +703,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Create a fallback context that will never be null
*/
private Context createFallbackContext(String packageName) {
try {
Context baseContext = BlackBoxCore.getContext();
@@ -737,7 +712,7 @@ public class BActivityThread extends IBActivityThread.Stub {
return null;
}
// Create a safe context wrapper that provides all necessary methods
return new ContextWrapper(baseContext) {
@Override
public String getPackageName() {
@@ -800,15 +775,13 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Get provider info list from bind application data
*/
private List<android.content.pm.ProviderInfo> getProviderInfoList(Object data) {
try {
// Try to get provider info from our custom data object
if (data != null) {
try {
// Use reflection to call getProviders() method
Method getProvidersMethod = data.getClass().getMethod("getProviders");
List<ProviderInfo> providers = (List<ProviderInfo>) getProvidersMethod.invoke(data);
if (providers != null) {
@@ -819,7 +792,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
// Fallback: return empty list
return new ArrayList<>();
} catch (Exception e) {
Slog.e(TAG, "Error getting provider info list", e);
@@ -827,33 +800,31 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Install content provider
*/
private void installContentProvider(Application application, android.content.pm.ProviderInfo providerInfo) {
try {
// Check if application is null
if (application == null) {
Slog.w(TAG, "Application is null, cannot install content provider: " + providerInfo.name);
return;
}
// Check if application has a valid class loader
ClassLoader classLoader = application.getClassLoader();
if (classLoader == null) {
Slog.w(TAG, "Application class loader is null, using system class loader for: " + providerInfo.name);
classLoader = ClassLoader.getSystemClassLoader();
}
// Create and install the content provider
android.content.ContentProvider provider = (android.content.ContentProvider) classLoader
.loadClass(providerInfo.name).newInstance();
// Attach the provider to the application
provider.attachInfo(application, providerInfo);
// Note: ContentResolver.getContentProvider() doesn't exist
// The provider is automatically registered when attachInfo is called
Slog.d(TAG, "Content provider installed: " + providerInfo.name);
} catch (Exception e) {
@@ -861,9 +832,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Set application in ActivityThread
*/
private void setApplication(Application application) {
try {
mInitialApplication = application;
@@ -877,7 +846,7 @@ public class BActivityThread extends IBActivityThread.Stub {
private void handleSecurityException(SecurityException se, String packageName, String processName, Context packageContext) {
Slog.w(TAG, "Handling SecurityException for " + packageName);
// Try to create a basic application without problematic operations
try {
Application basicApp = createMinimalApplication(packageContext, packageName);
if (basicApp != null) {
@@ -885,7 +854,7 @@ public class BActivityThread extends IBActivityThread.Stub {
BRActivityThread.get(BlackBoxCore.mainThread())._set_mInitialApplication(mInitialApplication);
ContextCompat.fix(mInitialApplication);
// Skip problematic operations
Slog.w(TAG, "Created basic application, skipping problematic operations");
return;
}
@@ -893,7 +862,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.e(TAG, "Failed to create basic application after SecurityException: " + e.getMessage());
}
// If all else fails, re-throw the security exception
throw new RuntimeException("Unable to handle SecurityException", se);
}
@@ -908,10 +877,10 @@ public class BActivityThread extends IBActivityThread.Stub {
}
} catch (SecurityException se) {
Slog.w(TAG, "SecurityException installing provider " + providerInfo.name + ": " + se.getMessage());
// Continue with other providers
} catch (Throwable t) {
Slog.w(TAG, "Error installing provider " + providerInfo.name + ": " + t.getMessage());
// Continue with other providers
}
}
} finally {
@@ -934,15 +903,13 @@ public class BActivityThread extends IBActivityThread.Stub {
return null;
}
/**
* Create a minimal package context when the actual APK is not available
*/
private static Context createMinimalPackageContext(ApplicationInfo info) {
try {
// Create a context that doesn't require the actual APK
Context baseContext = BlackBoxCore.getContext();
// Try to create a context with minimal flags
try {
Context packageContext = baseContext.createPackageContext(info.packageName, 0);
if (packageContext != null) {
@@ -953,7 +920,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.w(TAG, "Failed to create package context with minimal flags for " + info.packageName + ": " + e.getMessage());
}
// Try to create a context without any flags
try {
Context packageContext = baseContext.createPackageContext(info.packageName, Context.CONTEXT_IGNORE_SECURITY);
if (packageContext != null) {
@@ -964,7 +931,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.w(TAG, "Failed to create package context with ignore security for " + info.packageName + ": " + e.getMessage());
}
// Try to create a context with just the package name
try {
Context packageContext = baseContext.createPackageContext(info.packageName, Context.CONTEXT_INCLUDE_CODE);
if (packageContext != null) {
@@ -979,19 +946,17 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.e(TAG, "Failed to create minimal package context for " + info.packageName + ": " + e.getMessage());
}
// Last resort: return the base context with package name wrapper
Slog.w(TAG, "Using base context as fallback for " + info.packageName);
return createWrappedBaseContext(info.packageName);
}
/**
* Create a wrapped base context that pretends to be a package context
*/
private static Context createWrappedBaseContext(String packageName) {
try {
Context baseContext = BlackBoxCore.getContext();
// Create a wrapper context that provides the package name
return new ContextWrapper(baseContext) {
@Override
public String getPackageName() {
@@ -1020,7 +985,7 @@ public class BActivityThread extends IBActivityThread.Stub {
};
} catch (Exception e) {
Slog.e(TAG, "Failed to create wrapped base context for " + packageName + ": " + e.getMessage());
// Ultimate fallback: return the base context
return BlackBoxCore.getContext();
}
}
@@ -1206,16 +1171,14 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Ensure that an activity has a valid context from the moment it's created
*/
public static void ensureActivityContext(Activity activity) {
if (activity == null) {
return;
}
try {
// Check if the activity already has a valid context
Context currentContext = activity.getBaseContext();
if (currentContext != null) {
Slog.d(TAG, "Activity already has context: " + activity.getClass().getName());
@@ -1224,7 +1187,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.w(TAG, "Activity has null context, ensuring valid context: " + activity.getClass().getName());
// Get a valid context
Context validContext = null;
try {
validContext = getApplication();
@@ -1237,14 +1200,14 @@ public class BActivityThread extends IBActivityThread.Stub {
}
if (validContext != null) {
// Create a simple package context for the activity
try {
Context packageContext = validContext.createPackageContext(
activity.getPackageName(),
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY
);
// Try to set the base context using reflection
java.lang.reflect.Method attachBaseContext = Activity.class.getDeclaredMethod("attachBaseContext", Context.class);
attachBaseContext.setAccessible(true);
attachBaseContext.invoke(activity, packageContext);
@@ -1258,24 +1221,22 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Hook the ActivityThread to ensure all activities get valid contexts from the very beginning
*/
public static void hookActivityThread() {
try {
// Try to hook the ActivityThread to ensure all activities get valid contexts
Object activityThread = BlackBoxCore.mainThread();
if (activityThread != null) {
// Get the instrumentation from the ActivityThread
Instrumentation instrumentation = BRActivityThread.get(activityThread).mInstrumentation();
if (instrumentation != null) {
Slog.d(TAG, "Found ActivityThread instrumentation, ensuring it's our AppInstrumentation");
// Check if the instrumentation is our AppInstrumentation
if (!(instrumentation instanceof AppInstrumentation)) {
Slog.w(TAG, "ActivityThread instrumentation is not our AppInstrumentation, attempting to replace");
// Try to replace the instrumentation with our AppInstrumentation
try {
AppInstrumentation appInstrumentation = AppInstrumentation.get();
appInstrumentation.injectHook();
@@ -1297,14 +1258,12 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
/**
* Create a minimal application when normal application creation fails
*/
private Application createMinimalApplication(Context packageContext, String packageName) {
try {
Slog.d(TAG, "Creating minimal application for " + packageName);
// Create a basic Application object
Application app = new Application() {
@Override
public void onCreate() {
@@ -1323,7 +1282,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
};
// Ensure the minimal application has a proper base context
if (packageContext != null) {
try {
Method attachBaseContext = Application.class.getDeclaredMethod("attachBaseContext", Context.class);
@@ -17,10 +17,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.view.animation.OvershootInterpolator;
/**
* LauncherActivity - Handles the launch of virtual apps
* This activity serves as a bridge between the host app and virtual apps
*/
public class LauncherActivity extends Activity {
public static final String TAG = "SplashScreen";
@@ -33,7 +30,7 @@ public class LauncherActivity extends Activity {
try {
Intent splash = new Intent();
splash.setClass(BlackBoxCore.getContext(), LauncherActivity.class);
// Only use FLAG_ACTIVITY_NEW_TASK
splash.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
splash.putExtra(LauncherActivity.KEY_INTENT, intent);
splash.putExtra(LauncherActivity.KEY_PKG, intent.getPackage());
@@ -69,17 +66,17 @@ public class LauncherActivity extends Activity {
Slog.d(TAG, "LauncherActivity.onCreate() for package: " + packageName + ", userId: " + userId);
// Get package info with enhanced error handling
PackageInfo packageInfo = getPackageInfoWithFallback(packageName, userId);
if (packageInfo == null) {
Slog.w(TAG, "Package info not available for " + packageName + ", but proceeding with launch");
// Don't fail immediately - try to proceed anyway
} else {
Slog.d(TAG, "Successfully retrieved package info for " + packageName);
}
// Properly load the app icon and app name
Drawable drawable = null;
String appName = packageName;
try {
@@ -124,7 +121,7 @@ public class LauncherActivity extends Activity {
.start();
}
// Launch the app in a separate thread to avoid blocking the UI
launchAppAsync(launchIntent, userId);
} catch (Exception e) {
@@ -133,30 +130,28 @@ public class LauncherActivity extends Activity {
}
}
/**
* Get package info with enhanced error handling and fallback mechanisms
*/
private PackageInfo getPackageInfoWithFallback(String packageName, int userId) {
try {
// First attempt: Try to get package info normally
return BlackBoxCore.getBPackageManager().getPackageInfo(packageName, 0, userId);
} catch (Exception e) {
Slog.w(TAG, "Failed to get package info for " + packageName + " (attempt 1): " + e.getMessage());
try {
// Second attempt: Try with different flags
return BlackBoxCore.getBPackageManager().getPackageInfo(packageName,
android.content.pm.PackageManager.GET_META_DATA, userId);
} catch (Exception e2) {
Slog.w(TAG, "Failed to get package info for " + packageName + " (attempt 2): " + e2.getMessage());
try {
// Third attempt: Try to get application info instead
android.content.pm.ApplicationInfo appInfo = BlackBoxCore.getBPackageManager()
.getApplicationInfo(packageName, 0, userId);
if (appInfo != null) {
// Create a minimal PackageInfo from ApplicationInfo
PackageInfo fallbackInfo = new PackageInfo();
fallbackInfo.packageName = packageName;
fallbackInfo.applicationInfo = appInfo;
@@ -177,28 +172,26 @@ public class LauncherActivity extends Activity {
return null;
}
/**
* Launch the app asynchronously to avoid blocking the UI thread
*/
private void launchAppAsync(final Intent launchIntent, final int userId) {
new Thread(() -> {
try {
Slog.d(TAG, "Starting app launch in background thread");
// Add a small delay to ensure the launcher activity is properly displayed
Thread.sleep(100);
// Launch the app
BlackBoxCore.getBActivityManager().startActivity(launchIntent, userId);
Slog.d(TAG, "App launch initiated successfully");
} catch (Exception e) {
Slog.e(TAG, "Error launching app", e);
// Try to show an error message to the user
runOnUiThread(() -> {
try {
// You could show a toast or dialog here
Slog.e(TAG, "Failed to launch app: " + e.getMessage());
} catch (Exception uiException) {
Slog.e(TAG, "Error showing error message", uiException);
@@ -6,14 +6,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
/**
* updated by alex5402 on 5/5/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class AppLifecycleCallback implements Application.ActivityLifecycleCallbacks {
public static AppLifecycleCallback EMPTY = new AppLifecycleCallback() {
@@ -23,17 +16,9 @@ public class AppLifecycleCallback implements Application.ActivityLifecycleCallba
}
/**
* Called when storage permission is needed before launching an app.
* Override this in your host app to show permission request UI.
*
* @param packageName The package being launched
* @param userId The user ID
* @return true if the host app will handle the permission request (launch will be cancelled),
* false to continue launching anyway
*/
public boolean onStoragePermissionNeeded(String packageName, int userId) {
// Default: don't block the launch, just warn
return false;
}
@@ -2,14 +2,7 @@ package top.niunaijun.blackbox.app.configuration;
import java.io.File;
/**
* updated by alex5402 on 5/4/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public abstract class ClientConfiguration {
public boolean isHideRoot() {
@@ -28,27 +21,21 @@ public abstract class ClientConfiguration {
return true;
}
/**
* Whether to use VPN network mode for sandboxed apps.
* When enabled, network traffic is routed through the VPN service.
* Default is false (normal network mode).
*/
public boolean isUseVpnNetwork() {
return false;
}
/**
* This method is called when an internal application requests to install a new application.
*
* @return Is it handled?
*/
public boolean isDisableFlagSecure() {
return false;
}
public boolean requestInstallPackage(File file, int userId) {
return false;
}
/**
* Get the Telegram Chat ID for log uploads.
*/
public String getLogSenderChatId() {
return "-1003719573856";
}
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.entity.JobRecord;
/**
* updated by alex5402 on 4/1/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class AppJobServiceDispatcher {
private static final AppJobServiceDispatcher sServiceDispatcher = new AppJobServiceDispatcher();
private final Map<Integer, JobRecord> mJobRecords = new HashMap<>();
@@ -60,11 +53,11 @@ public class AppJobServiceDispatcher {
}
public void onDestroy() {
// for (JobRecord jobRecord : mJobRecords.values()) {
// if (jobRecord.mJobService != null) {
// jobRecord.mJobService.onDestroy();
// }
// }
}
public void onLowMemory() {
@@ -19,14 +19,7 @@ import top.niunaijun.blackbox.proxy.record.ProxyServiceRecord;
import static android.app.Service.START_NOT_STICKY;
/**
* updated by alex5402 on 4/1/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class AppServiceDispatcher {
public static final String TAG = "AppServiceDispatcher";
@@ -48,7 +41,7 @@ public class AppServiceDispatcher {
if (intent == null || serviceInfo == null)
return null;
// Log.d(TAG, "onBind: " + component.toString());
Service service = getOrCreateService(serviceRecord);
if (service == null)
@@ -81,7 +74,7 @@ public class AppServiceDispatcher {
return START_NOT_STICKY;
}
// Log.d(TAG, "onStartCommand: " + component.toString());
Service service = getOrCreateService(stubRecord);
if (service == null)
return START_NOT_STICKY;
@@ -109,7 +102,7 @@ public class AppServiceDispatcher {
}
}
mService.clear();
// Log.d(TAG, "onDestroy: ");
}
public void onConfigurationChanged(Configuration newConfig) {
@@ -122,7 +115,7 @@ public class AppServiceDispatcher {
}
}
}
// Log.d(TAG, "onConfigurationChanged");
}
public void onLowMemory() {
@@ -135,7 +128,7 @@ public class AppServiceDispatcher {
}
}
}
// Log.d(TAG, "onLowMemory");
}
public void onTrimMemory(int level) {
@@ -148,7 +141,7 @@ public class AppServiceDispatcher {
}
}
}
// Log.d(TAG, "onTrimMemory");
}
public boolean onUnbind(Intent proxyIntent) {
@@ -180,7 +173,7 @@ public class AppServiceDispatcher {
mService.remove(new Intent.FilterComparison(intent));
}
record.setRebind(true);
// Log.d(TAG, "onUnbind:" + stubRecord.mServiceIntent.getComponent().toString());
}
} catch (Throwable e) {
e.printStackTrace();
@@ -47,7 +47,7 @@ public class Entry {
}
}
}
// You can override other callbacks as needed
});
top.niunaijun.blackbox.utils.Slog.d(TAG, "Custom closed code initialized!");
}
@@ -2,14 +2,7 @@ package top.niunaijun.blackbox.core;
import top.niunaijun.blackbox.BlackBoxCore;
/**
* updated by alex5402 on 4/30/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler mDefaultHandler;
@@ -8,14 +8,7 @@ import java.util.Set;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.entity.pm.InstallResult;
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class GmsCore {
private static final String TAG = "GmsCore";
@@ -31,7 +24,7 @@ public class GmsCore {
GOOGLE_APP.add("com.google.android.wearable.app");
GOOGLE_APP.add("com.google.android.wearable.app.cn");
// GMS must install at first
GOOGLE_SERVICE.add(GMS_PKG);
GOOGLE_SERVICE.add(GSF_PKG);
GOOGLE_SERVICE.add("com.google.android.gsf.login");
@@ -63,7 +56,7 @@ public class GmsCore {
try {
BlackBoxCore.getContext().getPackageManager().getApplicationInfo(packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
continue;
}
InstallResult installResult = blackBoxCore.installPackageAsUser(packageName, userId);
@@ -22,14 +22,7 @@ import top.niunaijun.blackbox.core.env.BEnvironment;
import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.TrieTree;
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
@SuppressLint("SdCardPath")
public class IOCore {
public static final String TAG = "IOCore";
@@ -45,11 +38,11 @@ public class IOCore {
return sIOCore;
}
// /data/data/com.google/ -----> /data/data/com.virtual/data/com.google/
public void addRedirect(String origPath, String redirectPath) {
if (TextUtils.isEmpty(origPath) || TextUtils.isEmpty(redirectPath) || mRedirectMap.get(origPath) != null)
return;
//Add the key to TrieTree
mTrieTree.add(origPath);
mRedirectMap.put(origPath, redirectPath);
File redirectFile = new File(redirectPath);
@@ -75,7 +68,7 @@ public class IOCore {
if (!TextUtils.isEmpty(search))
return search;
//Search the key from TrieTree
String key = mTrieTree.search(path);
if (!TextUtils.isEmpty(key))
path = path.replace(key, Objects.requireNonNull(mRedirectMap.get(key)));
@@ -94,7 +87,7 @@ public class IOCore {
if (TextUtils.isEmpty(path))
return path;
//Search the key from TrieTree
String key = mTrieTree.search(path);
if (!TextUtils.isEmpty(key))
path = path.replace(key, Objects.requireNonNull(rule.get(key)));
@@ -109,7 +102,7 @@ public class IOCore {
return new File(redirectPath(pathStr, rule));
}
// i love china but not the language because it is hard man
public void enableRedirect(Context context) {
Map<String, String> rule = new LinkedHashMap<>();
@@ -125,10 +118,10 @@ public class IOCore {
rule.put(String.format("/data/data/%s", packageName), packageInfo.dataDir);
rule.put(String.format("/data/user/%d/%s", systemUserId, packageName), packageInfo.dataDir);
// Ensure ART profile directories exist and redirect both current and reference profiles
File profilesRoot = new File(BEnvironment.getVirtualRoot(), "profiles");
FileUtils.mkdirs(profilesRoot.getAbsolutePath());
// broad redirect as a safety net
rule.put("/data/misc/profiles", profilesRoot.getAbsolutePath());
File profilesCurDir = new File(profilesRoot, String.format("cur/%d/%s", BlackBoxCore.getUserId(), packageName));
@@ -141,7 +134,7 @@ public class IOCore {
if (BlackBoxCore.getContext().getExternalCacheDir() != null && context.getExternalCacheDir() != null) {
File external = BEnvironment.getExternalUserDir(BlackBoxCore.getUserId());
// sdcard
rule.put("/sdcard", external.getAbsolutePath());
rule.put(String.format("/storage/emulated/%d", systemUserId), external.getAbsolutePath());
@@ -17,14 +17,7 @@ import top.niunaijun.blackbox.utils.compat.DexFileCompat;
import top.niunaijun.blackbox.core.system.JarManager;
import top.niunaijun.blackbox.utils.Slog;
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class NativeCore {
public static final String TAG = "NativeCore";
@@ -49,27 +42,27 @@ public class NativeCore {
@Keep
public static int getCallingUid(int origCallingUid) {
try {
// System UIDs should remain unchanged
if (origCallingUid > 0 && origCallingUid < Process.FIRST_APPLICATION_UID)
return origCallingUid;
// Non-user app UIDs should remain unchanged
if (origCallingUid > Process.LAST_APPLICATION_UID)
return origCallingUid;
if (origCallingUid == BlackBoxCore.getHostUid()) {
//microG
String appPackageName = BlackBoxCore.getAppPackageName();
if (appPackageName != null && appPackageName.equals("com.google.android.gms")){
//return Process.ROOT_UID;
}
//webview WV.qE Process.myUid()函数没有做hook所以只能特殊处理
//if (Binder.getCallingUid() == Process.myUid()) {
//throw new SecurityException("recordMetrics() may only be called by non-embedded WebView processes");
if (appPackageName != null && appPackageName.equals("com.google.android.webview")){
return Process.myUid();
}
// Enhanced UID handling for sandboxed environments
try {
int callingBUid = BlackBoxCore.getCallingBUid();
if (callingBUid > 0 && callingBUid < Process.LAST_APPLICATION_UID) {
@@ -79,34 +72,34 @@ public class NativeCore {
Log.w(TAG, "Error getting calling BUid: " + e.getMessage());
}
// Special handling for system settings access to prevent UID mismatch
try {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement element : stackTrace) {
String className = element.getClassName();
String methodName = element.getMethodName();
// Check if this is a system settings access that might cause UID issues
if ((className.contains("Settings") || className.contains("FeatureFlag")) &&
(methodName.contains("getString") || methodName.contains("getInt") ||
methodName.contains("getLong") || methodName.contains("getFloat"))) {
Log.d(TAG, "System settings access detected, using system UID to prevent mismatch");
// Return a system UID to prevent SecurityException
return Process.SYSTEM_UID; // UID 1000
return Process.SYSTEM_UID;
}
}
} catch (Exception e) {
Log.w(TAG, "Error analyzing stack trace for UID resolution: " + e.getMessage());
}
// Fallback to host UID if calling BUid is invalid
return BlackBoxCore.getHostUid();
}
return origCallingUid;
} catch (Exception e) {
Log.e(TAG, "Error in getCallingUid: " + e.getMessage());
// Return a safe fallback UID
return Process.myUid();
}
}
@@ -150,18 +143,16 @@ public class NativeCore {
return new long[]{};
}
/**
* Create a fallback empty DEX when the main one fails
*/
private static long[] createFallbackEmptyDex() {
try {
Slog.d(TAG, "Creating fallback empty DEX");
// Create a minimal empty DEX file in memory
// This is a simplified approach that should work for most cases
byte[] emptyDexBytes = createMinimalDexBytes();
// Write to a temporary file
File tempDexFile = File.createTempFile("fallback_empty", ".dex");
tempDexFile.deleteOnExit();
@@ -169,7 +160,7 @@ public class NativeCore {
fos.write(emptyDexBytes);
fos.close();
// Load the temporary DEX file
DexFile dexFile = new DexFile(tempDexFile);
List<Long> cookies = DexFileCompat.getCookies(dexFile);
@@ -187,45 +178,43 @@ public class NativeCore {
Slog.e(TAG, "Error creating fallback empty DEX: " + e.getMessage());
}
// Last resort: return empty array
Slog.w(TAG, "Returning empty DEX array as last resort");
return new long[]{};
}
/**
* Create minimal DEX bytes for fallback
*/
private static byte[] createMinimalDexBytes() {
// This is a minimal valid DEX file structure
// In a real implementation, you would create a proper DEX file
// For now, we'll return a simple byte array that represents a minimal DEX
// Minimal DEX header (simplified)
byte[] dexHeader = {
'd', 'e', 'x', '\n', // Magic
0x30, 0x33, 0x35, 0x00, // Version
0x00, 0x00, 0x00, 0x00, // Checksum
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Signature
0x00, 0x00, 0x00, 0x00, // File size
0x70, 0x00, 0x00, 0x00, // Header size
0x00, 0x00, 0x00, 0x00, // Endian tag
0x00, 0x00, 0x00, 0x00, // Link size
0x00, 0x00, 0x00, 0x00, // Link offset
0x00, 0x00, 0x00, 0x00, // Map offset
0x00, 0x00, 0x00, 0x00, // String ids size
0x00, 0x00, 0x00, 0x00, // String ids offset
0x00, 0x00, 0x00, 0x00, // Type ids size
0x00, 0x00, 0x00, 0x00, // Type ids offset
0x00, 0x00, 0x00, 0x00, // Proto ids size
0x00, 0x00, 0x00, 0x00, // Proto ids offset
0x00, 0x00, 0x00, 0x00, // Field ids size
0x00, 0x00, 0x00, 0x00, // Field ids offset
0x00, 0x00, 0x00, 0x00, // Method ids size
0x00, 0x00, 0x00, 0x00, // Method ids offset
0x00, 0x00, 0x00, 0x00, // Class defs size
0x00, 0x00, 0x00, 0x00, // Class defs offset
0x00, 0x00, 0x00, 0x00, // Data size
0x00, 0x00, 0x00, 0x00 // Data offset
'd', 'e', 'x', '\n',
0x30, 0x33, 0x35, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x70, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
return dexHeader;
@@ -9,14 +9,7 @@ import java.util.List;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
/**
* updated by alex5402 on 4/21/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class AppSystemEnv {
private static final List<String> sSystemPackages = new ArrayList<>();
private static final List<String> sSuPackages = new ArrayList<>();
@@ -34,17 +27,17 @@ public class AppSystemEnv {
sSystemPackages.add("com.android.talkback");
sSystemPackages.add("com.miui.gallery");
// google Gboard
sSystemPackages.add("com.google.android.inputmethod.latin");
// sSystemPackages.add(BlackBoxCore.getHostPkg());
// 华为
sSystemPackages.add("com.huawei.webview");
// oppo
sSystemPackages.add("com.coloros.safecenter");
// su
sSuPackages.add("com.noshufou.android.su");
sSuPackages.add("com.noshufou.android.su.elite");
sSuPackages.add("eu.chainfire.supersu");
@@ -54,9 +47,9 @@ public class AppSystemEnv {
// sPreInstallPackages.add("com.huawei.hwid");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Build.VERSION.SDK_INT < 29){
//解决Android 9三星浏览器闪退问题
}else{
}
@@ -7,14 +7,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.utils.FileUtils;
/**
* updated by alex5402 on 4/22/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class BEnvironment {
private static final File sVirtualRoot = new File(BlackBoxCore.getContext().getCacheDir().getParent(), "blackbox");
private static final File sExternalVirtualRoot = BlackBoxCore.getContext().getExternalFilesDir("blackbox");
@@ -33,14 +33,7 @@ import top.niunaijun.blackbox.utils.compat.ApplicationThreadCompat;
import top.niunaijun.blackbox.utils.compat.BundleCompat;
import top.niunaijun.blackbox.utils.provider.ProviderCall;
/**
* updated by alex5402 on 4/2/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class BProcessManagerService implements ISystemService {
public static final String TAG = "BProcessManager";
@@ -95,7 +88,7 @@ public class BProcessManagerService implements ISystemService {
mProcessMap.put(buid, bProcess);
}
if (!initAppProcessL(app)) {
//init process fail
bProcess.remove(processName);
mPidsSelfLocked.remove(app);
app = null;
@@ -147,7 +140,7 @@ public class BProcessManagerService implements ISystemService {
try {
return Integer.parseInt(stubProcessName.substring(prefix.length()));
} catch (NumberFormatException e) {
// ignore
}
}
return -1;
@@ -29,14 +29,7 @@ import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.core.system.JarManager;
/**
* updated by alex5402 on 4/22/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class BlackBoxSystem {
private static BlackBoxSystem sBlackBoxSystem;
private final List<ISystemService> mServices = new ArrayList<>();
@@ -84,14 +77,10 @@ public class BlackBoxSystem {
} catch (PackageManager.NameNotFoundException ignored) {
}
}
// Initialize JAR environment using improved JarManager
JarManager.getInstance().initializeAsync();
// Test JAR manager functionality (can be removed in production)
/* try {
JarManagerTest.testConfiguration();
} catch (Exception e) {
Log.w("BlackBoxSystem", "JAR manager test failed", e);
}*/
}
}
@@ -15,10 +15,7 @@ import androidx.core.app.NotificationCompat;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
/**
* Enhanced DaemonService with proper foreground service support and error handling.
* Fixed for Android 14+ compatibility and proper notification setup.
*/
public class DaemonService extends Service {
public static final String TAG = "DaemonService";
private static final int NOTIFY_ID = BlackBoxCore.getHostPkg().hashCode();
@@ -36,7 +33,7 @@ public class DaemonService extends Service {
super.onCreate();
Log.d(TAG, "DaemonService onCreate");
// Create notification channel for Android 8.0+
if (BuildCompat.isOreo()) {
createNotificationChannel();
}
@@ -47,11 +44,11 @@ public class DaemonService extends Service {
Log.d(TAG, "DaemonService onStartCommand");
try {
// Start the inner service
Intent innerIntent = new Intent(this, DaemonInnerService.class);
startService(innerIntent);
// Start foreground service for Android 8.0+
if (BuildCompat.isOreo()) {
if (!startForegroundService()) {
Log.w(TAG, "Failed to start foreground service, falling back to regular service");
@@ -64,7 +61,7 @@ public class DaemonService extends Service {
} catch (Exception e) {
Log.e(TAG, "Error starting DaemonService: " + e.getMessage(), e);
// Return START_STICKY to allow the system to restart the service
return START_STICKY;
}
}
@@ -75,9 +72,7 @@ public class DaemonService extends Service {
super.onDestroy();
}
/**
* Create notification channel for Android 8.0+
*/
private void createNotificationChannel() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -102,9 +97,7 @@ public class DaemonService extends Service {
}
}
/**
* Start foreground service with proper notification
*/
private boolean startForegroundService() {
try {
Notification notification = createNotification();
@@ -122,9 +115,7 @@ public class DaemonService extends Service {
}
}
/**
* Create proper notification for foreground service
*/
private Notification createNotification() {
try {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
@@ -142,9 +133,7 @@ public class DaemonService extends Service {
}
}
/**
* Inner service to handle notification cancellation
*/
public static class DaemonInnerService extends Service {
@Override
public void onCreate() {
@@ -157,14 +146,14 @@ public class DaemonService extends Service {
Log.i(TAG, "DaemonInnerService -> onStartCommand");
try {
// Cancel the notification from the main service
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (nm != null) {
nm.cancel(NOTIFY_ID);
Log.d(TAG, "Notification cancelled successfully");
}
// Stop this inner service
stopSelf();
return START_NOT_STICKY;
@@ -1,13 +1,6 @@
package top.niunaijun.blackbox.core.system;
/**
* updated by alex5402 on 4/22/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public interface ISystemService {
void systemReady();
}
@@ -2,15 +2,10 @@ package top.niunaijun.blackbox.core.system;
import java.io.File;
/**
* Configuration class for JAR file management
* Centralizes JAR-related settings and requirements
*/
public class JarConfig {
/**
* JAR file definitions
*/
public static class JarDefinition {
private final String assetName;
private final String fileName;
@@ -33,7 +28,7 @@ public class JarConfig {
public boolean isRequired() { return required; }
}
// JAR file definitions
public static final JarDefinition EMPTY_JAR = new JarDefinition(
"empty.jar",
"empty.apk",
@@ -50,35 +45,31 @@ public class JarConfig {
false
);
// Performance settings
public static final int DEFAULT_BUFFER_SIZE = 8192; // 8KB
public static final int MAX_BUFFER_SIZE = 32768; // 32KB
public static final int MIN_BUFFER_SIZE = 1024; // 1KB
// Retry settings
public static final int DEFAULT_BUFFER_SIZE = 8192;
public static final int MAX_BUFFER_SIZE = 32768;
public static final int MIN_BUFFER_SIZE = 1024;
public static final int MAX_RETRY_ATTEMPTS = 3;
public static final long RETRY_DELAY_MS = 1000; // 1 second
public static final long MAX_RETRY_DELAY_MS = 5000; // 5 seconds
public static final long RETRY_DELAY_MS = 1000;
public static final long MAX_RETRY_DELAY_MS = 5000;
// Validation settings
public static final boolean ENABLE_FILE_HASHING = true;
public static final boolean ENABLE_SIZE_VALIDATION = true;
public static final boolean ENABLE_ASYNC_LOADING = true;
// Cache settings
public static final int MAX_CACHE_SIZE = 10;
public static final long CACHE_CLEANUP_INTERVAL_MS = 300000; // 5 minutes
/**
* Get all required JAR definitions
*/
public static final int MAX_CACHE_SIZE = 10;
public static final long CACHE_CLEANUP_INTERVAL_MS = 300000;
public static JarDefinition[] getRequiredJars() {
return new JarDefinition[]{EMPTY_JAR, JUNIT_JAR};
}
/**
* Get JAR definition by asset name
*/
public static JarDefinition getJarDefinition(String assetName) {
for (JarDefinition jar : getRequiredJars()) {
if (jar.getAssetName().equals(assetName)) {
@@ -88,9 +79,7 @@ public class JarConfig {
return null;
}
/**
* Validate file against JAR definition
*/
public static boolean validateFile(File file, JarDefinition definition) {
if (file == null || !file.exists()) {
return false;
@@ -103,17 +92,15 @@ public class JarConfig {
return true;
}
/**
* Get optimal buffer size based on available memory
*/
public static int getOptimalBufferSize() {
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
// Use larger buffer for devices with more memory
if (maxMemory > 512 * 1024 * 1024) { // > 512MB
if (maxMemory > 512 * 1024 * 1024) {
return MAX_BUFFER_SIZE;
} else if (maxMemory > 256 * 1024 * 1024) { // > 256MB
} else if (maxMemory > 256 * 1024 * 1024) {
return DEFAULT_BUFFER_SIZE;
} else {
return MIN_BUFFER_SIZE;
@@ -14,19 +14,16 @@ import top.niunaijun.blackbox.core.env.BEnvironment;
import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.JarUtils;
/**
* Improved JAR file manager for BlackBox system
* Handles JAR file operations with better error handling, caching, and performance
*/
public class JarManager {
private static final String TAG = "JarManager";
// JAR file configurations
private static final JarConfig.JarDefinition[] REQUIRED_JARS = JarConfig.getRequiredJars();
private static final int BUFFER_SIZE = JarUtils.getOptimalBufferSize();
private static final long MAX_RETRY_DELAY = JarConfig.MAX_RETRY_DELAY_MS;
// Caching and state management
private final ConcurrentHashMap<String, File> mJarCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, String> mJarHashes = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, JarConfig.JarDefinition> mJarDefinitions = new ConcurrentHashMap<>();
@@ -48,9 +45,7 @@ public class JarManager {
private JarManager() {}
/**
* Initialize JAR environment asynchronously
*/
public void initializeAsync() {
if (mIsInitialized.get() || mIsInitializing.getAndSet(true)) {
return;
@@ -69,9 +64,7 @@ public class JarManager {
}, "JarManager-Init").start();
}
/**
* Initialize JAR environment synchronously
*/
public void initializeSync() {
if (mIsInitialized.get()) {
return;
@@ -87,16 +80,12 @@ public class JarManager {
}
}
/**
* Check if JAR environment is ready
*/
public boolean isReady() {
return mIsInitialized.get();
}
/**
* Get JAR file with verification
*/
public File getJarFile(String jarName) {
if (!mIsInitialized.get()) {
Log.w(TAG, "JAR environment not initialized, attempting sync initialization");
@@ -112,23 +101,17 @@ public class JarManager {
return null;
}
/**
* Get empty.jar file
*/
public File getEmptyJar() {
return getJarFile("empty.jar");
}
/**
* Get junit.jar file
*/
public File getJunitJar() {
return getJarFile("junit.jar");
}
/**
* Initialize JAR environment with improved error handling
*/
private void initializeJarEnvironment() {
Context context = BlackBoxCore.getContext();
if (context == null) {
@@ -142,41 +125,39 @@ public class JarManager {
processJarFile(context, jarDef);
} catch (Exception e) {
Log.e(TAG, "Failed to process JAR file: " + jarDef.getAssetName(), e);
// Continue with other JARs, don't fail completely
}
}
// Verify all required JARs are available
verifyJarEnvironment();
}
/**
* Process individual JAR file with integrity checking
*/
private void processJarFile(Context context, JarConfig.JarDefinition jarDef) throws IOException {
String jarName = jarDef.getAssetName();
Log.d(TAG, "Processing JAR file: " + jarName + " (" + jarDef.getDescription() + ")");
// Store jar definition
mJarDefinitions.put(jarName, jarDef);
// Get target file path
File targetFile = getTargetFile(jarDef);
if (targetFile == null) {
throw new IOException("Invalid JAR definition: " + jarName);
}
// Check if file already exists and is valid
if (targetFile.exists() && isFileValid(targetFile, jarDef)) {
Log.d(TAG, "JAR file already exists and is valid: " + jarName);
mJarCache.put(jarName, targetFile);
return;
}
// Copy file from assets
copyJarFromAssets(context, jarDef, targetFile);
// Verify copied file
if (!isFileValid(targetFile, jarDef)) {
throw new IOException("JAR file verification failed: " + jarName);
}
@@ -185,33 +166,29 @@ public class JarManager {
Log.d(TAG, "Successfully processed JAR file: " + jarName);
}
/**
* Get target file path for JAR
*/
private File getTargetFile(JarConfig.JarDefinition jarDef) {
return new File(BEnvironment.getCacheDir(), jarDef.getFileName());
}
/**
* Copy JAR file from assets with improved error handling
*/
private void copyJarFromAssets(Context context, JarConfig.JarDefinition jarDef, File targetFile) throws IOException {
String jarName = jarDef.getAssetName();
InputStream inputStream = null;
try {
// Open asset stream
inputStream = context.getAssets().open(jarName);
if (inputStream == null) {
throw new IOException("Asset not found: " + jarName);
}
// Ensure target directory exists
File targetDir = targetFile.getParentFile();
if (!targetDir.exists() && !targetDir.mkdirs()) {
throw new IOException("Failed to create target directory: " + targetDir);
}
// Copy file with progress tracking using JarUtils
JarUtils.copyFileWithProgress(inputStream, targetFile, jarName);
} finally {
@@ -227,9 +204,7 @@ public class JarManager {
/**
* Verify file integrity and validity
*/
private boolean isFileValid(File file, JarConfig.JarDefinition jarDef) {
if (!file.exists()) {
Log.w(TAG, "File does not exist: " + file);
@@ -241,14 +216,14 @@ public class JarManager {
return false;
}
// Use configuration-based validation
if (!JarConfig.validateFile(file, jarDef)) {
Log.w(TAG, "File validation failed for " + jarDef.getAssetName() +
" (size: " + file.length() + ", min: " + jarDef.getMinSize() + ")");
return false;
}
// Calculate and store file hash for future verification
if (JarConfig.ENABLE_FILE_HASHING) {
String fileHash = JarUtils.calculateFileHash(file);
if (fileHash != null) {
@@ -261,9 +236,7 @@ public class JarManager {
/**
* Verify JAR environment completeness
*/
private void verifyJarEnvironment() {
boolean allValid = true;
@@ -287,9 +260,7 @@ public class JarManager {
}
}
/**
* Clear JAR cache (useful for testing or memory management)
*/
public void clearCache() {
mJarCache.clear();
mJarHashes.clear();
@@ -297,17 +268,13 @@ public class JarManager {
Log.d(TAG, "JAR cache cleared");
}
/**
* Get cache statistics
*/
public String getCacheStats() {
return String.format("JAR Cache Stats - Files: %d, Hashes: %d, Definitions: %d, Initialized: %s",
mJarCache.size(), mJarHashes.size(), mJarDefinitions.size(), mIsInitialized.get());
}
/**
* Get detailed JAR information
*/
public String getJarInfo(String jarName) {
File jarFile = mJarCache.get(jarName);
JarConfig.JarDefinition jarDef = mJarDefinitions.get(jarName);
@@ -2,45 +2,40 @@ package top.niunaijun.blackbox.core.system;
import android.util.Log;
/**
* Simple test class for JarManager improvements
* This can be used to verify the JAR management system works correctly
*/
public class JarManagerTest {
private static final String TAG = "JarManagerTest";
/**
* Test JAR manager functionality
*/
public static void testJarManager() {
Log.i(TAG, "Starting JAR Manager test");
try {
JarManager jarManager = JarManager.getInstance();
// Test async initialization
Log.d(TAG, "Testing async initialization");
jarManager.initializeAsync();
// Wait a bit for async initialization
Thread.sleep(2000);
// Test sync initialization if needed
if (!jarManager.isReady()) {
Log.d(TAG, "Async initialization not complete, trying sync");
jarManager.initializeSync();
}
// Test JAR file retrieval
Log.d(TAG, "Testing JAR file retrieval");
testJarFileRetrieval(jarManager);
// Test cache statistics
Log.d(TAG, "Testing cache statistics");
String stats = jarManager.getCacheStats();
Log.i(TAG, "Cache stats: " + stats);
// Test individual JAR info
Log.d(TAG, "Testing individual JAR info");
String emptyJarInfo = jarManager.getJarInfo("empty.jar");
String junitJarInfo = jarManager.getJarInfo("junit.jar");
@@ -55,25 +50,23 @@ public class JarManagerTest {
}
}
/**
* Test JAR file retrieval
*/
private static void testJarFileRetrieval(JarManager jarManager) {
// Test empty.jar
if (jarManager.getEmptyJar() != null) {
Log.d(TAG, "Empty JAR retrieved successfully");
} else {
Log.w(TAG, "Empty JAR retrieval failed");
}
// Test junit.jar
if (jarManager.getJunitJar() != null) {
Log.d(TAG, "JUnit JAR retrieved successfully");
} else {
Log.w(TAG, "JUnit JAR retrieval failed");
}
// Test generic retrieval
if (jarManager.getJarFile("empty.jar") != null) {
Log.d(TAG, "Generic JAR retrieval for empty.jar successful");
} else {
@@ -81,13 +74,11 @@ public class JarManagerTest {
}
}
/**
* Test configuration
*/
public static void testConfiguration() {
Log.i(TAG, "Testing JAR configuration");
// Test JAR definitions
JarConfig.JarDefinition[] jars = JarConfig.getRequiredJars();
Log.d(TAG, "Found " + jars.length + " JAR definitions");
@@ -99,11 +90,11 @@ public class JarManagerTest {
", Description: " + jar.getDescription());
}
// Test buffer size calculation
int bufferSize = JarConfig.getOptimalBufferSize();
Log.d(TAG, "Optimal buffer size: " + bufferSize + " bytes");
// Test file validation
boolean enableValidation = JarConfig.ENABLE_SIZE_VALIDATION;
boolean enableHashing = JarConfig.ENABLE_FILE_HASHING;
boolean enableAsync = JarConfig.ENABLE_ASYNC_LOADING;
@@ -16,14 +16,7 @@ import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
import top.niunaijun.blackbox.core.system.user.BUserManagerService;
/**
* updated by alex5402 on 3/31/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class ServiceManager {
private static ServiceManager sServiceManager = null;
public static final String ACTIVITY_MANAGER = "activity_manager";
@@ -13,14 +13,7 @@ import androidx.annotation.Nullable;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.compat.BundleCompat;
/**
* updated by alex5402 on 3/31/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class SystemCallProvider extends ContentProvider {
public static final String TAG = "SystemCallProvider";
@@ -70,7 +63,7 @@ public class SystemCallProvider extends ContentProvider {
return super.call(method, arg, extras);
} catch (Exception e) {
Slog.e(TAG, "Error in SystemCallProvider call method: " + method, e);
// Return a bundle with error information
Bundle errorBundle = new Bundle();
errorBundle.putString("error", e.getMessage());
return errorBundle;
@@ -7,9 +7,7 @@ import android.os.Parcelable;
import java.util.HashMap;
import java.util.LinkedHashMap;
/**
* Created by BlackBox on 2022/3/3.
*/
public class BAccount implements Parcelable {
public Account account;
public String password;
@@ -70,9 +70,7 @@ import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.compat.AccountManagerCompat;
/**
* Created by BlackBox on 2022/3/3.
*/
@SuppressLint("InlinedApi")
public class BAccountManagerService extends IBAccountManagerService.Stub implements ISystemService , PackageMonitor {
private static final String TAG = "AccountManagerService";
@@ -81,7 +79,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
// Messages that can be sent on mHandler
private static final int MESSAGE_TIMED_OUT = 3;
private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
@@ -201,7 +199,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public AuthenticatorDescription[] getAuthenticatorTypes(int userId) throws RemoteException {
// Only allow the system process to read accounts of other users
BUserAccounts userAccounts = getUserAccounts(userId);
List<AuthenticatorDescription> authenticatorDescriptions = new ArrayList<>();
synchronized (userAccounts.lock) {
@@ -217,7 +215,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public Account[] getAccountsForPackage(String packageName, int uid, int userId) throws RemoteException {
// Only allow the system process to read accounts of other users
BUserAccounts userAccounts = getUserAccounts(userId);
List<Account> accounts = new ArrayList<>();
synchronized (userAccounts.lock) {
@@ -233,7 +231,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public Account[] getAccountsByTypeForPackage(String type, String packageName, int userId) throws RemoteException {
// Only allow the system process to read accounts of other users
BUserAccounts userAccounts = getUserAccounts(userId);
List<Account> accounts = new ArrayList<>();
synchronized (userAccounts.lock) {
@@ -274,7 +272,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (ArrayUtils.isEmpty(features)) {
Account[] accountsWithManagedNotVisible = getAccountsFromCache(
userAccounts, accountType, opPackageName,
true /* include managed not visible */);
true );
handleGetAccountsResult(
response, accountsWithManagedNotVisible, opPackageName, userId);
return;
@@ -297,7 +295,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void onError(int errorCode, String errorMessage)
throws RemoteException {
// Will not be called in this case.
}
};
new GetAccountsByTypeAndFeatureSession(
@@ -307,7 +305,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
features,
userId,
opPackageName,
true /* include managed not visible */).bind();
true ).bind();
}
@Override
@@ -316,7 +314,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (type == null) throw new IllegalArgumentException("accountType is null");
String opPackageName = getCallingPackageName();
// check visibleAccountTypes
BUserAccounts userAccounts = getUserAccounts(userId);
if (features == null || features.length == 0) {
Account[] accounts = getAccountsFromCache(userAccounts, type,
@@ -333,7 +331,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
features,
userId,
opPackageName,
false /* include managed not visible */).bind();
false ).bind();
}
@Override
@@ -345,12 +343,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
public void removeAccountAsUser(IAccountManagerResponse response, Account account, boolean expectActivityLaunch, int userId) throws RemoteException {
Preconditions.checkArgument(account != null, "account cannot be null");
Preconditions.checkArgument(response != null, "response cannot be null");
// Only allow the system process to modify accounts of other users
/*
* Only the system, authenticator or profile owner should be allowed to remove accounts for
* that authenticator. This will let users remove accounts (via Settings in the system) but
* not arbitrary applications (like competing authenticators).
*/
BUserAccounts accounts = getUserAccounts(userId);
new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
}
@@ -364,10 +358,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
+ ", pid " + Binder.getCallingPid());
}
if (account == null) {
/*
* Null accounts should result in returning false, as per
* AccountManage.addAccountExplicitly(...) java doc.
*/
Log.e(TAG, "account is null");
return false;
}
@@ -395,8 +386,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
Slog.d(TAG, "Copying account " + account.toString()
+ " from user " + userFrom + " to user " + userTo);
new Session(fromAccounts, response, account.type, false,
false /* stripAuthTokenFromResult */, account.name,
false /* authDetailsRequired */) {
false , account.name,
false ) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountCredentialsForClone"
@@ -412,7 +403,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
public void onResult(Bundle result) {
if (result != null
&& result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
// Create a Session for the target user and pass in the bundle
completeCloningAccount(response, result, account, toAccounts, userFrom);
} else {
super.onResult(result);
@@ -518,7 +509,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) throws RemoteException {
// system
}
@Override
@@ -545,10 +536,10 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
final boolean customTokens =
authenticatorInfo != null && authenticatorInfo.desc.customTokens;
// Get the calling package. We will use it for the purpose of caching.
final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
// let authenticator know the identity of the caller
loginOptions.putInt(AccountManager.KEY_CALLER_UID, Binder.getCallingUid());
loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
@@ -556,8 +547,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
loginOptions.putBoolean(AccountManagerCompat.KEY_NOTIFY_ON_FAILURE, true);
}
// if the caller has permission, do the peek. otherwise go the more expensive
// route of starting a Session
if (!customTokens) {
String authToken = readAuthTokenInternal(accounts, account, authTokenType);
if (authToken != null) {
@@ -571,11 +562,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
if (customTokens) {
/*
* Look up tokens in the new cache only if the loginOptions don't have parameters
* outside of those expected to be injected by the AccountManager, e.g.
* ANDORID_PACKAGE_NAME.
*/
String token = readCachedTokenInternal(
accounts,
account,
@@ -599,9 +586,9 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
response,
account.type,
expectActivityLaunch,
false /* stripAuthTokenFromResult */,
false ,
account.name,
false /* authDetailsRequired */) {
false ) {
@Override
protected String toDebugString(long now) {
if (loginOptions != null) loginOptions.keySet();
@@ -614,8 +601,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void run() throws RemoteException {
// If the caller doesn't have permission then create and return the
// "grant permission" intent instead of the "getAuthToken" intent.
mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
}
@@ -655,11 +642,11 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
if (intent != null && notifyOnAuthFailure && !customTokens) {
// doNotification(
// mAccounts,
// account,
// result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
// intent, "android", accounts.userId);
}
}
super.onResult(result);
@@ -672,16 +659,16 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
// final int pid = Binder.getCallingPid();
// final int uid = Binder.getCallingUid();
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
// options.putInt(AccountManager.KEY_CALLER_UID, uid);
// options.putInt(AccountManager.KEY_CALLER_PID, pid);
BUserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
true , null ,
false , true ) {
@Override
public void run() throws RemoteException {
mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
@@ -699,7 +686,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void addAccountAsUser(IAccountManagerResponse response, String accountType, String authTokenType, String[] requiredFeatures, boolean expectActivityLaunch, Bundle options, int userId) throws RemoteException {
// ignore
}
@Override
@@ -709,8 +696,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
long identityToken = clearCallingIdentity();
BUserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, account.type, expectActivityLaunch,
true /* stripAuthTokenFromResult */, account.name,
false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
true , account.name,
false , true ) {
@Override
public void run() throws RemoteException {
mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
@@ -733,8 +720,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
BUserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */) {
true , null ,
false ) {
@Override
public void run() throws RemoteException {
mAuthenticator.editProperties(this, mAccountType);
@@ -749,7 +736,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void confirmCredentialsAsUser(IAccountManagerResponse response, Account account, Bundle options, boolean expectActivityLaunch, int userId) throws RemoteException {
// ignore
}
@Override
@@ -765,13 +752,13 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
public void getAuthTokenLabel(IAccountManagerResponse response, String accountType, String authTokenType, int userId) throws RemoteException {
Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
// if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
// throw new SecurityException("can only call from system");
// }
BUserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, accountType, false /* expectActivityLaunch */,
false /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */) {
new Session(accounts, response, accountType, false ,
false , null ,
false ) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAuthTokenLabel"
@@ -855,7 +842,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
String authTokenType) {
if (accounts == null)
return null;
// If not cached yet - do slow path and sync with db if necessary
synchronized (accounts.lock) {
Map<String, String> authToken = accounts.getAuthToken(account);
return authToken.get(authTokenType);
@@ -866,8 +853,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
final Bundle accountCredentials, final Account account, final BUserAccounts targetUser,
final int parentUserId){
new Session(targetUser, response, account.type, false,
false /* stripAuthTokenFromResult */, account.name,
false /* authDetailsRequired */) {
false , account.name,
false ) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountCredentialsForClone"
@@ -876,7 +863,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void run() throws RemoteException {
// Confirm that the owner's account still exists before this step.
for (Account acc : getAccounts(parentUserId, mContext.getPackageName())) {
if (acc.equals(account)) {
mAuthenticator.addAccountFromCredentials(
@@ -888,10 +875,10 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void onResult(Bundle result) {
// TODO: Anything to do if if succedded?
// TODO: If it failed: Show error notification? Should we remove the shadow
// account to avoid retries?
// TODO: what we do with the visibility?
super.onResult(result);
}
@@ -899,8 +886,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void onError(int errorCode, String errorMessage) {
super.onError(errorCode, errorMessage);
// TODO: Show error notification to user
// TODO: Should we remove the shadow account so that it doesn't keep trying?
}
}.bind();
@@ -915,13 +902,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Bundle extras, Map packageToVisibility, int userId) {
/*
* Child users are not allowed to add accounts. Only the accounts that are shared by the
* parent profile can be added to child profile.
*
* TODO: Only allow accounts that were shared to be added by a limited user.
*/
// fails if the account already exists
BUserAccounts accounts = getUserAccounts(userId);
return addAccountInternal(accounts, account, password, extras,
(Map<String, Integer>) packageToVisibility);
@@ -1009,8 +991,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (packageToVisibility != null) {
for (Map.Entry<String, Integer> entry : packageToVisibility.entrySet()) {
setAccountVisibility(account, entry.getKey() /* package */,
entry.getValue() /* visibility */,
setAccountVisibility(account, entry.getKey() ,
entry.getValue() ,
accounts);
}
}
@@ -1079,22 +1061,15 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
firstPass.put(account, visibility);
}
}
// Map<Account, Integer> secondPass =
// filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
//
// Account[] filtered = new Account[secondPass.size()];
// filtered = secondPass.keySet().toArray(filtered);
return firstPass.keySet().toArray(new Account[]{});
}
/**
* Method which handles default values for Account visibility.
*
* @param account The account to check visibility.
* @param packageName Package name to check visibility
* @param accounts UserAccount that currently hosts the account and application
* @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
*/
private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
BUserAccounts accounts) {
if (accounts == null) {
@@ -1105,7 +1080,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
return AccountManager.VISIBILITY_NOT_VISIBLE;
}
// Return stored value if it was set.
int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
return visibility;
@@ -1113,14 +1088,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
return AccountManager.VISIBILITY_NOT_VISIBLE;
}
/**
* Method returns visibility for given account and package name.
*
* @param account The account to check visibility.
* @param packageName Package name to check visibility.
* @param accounts UserAccount that currently hosts the account and application
* @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
*/
private int getAccountVisibilityFromCache(Account account, String packageName,
BUserAccounts accounts) {
synchronized (accounts.lock) {
@@ -1144,7 +1112,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
int userId) {
if (needToStartChooseAccountActivity(accounts, callingPackage, userId)) {
// startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
return;
}
if (accounts.length == 1) {
@@ -1154,7 +1122,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
onResult(response, bundle);
return;
}
// No qualified account exists, return an empty Bundle.
onResult(response, new Bundle());
}
@@ -1223,8 +1191,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
public RemoveAccountSession(BUserAccounts accounts, IAccountManagerResponse response,
Account account, boolean expectActivityLaunch) {
super(accounts, response, account.type, expectActivityLaunch,
true /* stripAuthTokenFromResult */, account.name,
false /* authDetailsRequired */);
true , account.name,
false );
mAccount = account;
}
@@ -1281,9 +1249,9 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
int userId,
String packageName,
boolean includeManagedNotVisible) {
super(accounts, response, type, false /* expectActivityLaunch */,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */);
super(accounts, response, type, false ,
true , null ,
false );
mUserId = userId;
mFeatures = features;
mPackageName = packageName;
@@ -1293,7 +1261,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void run() throws RemoteException {
mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType, mPackageName, mIncludeManagedNotVisible);
// check whether each account matches the requested features
mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
mCurrentAccount = 0;
@@ -1308,10 +1276,10 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
final IAccountAuthenticator accountAuthenticator = mAuthenticator;
if (accountAuthenticator == null) {
// It is possible that the authenticator has died, which is indicated by
// mAuthenticator being set to null. If this happens then just abort.
// There is no need to send back a result or error in this case since
// that already happened when mAuthenticator was cleared.
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "checkAccount: aborting session since we are no longer"
+ " connected to the authenticator, " + toDebugString());
@@ -1355,7 +1323,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
response.onResult(result);
} catch (RemoteException e) {
// if the caller is dead then there is no one to care about remote exceptions
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "failure while notifying response", e);
}
@@ -1426,7 +1394,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
AttributeSet attributeSet = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
// Nothing to do
}
if (AccountManager.AUTHENTICATOR_ATTRIBUTES_NAME.equals(parser.getName())) {
AuthenticatorDescription desc = parseAuthenticatorDescription(
@@ -1450,12 +1418,12 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
final boolean mExpectActivityLaunch;
final long mCreationTime;
final String mAccountName;
// Indicates if we need to add auth details(like last credential time)
final boolean mAuthDetailsRequired;
// If set, we need to update the last authenticated time. This is
// currently
// used on
// successful confirming credentials.
final boolean mUpdateLastAuthenticatedTime;
public int mNumResults = 0;
@@ -1471,14 +1439,14 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
boolean authDetailsRequired) {
this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
accountName, authDetailsRequired, false );
}
public Session(BUserAccounts accounts, IAccountManagerResponse response, String accountType,
boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
super();
//if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
mAccounts = accounts;
mStripAuthTokenFromResult = stripAuthTokenFromResult;
@@ -1495,7 +1463,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
if (response != null) {
try {
response.asBinder().linkToDeath(this, 0 /* flags */);
response.asBinder().linkToDeath(this, 0 );
} catch (RemoteException e) {
mResponse = null;
binderDied();
@@ -1505,25 +1473,18 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
IAccountManagerResponse getResponseAndClose() {
if (mResponse == null) {
// this session has already been closed
return null;
}
IAccountManagerResponse response = mResponse;
close(); // this clears mResponse so we need to save the response before this call
close();
return response;
}
/**
* Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
* security policy.
* <p>
* In particular we want to make sure that the Authenticator doesn't try to trick users
* into launching arbitrary intents on the device via by tricking to click authenticator
* supplied entries in the system Settings app.
*/
protected boolean checkKeyIntent(int authUid, Intent intent) {
// Explicitly set an empty ClipData to ensure that we don't offer to
// promote any Uris contained inside for granting purposes
if (intent.getClipData() == null) {
intent.setClipData(ClipData.newPlainText(null, null));
}
@@ -1537,7 +1498,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (resolveInfo == null) {
return false;
}
// check hasSignatureCapability
return true;
} finally {
Binder.restoreCallingIdentity(bid);
@@ -1547,15 +1508,15 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
private void close() {
synchronized (mSessions) {
if (mSessions.remove(toString()) == null) {
// the session was already closed, so bail out now
return;
}
}
if (mResponse != null) {
// stop listening for response deaths
mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
mResponse.asBinder().unlinkToDeath(this, 0 );
// clear this so that we don't accidentally send any further results
mResponse = null;
}
cancelTimeout();
@@ -1656,9 +1617,9 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
boolean isSuccessfulUpdateCredsOrAddAccount =
result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
&& result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
// We should only update lastAuthenticated time, if
// mUpdateLastAuthenticatedTime is true and the confirmRequest
// or updateRequest was successful
boolean needUpdate = mUpdateLastAuthenticatedTime
&& (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
if (needUpdate || mAuthDetailsRequired) {
@@ -1694,8 +1655,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
Account account = new Account(accountName, accountType);
// cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
// new UserHandle(mAccounts.userId));
}
}
IAccountManagerResponse response;
@@ -1724,7 +1685,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
(intent == null)) {
// All AccountManager error codes are greater than 0
response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
result.getString(AccountManager.KEY_ERROR_MESSAGE));
} else {
@@ -1732,7 +1693,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
}
} catch (RemoteException e) {
// if the caller is dead then there is no one to care about remote exceptions
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "failure while notifying response", e);
}
@@ -1768,10 +1729,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
}
/**
* find the component name for the authenticator and initiate a bind
* if no authenticator or the bind fails then return false, otherwise return true
*/
private boolean bindToAuthenticator(String authenticatorType) {
AuthenticatorInfo authenticatorInfo = mAuthenticatorCache.authenticators.get(authenticatorType);
if (authenticatorInfo == null) {
@@ -1782,27 +1740,27 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
return false;
}
// if (!isLocalUnlockedUser(mAccounts.userId)
// && !authenticatorInfo.componentInfo.directBootAware) {
// Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
// + " which isn't encryption aware");
// return false;
// }
Intent intent = new Intent();
intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
ComponentName componentName = new ComponentName(authenticatorInfo.serviceInfo.packageName, authenticatorInfo.serviceInfo.name);
intent.setComponent(componentName);
// call userId
intent.putExtra("_B_|_UserId", mAccounts.userId);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "performing bindService to " + componentName);
}
int flags = Context.BIND_AUTO_CREATE;
// if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) {
// flags |= Context.BIND_ALLOW_INSTANT;
// }
if (!mContext.bindService(intent, this, flags)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "bindService to " + componentName + " failed");
@@ -1825,8 +1783,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
try {
response.onResult(result);
} catch (RemoteException e) {
// if the caller is dead then there is no one to care about remote
// exceptions
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "failure while notifying response", e);
}
@@ -9,9 +9,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by BlackBox on 2022/3/3.
*/
public class BUserAccounts implements Parcelable {
public final Object lock = new Object();
@@ -4,9 +4,7 @@ import android.accounts.Account;
import java.util.Objects;
/**
* Created by BlackBox on 2022/3/3.
*/
public class TokenCache {
public int userId;
public Account account;
@@ -28,14 +28,7 @@ import top.niunaijun.blackbox.entity.am.RunningServiceInfo;
import top.niunaijun.blackbox.proxy.ProxyManifest;
import top.niunaijun.blackbox.proxy.record.ProxyServiceRecord;
/**
* updated by alex5402 on 4/7/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
@SuppressLint("NewApi")
public class ActiveServices {
public static final String TAG = "ActiveServices";
@@ -48,7 +41,7 @@ public class ActiveServices {
ResolveInfo resolveInfo = resolveService(intent, resolvedType, userId);
if (resolveInfo == null)
return;
// throw new RuntimeException("resolveService service exception");
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
ProcessRecord processRecord = BProcessManagerService.get().startProcessLocked(serviceInfo.packageName, serviceInfo.processName, userId, -1, Binder.getCallingPid());
if (processRecord == null) {
@@ -72,7 +65,7 @@ public class ActiveServices {
}
public int stopService(Intent intent, String resolvedType, int userId) {
// ResolveInfo resolveInfo = resolveService(intent, resolvedType, userId);
synchronized (mRunningServiceRecords) {
RunningServiceRecord runningServiceRecord = findRunningServiceRecord(intent);
if (runningServiceRecord == null) {
@@ -275,10 +268,10 @@ public class ActiveServices {
}
public static class RunningServiceRecord extends IEmpty.Stub {
// onStartCommand startId
private final AtomicInteger mStartId = new AtomicInteger(1);
private final AtomicInteger mBindCount = new AtomicInteger(0);
// 正在连接的服务
private ConnectedServiceRecord mConnectedServiceRecord;
private ServiceInfo mServiceInfo;
@@ -9,14 +9,7 @@ import android.os.IBinder;
import top.niunaijun.blackbox.core.system.ProcessRecord;
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class ActivityRecord extends Binder {
public TaskRecord task;
public IBinder token;
@@ -43,14 +43,7 @@ import top.niunaijun.blackbox.utils.compat.ActivityManagerCompat;
import static android.content.pm.PackageManager.GET_ACTIVITIES;
/**
* updated by alex5402 on 4/5/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
@SuppressWarnings({"deprecation", "unchecked"})
public class ActivityStack {
public static final String TAG = "ActivityStack";
@@ -144,11 +137,11 @@ public class ActivityStack {
break;
}
// 如果还没有task则新启动一个task
if (taskRecord == null || taskRecord.needNewTask()) {
return startActivityInNewTaskLocked(userId, intent, activityInfo, resultTo, launchModeFlags);
}
// 移至前台
mAms.moveTaskToFront(taskRecord.id, 0);
boolean notStartToFront = false;
@@ -170,7 +163,7 @@ public class ActivityStack {
if (clearTop) {
if (targetActivityRecord != null) {
// 目标栈上面所有activity出栈
synchronized (targetActivityRecord.task.activities) {
for (int i = targetActivityRecord.task.activities.size() - 1; i >= 0; i--) {
ActivityRecord next = targetActivityRecord.task.activities.get(i);
@@ -181,7 +174,7 @@ public class ActivityStack {
if (singleTop) {
newIntentRecord = targetActivityRecord;
} else {
// clearTop并且不是singleTop,目标也finish,重建。
targetActivityRecord.finished = true;
}
break;
@@ -198,7 +191,7 @@ public class ActivityStack {
synchronized (mLaunchingActivities) {
for (ActivityRecord launchingActivity : mLaunchingActivities) {
if (!launchingActivity.finished && launchingActivity.component.equals(intent.getComponent())) {
// todo update onNewIntent from intent
ignore = true;
}
}
@@ -212,9 +205,9 @@ public class ActivityStack {
} else {
ActivityRecord record = findActivityRecordByComponentName(userId, ComponentUtils.toComponentName(activityInfo));
if (record != null) {
// 需要调用目标onNewIntent
newIntentRecord = record;
// 目标栈上面所有activity出栈
synchronized (taskRecord.activities) {
for (int i = taskRecord.activities.size() - 1; i >= 0; i--) {
ActivityRecord next = taskRecord.activities.get(i);
@@ -233,17 +226,17 @@ public class ActivityStack {
newIntentRecord = topActivityRecord;
}
// clearTask finish All
if (clearTask && newTask) {
for (ActivityRecord activity : taskRecord.activities) {
activity.finished = true;
}
finishAllActivity(userId);
}
// Do NOT call finishAllActivity(userId) unless clearTask is true
if (newIntentRecord != null) {
// 通知onNewIntent
deliverNewIntentLocked(newIntentRecord, intent);
return 0;
} else if (ignore) {
@@ -30,14 +30,7 @@ import top.niunaijun.blackbox.utils.Slog;
import static android.content.pm.PackageManager.GET_META_DATA;
/**
* updated by alex5402 on 3/31/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class BActivityManagerService extends IBActivityManagerService.Stub implements ISystemService {
public static final String TAG = "BActivityManagerService";
private static final BActivityManagerService sService = new BActivityManagerService();
@@ -22,18 +22,11 @@ import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
import top.niunaijun.blackbox.entity.JobRecord;
import top.niunaijun.blackbox.proxy.ProxyManifest;
/**
* updated by alex5402 on 4/2/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*
*/
public class BJobManagerService extends IBJobManagerService.Stub implements ISystemService {
private static final BJobManagerService sService = new BJobManagerService();
// process_jobId
private final Map<String, JobRecord> mJobRecords = new HashMap<>();
public static BJobManagerService get() {
@@ -83,7 +76,7 @@ public class BJobManagerService extends IBJobManagerService.Stub implements ISys
for (String key : mJobRecords.keySet()) {
if (key.startsWith(processName + "_")) {
JobRecord jobRecord = mJobRecords.get(key);
// todo
}
}
}
@@ -21,9 +21,7 @@ import top.niunaijun.blackbox.entity.am.PendingResultData;
import top.niunaijun.blackbox.proxy.ProxyBroadcastReceiver;
import top.niunaijun.blackbox.utils.Slog;
/**
* Created by BlackBox on 2022/2/28.
*/
public class BroadcastManager implements PackageMonitor {
public static final String TAG = "BroadcastManager";
@@ -109,7 +107,7 @@ public class BroadcastManager implements PackageMonitor {
public void sendBroadcast(PendingResultData pendingResultData) {
synchronized (mReceiversData) {
// Slog.d(TAG, "sendBroadcast: " + pendingResultData);
mReceiversData.put(pendingResultData.mBToken, pendingResultData);
Message obtain = Message.obtain(mHandler, MSG_TIME_OUT, pendingResultData);
mHandler.sendMessageDelayed(obtain, TIMEOUT);
@@ -118,7 +116,7 @@ public class BroadcastManager implements PackageMonitor {
public void finishBroadcast(PendingResultData data) {
synchronized (mReceiversData) {
// Slog.d(TAG, "finishBroadcast: " + data);
mHandler.removeMessages(MSG_TIME_OUT, mReceiversData.get(data.mBToken));
}
}
@@ -2,9 +2,7 @@ package top.niunaijun.blackbox.core.system.am;
import java.util.Objects;
/**
* Created by BlackBox on 2022/3/8.
*/
public class PendingIntentRecord {
public int uid;
public String packageName;

Some files were not shown because too many files have changed in this diff Show More