本帖最后由 asfsagsdfdsfsfd 于 2025-7-1 20:01 编辑
在光猫等嵌入式设备上,系统的 rootfs(根文件系统)通常位于只读分区。如果直接修改该分区内容,极有可能导致 U-Boot 启动失败,或触发 CRC 校验错误,造成设备无法正常启动。 那么,如果我们希望在设备开机后自动执行自定义脚本或程序,应该如何实现呢? 主要有两种思路:
本文主要介绍第二种方式。具体的分析过程此处略去,我们直接看实现步骤。
1. 确定目标进程首先,查看系统中正在运行的 Java 进程: - ~ # ps | grep java
- 1757 java 13:21 java -noverify -Dfile.encoding=UTF-8 -Xcompactalways -Djava.net.preferIPv4Stack=false -Dsun.zip.disableMemoryMapping=true -Duser.timezone=GMT+8 -XX:ErrorFile=/usr/data/java_excp_log/java_error_2078.log -Djava.security.policy=/usr/local/osgi/local/j2re/lib/security/private.policy -Dorg.osgi.framework.security=osgi -Xms48M -Xmx128M -Xss256K -jar /usr/local/osgi/local/osgi/felix/bin/felix.jar
- 3251 root 0:52 cpulimit -l 80 -e java
- 11465 root 0:00 grep java
复制代码
可以看到,系统的主 Java 服务由以下 JAR 包启动: - /usr/local/osgi/local/osgi/felix/bin/felix.jar
复制代码
2. 确认分区是否可写接下来,进入该目录并检查分区挂载属性: - ~ # cd /usr/local/osgi/local/osgi/felix/bin
- /usr/local/osgi/local/osgi/felix/bin # df -h .
- Filesystem Size Used Available Use% Mounted on
- /dev/mtdblock10 30.0M 28.0M 2.0M 93% /usr/local/osgi
复制代码
确认分区是否可写: - /usr/local/osgi/local/osgi/felix/bin # mount | grep /usr/local/osgi
- /dev/mtdblock10 on /usr/local/osgi type jffs2 (rw,relatime)
复制代码
由此可得: 分区设备:/dev/mtdblock10 文件系统:jffs2 挂载方式:读写(rw)
说明此分区允许写入,可供我们进行Hook操作。
3. Hook 实现原理有了可写分区,我们可以通过封装启动逻辑的方式来 Hook: 编写一个新的 Java 程序,先执行自定义 Shell 脚本(即我们需要在开机时运行的逻辑)。 脚本执行完毕后,再调用原始的 felix.jar 启动系统服务。 如果没有找到java进程,那么可以寻找一个二进制进程(在可写分区),流程一致。
这样一来: 启动流程对原系统无任何功能影响。 无需修改只读分区。 脚本具备开机自动运行能力。
4. 具体操作我自己写了一个jar包,还有两个二进制Hook程序(arm/arm64)。 程序运行逻辑: 备份Hook程序到 devpai 目录下(为了防止系统更新把我们Hook程序覆盖了)。 启动一个线程/进程,一直判断Hook程序是否被覆盖,如果被覆盖,则我们再覆盖回去。 执行 devpai 目录下的 hook.sh ,这个就是我们的启动脚本了。 执行原始程序,不破坏原始流程。
部署Hook程序: 1.下载Hook程序到临时目录并解压,可以看到3个Hook程序。 - cd /tmp
- # 下载Hook程序
- curl -k -L -o hookd.tgz https://github.com/zooyer/devpai/archive/refs/tags/v1.0.0.tar.gz
- # 解压Hook程序
- tar -zvxf hookd.tgz
- # 查看Hook程序
- cd devpai-1.0.0/
- ls
- #hookd.jar hookd_arm hookd_arm64
复制代码2.通过上述方式找到Hook点,如:/usr/local/osgi/local/osgi/felix/bin/felix.jar 3.切换到Hook目录,复制对应Hook程序到该目录。 - # 切换到Hook目录
- cd /usr/local/osgi/local/osgi/felix/bin
- # 拷贝Hook程序,添加执行权限
- cp /var/tmp/devpai-1.0.0/hookd.jar .
- chmod a+x hookd.jar
- ls
- #felix.jar hookd.jar
- # 创建Hook程序运行时目录
- mkdir devpai
- # 把原始程序,放入运行时目录
- mv felix.jar devpai
- # 把Hook程序,替换成原始程序
- mv hookd.jar felix.jar
- /usr/local/osgi/local/osgi/felix/bin #ls
- devpai felix.jar
复制代码
4.创建Hook脚本:vi devpai/hook.sh - #!/bin/sh
- user="$(/usr/bin/whoami)"
- init="/usr/data/devpai/init.sh"
- # 以root用户运行
- if [ "$user" != "root" -a "$user" != "" ]; then
- echo "aDm8H%MdA" | su -c "$init"
- exit
- fi
- $init
复制代码
这里我有调用了另一个目录中的初始化脚本,因为一般Hook目录的存储空间很小,不适合存放数据。 后续启动脚本就都在/usr/data/devpai/init.sh这个里面了。 5.杀掉java进程,让守护进程自动重新拉起。 - ps | grep java
- 1757 java 2h26 java -noverify -Dfile.encoding=UTF-8 -Xcompactalways -Djava.net.preferIPv4Stack=false -Dsun.zip.disableMemoryMapping=true -Duser.timezone=GMT+8 -XX:ErrorFile=/usr/data/java_excp_log/java_error_2078.log -Djava.security.policy=/usr/local/osgi/local/j2re/lib/security/private.policy -Dorg.osgi.framework.security=osgi -Xms48M -Xmx128M -Xss256K -jar /usr/local/osgi/local/osgi/felix/bin/felix.jar
- 3251 root 14:13 cpulimit -l 80 -e java
- 7982 root 0:00 grep java
- # 这一步很重要,很多情况下如果没有这个步骤的话,那么下次重启则不会执行Hook程序
- kill -9 1757
复制代码
|