恩山无线论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 877|回复: 32

[k2p] CFE 编译、结构解析与二进制修改

  [复制链接]
发表于 2019-5-31 06:43 | 显示全部楼层 |阅读模式
本帖最后由 spoon 于 2019-6-1 21:09 编辑

编译有点经验的都会,不是我的重点,编译 CFE 是为了分析其生成过程,从而了解一个 CFE 的结构,了解了结构,就可以对没有源码的 CFE 反编译和修改,规避其中的校验逻辑。
规避校验逻辑是为啥,自然是为了方便在 CFE miniWeb 网页里直接刷第三方固件了,不用敲那么多命令、不用其他的软件和复杂的步骤,何乐而不为?




【2019/6/1】
将 cfe 压缩回 cfez 时,如果大小有变化,要修改压缩数据之前的四个字节,把它的值改为后面压缩数据的大小(包含 5D 00 00 01 00 在内的大小)。 lzma.png




【2019/5/31】

CFE 全称 Broadcom Common Firmware Environment (CFE),用于初始化硬件,启动固件,类似于电脑的 BIOS。相比 breed 和 U-Boot,CFE 开放性小,资料少,至今很多博通机型,比如我现在用的 K2P B1,在刷入第三方固件时,仍然需要通过命令 + ftp服务器的方式,无法做到和 breed 一样操作简单直观、只需要一个浏览器就可以完成刷机。当然,CFE 也不是完全闭源的,还是可以找到它的一些源码,梅林源码里就有 Broadcom SDK6 和 SDK7 的源码(K2P B1 使用 SDK9)。我试着编译了其中的 CFE 部分,并做了一些研究,简单分享一下。

以 asuswrt-merlin 源码为例来编译 CFE,步骤如下:
1、下载梅林源码。
执行命令 git clone https://github.com/RMerl/asuswrt-merlin
国内 clone 速度会很慢,可以在码云等国内代码托管网站上远程导入 github 仓库,再 clone 到本地:
remote_clone.png
注意 clone 到本地时尽量使用 SSH 模式而不是 HTTPS 模式,避免出现 error: RPC failed; curl 18 transfer closed with outstanding read data remaining 错误。

2、配置编译环境。
以 Ubuntu 系统为例,遵照梅林 wiki 页给出的说明进行操作,am-toolchains 在 https://github.com/RMerl/am-toolchains
确保每个依赖性都安装正确,如果编译时报错,很大概率是因为依赖项的安装没有符合要求。

3、编译 CFE。
假定源码的位置在 ~/asuswrt-merlin,以 SDK6 作为编译目标:
  • cd ~/asuswrt-merlin/release/src-rt-6.x.4708/cfe/build/broadcom/bcm947xx
  • export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/asuswrt-merlin/release/src-rt-6.x.4708/toolchains/hndtools-arm-linux-2.6.36-uclibc-4.5.3/lib/
  • export PATH=$PATH:/opt/brcm/hndtools-mipsel-linux/bin:/opt/brcm/hndtools-mipsel-uclibc/bin:/opt/brcm-arm/bin
  • export PATH=$PATH:~/asuswrt-merlin/release/src-rt-6.x.4708/ctools/
hndtools-arm 工具的 lib 目录需要添加到 LD_LIBRARY_PATH 里;加 ctools 到 PATH 里是因为编译 CFE 会用到里面的 lzma_4k 工具。


打开 bcm947xx 下的 Makefile 文件,第一句有 include ../../../../.config,所以还需要在 ~/asuswrt-merlin/release/src-rt-6.x.4708 下新建一个 .config 文件,要是之前编译过固件,那这个文件已经存在了。
.config 的内容是一些 export,如果没有这个文件,可以根据 Makefile 的参数手动输入,比如:
  • export BUILD_NAME=RT-AC56U
  • export RTAC56U=y
其他配置参数可查看 Makefile 补充。


此时执行 make 操作,稍等一会 CFE 就会编译完成:
cfez.png

CFE 编译部分完成,下面来看看它的结构:
首先浏览一下 bcm947xx 目录下的 Makefile,关键的部分在:
bcm947xx_mk.png
include 的 cfe.mk 会编译 ~/asuswrt-merlin/release/src-rt-6.x.4708/cfe/cfe/main 中的源码,再通过 ar 和 ranlib 合并为一个 libcfe.a 静态库。Makefile 的编译目标是 cfe.bin,会跳转到 compressed 子目录中。

~/asuswrt-merlin/release/src-rt-6.x.4708/cfe/build/broadcom/bcm947xx/compressed 目录的 Makefile 文件:
compressed_mk.png

大致了解一下它的编译流程就行,主要看它给出的几个注释:
# Link the loader and the kernel binary together
# Create a linkable version of the (possibly compressed) kernel binary
说的很清楚,CFE 中有一个 loader 和一个可能压缩了的 kernel。

看 Makefile 比较麻烦,可以直接看编译的输出:
  • arm-uclibc-linux-2.6.36-ar cr libcfe.a  一大堆.o文件
  • arm-uclibc-linux-2.6.36-ranlib libcfe.a
  • arm-uclibc-linux-2.6.36-cpp -P 各种参数 ~/asuswrt-merlin/release/src-rt-6.x.4708/cfe/cfe/arch/arm/common/src/cfe_ldscript.template ./cfe.lds
  • arm-uclibc-linux-2.6.36-ld -o cfe -Map cfe.map -static --gc-sections -g --script ./cfe.lds  后面省略,其中 cfe.map 用到了上面生成的 libcfe.a
  • arm-uclibc-linux-2.6.36-objdump -d cfe > cfe.dis
  • arm-uclibc-linux-2.6.36-objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S cfe cfe.bin
  • arm-uclibc-linux-2.6.36-objcopy --input-target=binary --output-target=srec cfe.bin cfe.srec
  • make  -C compressed
  • sed -e s/TEXT_START/0xc0000000/ -e s/TARGET_ARCH/arm/ < /home/spoon/asuswrt-merlin/release/src-rt-6.x.4708/shared/cfez_arm_shmoo.lds.in > cfez.lds
  • arm-uclibc-linux-2.6.36-objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S ../cfe piggy
  • lzma_4k e piggy piggz
  • arm-uclibc-linux-2.6.36-ld -no-warn-mismatch -T piggy.lds -r -o piggy.o -b binary piggz -b elf32-littlearm
  • arm-uclibc-linux-2.6.36-ld -static -Map cfez.map --gc-sections -no-warn-mismatch -T cfez.lds -o cfez ... -lgcc piggy.o
  • arm-uclibc-linux-2.6.36-objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S cfez cfez.bin
  • arm-uclibc-linux-2.6.36-objcopy -O srec -R .reginfo -R .note -R .comment -R .mdebug -S cfez cfez.srec

上面这些是从日志中挑选出来的的部分,粗体为命令的输出结果。可知 cfe 是 kernel,cfez 是 loader。
cfe 被 objcopy -R 去掉了 .reginfo、.note、.comment 和 .mdebug 段,再 -S 去掉了重定位信息和符号信息,以 -O binary 保存为 piggy,通过 lzma_4k 的压缩生成 piggz,再按 piggy.lds 生成 piggy.o,最后链接到 cfez 中。
cfez.bin 就是常说的用于刷入 boot 分区的 cfe 了,和 piggy 一样是去掉了相关 section 和重定位信息以及符号信息的。
当然,在刷入 cfez.bin 之前还要把基本的参数数据写进去,命令为:
  • ../../../../../ctools/nvserial -i cfez.bin -o cfe_rt-ac68u.bin -s 00 rt-ac68u_nvram.txt

如果 nvserial 工具加了 -z 参数,就会对 rt-ac68u_nvram.txt 中的数据进行 lzma 压缩,存放在 cfez 的 embedded nvram 数据区(0x400 开始,我之前的一篇帖子有分析)中,不加 -z 就是明文保存的。

通过十六进制编辑器可以直观地看到 piggy.o 中的压缩数据在 cfez 中的位置:
piggy_o_in_cfez.png
这里有一个小经验:lzma 压缩的数据通常有一个字节序列为 5D 00 00 01 00 的开头,可以通过这个快速搜索到压缩数据位置。

再来对比下链接 cfe 和 cfez 时使用到的 .o 文件:
cfe:
cfe_ld.png

cfez:
cfez_ld.png

这样就已经很清晰了,cfez 起 loader 的作用,只链接了一小部分必要的功能,cfe 被 cfez 解压后载入,拥有完整的 cfe 功能。
再分别挑两个典型源码来看看,以验证这一点。

先是 cfez 的 load.o,它编译自 ~/asuswrt-merlin/release/src-rt-6.x.4708/shared/load.c,看其中的 c_main 函数的最后:
boad_c_main.png

再看看这个 load 函数:
load_load.png
decompressLZMA 解压了 cfez 中的压缩数据块,解压得到的数据的地址就直接成为 LOADADDR 被载入执行。

然后再看看 cfe 的 net_http.o,它编译自 ~/asuswrt-merlin/release/src-rt-6.x.4708/cfe/cfe/net/net_http.c,看其中 httpd_load_program 函数的一段:
httpd_load_program.png
在 CFE miniWeb Server 页面点 upload 上传第三方固件刷机,就会看到红框里这个提示。


接下来说说如何在没有源码的情况下修改 cfe 以解除一些限制,其中会涉及到 cfe 和 cfez 的数据结构,其实它们的数据结构就是 ELF 文件结构,如果了解的话,很容易摸清楚。
以 K2P B1 的 CFE 为例,我使用的是 dd if of 命令获得的 mtd0.bin 文件。

搜索字节序列 5D 00 00 01 00,列出全部:
lzma_compressed_blocks.png

第一个压缩数据块是压缩的 nvram 参数数据,第二个就是压缩的 cfe 了。

把压缩的 cfe 数据块复制出来,存到一个文件里,比如 k2p_b1_cfe_compressed.bin:
cfe_compressed_in_cfez.png
从 5D 00 00 01 00 开始复制(包括在内),直到 FF 块为止。

进入 linux,使用 lzma_4k d k2p_b1_cfe_compressed.bin k2p_b1_cfe_uncompressed.bin 命令解压得到 k2p_b1_cfe_uncompressed.bin。
对照之前编译获得的 cfe,在 k2p_b1_cfe_uncompressed.bin 文件开头处插入 cfe 文件开头的 0x8000 个字节数据,这样 k2p_b1_cfe_uncompressed.bin 就有了 ELF 头,不过需要修改之后才能用。
使用 010 Editor + ELFTemplate 调整 k2p_b1_cfe_uncompressed.bin 的 ELF 文件头中 program_header_table 部分,主要是其中的 element0 和 element1。以 K2P B1 的 cfe 为例,element1 需要调整起始位置为 1A640h。element1 需要调整数据长度为 文件大小 - 8000h。
010editor_example.png
修改完成之后,另存为 k2p_b1_cfe_uncompressed_with_elf.bin。

之后,就可以使用 IDA 反编译这个 k2p_b1_cfe_uncompressed_with_elf.bin 文件了,弹出提示点确定继续即可。
查看一下 strings 数据:
ida_view_strings.png

对 String 栏使用 filter 过滤,搜索关键字 valid,双击 The file transferred is not a valid firmware image. 一句:
valid_fireware.png

双击后面的函数地址:
to_sub_F43AF8.png

看到红框处的 BNE,它其实对应了源码 net_http.c 中 httpd_load_program 的 rc = trx_validate ... switch (rc) ... 一段:
bne_to_beq.png

点开 菜单-Edit-Patch program-Change byte,查看其所在地址和字节序列:
ida_patch_bytes.png

将 BNE 改为 BEQ,就可以反转判断,trx_validate 函数校验出错反而进入刷机流程。
改法很简单,只是一些破解的基础操作,把开头的字节序列 08 00 00 1A 改为 08 00 00 0A 即可。我之前改过一次了所以上面截图里已经是 08 00 00 0A 了。
具体的 ARM 指令和 HEX 之间的互转,可以在 http://armconverter.com/hextoarm/ 上获取,注意选择适合 CPU 和固件的指令版本,比如 bcm4718 是 ARM v7 x32。
改的时候需要在十六进制编辑器里改,通过 IDA 给出的地址修改对应的字节即可。

下面的 loc_F43DAC 块最后也有一个 BNE,也需要改为 BEQ,用于返回正确的返回值 0。

梅林源码里的 trx_validate 只是一些简单的数据校验,确保 trx 文件没有数据错误,而 K2P B1 里的 trx_validate 是这样的:
trx_validate.png
其中 v8 是返回值,要返回 0 才可以。sub_F6173C 方法我没仔细去看,从出错提示信息来看应该是 AES 解密,然后校验。第三方的固件里没有这些数据,自然就校验不过。

改完之后的 k2p_b1_cfe_uncompressed_with_elf.bin,把它另存为 k2p_b1_cfe_uncompressed_hacked_with_elf.bin,然后删掉之前加在头部的 0x8000 个字符,另存为 k2p_b1_cfe_uncompressed_hacked.bin,使用 lzma_4k e k2p_b1_cfe_uncompressed_hacked.bin k2p_b1_cfe_compressed_hacked.bin,最后再重新覆盖到 mtd0.bin 中原来的压缩数据的位置上,生成新的 mtd0_new.bin,刷入 boot 分区。

不过我的研究也就到此为止了,因为修改的 cfe 有点问题,路由器暂时用不了了。
一开始我改了第一个 BNE,压缩出来的数据长度没变,覆盖粘贴另存为 mtd0_new.bin 刷进去,重启进入修改后的 CFE,选了一个第三方固件上传,提示确实变成 Upload completed.  System is going to reboot.<br>Please wait a few moments. 了,但只是提示变了而已,返回值不是 0。于是改了返回值,方法是把 loc_F43DE0 里的 MOV R3, #FFFFFFFF 改成 MOV R3, #0,结果压缩出来的数据变大了几个字节,偷懒没多研究,就使用 insert 粘贴的方法写到 mtd0.bin 里,删掉最后多出来的几个 0xff,抱着侥幸的心理再次刷机,然后路由器起不了了,没有 ttf 转 usb 线,看不到启动信息,编程夹子也不好使,老是不识别,没有电烙铁,研究中止,什么时候有空再看,还好还有个老路由可以用。

抛砖引玉,欢迎指正、交流。


评分

参与人数 7恩山币 +12 收起 理由
php.c + 2 率全体恩山路由党以及党魁向你学习!
懒懒猪 + 1 强大的恩山!(以下重复1万次)虽然看不懂。
jbzzz + 2 面对这种帖子,我内心复杂,真不知道说什么好……
samyi + 1 支持技术型人才
laoma348 + 2 面对这种帖子,我内心复杂,真不知道说什么好……
safehorse + 2 看到这样的楼主我总是见一次支持一次!
hcyme + 2 面对这种帖子,我内心复杂,真不知道说什么好……

查看全部评分

我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-5-31 07:10 | 显示全部楼层
自从Breed之后,好少有人研究CFE了
支持楼主!
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-5-31 07:12 来自手机 | 显示全部楼层
谢谢分享,实在太高级,只能看看啦
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-5-31 08:07 | 显示全部楼层
支持楼主的研究!

B1版的FLASH应该也是8脚SPI, 烙铁用起来吧, 应该是好搞的. 如果之前没用过烙铁, 只需要注意买把好用的黄花907S就行了.

在FLASH周围贴上白色那种胶带稍微保护下, 然后左右两边针脚加点松点末, 烙铁加到350度, 左右两三下后,用一支笔轻轻推FLASH侧面就马上滑到边上拆下来了

点评

哈哈,多谢说明,我没用过电烙铁,还是有点担心的,看完你的说明放心了很多,现在就去下单买一个  详情 回复 发表于 2019-5-31 15:40
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-5-31 09:46 | 显示全部楼层
这个要顶一下,BCM的好长时间没人研究过了...
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-5-31 14:31 | 显示全部楼层
很有深度的帖子,本人才疏学浅,一句也没看懂,有Breed真好
我的恩山、我的无线 The best wifi forum is right here.
 楼主| 发表于 2019-5-31 15:40 | 显示全部楼层
safehorse 发表于 2019-5-31 08:07
支持楼主的研究!

B1版的FLASH应该也是8脚SPI, 烙铁用起来吧, 应该是好搞的. 如果之前没用过烙铁, 只需要 ...

哈哈,多谢说明,我没用过电烙铁,还是有点担心的,看完你的说明放心了很多,现在就去下单买一个

点评

为了安全, 那种白色的美纹胶带可以贴个二层, 这样, 加上 松香的保护, 应该是比较安全了. 然后刚拆下来的时候, 你可以发现焊盘上也是有不少锡, FLASH的8个脚上也有, 分两步处理: 1. 空焊盘上的处理 : 烙铁温  详情 回复 发表于 2019-5-31 15:55
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-5-31 15:55 | 显示全部楼层
spoon 发表于 2019-5-31 15:40
哈哈,多谢说明,我没用过电烙铁,还是有点担心的,看完你的说明放心了很多,现在就去下单买一个


为了安全, 那种白色的美纹胶带可以贴个二层, 这样, 加上 松香的保护, 应该是比较安全了.

然后刚拆下来的时候, 你可以发现焊盘上也是有不少锡, FLASH的8个脚上也有, 分两步处理:

1. 空焊盘上的处理 : 烙铁温度就保持刚才那样或者调到300度, 然后因为上面还有松香残留, 所以你轻轻用烙铁一抹, 焊盘上的锡就被吸到烙铁上了, 自己抖掉或者买个吸锡球弄掉.

2. FLASH上锡的残留: 可以先用另外一支手拿着FLASH, 两边的引脚分别往松香末里扎几下, 让它带点松香.
然后你也用烙铁两边那边轻轻一抹, 引脚上的锡也被带到烙铁上了.

其实也可以买点细砂纸, 如果FLASH读不出来, 可以FLASH放平在砂纸上轻轻一磨, 再往CH341A上加一那种转接头一般就读出来了

点评

好的!全都是干货,感谢。  详情 回复 发表于 2019-5-31 16:00

评分

参与人数 1恩山币 +2 收起 理由
spoon + 2 多谢

查看全部评分

我的恩山、我的无线 The best wifi forum is right here.
 楼主| 发表于 2019-5-31 16:00 | 显示全部楼层
safehorse 发表于 2019-5-31 15:55
为了安全, 那种白色的美纹胶带可以贴个二层, 这样, 加上 松香的保护, 应该是比较安全了.

然后刚拆 ...

好的!全都是干货,感谢。
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-5-31 20:32 | 显示全部楼层
其实流程很多人都懂,只不过这东西放出来最后只会坑一批人,所以楼主准备好挨骂吧
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-5-31 21:02 | 显示全部楼层
支持楼主分享知识,很多害群之马,见不得别人分享东西,见不得别人有机会学东西,确实应该鄙视之。
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-6-12 10:46 | 显示全部楼层
支持楼主的研究,不过ida还是不太会用,以前学的汇编也忘的差不多了
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-6-12 19:33 | 显示全部楼层
支持楼主,干货
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-6-30 17:52 | 显示全部楼层
[k2p] CFE 编译、结构解析与二进制修改厉害了
我的恩山、我的无线 The best wifi forum is right here.
发表于 2019-7-3 11:44 | 显示全部楼层
编辑夹,一般需要把闪存拿下来写,而且已经有接触不良。八个角的好搞,希望楼主接着搞。。。
我的恩山、我的无线 The best wifi forum is right here.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|Archiver|恩山无线论坛(常州市恩山计算机开发有限公司版权所有) ( 苏ICP备05084872号 )

GMT+8, 2019-7-17 02:23

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表