内容转自至乎
附录一些常识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的说明 但我们可能一段地址区域, 里面只有少数几个是这样的寄存器, 把它们分别定义为不同的段很麻烦. 还有一个需要留意的地方, 外设寄存器不一定是和处理器字宽相同. 我简单想了下, 可能编译器的对齐访问的优化可能会意外的对另一个寄存器执行读取再写入的操作, 对内存地址无所谓, 对外设地址可能一读一写就会出现bug. 不过没有具体遇到这样的bug, 也不知道有没有相关的利用. 可能是我想多了吧. 外设寄存器还有一类(大多是无法挂到地址线的外设), 需要通过接口专属的协议, 比如IIC, SPI, 8080, 更加间接的读取. 而有些外设接口是可以挂载到地址直接访问的. 关于测试点的闲话零售机上为何会有测试点常看小说的人都会知道, 弃城撤退时候, 一般都会烧毁粮草, 砸碎攻城器械, 甚至井水下毒, 结合我们引子里面的话, 是不是有种似曾相似的感觉? 我们没法用产品来打击敌人, 但我们也不能资敌, 在我看来, 保留着调试/开发用的功能, 和电路板上关键测试点就是一种无法理解的行为. 可能很多搞硬件设计或者固件的不以为然, 我们再防, 别人只要重新做块板子/找人解密就可以搞定了, 不如做点实际的, 烧毁自身让破解的恶心一下… 原则上说, 很多测试点都不应该留在零售机上. 应该工程机和零售机上使用不同的电路板布线甚至不同的芯片, 防止用户将原本用于开发的接口变为分析调试的助手. 比如我就感觉盛大放的这些测试点方便了我. 但实际来看现阶段大部分手机和其他嵌入式设备(路由器/穿戴设备/智能家居)都预留了一些串口/SWD/JTAG的测试点/排针座. 手机维修领域的硬件设备, 比如Riff box, JPR, 东海等等, 都有大量机型的测试点接线资料. 很多手机维修小店铺, 就是靠这个来修砖赚钱的. 非要编一些理由的话, 比如有些故障, 在工程机环境就是不发生, 或者随着将零售机拆开/吹焊芯片后短时间内就无法再现, 必须要保留这个来检修/检测故障, 又或者由于成本考虑, 省略了原型, 开发, 批量阶段的硬件投入, 直接用同一套设计, 连测试架都不用重新订做了. 如何寻找特定的测试点我们关心的可能是串口(看看是不是有特殊日志输出), 也可能是调试接口(JTAG/SWD/BDM). 首先我们需要cpu的文档, 确定脚位和可重新分配的功能表. 因为很多CPU引脚的JTAG/SWD脚位都是不可路由的, 所以只要有线路图或者PCB图就可以很轻易的找到. 我们有了板子,找抄板公司整理出PCB图纸无疑是最方便的, 当然如果你对整机原理没有研究的需要的话, 还可以用一类叫做JTAG Finder的工具来定位, 上面提到的几个手机维修工具都有这种功能. 当然这类工具也有适用范围, 因为需要满足一次测试过程尽可能包含所有JTAG信号, 如果主板上测试点非常多, 可能多次组合才能确定下来, 只碰上一两根时候根据工具的原理和连上的线, 有可能测不出来, 有可能结果错误. 影响你分析. 如果没有引脚查找工具, 而且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来彻底移除调试打印, 而是定义一个变量, 通过"只有厂家才知道的"指令/其他配置可以打开日志. 这样的靠变量控制隐藏的"秘密日志"我想很多人分析时候都遇到过.
|
很有力量