第四章:固件加密与混淆——思科固件常见加密算法与绕过思路

说到固件逆向,加密这块儿是绕不开的坎儿。我刚开始做思科设备分析那会儿,第一件事就是被加密头给卡住了。你想想看,好不容易拿到固件,一打开全是乱码,那感觉就像你找到了一扇门,结果发现门是锁着的。

其实思科的加密思路并不复杂。说白了,他们就是想让你没法直接看到固件里的文件系统、内核镜像或者配置数据。但加密归加密,总得有个解密的过程——而这个解密过程,恰恰是我们逆向分析的突破口。

4.1 思科固件常见的加密算法

我个人习惯把思科的加密算法分成两类:对称加密简单混淆。对称加密里最常见的就是AES,简单混淆则基本是XOR的变种。

4.1.1 AES加密

AES在思科固件里用得挺多的,尤其是较新的设备。我记得有一次分析Cisco Catalyst 9000系列的固件,就遇到了AES-128-CBC模式。密钥通常藏在bootloader或者某个特定的配置段里。

识别AES加密有个小技巧:看熵值。加密后的数据熵值很高,接近8.0。如果你用binwalk或者entropy工具扫一下,会发现某个区域的数据分布非常均匀,那基本就是加密段了。

关键点:AES加密的固件通常有一个固定的加密头结构,里面会包含加密算法标识、密钥索引、IV向量等信息。

4.1.2 XOR混淆

XOR就简单多了。思科早期的一些设备,比如某些小型交换机或者老款路由器,喜欢用单字节XOR或者多字节XOR来做混淆。说白了就是不想让你直接用strings看到敏感信息。

我曾经遇到过一个案例,固件里有一段配置数据被XOR加密了,密钥是0xAA。你猜怎么着?我直接用010 Editor写了个脚本,几秒钟就解开了。所以别小看XOR,虽然简单,但确实能挡住不少新手。

4.2 识别加密头

加密头是固件加密的“身份证”。思科通常会在固件开头或者某个固定偏移位置放一个结构体,里面记录了加密相关的信息。

常见的加密头结构大概长这样:

struct cisco_encrypt_header {
    uint32_t magic;          // 魔数,比如0xABCDEF01
    uint32_t algo_id;        // 算法标识,0x01=AES, 0x02=XOR
    uint32_t key_len;        // 密钥长度
    uint32_t iv_len;         // IV长度
    uint8_t  key_data[32];   // 密钥数据
    uint8_t  iv_data[16];    // IV向量
    uint32_t data_offset;    // 加密数据起始偏移
    uint32_t data_len;       // 加密数据长度
};

嗯,这里要注意:不同型号的设备,加密头的结构可能不一样。我建议你先去查一下对应设备的文档,或者直接看bootloader的源码——有时候源码里会直接定义这个结构体。

小技巧:用010 Editor的模板功能,可以快速解析加密头。我自己写了一套思科固件头模板,省了不少事。

4.3 使用静态分析绕过加密

静态分析是绕过加密的核心手段。说白了,就是找到解密函数,然后模拟执行或者直接提取密钥。

4.3.1 定位解密函数

解密函数通常有几个特征:

  • 调用AES相关的指令(比如ARM平台的AESE、AESD指令)
  • 有固定的循环结构(XOR解密通常是循环异或)
  • 函数参数里会传入密钥和IV

我个人习惯用Ghidra或者IDA Pro来定位。先搜索AES的S盒常量,或者搜索XOR的固定模式。找到之后,直接看函数的调用链,就能知道密钥是从哪里来的。

4.3.2 提取密钥

密钥的存放位置通常有几种:

  1. 硬编码在代码里——直接搜索常量即可
  2. 从某个固定偏移读取——需要分析固件布局
  3. 由设备序列号或MAC地址生成——这个稍微复杂点,需要逆向生成算法

我记得有一次分析Cisco ISR 4000系列的固件,密钥居然藏在NVRAM的某个特定区域。我当时找了半天,最后发现是bootloader启动时从NVRAM读出来的。嗯,这种坑踩过一次就记住了。

4.3.3 模拟解密

拿到密钥和IV之后,就可以模拟解密了。我通常用Python写个脚本,直接调用pycryptodome库来解密。如果是XOR,那就更简单了,几行代码搞定。

# AES解密示例
from Crypto.Cipher import AES

key = bytes.fromhex('00112233445566778899AABBCCDDEEFF')
iv = bytes.fromhex('000102030405060708090A0B0C0D0E0F')
cipher = AES.new(key, AES.MODE_CBC, iv)

with open('encrypted.bin', 'rb') as f:
    encrypted_data = f.read()

decrypted_data = cipher.decrypt(encrypted_data)

with open('decrypted.bin', 'wb') as f:
    f.write(decrypted_data)

注意:有些固件会在解密后做校验,比如CRC或者哈希。如果解密出来的数据不对,先检查密钥和IV是否正确,再检查是否有额外的校验步骤。

4.4 知识体系与核心逻辑

下面这张图是我自己整理的思科固件加密分析流程,你可以参考一下:

思科固件加密分析流程 获取固件镜像 识别加密头(魔数、算法标识) 判断加密算法(AES/XOR) AES:定位S盒/密钥 XOR:提取密钥/模式 模拟解密,提取固件内容

4.5 避坑指南

做固件加密分析,有几个坑我踩过,分享给你:

  • 别只看固件开头——加密头不一定在文件开头,有时候在中间某个偏移位置
  • 密钥可能被二次处理——比如先做一次哈希,再作为AES密钥
  • IV可能不是固定的——有些设备每次启动都会生成新的IV,需要动态分析
  • XOR密钥可能是多字节的——别只试单字节,试试4字节或者8字节的XOR

我曾经遇到过一个设备,它的XOR密钥居然是设备MAC地址的后4个字节。我当时试了各种常见密钥都不对,最后看了启动日志才发现。嗯,这种坑踩过一次就长记性了。

4.6 小结

固件加密与混淆,说白了就是一层窗户纸。捅破了,后面就是一片坦途。AES也好,XOR也罢,只要找到解密函数和密钥,剩下的就是写脚本的事了。

我个人觉得,做固件逆向最重要的不是技术,而是耐心。有时候一个加密头结构可能要看上好几个小时,但一旦理清楚了,那种成就感是无可替代的。

最后提醒一句:做逆向分析一定要遵守法律法规,只分析自己合法拥有的设备。别为了练手去碰别人的东西,那是给自己找麻烦。

专注资料整理