固件提取的三类方法:
- 直接从官网上找到目标型号的设备固件下载
- 使用Telnet或者ssh从目标设备中获取固件
- 从开发板中的flash芯片中或者通过uart和jtag调试接口将固件提取下来
JTAG(Joint Test Action Group),是一种用于测试和调试电子设备的技术标准。它使用4线或5线接口,其中有一条信号线用于提供时钟信号,其余几条信号线用于传输数据,另外还有一条地线。JTAG接口主要用于控制和调试外围设备,也可以用于检测外围设备的故障,以及更新外围设备的固件。
UART(Universal Asynchronous Receiver/Transmitter)是一种用于连接外围设备与计算机的接口,其主要功能是接收和发送数据。UART接口主要用于串行通信,可以将外围设备的数据传输到计算机,也可以将计算机的指令传输到外围设备。UART接口一般使用2线接口,一条信号线用于传输数据,另一条信号线用于提供时钟信号,还有一条地线。
USART,全称Universal Synchronous/Asynchronous Receiver/Transmitter,通用同步异步收发传输器
第一种方法是简单的,找到相应官方的设备固件就可以下载了,我们这里来介绍一下ssh连接,来提取固件
远程提取
我们通过putty来提取固件的信息到tmp目录来
首先是配置我们的putty,IP地址的输入,连接输入password之后就会有shell,于是就直接去查看固件信息
cat /proc/mtd
可以获取到mtd中的所有固件信息
mtd0: 00030000 00010000 "u-boot"
mtd1: 00010000 00010000 "u-boot-env"
mtd2: 00010000 00010000 "Factory"
mtd3: 01000000 00010000 "fullflash"
mtd4: 00fb0000 00010000 "firmware"
mtd5: 00100000 00010000 "kernel"
mtd6: 00eb0000 00010000 "rootfs"
mtd7: 003d0000 00010000 "rootfs_data"
同时就可以备份到tmp文件夹了
dd if=/dev/mtd0 of=/tmp/u-boot.bin
//将/dev/mtd0的文件以u-boot.bin的名称复制到/tmp/目录
dd if=/dev/mtd1 of=/tmp/u-boot-env.bin
dd if=/dev/mtd2 of=/tmp/Factory.bin
dd if=/dev/mtd3 of=/tmp/fullflash.bin
dd if=/dev/mtd4 of=/tmp/firmware.bin
dd if=/dev/mtd5 of=/tmp/kernel.bin
dd if=/dev/mtd6 of=/tmp/rootfs.bin
dd if=/dev/mtd7 of=/tmp/rootfs_data.bin
然后我们通过WinSCP按照SCP协议进行连接(输入)相应的IP,password
然后直接把刚才备份的tmp文件进行拖拽到硬盘就可以了
硬件提取
编程器提取固件
用测试夹直接夹取flash芯片,通过相应的编程器软件直接进行提取
uart串口提取固件
先是去分辨引脚,通过万用表去测量引脚,然后通过USB设备转TTL设备
分辨完引脚,需要链接usb转ttl设备和uart接口,可以焊一排引脚或使用测试夹,测试夹更方便,这里使用测试夹。
连接时按照文章中的对应关系,GND接TTL设备GND,TXD接TTL设备RXD,RXD接TTL设备TXD,Vcc不用接。
本文设备的对应关系:灰-1-Vcc、紫-2-GND、蓝-3-RXD、绿-4-TXD
正确连接后应如下图所示,POW灯亮,TXD和RXD灯灭。
完成接线后就是使用终端软件来接收终端,终端软件有很多,这里使用SecureCRT,使用PuTTY或者在linux上使用Picocom也可以。然后使用SecureCRT去连接
然后就会获得getshell
可使用的命令如下,能dump内存、读写闪存、通过tftp协议上传和下载文件、查看文件系统信息、连接云服务端等。
flash命令
flash -layout
查看flash布局,FIRMWARE
就是固件,偏移是0x32000,大小为1848k
使用flash -read时,系统奔溃了,询问gpt可以了解每条报错的含义,这里大概是因为虚拟内存中0x00000000地址不可写。用flash命令提取固件不太方便。
fs -stat
发现内存中rom的基址是BF000000,mem命令可以dump内存,那么或许可以从内存中dump闪存
使用mem -dump
查看BF000000-BF200000的内存的16进制,和编程器提取的flash比较,发现是一致的,那么通过该命令即可转储闪存。
但是一次最多dump 16k的数据也就是0x1000,那么需要dump两百次,写脚本进行dump。
import serial
import serial.tools.list_ports
import os
def ser_readall(): #读取并打印所有数据,去除回车并转义输出
c = ser.read().decode('utf-8')
while (c):
if (c == '\r'):
c = ''
print(c, end='')
c = ser.read(1).decode('utf-8')
port_list = list(serial.tools.list_ports.comports()) #搜索可用串口
print(port_list)
if len(port_list) == 0:
print('无可用串口')
else:
for i in range(0,len(port_list)):
print(port_list[i])
ser = serial.Serial()
ser.port = 'COM9'
ser.baudrate = 117500
ser.timeout = 0.5
ser.open()
print('Port ' + ser.port + ' open state: ' + str(ser.isOpen()))
start = 0xbf000000
len = 0x1000
f = open('TL-WR886N.bin','wb')
for i in range(0x200):
ser.write(b'mem -dump ' + hex(start).encode('utf-8') + b' ' + hex(len).encode('utf-8') + b'\r')
start += len
line = ser.readline().decode('utf-8').replace('\r','').replace('\n','')
while(line):
if (line[0:2] == 'BF'):
#print(line)
data = line.split(' ')[1].replace(' -','')
#print(data)
byte = data.split(' ')
#print(byte)
for c in byte:
word = bytes.fromhex(c)
f.write(word)
line = ser.readline().decode('utf-8').replace('\r','').replace('\n','')
print(str(i) + '/512')
binwalk
binwalk -Me code/firmware.bin”,“-Me”表示根据magic签名的扫描结果对固件进行递归提取
终端输入“binwalk -I code/firmware.bin”。选项“-I”用于显示所有的扫描结果,包括扫描过程中被定义为“invalid”的项:
终端输入“binwalk -W code/firmware.bin code/firmware2.bin”。选项“-W”对给定的文件进行字节比较,可以指定多个文件
用法: binwalk [选项] [文件1] [文件2] [文件3] ...
文件签名扫描选项:
-B, --signature 使用常见的文件签名扫描目标文件
-R, --raw=<str> 使用指定字节序列扫描目标文件
-A, --opcodes 使用普通可执行操作码签名扫描目标文件
-m, --magic=<file> 使用指定的特殊格式文件
-b, --dumb 禁用智能签名关键字
-I, --invalid 显示标记为无效的结果
-x, --exclude=<str> 排除与str相匹配的结果
-y, --include=<str> 只显示与str相匹配的结果
提取选项:
-e, --extract 自动提取已知的文件类型
-D, --dd=<type:ext:cmd> 提取类型的签名<type>, 文件扩展名为 <ext>, 执行的命令 <cmd>
-M, --matryoshka 递归扫描提取文件
-d, --depth=<int> 限制-M递归的范围 (默认值: 8次)
-C, --directory=<str> 提取文件或文件夹至指定文件夹 (默认值: 当前工作文件夹)
-j, --size=<int> 限制每个提取文件的大小
-n, --count=<int> 限制提取文件的数量
-r, --rm 清除在提取过程中提取工具无法处理的零大小文件。
-z, --carve 从文件中切割数据,但是不执行提取程序
熵分析选项:
-E, --entropy 计算文件熵
-F, --fast 使用快速但是不详细的熵分析
-J, --save 自动将由-E生成的的熵图保存为PNG文件而不是直接显示。
-Q, --nlegend 将熵图的说明省略
-N, --nplot 不生成熵图
-H, --high=<float> 设置上升边缘熵触发阈值 (默认值: 0.95)
-L, --low=<float> 设置下降边缘熵触发阈值 (默认值: 0.85)
二进制比较选项:
-W, --hexdump 执行输入文件的十六进制转储(s)和颜色编码区分:绿色—这些字节在所有文件中都是相同的。红色-这些字节在所有文件中都是不同的。蓝色—这些字节在某些文件中是不同的。
-G, --green 只显示在所有文件中都相同的字节所在的行
-i, --red 只显示在所有文件中都不相同的字节所在的行
-U, --blue 只显示在某些文件中都不相同的字节所在的行
-w, --terse 比较所有文件,但是只显示第一个文件的16进制转储
原始压缩选项:
-X, --deflate 用蛮力识别可能的原始压缩数据流
-Z, --lzma 扫描原始LZMA压缩流
-P, --partial 只使用常用的压缩选项搜索压缩流,速度快。
-S, --stop 在获得第一个结果后停止
通用选项:
-l, --length=<int> 需扫描的字节数
-o, --offset=<int> 跳过文件偏移量开始扫描
-O, --base=<int> 为所有的打印结果偏移量增加一个基址
-K, --block=<int> 设置文件块大小
-g, --swap=<int> 在扫描前每n字节反转一次
-f, --log=<file> 把结果记录到文件
-c, --csv 把结果记录到CSV文件中
-t, --term 格式化输出,已使用终端窗口
-q, --quiet 禁用输出到标准输出
-v, --verbose 启用详细输出,包括目标文件MD5和扫描时间戳。
-h, --help 显示帮助信息
-a, --finclude=<str> 只扫描文件名匹配正则表达式的文件
-p, --fexclude=<str> 不扫描文件名匹配正则表达式的文件
-s, --status=<int> 在指定端口启动状态服务器
文件系统:
当我们要去了解一个固件时,需要去了解那些文件
-
根目录 (
/
:- 查看整体目录结构,了解固件的组织方式。
-
/etc
- 包含系统配置文件,如
fstab
(文件系统表)、network/interfaces
(网络配置)、passwd
(用户信息)等。 init.d/
或rc?.d/
目录中的启动脚本,特别是rcS
或S*
脚本,它们定义了系统启动时的初始化流程。
- 包含系统配置文件,如
-
/bin/和/usr/bin/:
- 包含系统命令和程序,这些命令和程序在固件运行时会被使用。
-
/lib/和/usr/lib/:
- 包含系统库文件,这些库文件为系统命令和程序提供必要的函数和接口。
-
/var/:
- 包含系统运行时产生的数据,如日志文件(
/var/log/
)、数据库文件等。这些文件可以提供关于系统运行的详细信息。
- 包含系统运行时产生的数据,如日志文件(
-
/proc/和/sys/:
- 这两个目录提供了内核和硬件的实时信息。
/proc
是虚拟文件系统,用于访问内核空间的信息;/sys
是用于访问内核设备模型中的设备的文件系统。
- 这两个目录提供了内核和硬件的实时信息。
-
/boot/:
- 包含启动加载器(如U-Boot、GRUB等)和内核映像(如
vmlinuz
)以及相关的初始化RAM磁盘(initrd或initramfs)。这些文件对于系统启动至关重要。
- 包含启动加载器(如U-Boot、GRUB等)和内核映像(如
-
/dev/:
- 设备文件目录,包含代表系统中物理和逻辑设备的特殊文件。这些文件允许用户空间程序与硬件设备进行交互。
-
/sbin/:
- 包含系统管理员使用的命令和程序,这些命令和程序通常用于维护系统或管理硬件。
-
/usr/sbin/:
- 与
/sbin/
类似,但通常包含更通用的系统管理员命令和程序。
- 与
-
/usr/share/:
- 包含系统文档、示例配置文件、本地化文件等。
-
/mnt/和/media/:
- 通常用于挂载外部文件系统和设备。虽然这些目录在固件中可能不包含任何内容,但它们的位置和用途是了解文件系统结构的重要部分。
-
内核模块和驱动程序(
/lib/modules/
/usr/lib/modules/
):
- 这些目录包含内核模块(
.ko
文件),这些模块允许内核在运行时加载额外的硬件支持或功能。
- 这些目录包含内核模块(
-
固件更新和恢复机制(如
/usr/lib/firmware/
/lib/firmware/
,具体取决于固件设计):
- 这些目录可能包含用于更新或恢复固件的程序、脚本和二进制文件。
-
日志文件(通常位于
/var/log/
/tmp/
):
- 日志文件可以提供有关固件运行状况、错误和警告的宝贵信息。
-
版本信息和构建脚本(可能位于
/etc/
/usr/share/doc/
或其他位置):
- 这些文件可以提供有关固件版本、构建日期、构建者和构建选项的信息。