作者 | 绿盟科技格物实验室 李东宏
前言
获得访问权限
pi@raspberrypi:~/modem $ cu -l /dev/serial0 -s 115200
Connected.
�
B3312inim S C 84(9 m
ose_VS 8
STesldlo rh 83 rs 10
STesldhi: _h 8, _s 13
Sync: 0
MemSize: 128 M
Chip ID: BCM3383D-B0
BootLoader Version: 2.4.0 fyl spiboot reduced DDR drive avs
Build Date: Nov 12 2015
Build Time: 14:31:43
SPI flash ID 0xef4016, size 4MB, block size 64KB, write buffer 256, flags 0x0
Cust key size 128
Signature/PID: 3383
Image 1 Program Header:
Signature: 3383
Control: 0005
Major Rev: 0003
Minor Rev: 0000
Build Time: 2015/11/26 08:47:57 Z
File Length: 1692841 bytes
Load Address: 80004000
Filename: ecram_sto.bin
HCS: e749
CRC: 175b753f
Found image 1 at offset 20000
Enter '1', '2', or 'p' within 2 seconds or take default...
Performing CRC on Image 1...
CRC time = 282177012
Detected LZMA compressed image... decompressing...
Target Address: 0x80004000
decompressSpace is 0x8000000
Elapsed time 736066500
Decompressed length: 8091524
Executing Image 1...
eCos - hal_diag_init
Ecos memory map:
BLOCK OWNER MIPS SIZE MEM
Block 0: Owner: 0 - 0x00000000 0x07e00000 0x00000000
Block 0: Owner: 0 - 0 MB 126 MB 0 MB
Block 1: Owner: 3 - 0x07e00000 0x00200000 0x07e00000
Block 1: Owner: 3 - 126 MB 2 MB 126 MB
126MB (129024KB) remaining for eCos
Init device '/dev/BrcmTelnetIoDriver'
Init device '/dev/ttydiag'
Init tty channel: 807bb020
Init device '/dev/tty0'
Init tty channel: 807bb040
Init device '/dev/haldiag'
HAL/diag SERIAL init
Init device '/dev/ser0'
BCM 33XX SERIAL init - dev: b4e00500.2
Set output buffer - buf: 0x80852408 len: 4096
Set input buffer - buf: 0x80853408 len: 4096
BCM 33XX SERIAL config
Init device '/dev/ser1'
BCM 33XX SERIAL init - dev: b4e00520.3
Set output buffer - buf: 0x80854408 len: 4096
Set input buffer - buf: 0x80855408 len: 4096
BCM 33XX SERIAL config
Init device '/dev/ser2'
InitBoard: MIPS frequency 637200000
...
Reading Permanent settings from non-vol...
Checksum for permanent settings: 0xe9d88f65
Setting downstream calibration signature to '5.7.1mp1|die temperature:70.775degC'
Settings were read and verified.
Reading Dynamic settings from non-vol...
Checksum for dynamic settings: 0x6e4a329
Settings were read and verified.
Console input has been disabled in non-vol.
Console output has been disabled in non-vol! Goodbye...
[00:00:00 01/01/1970] [Reset/Standby Switch Thread] BcmResetStandbySwitchThread::ProcessResetSwitchEvent: (Reset/Standby Switch Thread) Reset switch released; resetting...
[00:00:00 01/01/1970] [Reset/Standby Switch Thread] BcmResetStandbySwitchThread::ProcessResetSwitchEvent: (Reset/Standby Switch Thread) Cant Reset pfCmDocsisCtlThread==NULL...
从芯片中获取固件
当前的目标是启用串行控制台,这部分的参数很可能存储在引导加载程序、操作系统或配置中,这些配置数据一般是放在一个外置的存储芯片中,通过对板卡电路的分析发现了如下芯片(winbond 25Q32JV):
通过相关芯片资料可以知道芯片采用了SPI接口以及相关的管脚定义,主要的SPI管脚为VCC,片选(CS),时钟(CLK),数据输出(DO),数据输入(DI)和地。由于树莓派也存在一个SPI的控制端口,可以从芯片中读取数据,于是将导线焊接到其引脚上,并将它们连接到树莓派。地线接地(也可以使用更早的UART地线),VCC到树莓派的3.3v引脚,DO引脚连接到树莓派的SPI MISO(主机输入从机输出)引脚,DI引脚连接到MOSI引脚(主机输出从机输入)。最后,时钟连接到SCLK GPIO引脚,芯片选择连接到该CE0引脚。
要真正读取芯片,有一个很棒的工具叫做 flashrom,它支持大量芯片,并存在于树莓派的发行版本中。
通过如下命令可验证是否已检测到正确的接线。
flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=2000 --chip W25Q32.V
如果成功了则可以进行固件转储。
flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=2000 --chip W25Q32.V --read modem.bin
固件数据分析
快速浏览十六进制转储,可以看到大多数数据已压缩或加密,但是在最后,配置是可见的。
...
003f00c0: ffff ffff ffff ffff ffff 0000 07b0 369a ..............6.
003f00d0: 6336 0010 434d 4170 0002 0000 0002 0000 c6..CMAp........
003f00e0: 0000 0057 4d4c 6f67 0005 0004 7573 6572 ...WMLog....user
003f00f0: 0004 7573 6572 0005 6164 6d69 6e00 086d ..user..admin..m
003f0100: 6f74 6f72 6f6c 6102 7465 6368 6e69 6369 otorola.technici
...
set bfc.serial_console_mode "rw" ./bcm2-utils/bcm2cfg
bfc.serial_console_mode = rw
set userif.remote_acc_methods 0x3 ./bcm2-utils/bcm2cfg
userif.remote_acc_methods = http | telnet
set userif.remote_acc_pass abcd ./bcm2-utils/bcm2cfg
userif.remote_acc_pass = abcd
将修改后的文件前端用零填充,使配置信息位于0x003f0000处,然后用flashrom将配置写回到芯片上。为了避免重写整个芯片,需要创建一个布局文件,内容如下:
00000000:003effff fw
003f0000:003fffff cfg
flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=2000 --chip W25Q32.V --layout ./layout --image cfg --write modem-modified.bin
...
Reading Permanent settings from non-vol...
Checksum for permanent settings: 0xe9d88f65
Setting downstream calibration signature to '5.7.1mp1|die temperature:70.775degC^@^@^@^@^@'
Settings were read and verified.
Reading Dynamic settings from non-vol...
Checksum for dynamic settings: 0x2630e508
Settings were read and verified.
[00:00:00 01/01/1970] [tStartup] BcmBfcFpmDriver::Init: (BFC FPM Driver) Setting FPM Buffer size to: 256 Base Address: 0x87566600
[00:00:00 01/01/1970] [tStartup] BcmBfcFpmDriver::Init: (BFC FPM Driver) fFpmLargestBufferSize: 2048 fFpmSizeShiftBits: 0x8
[00:00:00 01/01/1970] [tStartup] BcmBfcFpmDriver::Init: (BFC FPM Driver) Pool index: 0 pool size: 2048
[00:00:00 01/01/1970] [tStartup] BcmBfcFpmDriver::Init: (BFC FPM Driver) Pool index: 1 pool size: 1024
[00:00:00 01/01/1970] [tStartup] BcmBfcFpmDriver::Init: (BFC FPM Driver) Pool index: 2 pool size: 512
[00:00:00 01/01/1970] [tStartup] BcmBfcFpmDriver::Init: (BFC FPM Driver) Pool index: 3 pool size: 256
[00:00:00 01/01/1970] [tStartup] BcmBfcFpmDriver::Init: (BFC FPM Driver) Lookup table index: 0 pool size: 3
...
[00:00:18 01/01/1970] [Scan Downstream Thread] BcmGenericCmDownstreamScanThread::ThreadMain: (Scan Downstream Thread) Scanning for a Downstream Channel...
[00:00:18 01/01/1970] [Scan Downstream Thread] BcmGenericCmDownstreamScanThread::ScanStarting: (Scan Downstream Thread) Scanning STD & HRC Annex B channel plan frequencies
Resetting EnergyDetected to false.
Forgetting energy frequency.
Executing fast scan algorithm...
Type 'help' or '?' for a list of commands...
CM> Scanned 489000000 Hz...
Scanned 495000000 Hz...
Scanned 501000000 Hz...
Scanned 507000000 Hz...
Scanned 513000000 Hz...
eCos控制台
cd cm_hal
scan_stop
逆向分析固件
./ProgramStore -f ./ecram_sto.bin -o decompressed_fw.bin -c 4 -x
case 0x24:
(**(code **)(*piParm1_00 + 0x1c))(piParm1_00); =
突破
CM> read_memory -n256 0x86fb3e80
86fb3e80: 00 00 06 8c 00 3f fe 48 00 00 06 41 00 20 00 3d | .....?.H...A. .=
86fb3e90: 00 00 08 56 00 20 02 11 00 00 0a b3 00 20 03 f2 | ...V. ....... ..
86fb3ea0: 00 00 0a 50 00 20 04 84 00 00 06 61 00 20 03 d7 | ...P. .....a. ..
86fb3eb0: 00 00 01 1d 00 20 02 da 00 1f fd f4 00 20 00 4d | ..... ....... .M
86fb3ec0: 00 1f fd 11 00 3f fc 20 00 1f fb 95 00 3f fa ad | .....?. .....?..
86fb3ed0: 00 1f fa 32 00 3f fd fc 00 1f fc a3 00 20 00 cb | ...2.?....... ..
86fb3ee0: 00 00 01 97 00 3f fe b5 00 00 04 0f 00 3f fb 6a | .....?.......?.j
86fb3ef0: 00 00 03 9f 00 3f fb d6 00 00 03 1d 00 3f fe 55 | .....?.......?.U
86fb3f00: 00 00 02 f8 00 3f ff a9 00 00 02 ee 00 20 01 49 | .....?....... .I
86fb3f10: 00 00 03 8f 00 20 04 87 00 00 03 94 00 20 05 09 | ..... ....... ..
86fb3f20: 00 00 01 81 00 3f ff bb 00 1f ff 14 00 3f fa 97 | .....?.......?..
86fb3f30: 00 1f fe 8d 00 3f fc 9d 00 1f ff 89 00 20 01 82 | .....?....... ..
86fb3f40: 00 00 00 be 00 20 00 09 00 00 01 8f 00 3f fa 3a | ..... .......?.:
86fb3f50: 00 00 01 78 00 3f fa 66 00 00 00 7b 00 20 01 35 | ...x.?.f...{. .5
86fb3f60: 00 1f ff 79 00 20 04 f6 00 1f fe e2 00 20 02 62 | ...y. ....... .b
86fb3f70: 00 1f fd 93 00 3f ff 4d 00 1f fa ee 00 3f fe 16 | .....?.M.....?..
Case 1: Case 2:
Q IQ IQ IQ I IQ IQ IQ IQ
| do nothing
v v
IQ IQ IQ IQ IQ IQ IQ
实践分析
memset = 0x80522d7c;
memcpy = 0x80004f30;
malloc = 0x80596998;
printf = 0x8052b178;
socket = 0x80332fd0;
bind = 0x800ae7bc;
listen = 0x80412ed4;
accept = 0x80413118;
send = 0x80413240;
recv = 0x804134bc;
tune_aux_channel = 0x80082108;
SECTIONS
{
. = 0x80810000;
.start : { *(.start) }
.text : { *(.text) }
.data : { *(.data) }
.rodata : { *(.rodata) }
}
使用如下命令进行编译:
measure.c
-march=mips32
-mabi=eabi
-msoft-float
-mno-abicalls
-fno-builtin
-nodefaultlibs
-nostartfiles
-T ./script.ld
mips-linux-objcopy -O binary
-j .start
-j .text
-j .data
-j .rodata
a.out bin
最后,编写了一个Python脚本,利用pexpect远程登录到调制解调器,使用write_memory命令将二进制文件写入目标地址。程序是通过call命令执行的。
为了查看是否可以接收FM广播,可以将其调谐到100MHz并获取数据。
使用numpy,scipy和matplotlib Python库,能够将数据解释为一个复杂的有价值的样本,计算FFT并将其绘制成图表,以查看具有明显峰值的带通滤波后的频谱。
将频谱移动到其中一个尖峰的中心,抽取频谱以隔离频率范围,并使用在网上找到的一种非常简单的复数值调频解调技术,可以清楚地看到广播的不同部分,包括19kHz导频。
优化
以每秒1500万个样本,每个样本占用8个字节的速度,不到一秒钟的数据可以存储在大约100MB的可用RAM中。一种明显的改进是在填充缓冲区后发送数据,然后捕获更多数据。根据处理时间和网络吞吐量计算得知两次捕获之间的间隔大约为11秒。通过实现一个新功能设置寄存器并启动捕获,从而将时间缩短至约5秒钟,从而消除了FFT计算和其他处理。在对未知寄存器值进行了一些实验之后,希望能找到一个会影响采样率的寄存器,将I和Q值限制为14个有效位的位。尽管它们每个样本仍占据8个字节,但这意味着可以将其中两个打包成一个32位字(需要注意ADC采样的位数)。编写另一个函数来确定它是否以I或Q值开头,然后遍历缓冲区,将每个I / Q对打包为单个整数并将其写入缓冲区中的下一个位置。
仅此一项并不能改善性能,但是仅通过获取第N个样本,就可以降低有效采样率,缩短处理时间并减少必须发回的字节数,从而大大提高了延迟。
使用双线程进行优化处理,一个线程将数据连续捕获到下一个可用缓冲区中,然后向另一个线程发出信号,表明已完成写入。第二个线程对数据进行打包,通过网络发送数据,然后发出可再次写入缓冲区的信号。
结论
本文为通过逆向分析将电缆调制解调器改装为SDR的一个初步实践,并不打算制作一个功能强悍的SDR,仅是对技术的一次挑战,希望能给后续有兴趣进行深入研究的同行一点思路上的引导,并用如下的内容结束本文:
“With so fewfirsts available in life, take those that present themselves and have a crack”
原文来源:关键基础设施安全应急响应中心
本文始发于微信公众号(网络安全应急技术国家工程实验室):初探逆向将电缆调制解调器改装为SDR
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论