本文仅用于个人学习与技术研究,不涉及任何商业目的。目标软件为闭源系统,本文分析仅为静态学习,未进行任何侵权或破解行为。作者不承担任何使用后果。
最近沉溺于ptrace注入和自制壳,耽搁了一周时间,现在还是要回归正轨的。
上次在逆向vrp的泥潭里止步不前,最后得到的东西也无法跟其他东西串联。我痛定思痛,觉得还是应该先把qemu的系统模拟跑起来再谈其他。
事实证明,我之前认为它跑不起系统,这个结论下得还是太早了。(至少debian是能跑起来的)
这里找了一个5.10同版本的内核编译。

启动脚本:

这里使用/bin/sh作为启动的pid=1进程而不是/sbin/init或者是/lib/systemd/systemd,是因为这是拿到qemu的shell最稳定的方式,而另外两者很容易受到文件系统内环境因素的干扰。
成功启动:

由于我们是/bin/sh启动的,所以/tmp,/sys等目录肯定都没有挂载临时文件系统,这里写个脚本挂载一下:

回顾一下multi-user.target的依赖关系,依赖basic.target,basic.target又依赖sysinit.target,同时wants目录下还有三个软链接:

分别查看:

看它们的描述,上来第一句注释就是“ This file is part of systemd.”,这强烈表明它们都是systemd内置的特殊单元,看Documentation,然后直接去man手册找它们:


systemd-getty-generator前两行就说它负责实例化serial-getty@.service,直接找到它:

wantedby getty.target,同时路径直指/dev/ttyAMA0,这正是我们qemu启动时在命令行参数里声明的console,但是getty.target自己并没有写明依赖需求,也没有wants目录,于是我们手动创建一个wants目录,并创建软链接。

创建成功后,理论上来讲,如果我们现在把systemd作为init启动,它就会把这个控制台交给我们,所以我们修改qemu启动脚本,将append的init设置为/lib/systemd/systemd。

可以看到,成功了
出现了登录界面,我们先暂时切回/bin/sh启动,把root密码改成空,尝试再次启动,不过又失败了。
我又试着用passwd将root更改密码,但是效果不太理想。
AI给了一些建议,不过大多都是一些瞎猜,最后我觉得还是直接把校验逻辑patch掉比较靠谱,直接找到/bin/login。


在IDA里简单观察,发现用的是pam的校验系统,我根据incorrect字符串交叉引用,定位到了“Login incorrect”字符串,并分析出了大概逻辑:
设置了一个循环,循环内使用pam_authenticate校验密码,成功则返回0并退出循环,失败就返回其他,同时重新执行循环。
| offset | item |
|---|---|
| 0000 | BL .pam_authenticate |
| 0004 | MOV W27,W0 |
| 0008 | MOV W0,W22 |
整个login只有这一处pam_authenticate调用,在aarch64汇编语法中,W0/X0可以用于存储返回值,那么我可以把MOV W27,W0替换成MOV W27,0,这样就相当于修改了它的返回值,直接进入正确逻辑,从而跳出循环。
如果这个办法不成功,我就会尝试更暴力的方法:直接替换掉/bin/login文件,用一个静态编译的程序来代替它,直接调用/bin/sh。
不过折腾过后,patch完就成功登录进去了:
