有幸参加今年11月份的上海Syscan360安全会议,会议期间有一个亮点就是360的独角兽团队设计了一款电子badge(胸牌)供参加人员进行破解尝试,相似于美国Defcon上面的那种解密puzzle的比赛,在参会现场的人均可以参加这种破解,总共9道题,规则是现场会给每道题谜面,在这块胸牌上面输入正确的谜底才能进入下一题,解题须要开脑洞,有好些人参与破解,并且有好些人都解出来了,今天笔者从这块胸牌的硬件和软件层面去揭密这个胸牌的一些有意思的功能和如何在不须要知道谜面的状况下,快速解密答案,算是硬件破解方面抛砖引玉。git
我这边看到有两块板,一块黑色一块红色,其中黑色以下web
硬件配置以下:算法
MCU:德州仪器TI CC1310 型号(CC1310F64RGZ)VQFN (48) 7.00 mm × 7.00 mm编程
ARM Cortex-M3处理器,时钟速度高达48Mhz安全
64KB片上可编程flash,20KB静态内存SRAM,30个GPIO口服务器
RF Core支持收发1Ghz如下的无线信号数据结构
外置存储器: Winbond 25Q32bvsig工具
32Mbits存储空间布局
一个LCD液晶屏学习
四个led灯,若干电阻和电容,6个按键和开关,全部的这些构成一个小型的嵌入式系统
使用方法:
6个按键,分别负责切换不一样的可打印的ASCII码,删除,进入和返回等功能
只有全部的关卡经过后才能出现控制闪灯和产生红外信号去关闭遥控电视的功能,这是后话,后面细讲。
要想了解里面的原理和功能,必须得拿到里面的代码逻辑。经过查阅MCU CC1310芯片的数据手册,咱们发现它支持jtag仿真调试,咱们只须要外挂支持ARM的仿真器,就能够进行整个内存空间的访问和片上动态调试,这一点对于咱们逆向来说很是有帮助,CC1310芯片布局以下。
DIO_16 26 Digital I/O GPIO, JTAG_TDO, high-drive capability
DIO_17 27 Digital I/O GPIO, JTAG_TDI, high-drive capability
咱们知道要进行jtag调试须要至少4根信号线分别是TMS,TCK,TDI,TDO,(RST可选)最后是GND(接地), 具体JTAG的定义和各个信号线的定义你们能够网上搜索,我就不赘述了,找到这几个信号线接到相应的仿真器上就能够进行调试了。
从该MCU的电子手册咱们得知这四个信号线的Pin脚位置以下。
TMS——24
TCK——25
TDO——26
TDI——27
而后咱们能够经过万电表量出这几个引脚引出来的位置,恰好这板子已经把这几个信号脚引出来了,也省去咱们很多麻烦。
好了,焊好线后,须要咱们的仿真器出场了,笔者使用的ft2232h mini module,固然你们也能够选用别的仿真器,像jlink之类的,简单说一下这个mini module,它是一个多硬件协议(MPSSE)集一身的小模块,好比SPI/JTAG/I2C等,共用GPIO口,很是方便,接下来就是连线了,链接图以下。
右边是mini module CN-2接口Pin脚,左边是CC1310的引脚,GND随便找一个板子接地的地方接上就行了。
下面就是ft2232h mini module
好了,接下来就是激动人心的时刻了。
硬件链接准备就绪后,咱们开始驱动仿真器来进行片上调试。
调试工具准备以下:
OpenOCD (开源的硬件调试软件)
Arm-none-eabi-gdb (arm版的gdb)
在使用openocd以前须要准备好cc1310的调试配置文件cc1310.cfg,在这里能够找到。
一切准备稳当,接下来就能够开始见证奇迹的时刻了。
运行telnet localhost 4444进行命令行来控制操做cpu或者内存空间,在这里咱们可把cpu halt暂停下来,cpu重置,设置断点等操做。
在这里咱们执行halt命令,cpu就断下来了,效果以下
这个时侯个人gdb就能够远程attach上去进行动态调试与内存空间访问了。
运行arm-none-eabi-gdb,gdb里面执行target remote localhost:3333
进行远程调试链接,能够内存空间访问与动态调试。
好了,咱们能够内存空间访问了,先把固件,flash,和内存数据dump出来,静态分析一下吧。
以下是cc13xx芯片的内存空间地址映射表,它可让咱们知道dump哪些有用的数据
0地址开始到0x10000是咱们CC1310F64型号的flash的地址空间
BootROM是从0x10000000到0x10020000
SRAM地址从0x20000000到0x20005000
好了,咱们就dump这三块位置。
在gdb里面运行以下命令
dump binary memory cc1310_flash.bin 0 0x10000 dump binary memory cc1310_brom.bin 0x10000000 0x10020000 dump binary memory cc1310_sram.bin 0x20000000 0x20005000
好了,合并这三个文件用IDA进行反汇编,不一样的段进行地址重定位,能够作到地址精确引用,以下。
好了,接下来就是逆向篇了,如何找到答案和分析其代码逻辑等等。
咱们经过IDA里面的一些字符串得到一些线索。
而后咱们很快找到每一道题的答案了
解释一下这里面的一些逻辑。
这里面每一道题的提示和答案,还有用户自定义ID存储在flash 0xe000开始的区域里面,总共长度0xe2个字节,运行时会把这块区域数据读到SRAM里面,在SRAM里面进行操做,而后把SRAM结果写回到0xe000这块区域里,以保证下次设备重启数据和进度不会丢失,其结构以下。
0xe000 ---0xe010 存储用户设置的ID
0xe014 --- 0xe015 存储用户过了多少关了(直接改为9就通关了:),修改SRAM里面相应的存储的数据,而后经过ID设置来触发写回到0xe014,这样就生效了)
以下是不一样关卡的提示和答案
比较每个关卡的用户输入答案,并进行更新
0x20001060存储着flash地址0xe000里面的数据
偏移0x14就是用户当前所在关卡数,若是答案比较相等,这个关卡数加1并写回到flash里面,并在屏幕上显示『right!』。
总共9道题的答案分别是
UR1NMYW0RLD!
42
ORDREDUTEMPLE
FQJPVDPOK
VYTX
LOYAL
GNILCS
FIBONACHI
WORLD
通关最后的结果以下
若是你只想知道答案,看到这里就能够了,接下来会讲讲里面的一些其它功能。
当全部的关卡都经过后,会多出来两项列表,分别是
Led Light
TVB Gone
进入Led Light前置的两个led灯能够显示3种颜色,这里是经过设置12号GPIO和19号GPIO口,对应在芯片上的引脚是18和29.
这里咱们重点关注这个TVB Gone功能,这个一个能够经过红外信号远程关闭不少不一样品牌的电视的小应用,具体介绍参考:https://en.wikipedia.org/wiki...
咱们知道咱们家里面使用的电视的遥控器,通常都是发射的红外信号,来控制电视的开关,调台等操做,这个TVB Gone的功能就是经过发射不一样品牌和不一样频率的控制信息来达到关闭遥控电视的目的。
红外控制信号经过必定频率的PWM(脉冲宽度调制)调制方式输出给led灯,led灯产生的红外信号影响遥控电视。
研究发现这个板子里面存储了80组红外控制信号源数据,经过特定的数据结构来存储,例如以下。
以下是存储每一组数据的地方指针列表
咱们挑选其中一组来看
解释一下每一个字段的含义
0x9600 表示这种数据的发射频率38400Hz
0x1a 表示有多少对数据须要发送出去
0x02 表示每发送一对信号里面承载着2个bit数据
0x9e38 表示存储时间对的指针地址
0x97b4 表示要发送的数据的指针地址
地址0x97b4在存储的数据以下
{0xe2, 0x20, 0x80,0x78,0x88,0x20,x10}
上面有讲这些数据须要发送26次,每次是2个bit,总共就是52个bit
上面是7个字节,总共是56个bit,还有4个bit怎么办,后面再说。
这个时候咱们须要说说存储时间对的指针了
地址0x9e38存储的时间对
{60,60,
60,2700,
120,60,
240,60}
这个时间对分别是time on和time off
解释这两个概念时先计算一下PWM调制的周期时间
1/38400=26μs(微秒)
该MCU的系统时钟是46Mhz,这里使用了一个16位的通用定时器GPT TimerB
咱们经过代码得知该PWM调制的占空比(duty cycle)是33.3%,什么是占空比,就是在一个PWM周期里面高电平占总电平的比例,以下图
这个PWM的周期是26μs,高电平是8.84μs,因此占空比就是8.84/26=33.3%,也就是1/3,咱们从代码里面也能看到。
这个PWM输出使用的是4号GPIO口,地址0x40022090是设置各个GPIO口置bit1的地方,这里赋值0x10恰好是置4号GPIO口bit1,也就是高电平,地址0x4001002c设置定时器时间,也就是这个高电平持续多长时间,后面0x400220a0是设置各个GPIO口清除bit1,也就是置bit0,这个是0x10,表示置4号GPIO口bit0,也就是进入低电平,设置定时器长度在地址0x4001002c,时长是高电平的2倍,这就是一个周期time on的状态,经过计算咱们可以得出一个周期高电平的时长。
系统时钟周期1/46000000
(46000000/38400/3.0)*( 1/46000000)=8.67μs
好了,继续回来上面的时间对Time on和time off
{60,60,
60,2700,
120,60,
240,60}
把每一个数字乘以10,时间单位是微秒,这个10怎么来的,代码里面看到的,不知道缘由(搞硬件的同窗帮忙解释下)
{600,600,
600,27000,
1200,600,
2400,600}
每对数字前的数字表示Time on,就是在这个数字的时间内,PWM信号周期性出现,后面的数字Time Off表示低电平没有PWM周期性变化。
这两个组合在一块儿的PWM信号就是表示数字信号里面的2个bit位,上面有提到
{600,600, 表明bit 位『0 0』
600,27000, 表明bit 位『0 1』
1200,600, 表明bit 位『1 0』
2400,600} 表明bit 位『1 1』
因此这个红外信号就是经过PWM的这种方法调制发射出去的,继续上面的例子,咱们要发送的数据以下。
{0xe2, 0x20,0x80,0x78,0x88,0x20,x10}
发送数据的顺序是MSB,就是从左到右开始发,好比0xe2的比特数据是
“ 11100010 ”
先发11,10,00,10对应的发送时间序列对就是
2400,600
1200,600
600, 600
1200,600
咱们能够经过逻辑分析仪来看这些信号发送的状况
第一组发送的比特11
Time on 2400微秒(也就是2.4毫秒),咱们观察到按照周期性变化的PWM信号长度就是2.4毫秒,低电平的时长就是600微秒左右
*第二组发送的比特10
time on时长1200微秒,time off时长600微秒
第三组发送的比特00
time on时长600,time off时长600
第四组发送的比特10
time on时长1200微秒,time off 600微秒
好了,上面咱们有提到要发送的数据是7个字节,56bit,可是只发送了26对也就是52bit,还有4bit怎么办,咱们看最后一个字节0x10对应的比特位是00010000
由于最后4位都是bit0,因此直接低电平补位了(猜想)。
最后在14秒左右遍历了80组红外信号来尝试关闭远端的摇控电视
咱们彷佛忘记了那个4MB的winbond的外置flash了,它的功能以下:
存储一些文字介绍信息
存储LCD文字显示映射码
存储启动的图片
存储了一个变量
若是dump外置flash?
先祭出个人神器FT2232h Min Module,用热风枪把外置flash吹下来,而后夹住,连线以下图,SPI接口一一对应好就能够了。
经过软件flashrom来读取flash里面的内容
运行
flashrom –p ft2232_spi:type=2232H,port=A –r flash_cc.bin
LCD显示是经过硬件I2C协议写入数据,ASCII码和UNICODE显示逻辑以下
汉字经过UTF8解码而后GBK编码后存储
因此想在显示屏上面显示中文汉字,只须要把汉字UTF8解码而后GBK编码后放到相应的位置就能够了,例如
>>> '谢君'.decode('utf8').encode('gbk') '\xd0\xbb\xbe\xfd'
这四个字节写入地址0x20001060处,而后写回内置flash就出来以下效果了。
该板子带一个无线收发功能,中心频率是433.92Mhz,速率50Kbps,2-GFSK方式调制,该无线功能一直处于监听状态,当收到服务端发过来的相应命令的数据包时,会作相应的解析,而且发相应的包响应。
这个无线功能有以下一些功能,我就挑选了几个:
广播请求客户端提交大家的用户id信息
广播请求客户端提交大家的经过关卡数的信息
服务端器发送无线数据格式以下:
0x00 0xaa无线通讯前导码(preamble)
0x01 数据包payload长度
0x02 请求命令
0x03-0x04 header 0x5555或者0x2b2
0x05 序列号(seq)
0x06 地址
0x07 子命令
end 两个字节的数据包校验和
客户端发送数据格式以下:
0x00 0xaa前导码
0x01 数据包长
0x02 请求命令
0x03-0x04头部header 0x02 0xb2
0x05 对应服务端发过来的地址
0x06 子命令
0x7—须要提交的一些数据
end两个字节的校验和
校验和算法:
把字段数据包长度后面的数据,不包括校验和字段,每一个字节数据相加结果再和校验和做比较。
我节选了几个数据交互对,因为咱们如今不可能收到服务器发的数据,因此只能根据逆向代码来判断发送的内容是什么样的:
recv是来自服务器发的,send是咱们的板子响应发出去的。
Seq是序列号,add是地址,各占一个字节
请求提交你过了多少关:
recv 0xaa 0x06 0x02 0x55 0x55 seq add 0x01 chk1 chk2
send 0xaa 0x08 0x03 seq 0x02 0xb2 add 0x01 0xff 0x09 chk1 chk2
请求提交板子的用户id,名字长度是16个字节
recv 0xaa 0x06 0x02 0x55 0x55 seq add 0x03 chk1 chk2
send 0x0a 0x16 0x03 seq 0x02 0xb2 add 0x03 username chk1 chk2
其它
recv 0xaa 0x06 0x04 0x02 0xb2 seq add 0x01 chk1 chk2
send 0xaa 0x05 0x05 seq 0x02 0xb2 add chk1 chk2
固然还有改进的空间,好比在解题算法代码上面,不要用明文存储答案,通过一些算法混淆处理,能够提升代码分析的门槛。
硬件上面的一些反调试对抗,能够考虑一些芯片硬件特性的支持,好比今年defcon上面使用的intel在quark d2000 x86芯片,里面有一个jtag的disable的OTP比特位,烧录设置后jtag硬件调试就不能用了。
相信他们在设计这块板子的时候也是付出了不少精力,逆向也是一个学习的过程,感谢。