
路由器固件逆向与解包实战指南在路由器尤其是传统的消费级型号的固件逆向中通常会遇到工具无法直接解包的情况。其中 90% 以上的“解包报错”属于假加密如格式混淆、魔改文件系统或头部校验。真正的高熵真加密往往出现在晚期防降级版本、运营商定制版或高阶机型中。一、 经典靶场清单与特征对照1. 假加密伪加密 / 魔改格式经典靶机这类固件使用普通的binwalk -e极易报错但熵值往往存在起伏或出现高压缩台阶熵值 0.95。型号与版本固件特征与练手方向Tenda FH1201V1.0魔改 SquashFS 3.0。篡改头部魔数需使用sasquatch或十六进制修复hsqs。Tenda FH456V6.0私有校验头伪装。头部带有数百字节干扰数据适合练习用dd命令精准切割。Tenda AC15V1.0标准 TRX 封装。极高熵0.99但属极限压缩非真加密适合配合 QEMU 模拟漏洞挖掘。Netgear WNDR3700v4非标准字典块1MB。需下载 GPL 源码编译专属unsquashfs进行解包。D-Link DIR-815定制节点表Inode Table。修改了底层 C 语言结构体导致解压报 Error Code 9。Netcore NI360单字节 XOR 混淆。适合练习利用补零对齐区泄漏密钥并用 Python 进行全片还原。D-Link DIR-600(B5)字节序颠倒Byte Swapping。相邻字节对调需编写 Python 脚本恢复。2. 真加密高熵混淆 / 密文校验对照组这类固件有效载荷区熵值呈 0.99 死直线数据被转化为白噪声无任何明文特征。型号与版本加密机制Tenda AC23V1.0晚期防降级与完整性密文校验。Tenda 5G03V1.1商业级 CPE 加密涉及 OTA 密文传输。TP-Link Archer C7V5标准 RSA AES-256-CBC 强制加密。熵值呈现完美的 0.999 死直线。破局方法通常是寻找历史过渡版本固件提取硬编码的 AES Key 和 IV。二、 黄金三步判定法真加密 vs 假加密面对一个高熵0.99且报错的固件可通过以下三步定性看特征签名的“存活度”执行binwalk 固件.bin。只要日志中能识别出具体结构如TRX firmware header、LZMA compressed data、Squashfs ... non-standard signature即证明数据特征未被破坏绝对是假加密。真加密的固件在工具眼中是彻底的未识别黑盒。十六进制“查水表”根据 binwalk 提供的偏移量如0x17576C使用hexdump -C跳转查看起始字节。若发现明显规律的变体如shsq、tqsh代替hsqs或5E 00 00 80代替 LZMA 的5D属于假加密。真加密的起始点数据完全随机。看周边明文泄漏若固件解包过程中外围掉落了 HTML 网页、PNG 图片或明文 Linux 内核但中间某段解不开则为假加密。工程逻辑上厂商不可能只加密一半系统。三、 假加密的四大类型与实战破局类型 1魔数篡改 / 字节序颠倒 (Magic Byte Obfuscation)原理将标准 SquashFS 魔数hsqs改为shsq、tqsh或私有数字或修改 LZMA 特征头。导致标准解压工具不认身份证而崩溃。破局方法自动化安装并调用sasquatch内置各类厂商补丁的开源缝合工具。纯手工编写 Python 脚本定点覆盖十六进制字节。Pythonpython3 -c with open(firmware.bin, rb) as f: f.seek(0x17576C); f.write(b\x68\x73\x71\x73)类型 2私有头部包袱包装 (Proprietary Header Wrapping)原理厂商在标准的压缩包如 LZMA前方拼接几十到几万字节不等的校验头部设备型号、编译时间、CRC32。直接解包会因偏移错误而卡死。破局方法使用binwalk确认真实压缩包的十进制起跳点例如10292使用dd命令做精准切割。Bash# bs1 确保以字节为单位skip 跳过前置包袱 dd iffirmware.bin ofclean_payload.lzma bs1 skip10292类型 3定制字典、节点表与非标准块 (Modded Filesystem/Inode)原理厂商在底层 SDK 修改了 SquashFS 的规范如字典块从 128KB 改为 1MB或在 Inode 节点表结构体中插入垃圾字段导致指针错位常伴随报出LZMA Error Code 9或corrupted filesystem。破局方法原厂 GPL 源码编译法前往厂商官网下载对应机型的 GPL 开源代码包。在源码中提取squashfs-tools目录内含厂商魔改过的unsquashfs.c。若厂商“阉割”了该目录通过供应链溯源下载同时期、同芯片组如 BCM4718的兄弟机型源码包使用tar -xvf单独剥离出工具目录。执行make编译生成自带原厂抗体的专属unsquashfs强制解压。类型 4简单字节混淆 (Simple XOR / Byte Swapping)原理利用固定 Key 进行全片单字节异或或进行相邻奇偶字节位置对调。破局方法获取 XOR 密钥的三种方式已知明文攻击用密文的第一字节异或已知文件头如 SquashFS 的0x68直接算出密钥。频率分析法利用固件分区填充的连续0x00。任何数 XOR0x00 它本身。出现频率最高的字节通常就是密钥。暴力穷举单字节 XOR 仅有 256 种可能脚本秒破。XOR 还原脚本Pythonwith open(encrypted.bin, rb) as f: data f.read() decrypted bytearray(b ^ 0x55 for b in data) with open(decrypted.bin, wb) as f: f.write(decrypted)字节颠倒Swapping还原脚本Pythonwith open(swapped.bin, rb) as f: data bytearray(f.read()) for i in range(0, len(data) - 1, 2): data[i], data[i1] data[i1], data[i] with open(fixed.bin, wb) as f: f.write(data)四、 核心底层原理解析1. 硬件分区对齐如何导致加密“露馅”路由器系统烧录在物理闪存Flash上擦写必须按 block如 64KB对齐边界。当某一分区如 RootFS大小不满足整数倍时打包工具会在尾部强行灌入大量全零字节0x00填充空位。厂商若采用简单的全片 XOR 混淆由于数学法则Key ^ 0x00 Key这些空白对齐区就会在十六进制下原形毕露将密钥成千上万次地直接印在文件中。2. Inode 节点表的作用与魔改后果Inode 节点表是文件系统的“总物流台账”记录了文件的权限、大小以及真实的物理数据坐标指针但不保存文件名文件名在 Directory 中。标准工具解析读取 Inode 结构体占 64 字节并据此寻址。若厂商在 C 语言层面修改struct squashfs_super_block插入自定义字节使每行变为 68 字节会导致所有物理指针向后错位。读取错位会导致工具抓取到被截断的 LZMA 头缺失 5 字节字典属性参数从而引发LZMA Error Code 9和段错误崩溃。3. 底层物理偏移量的寻址计算解压程序寻址并不是盲目搜索而是通过公式计算mksquashfs打包时将各区域大小累加算出 Inode 表的起始绝对地址如0x00287D78并将其刻入超级块固件第 64 字节。解包时unsquashfs读取基准坐标。查找特定文件时提取该文件的块偏移量Block Offset如0x00000100。CPU 运算目标绝对地址 0x00287D78 0x00000100 0x00287E78。指针精确跳转读取。修改节点表规则会破坏此公式的准确性。例子FH1201V1.0(V1.2.0.19)判断过程我们按照判断真假加密的三步法来判断这个是否是假的加密查看上图的这个熵值正常情况下在0.9~1之间且为直线应该是真加密但是这道题不是我们尝试进行解压发现这个日志中竟然出现了TRX firmware headerTRX固件头LZMA compressed dataLZMA压缩包Squashfs filesystem... non-standard signature非标准签名的 SquashFS正常情况下真加密不会出现这样的内容这里已经out掉了但是我们为了学习继续分析我们发现在解压的过程中这里出现了报错我们查看这里的16进制的代码-s 0x175760告诉hexdump工具直接快进跳到地址0x175760附近开始看。-n 64只打印它后面的 64 个字节。我们有了重大的发现标准的 SquashFS 魔数身份证号应该是68 73 71 73对应 ASCII 英文就是hsqs或sqsh。腾达为了做“假加密/伪装”故意把这几个字母颠倒了顺序改成了shsq、tqsh或者十六进制的28 34...因为它改了这 4 个特定字节普通解压软件不认识这个“假身份证”所以当场崩溃报错而你装的sasquatch见多识广认识这个变形的身份证所以今天一鼓作气帮你直接解出了squashfs-root这里我们发现这里就是 SquashFS 的魔数 被修改了解法1当我们装好sasquatch之后 我们可以直接使用这个binwalk进行固件解包这里完全不用提sasquatch这个工具binwalk这个工具非常的聪明当他发现你已经下载过 装好sasquatch之后在发现这种加密的时候就会直接进行修改1. 之前失败时的报文你没装sasquatch之前WARNING: Extractor.execute failed to run external extractor sasquatch(报错提示找不到 sasquatch解压失败)2. 现在成功时的报文你装好sasquatch之后WARNING: Symlink points outside of the extraction directory: .../squashfs-root/lib/modules/...(警告你有一个符号链接指向了外部文件)解法2使用py代码python3 -c with open(fixed_firmware.bin, rb) as f: f.seek(0x17576C); f.write(b\x68\x73\x71\x73)代码片段大白话翻译与底层原理python3 -c ...告诉终端“请直接运行引号里的这串 Python 代码不需要专门建立一个.py脚本文件”。open(fixed_firmware.bin, rb)最核心的一步以“读写二进制模式 (rb)”打开文件。⚠️为什么一定要加b(binary)因为路由器固件是纯二进制流不是普通文本。如果用普通文本文档模式打开系统会自动乱改里面的特殊符号导致固件直接崩溃损坏。f.seek(0x17576C)移动光标定位手术台seek()就像你在 Word 文档里用鼠标点光标。这里我们让计算机把“光标”瞬间移动到十六进制的0x17576C即文件的第 1529708 个字节位置。这正是我们之前在hexdump里发现假魔数shsq的开端f.write(b\x68\x73\x71\x73)动刀缝合覆盖写入在光标当前停靠的位置强行覆盖写入 4 个十六进制字节68 73 71 73在 ASCII 码里这正好对应标准 SquashFS 的身份证——hsqs。注意看这里已经使用py脚本进行修改了FH456 V6.0其实这个就是真假加密类型”中假加密的第二种类型类型 2私有头部包袱包装Proprietary Header Wrapping● 代表靶机 腾达 FH456 V6.0你刚切掉 10292 字节的那款、TP-Link 老固件TP-HDR、博通方案TRX Header● 原理 厂商在标准的压缩包如 LZMA 或 Kernel 镜像正前方强行拼接了一段几十字节到几万字节不等的“私有检验头部”里面记录了路由器设备型号、编译时间、CRC32 校验和以及固件长度。● 临床症状 熵值图最左侧开头会有一段低熵的波动剧烈区明文校验码往后才是平整的高熵压缩区。binwalk 扫得出后面的数据但直接用 unsquashfs 从头解会因为偏移错误而卡死。● 破局招式○ 通过 hexdump / 010 Editor 找到真正标准特征头如 LZMA 的 5D 00出现的准确十六进制偏移量Offset使用 dd ifxxx ofxxx bs1 skip偏移量 把前置包袱精准切掉解法一我们可以看到上图中有两处花线的额部分我们这里进行解释一下1. 第一段记录扫“最外层的快递盒”老文件10292 0x2834 LZMA compressed data...干了什么binwalk扫描了你下载的最原始固件.bin发现前 10291 个字节是腾达的伪加密校验包袱而到了第102920x2834个字节的位置发现了一个大长条 LZMA 压缩包。动作因为你加了-e参数工具立刻把这个位置后面的 LZMA 解压出来保存到了一个新文件里名字就叫2834。2. 第二段记录扫“拆出来的新东西”新文件Scan Time: 2026-07-15 18:02:53Target File: .../_US_FH456V6...extracted/2834DECIMAL HEXADECIMAL DESCRIPTION(这里下面就是你上一张图里看到的 eCos 内核、XML 文件等...)干了什么因为你加了-MMatryoshka / 俄罗斯套娃递归参数binwalk极其尽责它看到刚才解压出了一个名叫2834的新文件立刻马不停蹄地把这个2834新文件又放进扫描仪里做了第二次扫描动作这第二段表格记录的就是在脱掉最外层 LZMA 压缩壳之后那个裸露出来的 eCos 系统内部都长什么样、有什么关键文本和代码模块。现在说解法其实明眼人都能看出来此时这个固件已经成功的解包出来了这是为什么呢在这一台上你只要敲了binwalk -Me工具底层自动帮你干了两件事自动切掉头部它聪明地绕过了第 0 到 10291 字节的腾达私有“伪加密”校验头自动解压核心它抓住了第10292十六进制就是0x2834字节开始的超大 LZMA 压缩包并把里面的真实内容完整解压、释放出来了。其实在我们使用binwalk的时候就已经解包成功了解法二毕竟我们是进行学习所以尽量学的通透一点这个是详细的解法第一阶段侦查与诊断给陌生的固件拍 X 光当你拿到一个未知的.bin固件时绝对不要一上来就盲目解压。我们要先像医生一样通过工具看清它的内部构造步骤 1生成“熵值图”判断是否是真加密Bashbinwalk -E US_FH456V6.0RTL_V12.01.01.31_cn_TDC01.bin看图逻辑你之前看到的图最左侧短小的起伏段 右侧宽阔平整的高台熵值约0.95。诊断结论绝非真加密这符合“明文包袱头 高度压缩包”的典型结构。步骤 2生成“组织结构清册”定位心脏坐标Bashbinwalk US_FH456V6.0RTL_V12.01.01.31_cn_TDC01.bin查看终端输出寻找LZMA compressed data或 SquashFS所在的那一行。锁定坐标我们发现第10292十六进制0x2834个字节处是 LZMA 压缩包的真正起点诊断结论第0到10291字节是腾达工程师为了防止小白解包和防刷机故意附加的“厂商私有校验包袱假加密”。第二阶段外科手术切头手撕厂商保护壳虽然binwalk -Me可以自动帮我们跳过头部但作为真正想学技术的黑客必须掌握用通用 Linux 系统工具手动切除保护壳的标准杀招 ——dd命令在终端里执行这行“外科手术”命令剥离前 10292 字节的废料Bashdd ifUS_FH456V6.0RTL_V12.01.01.31_cn_TDC01.bin ofclean_payload.lzma bs1 skip10292这行命令的硬核解析面试必问点if...(Input File)告诉电脑手术源文件是谁原始带头固件。of...(Output File)告诉电脑切完之后保存成什么新文件名这里我们命名为干净的clean_payload.lzma。bs1(Block Size)以1 个字节为最小切割单位确保精度达到最高。skip10292核心动作让电脑精准跳过开头的10292个垃圾字节只把后面的精华拷贝出来