附录一些常识GPIO: 软件和硬件的桥梁
各位听众朋友你们肯定或多或少的听过驱动, IO这样的词语.
如果你做过手机或者嵌入式, 查看过驱动的代码, 会发现很多时候, 我们操作一个地址, 并不是改变内存, 而是改变管脚输出电平, 或者操作一个硬件的工作状态, 或者直接用某种电平组合从外部接口发出一组数据.
这里有几个概念, GPIO, soc, peripheral. GPIO通俗来说, 就是可以测量或者输出高低电平(高阻)的物理引脚. 当然除了少数情况下, 一个在真实世界的物理引脚, 是可以在内部借由多路开关(路由)连接到不同的功能模块的. GPIO是功能模块之一, 你可以认为它跟串口/DAC/定时器这一类设备一样, 都属于"资源". 单片机为了区分对指定地址的访问是存储器还是外设, 他有一张MemoryMap, 有的是可以配置的, 有的是固定的. 访问硬件资源的区域, 就是peripheral接口. 其中外设我们沿用的还是几十年之前的概念, 现代的cpu片内都集成了大量的接口和功能模块, 我们通常说的就是这些集成在芯片内的片上外设.这种架构就叫做SystemOnChip, 简称Soc. 有的芯片甚至集成了CPLD可以让用户扩充标准外设甚至编写非标准的外设. 但是是不是所有的厂商都会把常用电气接口都给集成在芯片呢? 是不是集成的都是最好的呢?
这一点有一些例外, 比如USB HighSpeed/SuperSpeed, 很多cpu是要靠外部的芯片实现电信号(D + /D - )的编码解码的, 有线网卡也是, CAN也是绝大多数需要收发器芯片的.
这些芯片我们通俗的叫他PHY, 多数是对外接口是数据引脚少而频率高, 对cpu接口数据引脚多而频率低, 又或者需要特别供电, 或者信号线上有干扰, 这样的一些应用场景. 也有的是因为用来传输信号的方式不同, 举个例子, 不同项目需要同轴, 双绞线, 光纤来传输, 都做片上集成不说成本, 兼容性肯定众口难调.
我们研究一套硬件的时候, 在真实世界看到的是引脚编号, 在代码中看到的是对地址的操作. 如果用户写代码都是一堆读写地址, 岂不是逆向的时候光查手册都累趴下了? 还好很多用户有使用厂家封装的外设库习惯, 我们需要对照厂家的文档, 通过查看使用参数/或者直接操作peripheral区域的代码, 逐个整理这些被静态链接到固件中的函数名称. 一份好的符号将大大有利于我们的分析. 当然, 如果你可以分析出固件编译和链接所用的工具链和大致的版本号, 你还可以使用BinDiff等工具, 让你的函数排查更精确.
形形色色的寄存器
刚才我们提到有些外设寄存器, 是通过地址访问的, 那这个寄存器跟R0~R15这样的寄存器, 有什么区别? 首先, 我们开发和逆向时候遇到的寄存器有三类, 第一就是R0~R15这样的CPU通用寄存器, 其中浮点寄存器VFP/NEON, 也可以归为这类. 他们要总结相同点就是能够直接访问里面的数据, 第二类就是特殊寄存器, 无法直接操作, 需要先复制到通用寄存器或者必须从通用寄存器传值, 有些可以改变协处理器的工作状态, 有的可以操作内存控制器. 不止是Cortex有, 一些8位16位芯片, 也有特殊寄存器, 比如STC, HCS12x, 不过有些不是专用指令复制而是通过低位地址访问.
第三类是外设寄存器, 不用严格区分片上外设还是片外的, 片内外设, 基本都是通过地址访问的. 这种地址有别于内存地址, 在逆向中我们需要注意到, 有些寄存器是只写的, 有些则是写入后(等待一段时间)会被擦掉某个bit的, 我们反编译时候, IDA无法识别这个地址的数据写入和读出会不一致, 可以参考IDA的说明
Hex-Rays Decompiler: Manual
但我们可能一段地址区域, 里面只有少数几个是这样的寄存器, 把它们分别定义为不同的段很麻烦.
还有一个需要留意的地方, 外设寄存器不一定是和处理器字宽相同. 我简单想了下, 可能编译器的对齐访问的优化可能会意外的对另一个寄存器执行读取再写入的操作, 对内存地址无所谓, 对外设地址可能一读一写就会出现bug. 不过没有具体遇到这样的bug, 也不知道有没有相关的利用.
可能是我想多了吧.
外设寄存器还有一类(大多是无法挂到地址线的外设), 需要通过接口专属的协议, 比如IIC, SPI, 8080, 更加间接的读取. 而有些外设接口是可以挂载到地址直接访问的.
关于测试点的闲话零售机上为何会有测试点
常看小说的人都会知道, 弃城撤退时候, 一般都会烧毁粮草, 砸碎攻城器械, 甚至井水下毒, 结合我们引子里面的话, 是不是有种似曾相似的感觉?
我们没法用产品来打击敌人, 但我们也不能资敌, 在我看来, 保留着调试/开发用的功能, 和电路板上关键测试点就是一种无法理解的行为. 可能很多搞硬件设计或者固件的不以为然, 我们再防, 别人只要重新做块板子/找人解密就可以搞定了, 不如做点实际的, 烧毁自身让破解的恶心一下…
原则上说, 很多测试点都不应该留在零售机上. 应该工程机和零售机上使用不同的电路板布线甚至不同的芯片, 防止用户将原本用于开发的接口变为分析调试的助手. 比如我就感觉盛大放的这些测试点方便了我.
但实际来看现阶段大部分手机和其他嵌入式设备(路由器/穿戴设备/智能家居)都预留了一些串口/SWD/JTAG的测试点/排针座.
手机维修领域的硬件设备, 比如Riff box, JPR, 东海等等, 都有大量机型的测试点接线资料. 很多手机维修小店铺, 就是靠这个来修砖赚钱的.
非要编一些理由的话, 比如有些故障, 在工程机环境就是不发生, 或者随着将零售机拆开/吹焊芯片后短时间内就无法再现, 必须要保留这个来检修/检测故障, 又或者由于成本考虑, 省略了原型, 开发, 批量阶段的硬件投入, 直接用同一套设计, 连测试架都不用重新订做了.
如何寻找特定的测试点
我们关心的可能是串口(看看是不是有特殊日志输出), 也可能是调试接口(JTAG/SWD/BDM). 首先我们需要cpu的文档, 确定脚位和可重新分配的功能表.
因为很多CPU引脚的JTAG/SWD脚位都是不可路由的, 所以只要有线路图或者PCB图就可以很轻易的找到. 我们有了板子,找抄板公司整理出PCB图纸无疑是最方便的, 当然如果你对整机原理没有研究的需要的话, 还可以用一类叫做JTAG Finder的工具来定位, 上面提到的几个手机维修工具都有这种功能.
当然这类工具也有适用范围, 因为需要满足一次测试过程尽可能包含所有JTAG信号, 如果主板上测试点非常多, 可能多次组合才能确定下来, 只碰上一两根时候根据工具的原理和连上的线, 有可能测不出来, 有可能结果错误. 影响你分析.
硬件工具列表参考JTAG 引脚自动识别 JTAG Finder, JTAG Pinout Tool, JTAG Pin Finder, JTAG pinout detector, JTAGULATOR, Easy-JTAG, JTAG Enumeration
如果没有引脚查找工具, 而且cpu封装是BGA/WCSP这类无引脚封装, 可以先拆下cpu, 从焊盘中定位目标功能可能对应的引脚, 焊接飞线并测试是否跟PCB上某测试点相通. 这种情况可以见后面章节的示例.
对于引脚裸露的封装的cpu (DIP, SOP, QFP, 单层QFN也算), 还可以尝试直接按照资料对应的脚位飞线出引线, 再测试是否是需要的功能.
这里提醒一句, 绝大多数用了单片机的消费产品, 都烧写后禁用了读出. 没人乖乖的等着你免费抄他们的东西, 老外也不例外.
JTAG/SWD/SWV关系
除了我们说的传统JTAG(单节点使用6~7条信号线), 还有一类缩减引脚的JTAG协议, 只使用TMS/TCK两个信号线. SWD也是这种协议. 有一些入门级的Cortex-M芯片甚至只提供SWD引脚, 不提供完整的JTAG引脚. 有的芯片额外提供了SWO引脚, 如果测试中发现它跟SWDIO/SWCLK测试点放在一起, 可能开发者开发过程中用它来输出一些调试用的业务信息. 因为有时候semihosting和uart都无法满足速度的要求. 当然正式版固件依然输出调试信息的可能性不大, 但确实遇到过. 比如不使用#define来彻底移除调试打印, 而是定义一个变量, 通过"只有厂家才知道的"指令/其他配置可以打开日志. 这样的靠变量控制隐藏的"秘密日志"我想很多人分析时候都遇到过.
如何防止芯片的调试功能被利用
烧录, 测试点, 工程模式
幸运的是, 开发阶段的芯片可控性跟零售产品之间的矛盾soc厂商已经想到了. 各个soc厂商假设了一些安全需求, 并实现了一些不同的保护功能. 举例来说: Marvell的PXA3X0系列处理器, 其芯片内置的bootrom, 在trust boot流程中, 会由bootrom本身禁用JTAG接口. 当然这个接口物理上还是存在的, 可以通过发送证书来重新开启.
有些厂家使用了熔丝, 在零售机出厂前使用某些指令将其熔断, 物理上断开内部的硬件调试模块. 也不排除有些厂家实现方式是用内部EEPROM/flash存储禁用调试接口的配置, 然后禁止对应外部引脚路由到内部调试模块. 这样勉强算是属于硬件实现, 只是并非物理上的熔断.
还有些厂家做的不彻底, 调试功能只能在上电后由用户代码来禁用, 这就属于鸵鸟政策.
提到调试功能很多人都会想到JTAG, 但你看到其他介绍硬件分析的都会煞有其事的告诉这东西是用来测试电路的, 然后就是经典的一个JTAG接口如何挂载多个被测设备接法. 让有心研究硬件hack的兄弟们知难而退.
半仙告诉你不要沉迷那些高大上的标准, 我们只需要知道现在手里面拿的产品, 它里面就是用普通的物理测试点在质检流程测试是否正常工作, 有的也有一些工程模式或者工程固件来测试周边的输入输出设备是否正常.
换句话说现实中JTAG不是用来"Test"的, 它留在电路板上要么是厂家用来刷机/维修, 要么就是早期开发过程调试. 也有很大可能你拿到的设备, 它们的开发人员就不用JTAG/SWD等等仿真接口调试, 这就要看做电路板时候工程师是不是习惯性预留了.
当然越来越多的cpu支持usb发送bootloader/payload进行引导或者烧录, 开发板厂家也会做好各种Bootloader用SD卡引导, 绝大多数产品研发都不需要接触烧写步骤, 哪怕你改了Bootloader也只写一下SD卡即可, 以后手机领域的开发人员可能逐渐就远离五花八门的各种仿真器了吧. 可能现在就工控, 穿戴, 还有各种xx杯比赛需要写裸机程序的, 这些人还会手里拿着一大把各种厂家的仿真器.
回到测试点的话题, 能找到定义最好的办法就是有维修手册或者电路图泄露. 当然这些只能出现在很流行但又不是最新的设备上.
一些小众的, 或者太新太老的就只能自己动手了. 如果是双面板, 可能我们把所有元件都吹下来, 进行抄板是最快的方式. 如果是四层乃至6,8层板, 个人来搞就很容易磨废掉. 这时候我们可以不打磨只测量. 当然, 我们关心的测试点是属于cpu/nand的部分.
如果这些芯片是BGA/wlcsp的, 需要预先拆下.
图3-1 拆掉后的eMCP(左)和CPU(右)
测试点是什么呢, 看图说话, 右边CPU白色方块旁边三个金色的铜箔就是. 说到这种BGA的布线, 肯定有人会看到布线规范里面要求把所有pad全部fanout, 不管你产品运行用的着用不着, 而是要留着品质测试(测试焊接质量?), 但是显然我国工程师擅长的是把6层板的东西缩到4层, 4层缩到双面, 所以不要太指望一些我们需要的引脚厂家帮我们做了测试点.
实际如果没有引出我们也有办法, 不过这需要我们去验证到底哪些引脚已经引出了. 刚才提到过抄板和自己找, 这里就演示一下自己找的例子. 这里面有个技巧, 可以焊接一个8pin排针, 然后对应8条不同颜色硅胶线(不要太粗30AWG即可), 再用一个8pin排座都短接在一起.
将这些排线空闲的一端选8个焊接到靠近的8个测试点上, 插到排座上再用万用表通断档在芯片引脚上扫过, 发现有导通的, 拔掉排座, 再测导通的是8pin里面哪一色的pin.
因为有颜色区分, 抄的时候不容易弄错临近的点. 甚至我考虑过用74系列+语音芯片简单做一个多pin测试的, 探通后自动扫描每一pin.
如果是LQFP这样封装的, 或者说测试点数量多于关注的引脚位置, 还可以8条导线焊接到cpu/flash引脚上, 反过去扫测试点.
我们把板子放到扫描仪上扫出背面图, 然后在Photoshop里面按照颜色选取, 将所有裸露的铜箔部分标记为绿色, 然后打印在A4纸上.
然后按照上述办法, 每找到一个跟cpu/eMCP芯片存在导通的测试点, 就用笔记录在该测试点的位置. 遇到对应的是JTAG或者可能存在uart复用的端口, 我们再最终记录测试.
图3-2整理中的标记示例
图3-3 焊接好的JTAG测试点
当然工厂的生产流程, 是会有制作一个测试冶具(支架), 需要在线测试的位置安装探针, PCBA放置固定后, 自动进行质检的.
我们自己用直接用细一些的导线或者漆包线焊上即可(我推荐铁氟龙线和硅胶线驳接的方式)
接着是找UART测试点, 前面我们分析过串口应该是GPIO109和GPIO110, 但在第一次测试中, 我们扫遍了电路板正面所有测试点都没有导通的. 后来测试键盘矩阵揭开窝仔片后还有一些触点也暴露出来, 果不其然, 其中正好有跟cpu的这2个脚位相通的.
应该只是凑巧被贴住了, 感觉电路板挂在测试架上时候是没有贴这块键盘的.
图3-3 找到的UART测试点, 在数字键3的右侧.
图4-1 Bus Blaster v4
这是基于FT2232H+CPLD的可编程buffer方案, 软件支持是openocd, 但bug很多. 开源的就这样.
图4-2 并口简易JTAG
WDT LPT Jtag, 固定buffer方案. 可以配合jflashmm烧写PXA320的闪存. 这是某韩国开发板厂家Hybus修改的烧写程序和配套的电路.
当然我们万能的山寨jlink, 配合openpxa补丁, 也可以用来调试不过我一定要说, 开源的东西我还没遇到在我手里不出bug的.
它调试起来各种bug, dump nand也数据不对. 我脑海中已经出现项目的作者"哎哟编译通过了连接成功了可以发布了"的画面.
图4-3 使用openocd+山寨Jlink-v8连接bambook
sudo openocd -f interface/jlink.cfg -f target/pxa3xx.cfg -c "adapter_khz 1000" -c "nand device pxa3xx.flash pxa3xx pxa3xx.cpu"
图4-4 使用山寨JLink-v8+openocd读取PXA310的nor flash闪存.
nand dump offset size file.bin
其他支持PXA的硬件我还找到有H-Jtag, banyan-U, 其中banyan-U我测试过, 也有一些问题.
还有一个是JtagKey, 同样基于FT2232的, 开发板厂商Toradex的一些烧录和调试软件支持这个转换器. 这个东西我们可以自己造, 网上有很多电路图.