news 2026/8/5 22:03:24

嵌入式Linux设备忘记root密码的三种应急恢复方法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式Linux设备忘记root密码的三种应急恢复方法详解

1. 问题场景:当嵌入式设备“锁”在门外时

作为一名嵌入式开发工程师,或者负责设备运维的技术人员,你很可能遇到过这种尴尬又紧急的情况:一台正在运行Linux的嵌入式设备,比如工控机、路由器、智能网关或者某个定制化的硬件盒子,你需要登录进去进行调试或维护,但root密码却没人记得了。可能是设备出厂后默认密码被改过但未记录,也可能是前任同事留下的“遗产”,总之,你现在被挡在了系统大门之外。

这不仅仅是“忘记密码”那么简单。与个人电脑不同,嵌入式设备往往没有显示器、键盘和鼠标(即没有“控制台”),通常只能通过串口或网络(SSH)访问。当密码未知时,这些访问通道就都失效了。更棘手的是,许多嵌入式系统为了安全或空间考虑,默认不提供像桌面Linux那样的“单用户模式”或“恢复模式”的便捷入口。直接对存储介质(如eMMC、SD卡、NAND Flash)进行物理操作,又需要专业工具和知识,风险很高。

因此,掌握在不知道root密码的情况下,合法、安全地重置密码并进入系统,是一项非常实用的应急技能。它不涉及任何系统漏洞利用,而是基于Linux系统启动流程和文件系统权限的基本原理,通过介入启动过程来临时获得修改关键文件(如密码文件)的权限。下面,我将以最常见的嵌入式Linux环境为例,手把手带你走通几种主流方法,并深入讲解其背后的原理与避坑要点。

2. 核心思路:介入Linux启动流程

在深入具体操作前,我们必须理解其核心原理。Linux系统启动后,最终会由init进程(可能是systemd,sysvinit,busybox init等)来启动各项服务并准备登录环境。/etc/shadow文件存储了加密后的用户密码,而root用户的密码就存放在其中。在系统正常运行时,这个文件受到严格的权限保护,普通方式无法直接修改。

我们的突破口在启动流程。如果能在内核加载完毕、但init进程尚未完全按照既定配置执行之前,获得一个具有root权限的交互式Shell,那么我们就可以在这个“黄金时间窗口”内,直接修改/etc/shadow文件。

对于嵌入式Linux,主要有三种介入方式,其选择取决于你的物理访问权限和设备的启动配置:

  1. 通过串口终端(Serial Console)修改内核启动参数:这是最经典、最可靠的方法,前提是你的设备有可用的串口,并且Bootloader(如U-Boot)支持交互式命令。
  2. 通过外部存储介质(SD/USB)引导一个临时系统:当无法通过串口访问Bootloader,或者Bootloader被锁定时,可以考虑从SD卡或U盘启动一个小的Linux系统(如BusyBox),然后挂载设备上原有的根文件系统进行修改。
  3. 在系统运行时利用Initramfs:有些系统在启动初期会使用一个初始内存文件系统(Initramfs),如果这个Initramfs内置了Shell并且允许交互,我们可以在启动时中断其流程。

接下来,我们将重点讲解前两种最实用的方法,并详细分析第三种方法的适用场景与风险。

3. 方法一:通过U-Boot串口终端修改启动参数

这是嵌入式领域最标准、最推荐的解决方案。U-Boot是嵌入式设备上最流行的开源Bootloader。它负责初始化硬件,加载内核和设备树,并传递启动参数。我们的目标就是在U-Boot的交互式命令行中,临时修改传递给内核的启动参数。

3.1 前期准备与连接

首先,你需要准备以下硬件和软件:

  • 硬件:目标嵌入式设备、USB转TTL串口模块(如CH340、CP2102、FT232等)、杜邦线(母对母)。
  • 软件:串口终端软件,如Windows下的Putty、MobaXterm,macOS/Linux下的screenminicompicocom
  • 关键信息:目标设备的串口引脚定义(通常是TX、RX、GND),以及串口波特率(常见的有115200、9600、57600等)。这些信息可以从设备原理图、硬件手册或主板丝印上找到。

连接步骤:

  1. 断电:确保目标设备完全断电。
  2. 连接串口线:将USB转TTL模块的GND连接到设备的GND引脚。将模块的TX引脚连接到设备的RX引脚,模块的RX引脚连接到设备的TX引脚。(注意:TX接RX,RX接TX,交叉连接)。
  3. 连接电脑:将USB转TTL模块插入电脑。
  4. 打开终端软件:在电脑上打开串口终端软件,选择正确的串口端口(如COM3、/dev/ttyUSB0),设置波特率(通常115200)、数据位(8)、停止位(1)、无校验位、无流控。
  5. 上电:给目标设备上电,并立刻在终端软件中连续按回车键或指定的中断键(如U-Boot通常是任意键,有些设备是空格键或Ctrl+C)。

如果成功,你将看到U-Boot的启动提示符,通常是=>U-Boot>

注意:有些生产设备可能会在U-Boot中设置密码或禁用命令行交互。如果按中断键无效,直接进入了内核启动,说明此路可能不通,需要尝试其他方法。

3.2 中断启动与修改内核命令行的艺术

成功进入U-Boot命令行后,我们通常使用printenv命令查看当前环境变量。其中,bootargsbootcmd变量包含了传递给内核的启动参数。

我们的核心策略是:让内核在启动后,不执行默认的init程序,而是直接执行一个Shell。这通过修改bootargs中的init参数来实现。

标准操作流程:

  1. 查看当前启动命令

    => printenv bootargs bootargs=console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait

    这个例子显示,内核启动参数设置了控制台和根文件系统位置,但没有指定init,系统会使用默认的/sbin/init

  2. 临时修改启动参数: 我们使用setenv命令来修改bootargs,添加init=/bin/shinit=/bin/bash。这告诉内核,启动后不要运行正常的init系统,直接运行一个Shell。

    => setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait init=/bin/sh'

    关键点:这里使用了单引号将整个参数字符串括起来,确保它被作为一个整体传递。根文件系统设备(如/dev/mmcblk0p2)需要根据你的实际情况修改,可以通过printenv查看原设置或使用mmc list等命令查看存储设备分区。

  3. 启动内核: 修改后,使用bootrun某个具体的启动命令(如run bootcmd)来启动内核。

    => boot

3.3 进入单用户Shell与密码重置实操

如果一切顺利,内核启动后,你会直接获得一个#提示符的Shell,并且拥有root权限。此时,根文件系统通常是以**只读(ro)**方式挂载的,这是第一个坑。

  1. 重新挂载根文件系统为可写

    # mount -o remount,rw /

    执行这条命令,将/文件系统重新挂载为读写模式。如果遇到错误,可能需要指定文件系统类型,如mount -o remount,rw -t ext4 /

  2. 使用passwd命令修改密码

    # passwd root

    然后输入两遍新密码。这是最标准、最安全的方式,因为它会自动处理/etc/shadow文件的加密和更新。

  3. (备选)直接编辑shadow文件: 如果passwd命令不可用(比如BusyBox精简版未包含),我们可以手动编辑/etc/shadow文件。首先,删除root用户的密码哈希值,使其密码为空。

    # vi /etc/shadow

    找到以root:开头的一行,将其第二个字段(两个冒号之间的加密密码)删除。例如,将:

    root:$6$salt$hashedpassword:19215:0:99999:7:::

    修改为:

    root::19215:0:99999:7:::

    保存退出。这样,root用户就可以无需密码登录了。注意:这是一个临时应急措施,进入系统后务必立即用passwd命令设置新密码。

  4. 同步与重启: 修改完成后,执行sync命令确保数据写入存储。然后重启设备。

    # sync # reboot -f

3.4 潜在问题与深度排查

  • 问题1:init=/bin/sh启动后,提示can‘t run ’/bin/sh‘: No such file or directory

    • 原因:根文件系统里可能没有/bin/sh,或者它链接到的BusyBox不在那个路径。嵌入式系统常用BusyBox,其Shell可能在/bin/busybox/bin/ash
    • 解决:尝试init=/bin/bashinit=/bin/ashinit=/bin/busybox sh。你可以先不修改启动参数,让系统正常启动一次(虽然进不去),通过串口日志观察系统调用的init路径是什么。
  • 问题2:根文件系统挂载失败,提示VFS: Unable to mount root fs

    • 原因root=参数指定的设备节点不对,或者文件系统类型内核不支持。
    • 解决:在U-Boot中,使用mmc listscsi scanusb start等命令查看可用的存储设备。然后尝试不同的设备节点,如/dev/mmcblk0p1/dev/mmcblk1p2/dev/sda1等。必要时,可能还需要在bootargs中指定文件系统类型,如rootfstype=ext4
  • 问题3:系统仍然启动了正常的init进程

    • 原因:有些内核或Bootloader会忽略命令行中的init=参数,或者系统使用了initramfs,其内部的脚本硬编码了init路径。
    • 解决:尝试更强大的参数组合。例如,在init=/bin/sh后面加上single-s参数(单用户模式),或者直接rd.break(针对systemd + initramfs)。例如:init=/bin/sh single。这需要你对系统的init体系有一定了解。

4. 方法二:从外部介质启动临时系统

当串口方法行不通时(比如Bootloader被锁定,或者设备根本没有引出串口),我们可以考虑“借壳生蛋”——从SD卡或U盘启动一个独立的、小型的Linux系统,然后用这个系统挂载嵌入式设备内部存储上的根文件系统,直接修改其/etc/shadow文件。

4.1 制作可启动的救援介质

你需要一台x86的Linux主机(或虚拟机)来制作启动介质。

  1. 准备镜像:下载一个轻量级的、支持你目标设备架构的Linux镜像。对于ARM设备,Raspberry Pi OS Lite(适用于树莓派类)或Armbian(适用于各种ARM开发板)的镜像非常合适。更通用的选择是BusyBox制作的极小根文件系统镜像,或者Buildroot构建的定制镜像。
  2. 识别设备:将SD卡或U盘插入主机。使用lsblkfdisk -l命令确认其设备名,例如/dev/sdb务必确认无误,否则可能格式化错误磁盘!
  3. 写入镜像:使用dd命令写入。假设镜像文件为rescue.img,SD卡为/dev/sdb
    sudo dd if=rescue.img of=/dev/sdb bs=4M status=progress conv=fsync
    写入完成后,SD卡上应该有两个分区:一个启动分区(FAT32,包含内核和DTB),一个根文件系统分区(通常是ext4)。

4.2 在临时系统中定位并修改目标系统

将制作好的SD卡插入目标设备,并配置设备从SD卡启动(可能需要修改跳线帽或进入Bootloader选择启动顺序)。启动后,你将进入临时系统。

  1. 挂载目标系统的根文件系统

    • 首先,使用fdisk -llsblk找到嵌入式设备内置的存储(如eMMC、NAND)。它可能显示为/dev/mmcblk0(SD/eMMC控制器)或/dev/mtdblock0(MTD设备)。
    • 查看分区:fdisk -l /dev/mmcblk0。通常,根文件系统在第二个或第三个分区(如/dev/mmcblk0p2)。
    • 创建挂载点并挂载:
    mkdir /mnt/original_root mount /dev/mmcblk0p2 /mnt/original_root
    • 如果挂载失败,提示文件系统错误,可以尝试指定文件系统类型:mount -t ext4 /dev/mmcblk0p2 /mnt/original_root
  2. chroot或直接编辑

    • 方法A(推荐,更干净):使用chroot切换到目标系统的环境,然后使用其自带的passwd命令。
    # 挂载必要的虚拟文件系统 mount -t proc proc /mnt/original_root/proc mount -t sysfs sys /mnt/original_root/sys mount -o bind /dev /mnt/original_root/dev # 执行chroot chroot /mnt/original_root /bin/sh # 现在你已经在目标系统的上下文里了 passwd root # 修改密码后退出chroot exit
    • 方法B(直接编辑):如果不支持chroot或想快速操作,可以直接编辑shadow文件。
    vi /mnt/original_root/etc/shadow

    同样,清空root用户的密码字段(删除两个冒号间的哈希值)。

  3. 清理与重启

    # 卸载文件系统 umount /mnt/original_root/proc umount /mnt/original_root/sys umount /mnt/original_root/dev umount /mnt/original_root sync # 关机或重启,并移除SD卡,让设备从内部存储启动 reboot

4.3 此方法的局限性与应对策略

  • 架构兼容性:你制作的救援镜像必须与目标设备的CPU架构(ARMv7, ARMv8/AArch64, MIPS等)完全一致。用x86的镜像启动ARM设备是绝对不可能的。
  • 驱动兼容性:临时系统的内核需要包含目标设备存储控制器(如eMMC/SD控制器、USB控制器)的驱动,否则无法识别内置磁盘。
  • 文件系统兼容性:临时系统需要支持目标根文件系统的类型(ext4, squashfs, jffs2, ubifs等)。
  • 应对策略:最稳妥的方式是,直接使用该嵌入式设备原厂或社区提供的系统镜像来制作救援盘。例如,对于树莓派,就用树莓派官方的Lite镜像;对于某款开发板,就用其SDK里生成的系统镜像。这样能最大程度保证兼容性。

5. 方法三:利用Initramfs进行突破

Initramfs(Initial RAM File System)是一个临时的根文件系统,它在内核启动后、挂载真实根文件系统之前被加载到内存中。它的任务是准备好挂载真实根文件系统所需的环境(比如加载特殊的驱动、解密磁盘等)。如果这个Initramfs内置了Shell并且允许交互,我们就有机会。

5.1 识别与中断Initramfs流程

当系统从串口启动时,观察内核日志。如果你看到类似 “Running /init” 或 “Welcome to Buildroot” 后,出现一个 “/ #” 或 “(initramfs)” 的提示符,并且停顿了几秒,说明系统进入了Initramfs的Shell。如果没有自动进入,可以在内核启动早期(出现Initramfs相关日志时)快速按下Ctrl+C或回车键,有时可以中断其脚本执行,掉入Shell。

5.2 在Initramfs中操作

一旦进入Initramfs的Shell,你通常已经拥有root权限,并且真实的根文件系统设备可能已经被识别但尚未挂载。

  1. 检查存储设备:使用ls /dev/mmcblk*ls /dev/sd*cat /proc/mtd查看块设备或MTD设备。
  2. 手动挂载根分区
    mkdir /new_root mount /dev/mmcblk0p2 /new_root
  3. 执行切换:现代Initramfs使用pivot_rootswitch_root来切换到真实根文件系统。但我们可以“欺骗”系统。
    • 一种方法是直接chroot/new_root,然后修改密码,操作同方法二。
    mount -t proc proc /new_root/proc mount -t sysfs sys /new_root/sys mount -o bind /dev /new_root/dev chroot /new_root /bin/sh passwd root exit
    • 另一种方法是,直接覆盖Initramfs的/init脚本,让它执行我们想要的命令(比如直接启动Shell而不挂载真正的根)。但这需要你对Initramfs的构造比较了解,风险较高。

5.3 风险与注意事项

  • 并非所有系统都有:很多嵌入式系统为了精简,编译内核时没有启用Initramfs,或者使用了极其精简的、无交互Shell的Initramfs。
  • 行为不可预测:不同发行版、不同构建系统(Yocto, Buildroot)生成的Initramfs,其内部脚本和行为差异很大。强行中断可能会破坏启动流程,导致无法正常挂载根文件系统。
  • 临时性:在Initramfs中所做的任何修改,如果只存在于内存中,重启后会失效。你必须确保修改的是已经挂载上来的、真实的根文件系统分区,并且执行了sync

6. 安全考量与后续加固

通过上述任何一种方法重置密码后,你都能重新获得系统的控制权。但这本身是一个巨大的安全漏洞,因此,在解决问题后,必须进行安全加固。

  1. 立即修改密码:如果你是通过清空shadow文件字段进入的,进入系统后第一件事就是使用passwd命令为root设置一个强密码。
  2. 评估访问控制
    • 串口访问:考虑在U-Boot中设置密码(setenv bootdelay 0只能防君子,真正需要修改U-Boot源码编译或设置环境变量密码)。对于生产设备,物理上封堵或禁用调试串口是常见做法。
    • Bootloader锁定:有些芯片提供安全启动(Secure Boot)功能,可以签名校验内核和Bootloader,防止被篡改。但这需要一套完整的密钥管理体系。
    • 文件系统加密:如果数据敏感,可以考虑对根文件系统进行加密(如LUKS)。这样即使通过外部系统挂载,没有密码也无法读取数据。但这会增加启动复杂性,并需要安全存储密钥。
  3. 审计与监控:确保系统日志(/var/log/auth.log,/var/log/secure)记录所有登录尝试。可以考虑部署入侵检测系统。
  4. 最小权限原则:避免日常使用root账户。创建具有sudo权限的普通用户进行运维。

7. 总结与最佳实践选择

面对嵌入式Linux设备忘记root密码的困境,选择哪种方法取决于你的物理访问权限、设备配置和技术储备。

  • 首选方案(强烈推荐)串口 + U-Boot修改启动参数。只要设备留有串口且Bootloader未锁,这就是最直接、最干净、侵入性最小的方法。它不需要额外的硬件(除了串口线),也不修改存储介质上的任何原始数据(除了密码文件),风险最低。
  • 备选方案从外部SD/USB启动临时系统。当串口不可用时,这是最通用的解决方案。它的成功率很高,但前提是你能制作一个与目标设备兼容的启动镜像。建议平时就为重要的设备准备好一个“救援镜像”SD卡,以备不时之需。
  • 探索性方案利用Initramfs。这个方法可遇不可求,取决于系统构建时的配置。可以作为前两种方法都失败后的尝试,但不要抱太大希望。

在实际操作中,务必保持谨慎。尤其是在使用dd命令或挂载操作时,反复确认设备名(如/dev/sdb,/dev/mmcblk0),避免误操作导致数据丢失。整个过程的核心思想是理解Linux的启动链条,并在链条的适当环节进行干预。掌握这项技能,不仅能解决“忘记密码”的问题,更是深入理解嵌入式Linux系统启动和调试的绝佳实践。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/5 22:00:07

PhantomFlow调试技巧:从debug模式到远程调试,解决UI测试难题

PhantomFlow调试技巧:从debug模式到远程调试,解决UI测试难题 【免费下载链接】PhantomFlow Describe and visualise user flows through tests with PhantomJS 项目地址: https://gitcode.com/gh_mirrors/ph/PhantomFlow PhantomFlow是一款基于Ph…

作者头像 李华
网站建设 2026/8/5 21:59:50

STM32 SPI+DMA驱动WS2812B优化:时序校准、双缓冲与稳定性实战

1. 项目概述与核心挑战 上次我们聊了用STM32的SPIDMA方式来驱动WS2812B-2020这款小尺寸的RGB彩灯,算是把灯给点亮了。但很多朋友在实际动手后,反馈回来一堆问题:灯带闪烁、颜色错乱、只能驱动几颗灯、程序一复杂就卡死…… 这太正常了&#x…

作者头像 李华
网站建设 2026/8/5 21:57:24

php-awesome实战案例:如何用精选资源快速构建企业级应用

php-awesome实战案例:如何用精选资源快速构建企业级应用 【免费下载链接】php-awesome PHP 优秀资源整理汇集 项目地址: https://gitcode.com/gh_mirrors/ph/php-awesome php-awesome是一个全面的PHP优秀资源整理汇集项目,它收录了从框架、类库到…

作者头像 李华
网站建设 2026/8/5 21:55:51

Multisim函数发生器设置全解析:从原理到实战排查指南

1. 项目概述:当函数发生器“不听话”时,我们该怎么办?在电子电路仿真领域,Multisim 几乎是每位工程师和学生都绕不开的经典工具。它把一堆昂贵的仪器设备搬进了电脑,让我们能在虚拟世界里搭电路、调参数、看波形。而函…

作者头像 李华
网站建设 2026/8/5 21:51:32

Unity UGUI高性能滚动视图开发指南:Super ScrollView原理与实战

1. 项目概述:为什么我们需要一个“超级”滚动视图?在Unity的UGUI开发里,滚动视图(Scroll View)几乎是每个项目都绕不开的基础组件。无论是角色列表、背包格子、聊天记录,还是商品展示墙,但凡内容…

作者头像 李华