【机翻】硬盘固件安全 - Phison S11

Drive Firmware Security - Phison S11

硬盘固件安全 - Phison S11

原文链接:硬盘固件安全 - Phison S11 |真脆 --- Drive Firmware Security - Phison S11 | trulycrisp



This page references many technical terms and concepts detailed in the Overview page, which should be read first.
本页引用了许多概览页面中详细描述的技术术语和概念,应先阅读该页面。

Code demonstrating topics covered in this page can by found in the Psychite repository.
展示本页涵盖主题的代码可在 Psychite 仓库中找到

Introduction 介绍

The Phison S11/3111 is one of the most common controllers used in SATA SSDs today, particularly for budget drives, with one drive model using this controller selling over 100 million units1. Although not the only SATA SSD controller Phison currently produces2 it's by far the most popular due to its low cost, S11 controllers are more commonly found in drives today than all other Phison SATA controllers combined. Manufacturers like Phison let smaller companies create and sell a unique SSD product without having to develop an entire controller and firmware platform themselves, Phison will sell vendors a base hardware and firmware package they can customise for their specific needs. For Phison controllers such as the S11 a vendor can purchase anything from a complete off-the-shelf reference design with vendor branding to a co-developed custom design where the S11 controller is combined with a custom PCB, specific NAND flash chips, and customised firmware. Although each drive model with an S11 controller has variations in branding or customisation, the controller hardware and core firmware of these drives are always the same.
Phison S11/3111 是当今 SATA SSD 中最常用的控制器之一,尤其是预算型硬盘,其中一款使用该控制器的驱动器型号销量超过 1 亿台 1 。虽然 Phison 目前生产 2 的 SSD 控制器并非唯一一款,但由于价格低廉,S11 控制器在硬盘中的使用频率超过了所有其他 Phison SATA 控制器的总和。像 Phison 这样的厂商允许小型公司自行开发和销售独特的 SSD 产品,而无需自行开发完整的控制器和固件平台,而 Phison 则会向供应商提供基础硬件和固件包,供他们根据具体需求定制。对于像 S11 这样的 Phison 控制器,厂商可以购买从带有厂商品牌的完整现成参考设计,到联合开发的定制设计,后者将 S11 控制器与定制 PCB、专用 NAND 闪存芯片和定制固件结合。虽然每个带 S11 控制器的驱动器型号在品牌或定制上有所不同,但这些驱动器的控制器硬件和核心固件始终相同。

In the context of security this makes these drives a desirable target to attack, as a capability developed for this single controller can be used for many different drive models from many different vendors. The table below shows a sample of some drive models that use the S11 controller3:
在安全背景下,这使得这些驱动器成为攻击目标,因为为该单一控制器开发的功能可用于多种不同厂商的驱动器型号。下表展示了部分使用 S11 控制器 3 的驱动器型号示例:

Vendor 供应商 Model
Addlink S22
Gigabyte 技嘉 SSD
Inland 国内 Pro. (SATA) 优点。(SATA)
KingMax KingMax(国王马克斯) SMV
Kingston 金斯顿 A400
Kingston 金斯顿 Q500
Kioxia 基奥克西亚 Exceria SATA 练习 SATA
Maxtor 马克斯托 Z1
MSI S270
Patriot 爱国者 Burst 爆发
Pioneer 先锋 APS-SL3
PNY CS2040
PNY CS900
PNY Elite 精英
Seagate 希捷 BarraCuda Q1 巴拉库达 Q1
Silicon Power 硅能 A58
Silicon Power 硅能 Bolt B75 Pro 螺栓 B75 Pro
Team 团队 GX1
Team 团队 L3 EVO
Toshiba/Kioxia 东芝/Kioxia TR200

Hardware 硬件

The S11 controller is a simple SOC design with a single core Xtensa processor, 32 KB mask ROM, 192 KB of Instruction RAM (IRAM), and 33 MB of SRAM. A block diagram showing the controller's components is included below:
S11 控制器采用简单的 SOC 设计,配备单核 Xtensa 处理器、32 KB 掩码 ROM、192 KB 指令 RAM(IRAM)和 33 MB SRAM。下面附有显示控制器组件的框图:

Controller diagram

The Xtensa CPU has no Memory Management Unit (MMU) or Memory Protection Unit (MPU), all code executes with access to the entire physical address space, with full Read-Write-Execute (RWX) access to all memory. On power up the CPU executes code from the controller mask ROM, covered in section Bootloader. The following shows a memory map of the address space within the controller:
Xtensa CPU 没有内存管理单元(MMU)或内存保护单元(MPU),所有代码执行时均可访问整个物理地址空间,并对所有内存实现完整的读-写-执行(RWX)访问。开机时,CPU 会从控制器掩码 ROM 执行代码,详见引导加载程序部分。以下展示了控制器内地址空间的内存映射:

Memory map

The main hardware-level attack surface of this controller is the UART and JTAG debug interfaces, which can be permanently disabled during the manufacturing process using eFuses. Testing of various drives found both of these debug interfaces were usually enabled at the hardware eFuse-level, however were not usable likely due to the firmware implementation.
该控制器的主要硬件级攻击面是 UART 和 JTAG 调试接口,可在制造过程中使用 eFuse 永久禁用。对各种驱动器的测试发现,这两种调试接口通常在硬件 eFuse 层面都能启用,但由于固件实现,可能无法使用。

A physical JTAG interface was found on the reference PCB and most vendor PCBs, identified with a JTAG bypass scan. However this interface did not return an IDCODE and could not be used, even where the relevant eFuse left the hardware feature enabled. The pin-out of this JTAG interface is shown in the image below:
在参考 PCB 和大多数厂商 PCB 上发现了物理 JTAG 接口,并通过 JTAG 旁路扫描识别。然而,该接口不返回 IDCODE,无法使用,即使相关的 eFuse 未启用硬件功能。该 JTAG 接口的引脚分布如下图所示:

JTAG pin-out

Bootloader 引导加载程序

When the controller powers on, the CPU executes code from the controller's mask ROM. The 32,768 byte contents of the mask ROM are loaded to address 0x5C0D8000, the same reset vector address the CPU then jumps to and executes. This ROM code is a minimal bootloader written in C and assembly, with the purpose of loading and executing the main firmware. Depending on when the controller was manufactured this bootloader has different versions with slight variations, observed version numbers are 2.0, 7.0, 9.0, and 9.2, of which 2.0 is by far the most common. The bootloader can load the main firmware through two methods: from flash for the standard boot process, or directly into memory by an external tool.
当控制器开机时,CPU 会从控制器的掩码 ROM 中执行代码。掩码 ROM 中 32,768 字节的内容被加载到地址 0x5C0D8000,CPU 随后跳转到并执行的复位向量地址。这段 ROM 代码是一个用 C 语言和汇编编写的最小引导加载程序,目的是加载和执行主固件。根据控制器的制造时间,该引导加载程序有不同版本,略有差异,观察到的版本号为 2.07.09.09.2,其中 2.0 是最常见的。引导加载程序可以通过两种方式加载主固件:标准启动过程从闪存加载,或通过外部工具直接加载到内存。

Bootloader - Firmware Load From Flash 引导加载程序 - 从闪存加载固件

Under normal conditions the bootloader enters the standard boot process, loading the main firmware from the drive's flash. For the first Chip Enable in each of the controller's two flash channels, it scans the first page of every block checking for the magic value 0x31113111 in the first 4 bytes of the page's Out-Of-Band (OOB) metadata area. When a matching page is found, the bootloader loads and parses it as a firmware header.
在正常情况下,引导加载程序进入标准启动进程,从驱动器的闪存加载主固件。对于控制器两个闪存通道中的第一个芯片启用,它会扫描每个块的首页,检查该页带外(OOB)元数据区域前 4 字节的魔术值 0x31113111。当找到匹配的页面时,引导加载程序会加载并解析该页面作为固件头。

The firmware header is 4,096 bytes in size, and is always loaded into memory at address 0x5C0D4000 by the bootloader. The header is verified by calculating a checksum over all but the last 8 bytes, and comparing the result to a checksum value in the last 4 bytes, using the algorithm detailed in CRC-32 Based Checksum with seed 0x31113111. The firmware header is then parsed with the following structure:
固件头部大小为 4,096 字节,引导加载程序始终在地址 0x5C0D4000 加载到内存中。通过计算除最后 8 字节外的所有校验和,并将结果与最后 4 字节的校验和值进行比较,使用 CRC-32 基于种子 0x31113111 的校验和算法进行验证。固件头随后会用以下结构解析:

Firmware flash header

The firmware header starts with magic bytes 49 44 'ID', followed by a sequence number incremented each time a new firmware header is written. The drive stores firmware as four duplicate copies for redundancy, two copies in the first Chip-Enable (CE) of each of the controller's two flash channels, and the header contains the block location of each in fields channel x copy y block.
固件头部以魔字49 44 “ID”开头,后面是每次写入新固件头时递增的序列号。驱动器将固件存储为四个副本以实现冗余,两个副本分别存储在控制器两个闪存通道的第一个芯片启用(CE)中,头部包含每个模块在通道 x 副本 y字段中的位置。

The bootloader begins the firmware loading process by first executing the setup init script if the relevant fields are configured, as described in section Init scripts. It then sequentially loads a set of firmware sections into memory depending on whether either the normal or alternate set of sections is enabled, if boolean field alt-sections is false it uses the Nor-sect count number of sections starting at section number Nor-sect start, otherwise it similarly uses alt-sect count and alt-sect start.
引导加载程序开始固件加载过程时,如果相关字段已配置,首先执行设置初始化脚本(setup init init script),详见 Init 脚本 章节。然后根据启用正常替代部分的顺序加载一组固件段到内存中,如果布尔字段 alt-sections 为假,则使用 Nor 分段计数 ,即从分段编号 Nor 分段开始的分段数,否则同样使用替代分段计数alt-分段起始

To load each section the bootloader reads the section x page count number of flash pages starting at page section x page start in the same flash block as the header, it loads these pages into memory starting at the address in field section x address with section x size as the total section size in bytes, use of this size field means section sizes are not required to be flash page aligned. If field skip CRC is false it then verifies the section's checksum, it calculates the checksum of all but the last 8 bytes of the section using the algorithm detailed in CRC-32 Based Checksum with seed 0x55AA55AA, verifying the result against the checksum value in the last 4 bytes of the section. After a section is loaded into memory it will execute the section and trigger init scripts if applicable, as detailed in Init scripts.
加载每个部分时,引导加载程序读取 section x 页数 ,闪存页数,从页面 x 页面开始 ,页面与头部相同的 Flash 块,加载这些页面从字段 section x 地址的地址加载到内存中,section x 大小为总节长(字节单位), 使用该尺寸字段意味着部分大小无需与闪存页面对齐。如果字段跳过 CRC 为假,则验证该节的校验和,使用基于 CRC-32 基于 Checksum 的算法(带种子 0x55AA55AA)计算除最后 8 字节外所有部分的校验和,并与该节最后 4 字节的校验和值进行验证。在加载到内存后,它会执行该段**并在适用时触发初始化脚本,详见 Init 脚本

After all sections are loaded into memory the bootloader then optionally performs a memory copy to Xtensa Instruction RAM (IRAM), which starts at address 0x5C0C8000. For the normal section set (field alt-sections false) if field load IRAM N is true, it does a memory copy using the source address in field IRAM source normal-sections and size in field IRAM size normal-sections. Similarly if the alternate section set is enabled (field alt-sections true) it uses fields load IRAM A, IRAM source alt-sections, and IRAM size alt-sections.
所有部分加载完毕后,引导加载程序可选择性地向 Xtensa 指令 RAM(IRAM)执行内存复制,IRAM 从地址 0x5C0C8000 开始。对于正常区集(字段 alt 区段为 false),如果字段加载 IRAM N 为真,则使用字段 IRAM 源正向截面中的源地址和字段 IRAM 大小的正常截面进行内存复制。同样,如果启用备用部分集(字段 alt-sections 为真),则使用加载 IRAM AIRAM 源 alt-sectionIRAM 大小 alt-section 的字段。

Finally with the firmware code now loaded from flash into memory, it jumps to the entry point at address 0x5C0E0400, handing over control to the main firmware.
最后,固件代码从闪存加载到内存后,会跳转到地址 0x5C0E0400 的入口点,将控制权交给主固件。

Bootloader - Firmware Load From Flash - Init Scripts 引导加载程序 - 从 Flash 加载固件 - 启动脚本

The firmware header contains a method for custom initialisation of hardware such as the NAND Flash Controller (NFC) before the main firmware is loaded, referred to here as init scripts. These are a sequence of instructions interpreted by a simple form of virtual machine, performing various operations directly on specified memory addresses. Each init script has a length representing the number of entries, where each entry has the following structure:
固件头包含一种在加载主固件前对硬件(如 NAND 闪存控制器,NFC)进行自定义初始化的方法,这里称为初始化脚本 。这些指令是由简单形式的虚拟机解释的一系列指令,直接对指定的内存地址执行各种操作。每个初始化脚本的长度表示条目数,每个条目结构如下:

Init script entry

If the operation field is either 0 or 0xFF the script is ended, otherwise it contains the following sub-fields:
如果操作字段为 0 或 0xFF,脚本结束;否则包含以下子字段:

Bit 比特 Description 描述
5 Operand 2 is indirect 操作数2是间接的
4 Operand 1 is indirect 操作数1是间接的
3:0 Opcode 操作码

Sub-fields operand 1/2 is indirect mean that the value in the relevant operand field is treated as an address and dereferenced to the value it points to before use. The opcode field specifies which of the following operations is performed:
子字段操作数 1/2 是间接的意思,即相关操作数字段中的值被视为地址,并在使用前被取消引用到它所指向的值。 操作码字段指定执行以下操作中的哪一项:

Opcode 操作码 Description 描述
1 Write operand 1 to target address 将操作数1写入目标地址
2 Write result of bitwise OR with operands 1 and 2 to target address 将带有操作数1和2的位位或结果写入目标地址
3 Write result of bitwise AND with operands 1 and 2 to target address 将逐位 AND 的结果(操作数 1 和 2)写入目标地址
4 Wait while value at operand 1 address bitwise ORd with operand 2 value equals target value 在操作数 1 处等待时,值在操作数 1 处按位地址,ORd,操作数值为 2,等于目标值
5 Wait while value at operand 1 address bitwise ORd with operand 2 value doesn't equal target value 等待时,操作数 1 的值在操作数 1 处,按位地址进行 ORD 且操作数值为 2,但目标值不等于
6 Wait while value at operand 1 address bitwise ANDd with operand 2 value equals target value 在操作数1处的等待值,按位地址;当操作数值为2时,值为目标值
7 Wait while value at operand 1 address bitwise ANDd with operand 2 value doesn't equal target value 等待时,操作数1的值按位地址,且操作数2的值不等于目标值
8 No operation 没有手术

The size code field represents the size or data width used for all steps in the operation, with the following possible sizes:
大小代码字段表示操作中所有步骤所使用的大小或数据宽度,可能大小如下:

Size code 尺寸码 Size in bytes 字节大小
0 4
1 2
2 1

An init script has associated address and length fields in the firmware header, where address is the raw memory address where the script is located, and length is the number of entries the script has. These init scripts are able to be located using a raw memory address field instead of an offset due to the firmware header always being loaded to the static address 0x5C0D4000 by the bootloader, the address always points to some area within the firmware header itself.
初始化脚本在固件头部中包含对应的地址长度字段, 其中地址是脚本所在的原始内存地址, 长度是脚本拥有的条目数。由于固件头总是被加载到引导加载程序 0x5C0D4000 的静态地址,且地址始终指向固件头内部的某个区域,这些初始化脚本可以通过原始内存地址字段而非偏移量来定位。

For the standard boot process the firmware header supports three separate init scripts, executed at different stages of the firmware load process. The setup script is executed immediately as the firmware header is parsed, before any sections are loaded into memory. The section script is executed after each firmware section is loaded, for every section, the only script that can execute multiple times. And the trigger script is executed by a handler triggered after a specific section is loaded, gated by boolean field trigger with the section number in field trigger section.
在标准启动过程中,固件头支持三个独立的初始化脚本,分别在固件加载过程的不同阶段执行。当解析固件头部时, 安装脚本会立即执行,然后才加载任何部分到内存中。每个固件部分加载完后执行该脚本,每个部分是唯一能多次执行的脚本。而触发脚本则由处理程序执行,该处理程序在特定部分加载后被触发,并通过布尔字段触发器**和字段触发部分中的段号进行门禁。

Bootloader - Firmware Load In Memory 引导加载程序 - 内存中的固件加载

The bootloader has an alternate mode distinct from loading firmware from flash, commonly known in storage drive terminology as safe mode. This mode is entered either by the firmware load from flash process failing, by a hardware jumper on the PCB being bridged, or by the main firmware triggering it by setting the controller register at address 0x04000044 to 0x02 before initiating a reboot.
引导加载程序有一种与从闪存加载固件不同的备用模式,在存储盘术语中通常称为安全模式 。该模式可通过固件加载(闪存进程失败)、PCB 上的硬件跳线桥接,或主固件在启动前将地址 0x04000044 的控制器寄存器设置为 0x02 触发。

In this state the bootloader activates the SATA interface with its own implementation of a minimal set of ATA commands, with the main intended purpose of implementing a method for external vendor tools to load firmware directly into controller memory through the standard host interface. The S11 bootloader implements this functionality through Vendor Unique Commands (VUCs), using the command system detailed in Vendor Unique Commands.
在此状态下,引导加载程序通过自身实现的最少 ATA 命令集激活 SATA 接口,主要目的是实现一种方法,使外部厂商工具能够通过标准主机接口直接将固件加载到控制器内存。S11 引导加载程序通过供应商唯一命令(VUC)实现此功能,使用供应商唯一命令中详细描述的命令系统。

Bootloader - Firmware Load In Memory - Instruction RAM 引导加载程序 - 内存中的固件加载 - 指令内存

To start the process of loading firmware into memory the sections resident in Xtensa Instruction RAM (IRAM) must be loaded first, using the VUC write operation Program PRAM 0x40. This operation must be used by first executing VUC write operation Set Parameter 0x24 with relevant parameter data, this parameter data has the structure 4 byte address 4 byte size. With the destination address and size parameters set, the Program PRAM VUC is then executed with the relevant data, if bits 15:8 of the LBA register are non-zero (boolean true) this VUC also decrypts the data as described in CRC-16 Based Cipher using a seed value derived from data received through VUC write operation Send Seed 0x80. A maximum size of 65,536 bytes can be loaded in a single Program PRAM operation, so multiple may be required for a single section, this is repeated until all IRAM-resident sections are loaded into memory.
要开始将固件加载到内存的过程,必须先通过 VUC 写操作 Program PRAM0x40 加载 Xtensa 指令 RAM(IRAM)中的部分。必须先执行 VUC 写操作 Set Parameter0x24 与相关参数数据,该参数数据结构为 4 字节地址 ``4 字节大小 。在目标地址和大小参数设定后,程序 PRAM VUC 会以相关数据执行,如果 LBA 寄存器的第 15:8 位非零(布尔真),该 VUC 也会根据 CRC-16 密码中描述的数据解密数据,该值通过 VUC 写操作发送种子 0x80 获得。单次程序 PRAM 操作最大可加载 65,536 字节,因此单个段可能需要多个字节,重复此过程直到所有 IRAM 驻留部分加载到内存中。

With the IRAM sections loaded, the VUC write operation ISP Jump 0xF is executed to jump to the firmware entry point at address 0x5C0E0400. This results in the bootloader executing and handing over control to the IRAM-loaded firmware, which must itself complete its own loading process.
在 IRAM 部分加载后,执行 VUC 写操作 ISP 跳转 0xF,跳转到地址 0x5C0E0400 的固件入口点。这导致引导加载程序执行并将控制权交给加载 IRAM 的固件,而 IRAM 固件必须完成自己的加载过程。

Bootloader - Firmware Load In Memory - SRAM 引导加载程序 - 内存固件加载 - SRAM

Firmware intended for in-memory execution, referred to as a burner in Phison terminology, is designed to implement a minimal set of functionality entirely in the Instruction RAM sections, without requiring any SRAM sections to be loaded. This minimal set of functionality implements everything necessary to load the remaining firmware, which uses the VUC system detailed in Vendor Unique Commands.
用于内存执行的固件,在 Phison 术语中称为刻录器,旨在完全实现指令 RAM 部分的最低限度功能,无需加载任何 SRAM 部分。这套最简的功能实现了加载剩余固件所需的一切,剩余固件使用了供应商唯一命令中详细描述的 VUC 系统。

Loading a firmware section into SRAM uses VUC write operation Program PRAM ICode 0xBD. Register LBA bits 23:16 are the offset in units of 65,536 bytes from SRAM base address 0x60000400, while LBA bits 15:8 being non-zero (boolean true) signify the final operation that completes all SRAM firmware loading. In contrast with the bootloader's Program PRAM operation using optional standard firmware encryption, data for Program PRAM ICode has non-optional encryption of simply XORing each byte with 0xFF. A maximum size of 65,536 bytes can be loaded in a single Program PRAM ICode operation, so multiple may be required for a single section, this is repeated until all SRAM-resident sections are loaded into memory.
向 SRAM 加载固件部分使用 VUC 写操作程序 PRAM ICode 0xBD``。寄存器 LBA 位 23:16 是从 SRAM 基址 0x60000400 的 65,536 字节的偏移量,而 LBA 位 15:8 为非零(布尔真)表示完成所有 SRAM 固件加载的最终操作。与引导加载程序使用可选标准固件加密的 Program PRAM 操作不同,Program PRAM ICode 的数据采用非可选加密方式,即每个字节与 0xFF 进行异或(XOR)。单次程序 PRAM ICode 操作最大可加载 65,536 字节,因此单个段可能需要多个字节,重复此过程直到所有驻留 SRAM 的段加载到内存中。

With all SRAM sections loaded into memory, the firmware loading process is now complete and the firmware fully operational.
所有 SRAM 部分加载到内存后,固件加载过程完成,固件完全可运行。

Firmware 固件

The firmware code used for the S11 controller is a Real Time Operating System (RTOS) based on a 2014-era version of ThreadX, with the version string Copyright (c) 1996-2014 Express Logic Inc. * ThreadX Xtensa Version G5.6.5.8 SN: 3773-198-3201 *. Although the controller only has a single processor core, the firmware makes use of task concurrency through ThreadX's multi-threading functionality. The firmware has three separate threads, mainTask for core high-level functionality such as ATA command handling, ftlTask for the Flash Translation Layer (FTL), and flaTask for NAND flash operations.
S11 控制器使用的固件代码是基于 2014 年版本 ThreadX 的实时操作系统(RTOS),版本字符串为 Copyright (c) 1996-2014 Express Logic Inc. * ThreadX Xtensa 版本 G5.6.5.8 SN: 3773-198-3201 *。虽然控制器只有一个处理器核心,但固件通过 ThreadX 的多线程功能实现了任务并发。固件有三个独立线程:mainTask 负责核心高级功能(如 ATA 命令处理),ftlTask 负责闪存转换层(FTL),flaTask 负责 NAND 闪存操作。

S11 firmware is distributed as files with extension .BIN. These firmware files are designed to be usable both to update the existing firmware on a drive through the standard ATA DOWNLOAD MICROCODE 0x92 command, and usable for manufacturing or repair where the drive currently has no functional firmware installed. This dual-purpose is achieved by having each firmware file actually contain two separate firmware images, the standard firmware intended for installation to a drive, and the burner firmware intended for loading into memory from the bootloader to install the aforementioned standard firmware. The burner component is unused when sent to the drive as a firmware update, its only purpose is for loading into memory by Phison vendor tools, as detailed in Firmware Load in Memory.
S11 固件以扩展名为 的 文件形式分发 .bin 。这些固件文件设计既可用于通过标准的 ATA 下载微码 0x92 命令更新硬盘上的现有固件,也可用于制造或维修,当硬盘目前没有安装功能性固件时。这种双重功能是每个固件文件实际上包含两个独立的固件映像,一个是用于安装到硬盘上的标准固件,另一个是用于从引导加载程序加载到内存中安装上述标准固件的烧录固件。当作为固件更新发送到驱动器时,燃烧组件不会被使用,其唯一用途是通过 Phison 厂商工具加载到内存,详见《 固件加载内存 》一文。

The firmware format begins with a 512 byte header with the following structure:
固件格式以一个512字节的头部开始,结构如下:

Firmware header

The main purpose of this header is providing necessary values to locate and parse the three possible segments the firmware can contain in the data that follows, burner code, normal code signature, and normal code, always in that order.
该首部的主要目的是提供必要的值,以定位和解析固件可能包含的三个可能段,分别是烧录代码普通代码签名普通代码 ,顺序始终相同。

The burner code begins immediately after the header with the size in bytes given by field burner code size, with the burner code checksum being a 16-bit word sum of the segment's data. If the value in field signature is 0x33 the burner code is immediately followed by a normal code signature segment, as detailed in Signature. If there is no normal code signature, the normal code segment begins immediately after the burner code, otherwise if a signature is present it begins at the offset given by field normal code offset. The normal code segment has equivalent size and checksum fields as detailed earlier for the burner code, using fields normal code size and normal code checksum. The structure of both the burner and normal code segments is equivalent, with the format detailed in Code Segment.
烧录码紧接头部开始,大小以字段烧录码大小表示, 烧录码校验和为段数据的 16 位字和。如果字段签名中的值 0x33,临时代码紧接着一个普通代码签名段,详见签名部分。如果没有正常码签名,则普通码段紧接着烧录码开始;否则如果有签名,则从由字段正常码偏移给出的偏移量开始。普通代码段的大小和校验和字段与之前详细描述的烧录码相同,使用了 “正常代码大小 ”和“ 正常代码校验和 ”字段。燃烧器段和普通码段的结构是等价的,格式详见代码段

Firmware - Format - Code Segment 固件 - 格式 - 代码段

Each code segment begins with 16,384 bytes of data called a seed, this seed starts with a 1,024 byte header with the following structure:
每个代码段以 16,384 字节的数据开始,称为种子 ,该种子以一个 1,024 字节的头部开始,结构如下:

Seed header

Depending on the type of code, burner or normal, this seed header uses a different set of fields which contain the load address and size in bytes of each section in the code. Following the header, the remaining data of the seed is a key used to decrypt the code.
根据代码类型(烧录代码还是普通代码),该种子头使用不同的字段集合,字段包含代码中每个部分的加载地址和字节大小。在头部之后,种子剩余的数据作为密钥,用于解密代码。

Following the seed, the remaining data of the code segment is the encrypted data of each section appended sequentially, the encryption used varies based on whether it is burner code or normal code. For burner code all instruction RAM (IRAM) sections are just encrypted with the cipher detailed in CRC-16 Based Cipher with a seed value derived from the key data of the segment seed detailed above, while SRAM sections simply have each byte XORd with 0xFF. Normal code is encrypted the same as the burner code IRAM sections with the same CRC-16 based cipher, however optionally with an additional layer of scrambling with the algorithm detailed in XOR 0561, whether XOR 0561 is used varies by firmware version and is possibly related to the type of flash it's intended for.
种子之后,代码段剩余数据是每个段的加密数据,按顺序附加,所使用的加密方式取决于是烧录代码还是普通代码。对于烧录代码,所有指令 RAM(IRAM)段都用 CRC-16 密码中描述的密码加密,种子值由上述段种子的密钥数据推导出,而 SRAM 段则每个字节与 0xFF 进行 XORd。普通代码与烧录码 IRAM 部分相同的加密方式相同,使用相同的 CRC-16 密码,但可选地通过 XOR 0561 中描述的算法进行额外加扰,是否使用 XOR 0561 因固件版本而异,可能与其针对的闪存类型有关。

Firmware - Format - Signature 固件 - 格式 - 签名

The firmware format has the optional capability to include a nominal cryptographic signature for the normal code segment, intended to verify it is legitimate and has not been tampered with. This signature is included as a separate segment in the firmware format, with a total size of 3,072 bytes.
固件格式可选地包含普通代码段的名义加密签名,用于验证其真实性且未被篡改。该签名作为固件格式中的独立段包含,总大小为3,072字节。

This signature starts with a 512 byte header with an unknown structure. Although examining examples of these headers in Phison factory firmware shows they clearly have some defined structure with fields, no fields within it are actually extracted or parsed by the firmware during the firmware update process, and it's simply used as a single opaque block of arbitrary data. An example of one of these signature headers in a factory firmware file is included below:
该签名以一个 512 字节的头部开始,头部结构未知。虽然在 Phison 工厂固件中查看这些头部的例子,显示它们明显有定义的字段结构,但在固件更新过程中,固件实际上没有提取或解析其中的字段,它只是作为一个不透明的任意数据块使用。以下是出厂固件文件中此类签名头的一个示例:

00000000: 43 4f 44 45 20 42 4c 4f 43 4b 55 aa aa 55 00 ff 50 30 30 38 00 00 02 02 50 53 33 31 31 31 00 00  CODE BLOCKU..U..P008....PS3111..
00000020: 00 00 00 00 00 00 00 00 00 20 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ......... ......................
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
00000060: 50 30 30 38 00 00 00 00 00 00 00 00 00 00 00 00 32 30 32 30 2d 30 31 2d 30 38 31 36 31 39 32 34  P008............2020-01-08161924
00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
00000100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
00000120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
00000140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
00000160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
00000180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
000001a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
000001c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

The header detailed above is then followed by a 256 byte RSA signature. This signature is generated by prepending the previous header data to the normal code segment, hashing the result with SHA256, and encrypting the resulting hash with RSA.
上述头部后面跟着一个 256 字节的 RSA 签名。该签名通过将前一个头部数据置于正常代码段前,使用 SHA256 哈希结果,再用 RSA 加密哈希生成。

The RSA signature data is then followed by the 256 byte RSA public modulus used to verify the signature, 1,024 padding bytes, and then XOR 0561 obfuscated SHA-256 round constants and initial values used for the hash in the signature.
RSA 签名数据后接着是用于验证签名的 256 字节 RSA 公共模数、1024 个填充字节,然后是 XOR 0561 混淆的 SHA-256 轮常量和用于签名中哈希的初始值。

Vendor Unique Commands 供应商独有命令

The S11 uses a Vendor Unique Command (VUC) system of avoiding the designated vendor-specific ATA opcodes, and instead implementing extra functionality when standard ATA commands are executed with specific magic parameters. VUC requires a sequence of two separate ATA commands, first a STANDBY IMMEDIATE 0xE0 command with magic register values, followed by either a READ SECTOR(S) (without retry) 0x21 command for a read or a WRITE SECTOR(S) (without retry) 0x31 command for a write.
S11 采用供应商唯一命令(VUC)系统,避免使用指定的厂商专属 ATA 操作码,而是在标准 ATA 命令执行时以特定魔术参数实现额外功能。VUC 需要两个独立的 ATA 命令序列,首先是带有魔术寄存器值的 STANDBY IMMEDIATE0xE0 命令,然后是用于读取的 READ SECTOR(S)(无重试)0x21 命令,或写 Sector(S)(无重试)0x31 命令用于写入。

The STANDBY IMMEDIATE 0xE0 command uses magic register values 0x6F for Count and 0xFAEFFE for LBA, Phison vendor tools refer to this command as set AP key. This command enables a temporary alternate VUC mode for the 0x21 and 0x31 commands, where the next of either of those commands is handled as a VUC. This temporary VUC mode can also be deactivated by the same 0xE0 command with magic register values 0x90 for Count and 0x51001 for LBA, which Phison vendor tools refer to as unset AP key.
STANDBY IMMEDIATE0xE0 命令使用魔法寄存器值,0x6F Count0xFAEFFE 用于 LBA,Phison 厂商工具称此命令为 set AP 密钥 。该命令使 0x210x31 命令的临时替代 VUC 模式成为可能,其中任一命令的下一个作为 VUC 处理。该临时 VUC 模式也可以通过同一 0xE0 命令停用,并使用魔法寄存器值 0x90 计数,**LBA号 0x51001,Phison 厂商工具称之为未设置 AP 密钥

The specific VUC operation is selected by the Feature register value of the READ SECTOR(S) (without retry) 0x21 or WRITE SECTOR(S) (without retry) 0x31 command, with the LBA register used for parameters.
特定的 VUC 操作由 READ SECTOR(S)(无重试)0x21WRITE SECTOR(S)(无重试)0x31 命令的特征寄存器值选择,参数使用 LBA 寄存器。

A list of identified VUC operations is included below:
以下是已识别的 VUC 运营列表:

Operation 运营 Name 名称 Description 描述
0x1 Restart 重启 Soft restart 软重启
0x2 Reset Smart 重置智能 Reset SMART 重置智能
0x8 Preformat 预格式化 Format/initialise System Area 格式化/初始化系统区域
0xF ISP Jump ISP 跳跃 Jump to code in RAM 跳转到内存中的代码
0x10 Read Flash 阅读闪电 Read raw flash page 阅读原始闪存页面
0x12 Read SRAM 阅读 SRAM Read SRAM memory 读取 SRAM 内存
0x13 System Info 系统信息 Read system information 读取系统信息
0x14 Flash Id 闪光身份 Read flash ID for one CE 读取闪存 ID 以获取一个 CE
0x15 Flash Id All 闪光身份 Read flash ID for all CEs 所有 CE 都要读闪光识别
0x20 Write Flash 写入闪存 Write raw flash page 写入原始闪存页面
0x22 Erase Flash 抹消闪光 Erase raw flash block 擦除原始闪光块
0x24 Set Parameter 参数设置 Set VUC parameter data for next command 为下一个命令设置 VUC 参数数据
0x25 Write Info Block 写入信息块 Write drive configuration data 写入驱动器配置数据
0x26 Erase All Block 清除所有屏蔽 Erase all blocks 清除所有方块
0x28 Read Info Block 阅读信息块 Read drive configuration data 读取驱动器配置数据
0x30 Check CRC 查查 CRC Verify CRC of code in RAM 验证 RAM 中代码的 CRC
0x31 Verify Flash 验证闪光 Read installed firmware from flash 从闪存读取已安装固件
0x40 Program PRAM 程序 PRAM Write code to instruction RAM 将代码写入指令 RAM 中
0x41 Program Flash Header 程序闪存头 Write firmware header to flash 将固件头写入闪存
0x60 Write Register 写寄存器 Write memory value 写入内存值
0x61 Read Register 阅读寄存器 Read memory value 读取内存值
0x80 Send Seed 发送种子 Send firmware metadata/seed 发送固件元数据/种子
0x82 Program Flash Code 程序闪存代码 Write firmware code to flash 写固件代码到闪存
0xA7 ONFI Parameter Page ONFI 参数页面 Read ONFI parameter page 阅读 ONFI 参数页面
0xBD Program PRAM ICode 程序 PRAM ICode Write code to SRAM 编写代码到 SRAM
0xBE Verify PRAM ICode 验证 PRAM ICode Read back code from SRAM 从 SRAM 读取回溯代码
0xC4 VUC Unlock Start VUC 解锁启动 Start VUC unlock sequence 启动 VUC 解锁序列
0xC5 VUC Unlock Read VUC 解锁读取 Read VUC unlock challenge 阅读 VUC 解锁挑战
0xC6 VUC Unlock Write VUC 解锁写入 Write VUC unlock response 写入 VUC 解锁响应
0xC7 VUC Lock VUC 锁 Lock VUC access 锁定 VUC 访问
0xDA Read Product History 阅读产品历史 Read product history data 阅读产品历史数据
0xDB Write Product History 撰写产品历史 Write product history data 写入产品历史数据
0xFB Block Map 街区地图 Read map of flash blocks for first CE of channel 读取通道第一 CE 的闪光块映射

Vendor Unique Commands - Unlocking 供应商独特命令——解锁

S11 firmware versions can optionally require an unlock procedure before sensitive VUCs are accessible, this uses a challenge-response scheme implemented in a subset of VUCs that are accessible before the drive is unlocked.
S11 固件版本可选择性地要求在访问敏感 VUC 前先解锁程序,这使用了在部分 VUC 子集中实现的挑战-响应方案,这些 VUC 在硬盘解锁前即可访问。

To start the unlock procedure VUC System Info is executed to get the current lock state and configuration. The current state is in field VUC mode, and an identifier for the specific configured unlock key is in field VUC key, for firmware versions without any VUC lock support these fields will both be absent with null bytes in their place.
要启动解锁过程,需执行 VUC 系统信息以获取当前的锁状态和配置。当前状态为字段 VUC 模式 ,具体配置的解锁密钥标识符在字段 VUC 密钥中,对于不支持 VUC 锁的固件版本,这两个字段都会缺失,取而代之的是空字节。

The VUC mode field can be one of the following values:
VUC 模式字段可以是以下值之一:

Value 价值 Description 描述
1 Locked 锁定
2 Engineering 工程
3 Unlocked 解锁
4 No lock (no key configured) 没有锁(没有配置钥匙)

The normal default mode of a drive is Locked, where the only accessible VUC operation is System Info 0x13. Under some conditions the default mode can instead be Engineering, such as if the drive enters a state commonly known as protected mode or SATAFIRM due to an internal error, or if the firmware is a burner version intended for in-memory loading. When in Engineering mode access is granted to the VUC operations for the unlock procedure, Unlock Start 0xC4, Unlock Read 0xC5, Unlock Write 0xC6, and Lock 0xC7.
硬盘的正常默认模式是锁定 ,唯一可用的 VUC 操作是系统信息 0x13。在某些情况下,默认模式可以改为工程模式 ,例如驱动器因内部错误进入通常称为保护模式SATAFIRM 的状态,或者固件是用于内存加载的烧录版本。在工程模式下,VUC 操作可执行解锁程序,如解锁启动 0xC4解锁读取 0xC5解锁写 0xC6锁定 0xC7

If the drive is in Locked mode, it must be changed to Engineering mode through ATA command DOWNLOAD MICROCODE. Although the command is normally used for updating firmware, additional functionality is implemented where a firmware header with the byte 0x33 at offset +0x35 will change the drive to Engineering mode instead of performing a firmware update.
如果驱动器处于锁定模式,必须通过 ATA 命令下载微将其切换为工程模式。虽然该命令通常用于固件更新,但还实现了额外功能,比如将字节 0x33 偏移为 +0x35 的固件头部会将驱动器切换到工程模式,而不是执行固件更新。

In Engineering mode, the challenge-response handshake is started by executing VUC write operation Unlock Start 0xC4 with a single sector of any data.
工程模式下,挑战响应握手通过执行 VUC 写操作 Unlock Start0xC4 对任意数据的单个扇区启动。

VUC read operation Unlock Read 0xC5 is then used to read a single sector of challenge data from the drive. The challenge data is then encrypted using the algorithm detailed in CRC-16 Based Cipher, with a seed value matching the drive's unlock key identified earlier in VUC System Info field VUC key.
随后使用 VUC 读取操作解锁读取 0xC5 从驱动器读取单个挑战数据扇区。挑战数据随后使用 CRC-16 基于密码的算法加密,种子值与之前在 VUC 系统信息字段 VUC 密钥中识别的驱动器解锁密钥相匹配。

The challenge response, the encrypted challenge data, is then sent back to the drive using VUC write operation Unlock Write 0xC6. If the challenge response is correct, the drive will then enter VUC mode Unlocked where VUCs are accessible.
挑战响应,即加密的挑战数据,随后通过 VUC 写操作 Unlock Write0xC6 返回硬盘。如果挑战响应正确,驱动器将进入 VUC 模式( 解锁 ),VUC 可访问。

The drive can then optionally be returned to the default mode with VUC write operation Lock 0xC7 with a single sector of any data.
驱动器随后可通过 VUC 写操作锁定 0xC7,选择性地返回默认模式,使用任意数据的单个扇区。

Vendor Unique Commands - VUC System Info 供应商唯一命令 - VUC 系统信息

VUC read operation System Info 0x13 is the most basic and common VUC used, and the only one accessible when a drive is in a fully VUC locked state. It returns a 512 byte structure that includes a variety of information on flash geometry, controller hardware, and firmware state. The structure of key fields in this System Info data is shown below:
VUC 读取操作系统信息 0x13 是最基本且常用的 VUC,也是当驱动器处于完全 VUC 锁定状态时唯一可用的。它返回一个 512 字节的结构,包含闪存几何形状、控制器硬件和固件状态等多种信息。系统信息数据中关键字段的结构如下所示:

System info

Algorithms 算法

Algorithms - CRC-32 Based Checksum 算法 - 基于 CRC-32 的校验和

The S11 implements a custom 32-bit checksum algorithm loosely based on CRC-32, used for various purposes such as firmware verification. This algorithm is implemented in the controller hardware itself, the firmware code has no software implementation. It uses a variable initial seed value to generate a checksum over data, different seed values result in different output, and different seed values are used in the firmware for different specific purposes. A Python implementation of this checksum is included below:
S11 实现了基于 CRC-32 的自定义 32 位校验和算法,广泛用于固件验证等多种用途。该算法是在控制器硬件中实现的,固件代码没有软件实现。它使用变量初始种子值生成数据校验和,不同的种子值会产生不同的输出,固件中不同种子值用于不同特定用途。以下附有该校验和的 Python 实现:

def checksum_crc32(data: bytes, seed: int) -> int:
    state: int = seed

    for offset in range(0, len(data), 4):
        state ^= int.from_bytes(data[offset : offset + 4], "little")

        for _ in range(32):
            feedback: bool = bool(state & (1 << 31))
            state = (state << 1) & 0xFFFFFFFF

            if feedback:
                state ^= 0x4C11DB7

    return state

Algorithms - CRC-16 Based Cipher 算法 - 基于 CRC-16 的密码

The S11 controller implements a custom and unusual symmetric stream cipher based on the CRC-16 checksum algorithm. The cipher generates a keystream from a 32-bit seed value used as a key, that keystream is then XORd with each byte of the plaintext for encryption, or inversely with ciphertext for decryption. This cipher is entirely implemented in controller hardware, and does not have any software implementation in the firmware.
S11 控制器实现了基于 CRC-16 校验和算法的定制且不寻常的对称流密码。密码从一个 32 位种子值生成密钥流,然后对明文的每个字节进行异或处理以进行加密,或反向与密文进行解密。该密码完全由控制器硬件实现,固件中没有任何软件实现。

This algorithm was likely chosen due to CRC-16 primitives already being hardware-accelerated in the controller, making it easier to implement hardware-accelerated than a more conventional symmetric cryptography standard algorithm. A Python implementation of this cipher is included below:
选择该算法可能是因为 CRC-16 原语已在控制器中实现硬件加速,使其实现硬件加速比传统的对称密码学标准算法更为容易。下面包含该密码的 Python 实现:

def advance(state: int) -> int:
    for _ in range(16):
        state = ((state << 1) ^ (0x8005 if state & (1 << 15) else 0)) & 0xFFFF

    return state

def reflect(value: int) -> int:
    return int(f"{value:016b}"[::-1], 2)

def cipher_crc16(data: bytes, seed: int, offset: int = 0) -> bytes:
    start, skip = divmod(offset, 512)
    seed = (seed + start) & 0xFFFFFFFF
    keystream: bytearray = bytearray()
    
    while len(keystream) < skip + len(data):
        state: int = advance(advance(0x1234 ^ reflect(seed & 0xFFFF)) ^ reflect(seed >> 16))
        seed = (seed + 1) & 0xFFFFFFFF
        
        for _ in range(16):
            reflected: int = reflect(state)
            inverse: int = state ^ 0xFFFF
            inverse_reflected: int = reflected ^ 0xFFFF
            values: tuple[int, ...] = (
                ((state << 4) & 0xFF00) | ((state >> 2) & 0xFF),
                ((inverse_reflected << 10) & 0xF000) | ((state >> 3) & 0xFFF),
                ((reflected << 4) & 0xFFF0) | ((inverse >> 8) & 0xF),
                ((state << 3) & 0xFFF0) | ((reflected >> 2) & 0xF),
                reflected,
                ((inverse << 8) | (state >> 8)) & 0xFFFF,
                ((reflected << 4) & 0xF000) | (inverse & 0xFFF),
                state,
                ((reflected << 1) & 0xFFF0) | ((state >> 11) & 0xF),
                inverse_reflected,
                ((state << 8) | (state >> 8)) & 0xFFFF,
                ((reflected << 8) | (reflected >> 8)) & 0xFFFF,
                inverse,
                reflected,
                ((state << 2) & 0xFFF0) | ((reflected >> 1) & 0xF),
                state,
            )
            keystream += struct.pack("<16H", *values)
            
            for x in values:
                state = advance(state ^ reflect(x))
                
    return bytes(x ^ y for x, y in zip(data, keystream[skip:]))

Algorithms - XOR 0561 算法 - XOR 0561

Phison NAND Flash Controllers (NFC) implement a pseudo-RNG based data scrambling algorithm applied to data stored on flash, variants of this same algorithm are commonly referred to as XOR 0561 in data recovery resources. This algorithm works by generating a keystream that then has each byte XORd with the relevant data, the specifics of how the keystream is generated are unknown, however it is constant and static always resulting in the same data, and has a repeating period of 16,384 bytes.
Phison NAND 闪存控制器(NFC)实现了一种伪随机数生成器的数据扰码算法,应用于存储在闪存中的数据,该算法的变体在数据恢复资源中通常称为 XOR 0561。该算法通过生成一个密钥流,每个字节与相关数据进行 XOR 处理,具体生成方式尚不清楚,但密钥流是常数且静态的,始终得到相同的数据,且重复周期为 16,384 字节。

A sample of the first 512 bytes of the keystream is included below:
以下是密钥流前512字节的示例:

00000000: 05 61 7f 9c 2d c8 0f 0b 3a 29 67 c7 c9 d2 ad 0b f4 56 ea 1c 3b 53 15 f0 cf d0 0f 9b 56 fb 19 94  .a..-...:)g......V..;S......V...
00000020: 44 ba 8c f1 6d 2e 60 a6 a2 d9 d1 38 d1 23 6b e4 1c 48 81 27 49 5d 7a d3 c5 90 de 66 c3 19 58 81  D...m.`....8.#k..H.'I]z....f..X.
00000040: 3c 8b 08 2f 40 02 72 8d 51 17 a7 3d 0b cb 36 a4 64 ba ae 88 64 8e 1b 90 13 e1 9b 1a 2e 76 c3 0c  <../@.r.Q..=..6.d...d........v..
00000060: 52 b0 a0 16 7f b2 e7 1f 35 66 03 30 83 9c 03 70 b8 08 55 00 9f fb 77 bf d9 75 b8 ff a5 83 44 42  R.......5f.0...p..U...w..u....DB
00000080: 1a 96 1d 0c 71 c0 9a 31 ce 2a da a7 7f 00 f0 0e 1a 2a 6f 0e 46 d5 c9 0c 3c 07 57 a7 68 63 9a 15  ....q..1.*.......*o.F...<.W.hc..
000000a0: 5b 23 62 bf dd a7 ef f5 e9 b9 94 1c 82 0e 70 1f 52 68 3b a4 9b 39 11 4a af 74 2e 82 ce 8f 64 65  [#b...........p.Rh;..9.J.t....de
000000c0: 2d 2b 56 e4 2b ad 47 ba a1 62 9f b4 e0 6c f7 1b c9 b5 85 ba 96 f3 db b3 3d 4d 01 22 cf 8b 5e c8  -+V.+.G..b...l..........=M."..^.
000000e0: ed c9 c4 3a bf 85 d8 1a af cf 3a f3 f6 01 0b dd 2f e8 56 3c b6 4d bf da 10 a9 0b 15 6a d0 63 1b  ...:......:...../.V<.M......j.c.
00000100: 4b 7d f1 59 ad 74 c9 dd 24 a1 86 91 73 8b 64 14 33 bb 3e ba 46 b4 d1 d1 15 ba 5b 39 aa 5a 95 b1  K}.Y.t..$...s.d.3.>.F.....[9.Z..
00000120: ae e6 ec ba fd 4b e3 d4 94 ef 00 0d 7f 9a ef 00 a2 b2 e0 e0 6b 2a 33 1d 71 89 20 32 51 64 68 6a  .....K..............k*3.q. 2Qdhj
00000140: ae c0 41 01 74 d7 db 46 9c f6 51 e4 82 14 3d 41 aa a8 13 25 db c2 4d 8b e8 6b 75 41 ac e3 30 46  ..A.t..F..Q...=A...%..M..kuA..0F
00000160: 38 a6 1b 8c 3f 5d ab a2 5d c1 09 2e dd fc 5f aa 60 33 49 ba 7b ee 24 13 09 4a 5c 3d ed 4e 5d 4d  8...?]..]....._.`3I.{.$..J\=.N]M
00000180: a5 20 7b 24 6c 6d 70 41 70 56 84 c1 ef 27 b2 ec c4 5e e0 3b 6a 71 2f 5b e9 44 5a 27 f7 8c b6 c8  . {$lmpApV...'...^.;jq/[.DZ'....
000001a0: 95 9a 17 63 83 d3 42 a4 bb fe ae 0b 24 1d a9 87 96 2f c5 07 2f 55 10 e7 76 54 7b b6 49 26 06 55  ...c..B.....$..../../U..vT{.I&.U
000001c0: bd b1 f7 3f 88 0f ef e9 c0 18 b4 ca b6 b6 81 33 28 d0 2a 52 fd 6b 74 53 91 52 3c 3a c6 b5 f4 bb  ...?...........3(.*R.ktS.R<:....
000001e0: 8c 43 18 62 9d 9e 30 cf 71 ff 27 81 f6 23 ba f7 5a 69 18 92 77 bb e3 c2 50 cf c9 41 12 e1 34 e6  .C.b..0.q.'..#..Zi..w...P..A..4.

Conclusion 结论

Overall the security of the Phison S11 controller is poor, with no functional protections against malicious firmware modification or Vendor Unique Command (VUC) access.
总体来说,Phison S11 控制器的安全性较差,没有针对恶意固件修改或供应商唯一命令(VUC)访问的功能性保护。

As detailed in Firmware - Format - Signature the nominal cryptographic signature in the firmware format is not only completely optional, able to be absent with no consequences, but also provides no actual security protections. The RSA public modulus used to verify the signature is itself contained in the signature data, meaning a valid signature can simply be generated with an arbitrary RSA keypair and added to a tampered firmware file, which a drive will accept and install. This signature is also only used through the standard firmware update procedure, using the ATA DOWNLOAD MICROCODE command, no signature is present with the firmware installed to flash, the only firmware verification the bootloader is capable of during the boot process is validating the simple 32-bit checksum detailed in CRC-32 Based Checksum. Even if a cryptographic signature of the firmware code was verified during boot, the Init Scripts feature of the firmware metadata header provides arbitrary memory write primitives usable for code execution before the firmware code can even be loaded for verification.
如固件 - 格式 - 签名中详细说明,固件格式中的名义密码签名不仅完全可选,可以无后果地不存在,而且不提供实际的安全保护。用于验证签名的 RSA 公共模数本身包含在签名数据中,这意味着只需用任意的 RSA 密钥对生成有效签名,并添加到被篡改的固件文件中,驱动器就会接受并安装该文件。该签名也仅通过标准固件更新程序使用,即 ATA 下载微码命令,固件安装后不存在签名,启动过程中引导加载程序唯一能进行的固件验证是验证 CRC-32 基于校验码中详细描述的简单 32 位校验和。即使固件代码的密码签名在启动时被验证,固件元数据头部的 Init 脚本功能仍提供任意内存写入原语,可用于代码执行,甚至在固件代码加载验证前即可。

Outside of the above detailed firmware signature's non-functional use of RSA and SHA256, no legitimate cryptographic algorithms are used for any security feature. The main cipher used, such as for firmware encryption and VUC unlocking, is the dubious cipher detailed in CRC-16 Based Cipher based on primitives of a non-cryptographic checksum, seemingly chosen for simplicity of hardware acceleration rather than security.
除了上述详细固件签名对 RSA 和 SHA256 的非功能性使用外,任何安全特性都没有使用合法的加密算法。主要使用的密码,如固件加密和 VUC 解锁,是基于非密码校验和原语的 CRC-16 加密中描述的可疑密码,似乎更注重硬件加速的简化而非安全性。

Code to demonstrate these vulnerabilities, including reading and writing firmware from a drive, packing and unpacking firmware files for modification, and various low-level access to drive internals through VUCs, can be found in the Psychite repository.
用于展示这些漏洞的代码,包括从驱动器读取和写入固件、打包和解压固件文件进行修改,以及通过 VUC 访问驱动器内部的各种低级别访问权限,都可以在 Psychite 仓库中找到。

  1. https://www.pcgamer.com/hardware/ssds/sata-drives-are-still-going-strong-as-kingston-announces-it-has-shipped-100-million-a400-ssds
  2. https://www.phison.com/en/solutions/ssd
  3. https://docs.google.com/spreadsheets/d/1B27_j9NDPU3cNlj2HKcrfpJKHkOf-Oi1DbuuQva2gT4
posted @ 2026-06-15 09:22  DirWangK  阅读(49)  评论(0)    收藏  举报