首页
社区
课程
招聘
3
[原创]关于--inline-max-code-units=0的隐藏
发表于: 2025-4-16 11:13 1108

[原创]关于--inline-max-code-units=0的隐藏

2025-4-16 11:13
1108

前言

在LSPosed中, 已通过mount --bind的方式拦截了dex2oat的调用, 并添加了--inline-max-code-units=0参数, 但是在base.odex中还是有痕迹, Native Detector还是可以检测出来.
图片描述
LSPosed的实现参考: Xposed 框架 ART 参数修复

确认

在adb shell中

1
2
cd /data/app/~~*==/com.reveny.nativecheck-*/oat/arm64/
strings base.odex | grep dex2oat-cmdline -A3

图片描述

解决

在生成base.odex后删除相关字符串

思路

由于LSPosed daemon已经拦截中真实的dex2oat, 直接在假的dex2oat与daemon通信时传递--oat-location中的路径和通知真实dex2oat运行结束就行

  1. 传递odex路径
  2. fexecve会替换进程, fork后, 等待结束后通知daemon
  3. daemon收到结束通知后(要等一会, 文件好像没写入), 替换base.odex中的--inline-max-code-units=0为等长的空格

代码(这里我偷个懒, 直接用shell执行替换)

dex2oat/src/main/cpp/dex2oat.c
write_int传递路径

1
2
3
4
5
6
7
8
9
10
11
12
13
write_int(sock_fd, ID_VEC(LP_SELECT(0, 1), strstr(argv[0], "dex2oatd") != NULL));
char location_odex[NAME_MAX];
for (int i = 1; i < argc; i++) {
    // LOGD("dex2oat argv[%d]: %s", i, argv[i]);
    if (strncmp(argv[i], "--oat-location=", 15) == 0) {
        strcpy(location_odex, argv[i] + 15);
        LOGV("dex2oat location-odex: %s, uid: %d", location_odex, getuid());
    }
}
size_t ps = strlen(location_odex);
write(sock_fd, &ps, sizeof(char)); // 255以下
write(sock_fd, location_odex, ps);
int stock_fd = recv_fd(sock_fd);

daemon/src/main/java/org/lsposed/lspd/service/Dex2OatService.java

1
2
3
4
5
6
7
8
9
var id = is.read();
var ignore = is.skip(3);
int path_len = is.read();
byte[] bytes = new byte[path_len];
if (is.read(bytes) > 0) {
    String odex = new String(bytes).trim();
    Credentials credentials = client.getPeerCredentials();
    new Thread(() -> waitDex2oatExit(odex, credentials)).start();
}

waitDex2oatExit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private void waitDex2oatExit(String odex, Credentials credentials) {
    try {
        Log.d(TAG, "path=" + odex + ", uid=" + Os.getuid() +
                   ", peer_uid=" + credentials.getUid() +
                   ", peer_pid=" + credentials.getPid() +
                   ", path_len=" + odex.length());
        String command = "while [ -d \"/proc/" + credentials.getPid() + "\" ]; do sleep 1; done";
        java.lang.Process process = Runtime.getRuntime().exec(new String[]{"/system/bin/sh", "-c", command});
        process.waitFor(1, TimeUnit.HOURS);
        // 要替换成等长字符 has invalid shdr offset/size: 123616/640
        String command2 = "sleep 3; PATH=$(magisk --path)/.magisk/busybox:$PATH; sed -i 's/--inline-max-code-units=0/                         /g' '" + odex + "'";
        java.lang.Process process2 = Runtime.getRuntime().exec(new String[]{"/system/bin/sh", "-c", command2});
        new Thread(() -> {
            try (var out = new BufferedReader(new InputStreamReader(process2.getInputStream()))) {
                String line;
                while ((line = out.readLine()) != null) {
                    Log.i(TAG, "dex2oat out: " + line);
                }
            } catch (IOException e) {
                Log.e(TAG, "Failed to read dex2oat output", e);
            }
        }).start();
        new Thread(() -> {
            try (var err = new BufferedReader(new InputStreamReader(process2.getErrorStream()))) {
                String line;
                while ((line = err.readLine()) != null) {
                    Log.e(TAG, "dex2oat err: " + line);
                }
            } catch (IOException e) {
                Log.e(TAG, "Failed to read dex2oat errput", e);
            }
        }).start();
        process2.waitFor(30, TimeUnit.SECONDS);
        Log.i(TAG, "dex2oat exit with code " + process2.exitValue());
    } catch (Exception e) {
        Log.e(TAG, "Failed to wait for dex2oat exit", e);
    }
}

确认修复

图片描述

调试

Native Detector测试总是要卸载再安装, 可以使用cmd package compile -m interpret-only -f com.reveny.nativecheck主动调用dex2oat

下一期讲讲怎么在/proc/self/maps中改名


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2025-4-16 11:35 被无味编辑 ,原因: 代码错误
收藏
免费 3
支持
分享
赞赏记录
参与人
雪币
留言
时间
你瞒我瞒
你的分享对大家帮助很大,非常感谢!
1天前
陈某人
为你点赞!
2025-4-17 13:43
逆天而行
谢谢你的细致分析,受益匪浅!
2025-4-17 13:04
最新回复 (5)
雪    币: 2723
活跃值: (11446)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
如果反检测,那是不是可以判断后面是否有等长度空格?
1天前
0
雪    币: 76
活跃值: (474)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
你瞒我瞒 如果反检测,那是不是可以判断后面是否有等长度空格?[em_055]
我只是偷懒, 应该是删除后, 修复一下so文件的格式就行, odex就是一个elf格式的so文件
1天前
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
大佬,detected mounted abnormality是什么异常
23小时前
0
雪    币: 76
活跃值: (474)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mb_lfvhycml 大佬,detected mounted abnormality是什么异常
有空出个文章
6小时前
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
大佬。你一直是在对抗 牛头人的吗 -小弟跟紧大哥脚步。能出一个教程吗。我想检测 【--inline-max-code-units=0参数】, 但是不知道怎么检测~
3小时前
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册