You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解析rootadb在ELF二进制文件中定位方法调用的原理

拆解rootadb工具修补adbd的核心逻辑

让我一步步给你掰明白这段代码到底是怎么找到并修改adbd里的setuid/setgid调用的,还有那些变量到底存了啥——

首先先把核心代码贴出来:

u32 *sgid = (u32*)&setgid;
int fd = open( "/sbin/adbd", O_RDWR );
fstat( fd, &st );
buf = memalign( 32, st.st_size );
read( fd, buf, st.st_size );
lseek64( fd, 0, SEEK_SET );
for( start = buf, end = start + st.st_size - 0x20; start < end; start++ )
    if( !memcmp( &start[1], &sgid[1], sizeof( u32 ) * 2 ) )
        memcpy( &start[1], patch, sizeof( patch ) );

一、先搞懂sgid变量到底存了什么

你看到的u32 *sgid = (u32*)&setgid;这行,核心逻辑是拿当前进程里libc库中setgid函数的机器指令当“特征模板”:

  • &setgid取的是C标准库中setgid函数的入口地址,把它转成u32*指针,是因为Android常用的ARM架构里,每条机器指令都是4字节(刚好对应一个u32)。
  • 所以sgid[0]就是setgid函数的第一条指令,sgid[1]、sgid[2]就是接下来的第二条、第三条指令。比如ARM上setgid的实现通常是先把参数放到指定寄存器,再触发软中断(SWI指令)调用内核系统调用,这些指令的二进制值就存在sgid数组里。

二、代码的整体工作流程

  1. 读取adbd二进制到内存:打开/sbin/adbd(读写模式),获取文件大小后,把整个文件读到内存缓冲区buf里——直接修改磁盘文件容易出问题,先在内存里改完再写回磁盘更安全。
  2. 遍历缓冲区找匹配的指令:循环从buf开头遍历到接近结尾的位置(留0x20字节是为了防止越界访问),每次检查从start[1]开始的8字节(两个u32,也就是两条ARM指令),是不是和sgid[1]开始的8字节完全一致。
    • 为什么跳过start[0]和sgid[0]?因为函数开头的第一条指令通常是函数序言(比如push {r4, lr}这类保存寄存器的操作),不同函数的序言可能略有差异,但真正触发系统调用的核心指令(比如SWI)是统一的,所以跳过第一个指令,匹配后面的核心指令序列。
  3. 替换成NOP指令:一旦找到匹配的位置,就用patch数据覆盖原来的指令——patch里肯定是NOP(空操作)指令的二进制值,ARM上NOP通常是0xE1A00000,替换之后adbd执行到这里就不会调用setgid/setuid放弃root权限了。

三、为什么这种匹配方式能生效?

因为adbd也是用同一个libc库编译出来的,它调用setgid和setuid的指令序列,和当前进程里libc中setgid函数的指令序列是完全一致的——所以用当前进程的setgid指令当模板,就能精准定位adbd里的系统调用位置。

内容的提问来源于stack exchange,提问作者cweiske

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:05:40