【转载】浅谈 Android 安全机制(2025)

原文内容疑似由 AI 生成,仅转载归档留作参考,请注意甄别。

🔍 2025 年技术有效性分析

技术 2025 年有效性 原因
Linux 沙箱机制 ✅ 核心不变 仍是 Android 安全基石
ptrace 注入 ❌ 基本失效 SELinux 限制 + 内核防护
ELF/GOT Hook ✅ 部分有效 需绕过 CFI 等新防护
Inline Hook ✅ 有效但更复杂 ARMv9 + PAC 加大难度
DEX 内存加载 ✅ 核心未变 ART 内部机制稳定
Java 方法 Hook ✅ 依然有效 虚拟机机制未本质改变

📚 有效技术原理详解

🛡️ 1. ELF/GOT Hook(劫持快递员)

故事比喻:想象动态库 (so) 是快递公司,函数是快递员。GOT 表 (全局偏移表) 是快递调度中心,记录着每位快递员的位置。黑客可以修改调度中心的记录(GOT 表项),把送珠宝的快递员(关键函数)替换成自己的同伙(Hook 函数)。

2025 年实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 1. 定位目标函数在 GOT 表的位置
void* get_got_address(const char* lib_name, const char* func_name) {
// 使用 dl_iterate_phdr 遍历进程加载的模块
// 在目标库的 .dynamic 段找到 PLT/GOT 地址
}

// 2. 修改 GOT 表项(需绕过内存保护)
void hook_got(void* old_func, void* new_func) {
// 计算目标 GOT 页面的内存属性
uintptr_t page_start = (uintptr_t)old_func & ~(PAGE_SIZE-1);

// 临时取消写保护
mprotect((void*)page_start, PAGE_SIZE, PROT_READ | PROT_WRITE);

// ARMv8+ 使用原子操作避免竞争
__atomic_store_n((void**)old_func, new_func, __ATOMIC_SEQ_CST);

// 恢复内存保护(可选)
mprotect((void*)page_start, PAGE_SIZE, PROT_READ | PROT_EXEC);
}

绕过新防护

  • CFI(控制流完整性):伪造合法函数签名
1
2
3
4
5
// 伪造符合 CFI 检查的跳板函数
__attribute__((cfi_jump_table))
void fake_func() {
asm("mov x16, %0; br x16" :: "r"(real_func));
}
  • PAC(指针验证):在 Hook 前剥离 PAC 标签
1
2
3
4
void* strip_pac(void* ptr) {
asm("xpacd %0" : "+r"(ptr));
return ptr;
}

⚔️ 2. Inline Hook(道路劫持)

故事比喻:关键函数是高速公路,Inline Hook 相当于在公路起点埋设传送门。当车辆(执行流)进入这条路时,瞬间被传送到秘密基地(Hook 函数),执行完秘密任务后再送回原公路。

ARMv9 实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1. 构建跳板代码(考虑 PAC 和 BTI)
uint32_t trampoline[] = {
0xD503245F, // BTIC 跳过下条指令(v9 特性)
0xD51B0A20, // PACIBSP(保护返回地址)
0x58000051, // LDR X17, #8
0xD61F0220 // BR X17
};

// 2. 劫持目标函数头部
void inline_hook(void* target, void* hook) {
// 备份原指令(最小 12 字节)
memcpy(orig_code, target, HOOK_SIZE);

// 设置跳转目标
*(void**)(trampoline + 4) = (void*)((char*)target + HOOK_SIZE);

// 写入跳板代码(需要内存属性修改)
write_memory(target, trampoline, sizeof(trampoline));

// 构建绝对跳转指令到 Hook 函数
uint32_t jump_code = build_absolute_jump(target, hook);
write_memory((char*)target + sizeof(trampoline), &jump_code, 4);
}

关键突破

  • 指令重定位引擎:自动处理 PC 相关指令
1
2
3
4
5
6
7
8
void relocate_arm_insn(uint32_t insn, void* src, void* dst) {
if(is_blx(insn)) {
int32_t offset = extract_bl_offset(insn);
offset += (char*)src - (char*)dst;
return rebuild_bl_insn(offset);
}
// 处理其他指令类型...
}
  • 运行时代码生成:避免 ROP 检测
1
2
3
4
void* alloc_executable_mem(size_t size) {
return mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
}

📦 3. DEX 内存加载(记忆迷宫)

故事比喻:原始 DEX 是藏宝图,加壳程序把地图撕碎后混入迷宫(加密)。只有用特制眼镜(运行时解密)才能看到碎片内容,但每次只能看到眼前的一小块区域(按需解密)。即使敌人抢走眼镜,看到的也是不断变化的迷宫(多态引擎)。

2025 实现方案

1
2
3
4
5
6
7
8
9
// 1. 元数据加密(ART 兼容)
public class InMemoryDexLoader {
static {
System.loadLibrary("dexshield");
}

// JNI 方法:加载加密 DEX
public native void loadEncryptedDex(byte[] encrypted, String key);
}

Native 层核心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 使用 ART 的 hidden_api 扩展
void JNICALL loadEncryptedDex(JNIEnv* env, jobject, jbyteArray data, jstring key) {
// 1. 解密 Dex 文件头(仅获取类索引)
DexHeader* header = decrypt_header(env, data, key);

// 2. 注册类加载回调
art::Runtime::Current()->AddClassLoader(
env->NewGlobalRef(loader),
[](void* ctx, const char* name) -> bool {
// 3. 按需解密类字节码
ClassData* decrypted = decrypt_class(name);
// 4. 动态插入 ART 运行时
art::DexFile::RegisterMemoryDexFile(decrypted);
}
);
}

反逆向技巧

  • JIT 陷阱:在解密函数中插入反调试代码
1
2
3
4
5
if (ptrace(PTRACE_TRACEME, 0, NULL, 0) == -1) {
// 触发内存自毁
memset(decrypted, 0, size);
kill(getpid(), SIGKILL);
}
  • 多态引擎:每次解密生成不同字节码
1
2
3
4
5
6
void polymorphic_decrypt(uint8_t* data, size_t len) {
for(int i=0; i<len; i++) {
data[i] ^= rand(); // 使用随机密钥流
// 额外插入垃圾指令再通过 NOP 雪崩覆盖
}
}

🎩 4. Java 方法 Hook(魔术戏法)

故事比喻:Java 方法是舞台上的魔术师,Hook 技术是更厉害的魔术师。当原魔术师准备表演时(方法调用前),新魔术师瞬间替换他(修改 ArtMethod 结构),观众看到的是新节目(Hook 逻辑),而原魔术师在后台休息(可选择性调用)。

ART 2025 实现

1
2
3
4
5
6
7
8
// 通过 JNI 修改 ArtMethod 结构
public class ArtMethodHooker {
static {
System.loadLibrary("arthook");
}

public static native void hook(Method target, Method hook);
}

Native 关键代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
extern "C" void hookArtMethod(JNIEnv* env, jobject, jobject target, jobject hook) {
// 1. 获取 ArtMethod 指针
void* target_method = getArtMethod(env, target);
void* hook_method = getArtMethod(env, hook);

// 2. 复制函数入口信息
const size_t method_size = 64; // ARM64 ArtMethod 大小
memcpy(target_method, hook_method, method_size);

// 3. 修复访问标志(绕过隐藏 API 检查)
setAccessFlags(target_method, kAccPublic | kAccNative);

// 4. 设置快速解释器入口
if (art::interpreter::IsQuickCodeEnabled()) {
setEntryPoint(target_method, art_quick_generic_jni_trampoline);
}
}

绕过新限制

  • 隐藏 API 策略:伪造方法为平台类成员
1
2
3
4
void disguiseAsPlatformMethod(void* method) {
art::ArtMethod* art_method = reinterpret_cast<art::Method*>(method);
art_method->declaring_class_ = getClass("android/os/Binder");
}
  • JIT 内联防护:随机化方法热力值
1
2
3
4
void disableJitInline(void* method) {
art::jit::Jit* jit = art::Runtime::Current()->GetJit();
jit->SetMethodCounter(method, 0); // 设为冷方法
}

🛡️ 2025 安全加固黄金法则

  1. 分层混淆
graph LR
    A[Java层] --> B[Native层] --> C{内核模块} --> D[TrustZone]
  1. 动态防御
    • 运行时代码加密
    • 反模拟器技术(检测 /dev/qemu_pipe 等 50+ 特征)
    • 时间炸弹(延迟触发关键逻辑)
  2. 硬件协同
    • 使用 TEE (可信执行环境) 存储密钥
    • 绑定设备熔丝密钥(Android StrongBox)

就像现代银行用动态口令 + 生物识别 + 保险库多重防护,2025 年的 App 防护已进入「AI 驱动的动态防御 + 硬件级信任」时代。

参考


【转载】浅谈 Android 安全机制(2025)
https://neo.mufanc.xyz/posts/50397/
作者
Mufanc
发布于
2026年4月19日
许可协议