freeBuf
手上有啥就搞啥(七) 电纸书
2023-11-11 16:10:30

本篇是”手上有啥就搞啥“系列的第七篇,本来系列已完结,本篇是番(意)外篇,研究对象是电纸书,侧重点是固件提取和逆向

内容主要包括:

  • 0x00 缘起:一次偏离正轨的研究
  • 0x01 站在巨人肩上:硬件信息
  • 0x02 自己动手做:固件提取和逆向
  • 0x03 做个总结:简单总结
  • 0x04 写在最后:系列总结
  • 0x05 参考资料:参考链接

往期回顾:

手上有啥就搞啥(一) — 小米手环3

手上有啥就搞啥(二) — 猫盘

手上有啥就搞啥(三) — WiFi信号放大器

手上有啥就搞啥(四) — H3C 智能摄像头

手上有啥就搞啥(五) — 小米电力猫

手上有啥就搞啥(六) — 智能插座

0x00缘起

此次研究纯属意外,而且离初衷越走越远。收拾东西的时候发现一个古董级电纸书 汉王N510,用是没法用了,就想把屏幕拆下来做个墨水屏电子相册。后来本着拆都拆了研究下电路板吧,又到芯片,再到固件,一步步”误入歧途“。

0x01 站在巨人肩上

如下简单给出墨水屏Nand Flash处理器信息。

0x01 - 00 ED050SC3(LF)墨水屏

0x01 - 01HY27UF084G2B Flash DataSheet

0x01 - 02 Ingenic JZ4740 DataSheet

0x02 自己动手做

0x02 - 00 拆、拆、拆

拆机十分简单,主要目的是把屏幕拆下来:

屏幕型号是 ED050SC3,33 pin 墨水屏,之后主线应该是围绕驱动板图像处理硬件显示代码的开发,然而…

芯片是 Ingenic JZ4740 DataSheetmipsel架构,Nand Flash 是 hynix HY27UF084G2B

这里只把 Flash 吹下来提取固件:

0x02 - 01 固件提取

该Flash是TSOP48 封装,使用编程器选择正确的类型,读取固件,大小为 528M,与 DataSheet 中描述的存储结构相符。

0x02 - 03 固件分析

直到此刻都非常顺利,接下来只要运行 binwalk -e,快速搞定之后就能回去做正紧开发了,然而部分信息如下:

> binwalk Hynix HY27UF084G2B.bin
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
384112        0x5DC70         U-Boot version string, "U-Boot 1.1.6 (Sep 10 2009 - 15:22:56)"
385504        0x5E1E0         CRC32 polynomial table, little endian
4194304       0x400000        uImage header, header size: 64 bytes, header CRC: 0xEB6E491A, created: 2010-04-02 03:17:58, image size: 1487278 bytes, Data Address: 0x80010000, Entry Point: 0x802800C0, data CRC: 0xB8409BA4, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: gzip, image name: "Linux-2.6.24.3"
4194368       0x400040        gzip compressed data, maximum compression, has original file name: "vmlinux.bin", from Unix, last modified: 2010-04-02 03:17:58
25495523      0x18507E3       MySQL MISAM index file Version 2
26059613      0x18DA35D       MySQL MISAM compressed data file Version 9
26102424      0x18E4A98       MySQL MISAM index file Version 2
51828922      0x316D8BA       MySQL ISAM compressed data file Version 7
52586619      0x322687B       MySQL MISAM index file Version 4
54650826      0x341E7CA       MySQL ISAM index file Version 4
55179998      0x349FADE       MySQL MISAM index file Version 2
58751182      0x38078CE       MySQL ISAM compressed data file Version 11
58751288      0x3807938       MySQL ISAM compressed data file Version 11
58964726      0x383BAF6       Copyright string: "Copyright DynaComware Corp. 2009DFPHeiHK-W5DFPHeiHK-W5DFPHeiHK-W5RegularVersion 1.00Trademark by DynaComware Corp."
59047936      0x3850000       JPEG image data, JFIF standard 1.02
59047966      0x385001E       TIFF image data, big-endian, offset of first image directory: 8
59048268      0x385014C       JPEG image data, JFIF standard 1.02
59050819      0x3850B43       JPEG image data, JFIF standard 1.02
59064320      0x3854000       JPEG image data, JFIF standard 1.02
59064350      0x385401E       TIFF image data, big-endian, offset of first image directory: 8
59064652      0x385414C       JPEG image data, JFIF standard 1.02
59069983      0x385561F       JPEG image data, JFIF standard 1.02
59101184      0x385D000       JPEG image data, JFIF standard 1.02
59101214      0x385D01E       TIFF image data, big-endian, offset of first image directory: 8
59101516      0x385D14C       JPEG image data, JFIF standard 1.02
59104127      0x385DB7F       JPEG image data, JFIF standard 1.02
59111992      0x385FA38       Copyright string: "Copyright (c) 1998 Hewlett-Packard Company"
59123712      0x3862800       JPEG image data, JFIF standard 1.02
59123742      0x386281E       TIFF image data, big-endian, offset of first image directory: 8
59124044      0x386294C       JPEG image data, JFIF standard 1.02
59128366      0x3863A2E       JPEG image data, JFIF standard 1.02
59138192      0x3866090       Copyright string: "Copyright (c) 1998 Hewlett-Packard Company"
59172864      0x386E800       JPEG image data, JFIF standard 1.02
59172894      0x386E81E       TIFF image data, big-endian, offset of first image directory: 8
59173196      0x386E94C       JPEG image data, JFIF standard 1.02
59176220      0x386F51C       JPEG image data, JFIF standard 1.02
59184759      0x3871677       Copyright string: "Copyright (c) 1998 Hewlett-Packard Company"
59199488      0x3875000       JPEG image data, JFIF standard 1.02
59199518      0x387501E       TIFF image data, big-endian, offset of first image directory: 8
59199820      0x387514C       JPEG image data, JFIF standard 1.02
59208025      0x3877159       JPEG image data, JFIF standard 1.02
59221479      0x387A5E7       Copyright string: "Copyright (c) 1998 Hewlett-Packard Company"
59322368      0x3893000       PDF document, version: "1.4"
59323055      0x38932AF       Zlib compressed data, best compression
59662336      0x38E6000       JPEG image data, JFIF standard 1.01
59674624      0x38E9000       JPEG image data, JFIF standard 1.01
59756544      0x38FD000       JPEG image data, JFIF standard 1.02
......
92250582      0x57FA1D6       Unix path: /var/run/wvdial.%iface% -s 2
92264872      0x57FD9A8       Unix path: /etc/iproute2/rt_tables
92267112      0x57FE268       Unix path: /var/run/udhcpd.pid
92278136      0x5800D78       Unix path: /var/run/syslogd.pid
92288396      0x580358C       Unix path: /dev/misc/rtc
92295543      0x5805177       POSIX tar archive (GNU), owner user name: " magic", owner group name: "not stat tar file"

自动解包没有任何结构被解出,手动寻址发现很多误报,除了 U-BootuImage这种有头信息但解不开以外,唯一涨知识的点就是知道了 Hewlett-Packard是 惠普的全称。

当然解不开是正常的,因为是直接读取的 Flash,所以要手动去除 OOB,就是正常数据是512M,但每块都夹杂冗余信息,所以整体数据为 528M,具体结构如下:

Memory: 4096 blocks × 64 pages/block × 4 sectors/page × 512 Byte/sector = 512 MiB
Spare memory: 4096 blocks × 64 pages/block × 4 sectors/page × 16 Byte/sector = 16 MiB
Overall memory: 512 MiB + 16 MiB = 528 MiB

可以使用Flash工具,也可以简单写个脚本去除:

def fix_data(i, src_file, dst_file):
    with open(src_file, "rb") as fpr:
        with open(dst_file, "wb") as fpw:
            while(i > 0):
                fpw.write(fpr.read(0x800))
                gap = fpr.read(0x40)
                i = i - 0x800 - 0x40

if __name__ == '__main__':
    total = int(sys.argv[3], 16)
    src_file = sys.argv[1]
    dst_file = sys.argv[2]
    fix_data(total, src_file, dst_file)

此时再使用 binwalk 就可以解出 gzip 格式的 uImage,解压后是 vmlinux.bin,侧面说明之前的操作正确。

至于 binwalk识别的一长串后续信息,很多是误报,说明 rootfs很可能是 RTOS,使用 binwalk -A发现大量 mipsel指令也证明了这一点,这也是走入误区的开始。

精简过固件去掉其尾部的 0xff 后,按照猜测拖入IDA分析,虽然确实识别出很多指令和字符串,但载入地址毫无头绪,只能先回过头来看 vmlinux.bin

不管从 binwalk 识别的信息,还是其名字本身都基本能确定这是 Linux 内核,说明该电纸书使用的是 Linux 系统,这与之前的 RTOS 相矛盾,但 rootfs却没有被识别出来,甚至任何有用的头信息也没有。

于是回到固件本身,搜索有用的字符串,先从Uboot着手:

得到了启动参数:

bootargs=mem=64M console=ttyS0,57600n8 ip=172.17.2.26 rootfstype=yaffs2 root=/dev/mtdblock2
bootcmd=nand read 0x80600000 0x400000 0x200000;bootm
bootdelay=3
baudrate=57600
loads_echo=1
ethaddr=00:2a:cc:2a:af:fe
ipaddr=172.17.3.30
serverip=172.17.3.113
autoload=n
bootfile="uImage"

bootargs很明显看出使用的是 Linux系统, rootfs使用 Yaffs2结构,存储在 mtdblock2中,固件结构很可能如下:

uboot 根据字符串和 Flash Block 也可以手动解开,但是 yaffs2 开始没有解开,重要原因是无法找到mtdblock2 的起始地址,而 bootcmd 中的 0x400000 读取地址显然也不是。此时就感慨拆早了,常规研究方法是找到动态调试接口,获取dmesg信息,这样很容易知道 mtdblock2地址。

从固件中找了几个包含 ELF头的结构,确实可以恢复出来,且还有符号:

说明确实是有文件结构的,并非通过调度实现。因为把 Flash 焊回去更麻烦,就从 yaffs2 出发,笔者前段时间刚用同样的方式分析过 UBI 结构,这里 yaffs2 没有压缩,直接通过链的形式存储在 Flash 中。搜索了 yaffs2 的 magic 信息,固件中无法找到,甚至想直接利用 unyaffs 遍历爆破,但是文件太大。

抱着试试看的心态真的找到了该电纸书差不多型号的固件包:

从名字和大小基本可以知道功能和启动顺序:

uboot → kernel → initramfs → application

因为型号有所区别,所以固件格式并不完全相同,其中最大的 application_upgradeyaffs2格式。

此处废话:ubi 和 yaffs2 等格式的 rootfs 解包思路一般两种

  • 使用 unyaffs/ ubi_reader等工具直接解析结构
  • 使用 nandsim模拟 Flash 后挂载

前者虽然比较容易,但是对工具要求高,从 Flash 读取的内容很可能报错,笔者在修改多处 ubi_reader 源码后果断放弃,选择修改固件数据并使用第二种 nandsim 的方式。但此处可以直接使用 unyaffs解包。

unyaffs通过 apt install 安装,可直接识别上述 application_upgrade 的 yaffs2 格式:

通过分析 application_upgrade 格式,在需要分析的固件中搜索以下字符串:

03 00 00 00 01 00 00 00 FF FF 00 00 00 00 00 00

只有一个,根据 Flash 结构去掉尾部 0xff 提取,同样使用 unyaffs 解析,但是报错:

> unyaffs -d test
Detect no layout(s)

这就很尴尬了,只能又回到修改源码打印结构的老路上…

还有个办法,就是对比两个文件的 Block 头结构,发现完全一致,但是第一个 Block 的结尾有明显区别:

提取的文件结构到 0x800 结束:

application_upgrade 到 0x8400 结束:

不由让人想到 0x40 字节的 OOB,于是直接从未处理的固件数据中找到 yaffs2 头并提取,成功获得 rootfs 数据:

这样全部需要的结构都提取完毕,接下来就可以分析

个 P 啊 ~

固件解包完毕就结束吧,毕竟不是主线任务。此时再回溯,发现解包过程就是:

去掉OOB,提取 Uboot,vmlinux.bin

原始文件找到 03 00 00 00 01 00 00 00 FF FF 00 00 00 00 00 00,提取数据使用 unyaffs 恢复 yaffs2 rootfs。

so easy,但是就像漏洞挖掘一样,指给你看可能就一句话,自己找就费劲了。

0x02 - 04 回归开发

开发是另一个专题了,篇幅有限这里简单提及。

使用EPDIY 方案,对该墨水屏是支持的:

因为开源需要自己设计,就在 JLC 找了个现成的 ESP32 集成方案,因为笔者并不专业,正在继续踩坑中…

0x03 做个总结

此次研究因诸多原因较为曲折,后期梳理发现其实非常简单,总结如下:

0x04 参考资料

https://maehw.wordpress.com/2017/04/07/dumping-a-nand-flash-part-1/

https://cloud.tencent.com/developer/article/1554403

opennoah.github.io/datasheet/JZ4740_ds.pdf

https://dubeyko.com/development/FileSystems/YAFFS/HowYaffsWorks.pdf

https://epdiy.readthedocs.io/en/latest/getting_started.html#use-with-esp-idf

https://github.com/vroland/epdiy

https://www.alldatasheet.com/view.jsp?Searchword=Hy27uf084g2b&gclid=EAIaIQobChMIodnrhaqGgQMVWZJmAh2GSASlEAAYASAAEgIdtfD_BwE

本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
文章目录