首页
社区
课程
招聘
[原创]浅谈安卓改机
发表于: 5小时前 185

[原创]浅谈安卓改机

5小时前
185

不说废话, 不ai水文从我做起
指纹对抗细节这块已经有很多大佬写过了 这里仅记录下总结和理解

按实现方式划分,大概可以分四种途径

没啥说的,逆明白了hook把指纹换了就行,无通用性

安卓指纹细碎繁杂,从语义上来说往往包括了

从功能性上大概可分

纸上得来终觉浅,自己实际完整逆一个才理解

好了,知道收集了啥那怎么改呢

从采集路径看,大部分指纹不是 App 直接读“某个真实字段”,而是经过一层或多层系统接口汇聚后再返回给 App

对应到核心切入点就是两类:

改rom切入点是底层数据源,但要考虑到用户层/内存缓存值的问题,也可以魔改art对所有调用的方法过滤并修改返回结果
内核模块/lsp 都可以选择上面两类标准切入点进行切入,lsp也可以选择从java层具体方法进行切入

[!] 其实还有prop,但面具系的resetprop工具很容易就改了,难度路边一条
[!] 不过说到底,关键节点就只有 bindersyscall

[Q] 啥是binder
[A]
Binder 是 Android 的跨进程通信机制(IPC),用于在 Client 和 Server 之间传递请求、参数、返回值和对象引用。

App、系统服务、HAL 服务通常运行在不同进程中,不能直接互相调用函数,所以需要 Binder 作为通信通道。

[Q] 为啥安卓设计成这样
[A]
从流程上来看
用户 App -> Java API -> binder -> system_server / native service -> 底层数据/驱动

这种设计把上层接口和底层实现解耦。厂商可以在 HAL/驱动层适配硬件或扩展功能,上层 App 和 Framework 只依赖稳定接口,通常不需要跟着底层实现一起改。

[Q] binder实际长啥样
[A] binder实际上是个通信协议,parcel 才是里面的帧包

一次 Binder 调用

类比下 request 就理解了
请求头 + 目标服务 + 方法编号 + 一块 Parcel 数据 + 对象偏移表

binder_write_read 是 ioctl 的外壳;
BC_TRANSACTION / BR_REPLY 是请求和返回命令;
binder_transaction_data 描述目标、方法和数据位置;
Parcel 才是真正装参数和返回值的地方。

ok,反正就是这么个像 request 似的东西,在 java方法 和 系统服务 之间通信,我们要做的就是抓他的原始包,解析,修改替换

[Q] 为什么在 ioctl 拦 Binder, ioctl 是干什么用的?
[A]
ioctl 是进程和 Binder 驱动交换 Binder 命令的入口;
拦 Binder ioctl,就等于卡在 Client 和 Server 通信的总路口。
[!] 但 ioctl 不只 Binder 用。它是 Linux/Android 里 用户进程和各种设备驱动做控制通信 的通用入口, 我们只是在这筛选出binder相关的流量然后改

好了,网上用lsp hook改binder包的项目还不少,开动你的ai和????看看怎么实现,动手在内核里解析一个最简单的包看看

不阻塞等待结果
没有 BR_REPLY
适合通知、事件投递 (但一般不管这种,都是拦双边的)

有请求,有返回,最常见,App 调系统服务多数是这种 (改的时候就类似中间人改response)
比如
getPackageInfo()
Settings.Secure.getString()
MediaDrm.getPropertyByteArray()

Client 先把一个 Binder callback 对象传给 Server,之后 Server 可以反过来调用 Client。

不是同一次请求里的返回
而是 Server 后续主动反向调用 Client (可以理解为异步返回,这时就不能即时修改了,要维护一个栈,拦截到请求包时stack.add, 等拦截到返回包时再stack.pop顺便改返回包)

比如
Broadcast receiver
listener callback
IAppSetIdCallback.onResult
LocationListener

第一次调用只拿到一个对象/游标/分页 retriever,后续再通过这个 handle 继续取数据。

这种你可以理解为下载请求,拿到对象后再进行实际下载,下载的包可不一定只有一个,也是得用栈来记录,全执行完再pop出去

比如

实际工程实现上要复杂得多

有时一个指纹字段不仅仅能从java层获取到,也能从native层获取到,比如包路径,或者一些字段只从native层获取,这时候就必须拦截syscall了

常见的拦截点

防护端不应该只收集指纹字段本身,更应该多方法校验同一个字段获取到的值是否真实(你这指纹保熟吗),至少算是增加对抗成本

看完本篇再看这几篇会更好理解,具体实现方式也在其中

https://bbs.kanxue.com/thread-289758.htm
https://bbs.kanxue.com/thread-279725.htm
https://bbs.kanxue.com/thread-281889.htm
https://bbs.kanxue.com/thread-278982.htm
https://bbs.kanxue.com/thread-277637.htm
https://bbs.kanxue.com/thread-277402.htm

┌──────────────────────────── 底层数据源 ────────────────────────────┐
│ 文件/目录      /proc /sys /data /system/fonts /apex /vendor        │
│ 系统属性       ro.* / persist.* / vendor.* / init.svc.*            │
│ 系统数据库     Settings / GSF / MediaStore / PackageManager DB     │
│ 硬件/HAL       DRM / Keymaster / Sensor / Camera / Bluetooth      │
│ 网络状态       Netlink / ifaddr / route / DNS / proxy              │
│ 运行时状态     进程 / maps / fd / mount / uptime / storage          │
└──────────────┬──────────────────┬──────────────────┬──────────────┘
               │                  │                  │
               ▼                  ▼                  ▼
┌────────────────────────┐ ┌────────────────┐ ┌────────────────────────────┐
│ syscall / VFS / netlink│ │ property area  │ │ system_server / native svc  │
│ open/stat/readlink     │ │ libc property  │ │ PackageManager / Settings   │
│ getdents/statfs        │ │ property svc   │ │ MediaDrm / keystore / HAL   │
│ recvmsg(netlink)       │ └────────┬───────┘ └──────────────┬─────────────┘
└────────────┬───────────┘          │                        │
             │                      │                        ▼
             │                      │              ┌───────────────────────┐
             │                      │              │ binder / hwbinder     │
             │                      │              │ Parcel / HwParcel     │
             │                      │              └───────────┬───────────┘
             │                      │                          │
             └──────────────┬───────┴──────────────────────────┘
                            ▼
                  ┌──────────────────┐
                  │ 用户 App / SDK    │
                  │ Java API / JNI   │
                  │ Lua/检测脚本      │
                  └──────────────────┘
┌──────────────────────── 用户进程 / Client ────────────────────────┐
│ App / SDK / 检测脚本                                                │
│                                                                    │
│ Java API / Native API                                               │
│ Settings.Secure / PackageManager / MediaDrm / ContentResolver       │
└──────────────────────────────┬─────────────────────────────────────┘
                               │
                               │ Binder / HwBinder 调用
                               ▼
┌──────────────────────── 系统服务 / Server ────────────────────────┐
│ system_server                                                       │
│ ActivityManager / PackageManager / SettingsProvider / ContentProvider│
│                                                                    │
│ native service / HAL                                                │
│ keystore / drm hal / sensor hal / camera hal                        │
└──────────────────────────────┬─────────────────────────────────────┘
                               │
                               │ syscall / driver / database / HAL
                               ▼
┌──────────────────────── 底层资源 / Kernel & Data ─────────────────┐
│ Kernel / Driver                                                     │
│ 文件系统 / 属性 / proc / sys / netlink / sqlite / 硬件              │
└────────────────────────────────────────────────────────────────────┘
binder_write_read
├─ write_buffer                         Client -> Binder Driver
│  └─ BC_TRANSACTION                    发起一次 Binder 请求
│     └─ binder_transaction_data
│        ├─ target.handle               目标服务
│        ├─ code                        调用哪个方法
│        ├─ flags                       调用标志
│        ├─ data_size                   Parcel 数据大小
│        ├─ offsets_size                Binder 对象偏移表大小
│        └─ data.ptr
│           ├─ buffer                   Parcel 数据区
│           │  ├─ interface token       目标接口名
│           │  ├─ arguments             方法参数
│           │  ├─ String / int / Bundle / Parcelable
│           │  └─ flat_binder_object    binder 对象 / handle / fd
│           └─ offsets                  buffer 内 Binder 对象的位置表
│
└─ read_buffer                          Binder Driver -> Client
└─ BR_REPLY                          返回一次 Binder 结果
└─ binder_transaction_data
├─ code / flags / sender       返回上下文
└─ data.ptr
├─ buffer                   Reply Parcel 数据区
│  ├─ exception code
│  ├─ return value
│  └─ String / int / Bundle / Parcelable
└─ offsets                  返回对象偏移表
Client -> BC_TRANSACTION
Server -> BR_TRANSACTION
Server 处理完成 -> BC_REPLY
Client -> BR_REPLY
Client 注册 callback -> Server
Server 保存 callback handle

后续事件发生,直到 Server 准备好返回 
...
 
Server -> callback Binder -> Client
ContentProvider.query() -> 返回 BulkCursor handle

Client -> IBulkCursor.getWindow() -> 拉 CursorWindow
Settings
IContentProvider.query -> IBulkCursor.getWindow
用于 android_id / settings 字段

PackageManager 列表
getInstalledPackages/getInstalledApplications -> retriever.getList (返回一堆包)
  • 过环境检测
  • 指纹字段修改
  • 添加特殊功能/业务功能
  • 自定义rom
  • 自定义内核
  • lsp模块
  • 内核模块
  • 侵入式hook修改(严格意义上不算)
    上面几种方案的切入点、生态各有特色,一套改机方案可以同时使用上述多种途径组合实现
  • 具体实现方式: 暂未知
  • 优势: 隐藏最彻底, 理论效果应该最好;可以添加系统级自定义妙妙功能
  • 兼容性和迁移成本: 依赖开源rom源码,不开源rom机型不适用;适配机型有限,修改点较零散,机型间迁移成本高;
  • 开发周期: 开发周期相对长(不过有ai还真不好说); 编译测试成本高,迭代相对慢
  • 学习门槛: (全ai梭哈可以不看这条) 能配置aosp编译环境,对源码和安卓机制较深理解。
  • 具体实现方式: 暂未知
  • 优势: 隐藏效果好, 可以集成硬断,自动化操作等妙妙功能(挂哥最爱)
  • 兼容性和迁移成本: 通用性较强,兼容同内核版本机型。不同内核版本间迁移成本低, 必须gki内核,版本5.10+
  • 开发周期: 编译测试成本中等,比编rom快,比下面两种慢
  • 学习门槛: 熟悉linux底层,熟悉内核机制
  • 具体实现方式: hook java方法/系统服务的binder/native方法 + hook svc + 环境模块
  • 优势: 生态好,开发体验较好,网络资料多易入门
  • 兼容性和迁移成本: 兼容性极高,对于不同厂商/版本需要适配,迁移成本低
  • 开发周期: 常规字段开发速度快,MediaDrm 相关的字段处理麻烦
  • 学习门槛: 门槛低,理解lsp作用机制和检测对抗点
  • 具体实现方式: hook binder + hook syscall + 环境模块
  • 优势: 隐藏效果好,可以集成硬断,但自由度低于自编译内核
  • 兼容性和迁移成本: 兼容性极高,对于不同厂商/版本需要适配,迁移成本低
  • 开发周期: 开发周期短,迭代快
  • 学习门槛: 门槛略低于编译内核,需要对binder,syscall机制有深度理解
  • 基本信息(机型信息,内核rom信息,一些prop)
  • 广义安卓id(ssaid,oaid,gaid,bootid等)
  • 硬件信息(磁盘大小,MediaDrm相关,keybox)
  • 外设信息(传感器型号数量,蓝牙,相机,屏幕信息等)
  • 证书和字体文件
  • java指纹(版本,进程,环境真实性检测)
  • 时序特征(开机时间,指纹收集用时,时区等)
  • 网络信息
  • proc/maps
  • 文件系统特征 路径/文件属性
  • 安装包/文件路径相关
  • 应用列表(安装时间,权限,版本,签名)
  • 环境检测(模拟器检测,xp系检测,root检测,hook检测等)
  • 动态下发/生成字段
  • 加密/hash/组合/脱敏 后的指纹字段,和上面提到的字段交叉校验/增强唯一性
  • ...
  • 唯一性字段
  • 环境合法性字段
  • 聚类字段
  • 交叉校验联动字段
  • binder / hwbinder
  • syscall / VFS / netlink
    [!] 上面看着字段挺多,但弄明白这两块就可以 全改掉
  • execve/execveat -> pm/cmd 包路径
  • seq_read -> procfs 文本输出
  • do_filp_open -> boot_id/profile 文件打开重定向
  • readlink/readlinkat -> fd/ashmem/path 链接结果
  • vfs_statx/getattr -> inode 元信息
  • vfs_fstat -> fd stat 元信息
  • iterate_dir -> 目录枚举
  • faccessat/faccessat2 -> 文件存在性探测
  • statfs/fstatfs -> 存储总容量
  1. 单向调用
    Client -> Server
    Client 只发请求,不等返回值。[TF_ONE_WAY]
  1. 同步调用
    Client -> Server -> Client
    Client 发请求后阻塞等待 Server 返回
  1. 回调型双向通信
    Client -> Server
    Client <- Server
  1. 多阶段通信
    Client -> Server -> 返回一个 handle
    Client -> handle -> 拉取后续数据
  • 过环境检测
  • 指纹字段修改
  • 添加特殊功能/业务功能

  • [招生]科锐逆向工程师培训(2026年7月3日实地,远程教学同时开班, 第56期)!

    收藏
    免费 20
    打赏
    分享
    最新回复 (4)
    雪    币: 411
    活跃值: (251)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    2
    666
    5小时前
    0
    雪    币: 95
    活跃值: (3122)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    3
    6666666
    3小时前
    0
    雪    币: 2
    能力值: ( LV1,RANK:0 )
    在线值:
    发帖
    回帖
    粉丝
    4
    666
    59分钟前
    0
    雪    币: 1893
    活跃值: (3285)
    能力值: ( LV4,RANK:40 )
    在线值:
    发帖
    回帖
    粉丝
    5
    已严肃学习
    7分钟前
    0
    游客
    登录 | 注册 方可回帖
    返回