> For the complete documentation index, see [llms.txt](https://wokough.gitbook.io/iot-firmware-aio/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wokough.gitbook.io/iot-firmware-aio/wiki/gu-jian-jie-mi.md).

# 固件解密

有些IOT设备会对固件加密甚至签名来提高研究门槛和升级时的安全性，因为加解密比较耗费资源，这类设备一般配置会比较高，比如一些路由器和防火墙。

### 一、**固件加密判断**

判断固件是否加密比较简单，有经验的小伙伴有二进制编辑器打开就能看出一二，一般会存在以下特性。

除了固件指示头没有可见字符，(除去header)数据按比特展开01频率基本一致binwalk(-e)无法解析固件结构，且(-A)没有识别出任何cpu架构指令。

如果满足上述特点，就会猜测固件已被加密，固件解密一般会从这几个角度，但也不局限于下面的方法。

### 二、**硬件获取密钥**

此种方法只限于固件始终以加密状态存在，当系统启动时才通过解密解包加载至flash，且设备缺乏(UART/JTAG等)动态调试手段。由于flash中有完整的解密过程，可以通过编程器读取flash，逆向解密算法和密钥，达到解密固件的目的。比如从某设备的读取的flash内存分布如下：

```
0x000000-0x020000 boot section
0x020000-0x070000 encrypt section
0x070000-0x200000 encrypt section
0x200000-0x400000 config section
```

显然我们需要的加密过程在boot section中，我们需要从中找到加密算法和密钥，一般加密都采用AES等公开分组算法，关键是找到分组模式，IV(非ECB)和密钥。将boot加载到IDA pro中，并没有自动识别：

![](https://image.3001.net/images/20201108/1604819400_5fa799c8397b91f658e6c.jpg)

可以通过对比ARM代码最开始部分的中断向量表结构手动识别，常见的入口代码如下所示。

```
.globl _start
_start:
    b       reset
    ldr     pc, _undefined_instruction
    ldr     pc, _software_interrupt
    ldr     pc, _prefetch_abort
    ldr     pc, _data_abort
    ldr     pc, _not_used
    ldr     pc, _irq
    ldr     pc, _fiq
...
_irq:
        .word irq
```

之后可以就可以逆向得到加密算法为AES，密钥通过设备序列号的sha256哈希获得。

![](https://image.3001.net/images/20201108/1604819431_5fa799e7b59c119be629e.jpg)

通过IDA pro识别此类结构将在后文介绍RTOS时探讨，利用这种固件加密方式的设备安全级别教高，一般设备只在升级时进行解密验证。

### 三、**调试直接读取**

这个方法最容易理解，即在设备启动后利用UART、JTAG、Console或网络等手段把固件(打包)回传，这样就绕过了解密环节。值得注意的是需要设备提供这些接口，具体方法因设备不同而异，这些接口的使用将会在硬件篇里作介绍。

### 四、**对比边界版本**

此种方法适用于厂商一开始没采用加密方案，即旧版固件未加密，在某次升级中添加了解密程序，随后升级使用加密固件。这样我们就可以从一系列固件中找到加密和未加密之间的边界版本，解包最后一个未加密版本逆向升级程序即可还原加密过程。

![](https://image.3001.net/images/20201108/1604819495_5fa79a2713d8aa24f8eab.jpg)

通过下载上图所示某路由器固件，解包后通过搜索包含诸如“firmware”、“upgrade”、“update”、“download”等关键字的组合定位升级程序位置。当然存在调试手段也可以在升级时ps查看进程更新定位升级程序和参数：

```
/usr/sbin/encimg -d -i <fw_path> -s <image_sign>
```

通过IDA pro逆向encimg程序很快得到加解密过程代码，采用了AES CBC模式：

```
AES_set_decrypt_key (
   // user input key
   const unsigned char *userKey,
   // size of key
   const int bits,
   // encryption key struct which will be used by
   // encryption function
   AES_KEY *key
)

AES_cbc_encrypt (
   // input buffer
   const unsigned char *in,
   // output buffer
   unsigned char *out,
   // buffer length
   size_t length,
   // key struct return by previous function
   const AES_KEY *key,
   // initializatin vector
   unsigned char *ivec,
   // is encryption or decryption
   const int enc
)
```

### 五、**向升级程序**

此种方法适用于已经通过接口或边界版本得到升级程序，可以利用分组算法的盒检测工具来判别加密算法和定位位置，当然binwalk也可以解析某些简单情况，比如某工控HMI固件：

```
iot@attifyos ~/Documents> binwalk hmis.tar.gz
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
34       0x22        OpenSSL encyption, salted, salt:0x5879382A7
```

直接加载升级程序，定位openssl调用很容易就得到解密命令：

![](https://image.3001.net/images/20201108/1604819530_5fa79a4acd776fcb96ba9.jpg)

### 六、漏洞获取密钥

如果找不到边界版本，又找不到调试接口或不熟悉硬件调试，可以考虑采用历史版本漏洞先获取设备控制权，在拿到升级程序逆向加密算法。这种方法比较取巧，需要设备存在RCE漏洞的历史固件，通过降级操作植入漏洞获取权限，下载所需升级程序，然后逆向得到加密算法。
