mirror of
https://github.com/QM4RS/FridaBox.git
synced 2026-10-15 04:12:20 +02:00
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:
+6
-8
@@ -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
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
//
|
||||
// updated by alex5402 on 4/10/21.
|
||||
//
|
||||
|
||||
#include "BaseHook.h"
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// updated by alex5402 on 4/25/21.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
#include "BinderHook.h"
|
||||
#include <IO.h>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -11,4 +11,4 @@ public:
|
||||
};
|
||||
|
||||
|
||||
#endif //BLACKBOX2_DEXFILEHOOK_H
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// updated by alex5402 on 5/5/21.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
#include "RuntimeHook.h"
|
||||
#import "JniHook/JniHook.h"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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") ||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// updated by alex5402 on 2020/8/18.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
bool disable_hidden_api(JNIEnv*);
|
||||
bool disable_resource_loading();
|
||||
|
||||
#endif //BLACKBOX2_HIDDEN_API_H
|
||||
#endif
|
||||
|
||||
+53
-53
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
+3
-18
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+8
-21
@@ -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";
|
||||
}
|
||||
|
||||
+6
-13
@@ -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() {
|
||||
|
||||
+8
-15
@@ -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;
|
||||
|
||||
+123
-165
@@ -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) {
|
||||
|
||||
+1
-8
@@ -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
Reference in New Issue
Block a user