首页
社区
课程
招聘
[原创] 关于NativeBridge注入的检测和隐藏
发表于: 2025-4-18 20:39 3352

[原创] 关于NativeBridge注入的检测和隐藏

2025-4-18 20:39
3352

前言

在装有Riru/LSPosed的机子上, 突然发现中国移动(com.greenpoint.android.mc10086.activity)(中国电信也是)打不开了, 一直卡在启动页上, 让我看看是怎么回事.

  1. 停用LSPosed依旧打不开
  2. 停用Riru能打开
  3. 注释jni_hooks依旧打不开
  4. 注释loader(空loader.so)也不行
  5. 注释system.prop中的ro.dalvik.vm.native.bridge=libriruloader.so 正常
  6. 随意resetprop ro.dalvik.vm.native.bridge xxam restart, 还原再打开也不行
  7. 只有zygote启动前没有ro.dalvik.vm.native.bridge值或者为0才正常证明检测了ro.dalvik.vm.native.bridge的值,或者检测到了resetprop的修改

关于resetprop的检测可以看这个: d56K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1i4K6u0W2L8h3g2Q4x3V1k6F1N6h3I4D9M7s2c8J5i4K6g2X3k6r3g2$3i4K6u0r3y4U0l9`.
图片描述
不过也证明不是, 因为改了之后再还原, 依旧打不开, 唯二的可能是就zygote中记录了参数值(也证明不是, 因为整个内存搜索了没有参数被记录)或者有标识成已尝试加载NativeBridge.

确认

NativeBrige流程

具体就不啰嗦了, 可以看看这个文章: 080K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8W2u0G2L8r3q4F1k6q4)9#2k6W2y4#2L8W2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3y4o6V1$3z5o6R3K6x3e0p5`.

关键看LoadNativeBridge, 只要ro.dalvik.vm.native.bridge不空或者0都会执行到这
图片描述
看出来了吧, 只要有值(不是''或者0)就会调用CloseNativeBridge
看看CloseNativeBridge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
......
// Whether we had an error at some point.
static bool had_error = false;
......
 
static void CloseNativeBridge(bool with_error) {
  state = NativeBridgeState::kClosed;
  had_error |= with_error;
  ReleaseAppCodeCacheDir();
}
 
.........
 
bool NativeBridgeError() {
  return had_error;
}

had_error关键的值, 只要设置为true, 就再也不会是false了
NativeBridgeError会返回had_error
写个代码试下:

1
2
3
4
5
6
7
8
SandHook::ElfImg nativeBridge("libnativebridge.so");
using NativeBridgeError_t = bool();
auto *NativeBridgeError = nativeBridge.getSymbAddress<NativeBridgeError_t *>("NativeBridgeError");
LOGI("NativeBridgeError[%p]=%d", NativeBridgeError, NativeBridgeError());
 
bool *nbm = (bool *) ((uintptr_t) nativeBridge.getBase() + 0x5288);
*nbm = 0;
LOGI("NativeBridgeError, from memory[%p]=%d", nbm, *nbm);

这个0x5288是从IDA写复制来的
图片描述
通过resetprop ro.dalvik.vm.native.bridge [0/xxx]再次测试, 确认是这个检测点

1
2
3
4
20:23:53.066 10026-10061 NativeGuard   I  dl_iterate_phdr, get module base /apex/com.android.art/lib64/libnativebridge.so: 0x7b13725000
20:23:53.066 10026-10061 NativeGuard   I  NativeBridgeError[0x7b13727ef0]=1
20:23:53.066 10026-10061 NativeGuard   I  NativeBridgeError, from memory[0x7b1372a288]=0
20:23:53.066 10026-10061 NativeGuard   I  NativeBridgeError check[0x7b13727ef0]=0

修复

那这个0x5288怎么搞出来呢? had_error 是个static, 没有符号, NativeBridgeError返回的也是值, 不是指针, 那只能得到NativeBridgeError指针后, 拿到汇编hex, 再去转换汇编码, 得到地址, 修复数据, 说干就干, 在线测试: 95aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6K9r3g2D9L8q4)9J5k6s2y4@1L8%4u0E0i4K6u0W2L8%4u0Y4i4K6u0r3L8$3&6D9K9h3&6W2i4K6u0r3e0$3&6D9K9h3&6W2i4K6u0V1b7i4y4K6k6h3#2T1L8r3g2J5i4K6u0V1j5h3&6V1i4K6u0V1c8r3W2K6j5i4y4K6k6h3#2T1L8r3g2J5i4K6u0r3i4K6y4r3L8%4m8U0L8$3c8W2M7#2)9K6c8o6l9^5i4K6u0n7x3o6m8Q4x3V1t1H3x3q4)9J5b7V1j5H3i4K6u0n7x3o6m8Q4x3V1t1J5x3g2)9J5b7U0c8m8i4K6u0n7x3K6W2Q4x3U0k6S2L8i4m8Q4x3@1u0S2M7X3y4Z5i4K6y4p5j5i4u0E0y4U0c8Q4x3U0k6S2L8i4m8Q4x3@1u0W2L8X3c8A6j5h3&6F1k6i4y4K6i4K6y4p5L8r3W2@1N6r3I4W2i4K6t1$3j5h3#2H3i4K6y4n7j5X3q4V1k6s2u0Q4x3@1b7H3P5o6l9H3x3o6l9H3x3o6l9H3i4K6t1$3j5h3#2H3i4K6y4n7k6r3W2K6i4K6g2X3N6$3W2@1K9q4)9#2k6X3q4V1k6s2u0Q4x3@1c8f1M7Y4g2W2i4K6t1$3j5h3#2H3i4K6y4n7k6r3W2K6i4K6g2X3N6$3W2@1K9q4)9#2k6Y4u0S2N6#2)9K6c8q4c8J5N6h3g2Q4x3U0k6S2L8i4m8Q4x3@1u0V1K9i4y4Q4y4h3k6%4K9i4c8Z5i4K6g2X3K9h3&6K6i4K6y4p5g2s2u0#2k6g2)9J5x3$3c8A6M7$3q4K6M7$3g2E0j5X3I4&6

为什么要放弃

太难

别的方法?

图片描述
这个值好像正好在.bss块的头上, 直接尝试读取.bss的指针试下
图片描述

这里偷懒一下, 正常应该通过文件获取ehdr指针, 再获取.bss块的首地址的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// fix native bridge detection
void hideNativeBridgeError() {
    // fix native bridge detection
    dl_iterate_phdr([](struct dl_phdr_info *info, size_t map_size, void *data) -> int {
        if (strstr(info->dlpi_name, "libnativebridge.so")) {
            for (int i = 0; i < info->dlpi_phnum; i++) {
                auto phdr = &info->dlpi_phdr[i];
                if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) && (phdr->p_flags & PF_R) && phdr->p_filesz == 0) {
                    LOGI("Riru found NativeBridge.had_error: 0x%lx", (off_t) phdr->p_vaddr);
                    void *nb_point = reinterpret_cast<void *>(info->dlpi_addr);
                    bool *nb_error_point = reinterpret_cast<bool *>(info->dlpi_addr + phdr->p_vaddr);
                    LOGI("Riru NativeBridge: %p, NativeBridgeError: %p ==> %d", nb_point, nb_error_point, *nb_error_point);
                    if (*nb_error_point != 0) {
                        *nb_error_point = 0;
                        LOGI("Riru fix NativeBridgeError: %p ==> %d", nb_error_point, *nb_error_point);
                    }
                    break;
                }
            }
            return 1;
        }
        return 0;
    }, nullptr);
}

放进RIRU测试下

1
2
3
4
5
6
7
...
19:45:37.350   705-705   Riru64        D  jniRegisterNativeMethods com/android/internal/os/Zygote
19:45:37.350   705-705   Riru64        I  Riru found NativeBridge.had_error: 0x5288
19:45:37.350   705-705   Riru64        I  Riru NativeBridge: 0x7dbb1a9000, NativeBridgeError: 0x7dbb1ae288 ==> 1
19:45:37.350   705-705   Riru64        I  Riru fix NativeBridgeError: 0x7dbb1ae288 ==> 0
19:45:37.350   705-705   Riru64        I  replaced com.android.internal.os.Zygote#nativeForkAndSpecialize
...

这个注意下, 要dlopebnn执行完后再修复, 一般放在onRegisterZygote方法里

打开了, 也结束了


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 6
支持
分享
最新回复 (3)
雪    币: 2860
活跃值: (11724)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
看不懂系列
2025-4-24 09:35
0
雪    币: 3101
活跃值: (5899)
能力值: ( LV11,RANK:185 )
在线值:
发帖
回帖
粉丝
3
这个点确实没研究过,有时间研究下,不过目前ro.dalvik.vm.native.bridge的方式其实已经不太行了
2025-4-24 09:47
0
雪    币: 79
活跃值: (554)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
Thehepta 这个点确实没研究过,有时间研究下,不过目前ro.dalvik.vm.native.bridge的方式其实已经不太行了
方便注入和隐藏呀, LD_PRELOAD隐藏总是比较麻烦
2025-4-24 10:30
0
游客
登录 | 注册 方可回帖
返回