使用AI对天猫精灵IoT模块进行逆向分析(二)
上一篇文章核心内容就是让AI通过UART帮我分析出电机协议,然后指导我设计wifi模块,开发固件,然后替换掉原装板子。然后再帮我逆向原装板子,发现了ALCS协议。
在上一篇文章完成窗帘电机的改装后,我又把目标看向了我家客厅的梦幻帘电机。该电机也是窗帘厂家提供的,说是乐屋梦幻帘电机,也是连接到天猫精灵上。
1. 天猫精灵APP逆向分析
由于我家梦幻帘电机装的位置比较难拆,所以我第一考虑不之前的流程(先拆电机)。而是尝试之前发现的这个ALCS协议,并且通过探测,我发现这个电机同样开启了ALCS协议的端口。
但是使用之前的脚本进行测试,认证是失败的,无法认证成功。根据之前的分析文章,应该是不同设备的DEVICE_NAME和PRODUCT_KEY,DEVICE_SECRET不同,那么,我们就需要想着如何获取该设备的这两个值。
按照我的想法,天猫精灵的云端肯定是要储存这些值的,要不然天猫精灵如何在离线的情况下进行设备控制呢?
所以,接下来我考虑让AI帮我对天猫精灵APP进行逆向分析,我给AI提供了一台我有ADB root权限的手机,让其帮我逆向,然后找到我梦幻帘的这两个值。
花了一些Token和时间后,AI说直接进行逆向分析的难度有点大,建议我进行抓包分析。首先尝试注入系统证书,然后进行中间人抓包。但是天猫精灵对这一块有防护,即使注入了系统证书也没法进行中间人抓包。
我看AI在这部分又花了一些token和时间后,我进行介入。我建议AI使用eCapture进行抓包,但是AI发现我当前手机的内核不支持使用eCapture进行抓包。随后,我又想起来,我以前研究过一段时间的BPF(参考:https://nobb.site/2022/11/02/0x7D/),可以使用uprobe进行抓包。

AI成功帮我获取到了梦幻帘的PRODUCT_KEY,但是DEVICE_NAME却无法在流量中抓到。随后我开始介入,我让AI参考之前已经搞定的窗帘的信息,然后去看看相关字段的值在哪里。这次AI能很确定地告诉我,在流量中不存在设备名,但是AI却发挥了主观能动性,它发现设备名有点像是MAC地址去掉冒号以后的值,我就让他进行尝试,使用梦幻连的MAC地址作为设备名,去探测ALCS协议。

成功找到了PRODUCT_KEY,但是,还有最后一个DEVICE_SECRET 未知,如果不知道该值那么就过不了签名认证。

2. 拆机连接串口
经过AI分析,我发现现在我不得不拆机了,没办法,经过了九牛二虎之力,我成功把电机拆了下来,拆开后查看芯片。该设备的板子使用的是MXCHIP EMC3020-P芯片,并且是直接焊接到电基板之上,并且没有对外暴露出TX、RX引脚,我让AI帮我搜索该芯片的手册,然后找到RX TX引脚,再焊接飞线上去。
在使用UART串口读取数据的过程中,还踩了一个大坑。该芯片的串口默认波特率为2Mbps,但是我手上的TTL转串口为CP2102模块,最大支持的波特率为1Mbps。因此,我又下单买了一个CH340模块的板子,该模块支持的最大波特率为2Mbps。
连上串口以后,该设备的所有信息我都能成功获取了:

但是获取了这所有信息以后,仍然无法使用ALCS协议控制电机。接着,我把WiFi芯片切换到下载模式,把Flash给dump出来。让A I进行对固件进行逆向分析。

经过完整分析以后我发现,天猫精灵APP本身并不支持ALCS协议,应该是需要某些天猫精灵的硬件设备才能支持。或者是ALCS协议的代码只是SDK里面的固定代码,开发商没有使用该功能,也没有把这部分代码给去掉,所以就被刷到固件里了。
2.1 方案一:通过MQTT控制
到这里,似乎使用ALCS协议控制设备的想法落空了,然后我又想到,既然我已经获取了所有信息,那么我是否可以通过MQTT来控制设备呢?让AI编写代码进行测试研究,发现天猫精灵的MQTT服务有保护机制,订阅者和发布者是不一样的认证信息,这就让我没办法使用设备上获取的信息来控制设备。
这部分由于尝试是失败了,我最后让AI输出报告的时候,AI就没有输出这部分的分析报告,所以下面就没有截图了。
2.2 方案二:更换wifi模块
这个方案就是跟上篇文章的思路是一样的,不过该方案过于麻烦,时间周期长,因为方案三的成功,所以我没有采用该方案,该方案只是作为最终的备用方案。。
2.3 方案三:patch固件
该方案是AI提供给我的。在我原先的想法中,patch固件是一个非常麻烦的事,需要分析固件的结构,然后地址引用之类的。
但是,让 AI 执行该方案却异常地快速和顺利。
最开始,AI的方案只需要patch一个字节,让ALCS协议注册到代码中。但是该固件却翻车了,我刷到WiFi模块中,WiFi模块无法正常的启动。AI在消耗一些token和时间后没有解决,我开始介入,让AI分析一下是否有固件的校验字段,AI成功分析出了校验结构,然后重新patch,我再刷到设备上,设备成功启动。

patch后的固件成功刷到设备上以后,经过测试仍然无法通过ALCS协议对电机进行控制。让AI尝试结合天猫精灵控制设备的UART日志继续分析,AI给出的最终结论为:
厂商固件里”ALCS 收到请求 → 转发给电机 MCU”这一段的具体接线在这个 build 里没有走通(可能是编译时机/条件没触发,具体哪一步不重要),但底层”发送字节给电机 MCU”的函数是现成、干净、可以直接调用的。于是**放弃继续复原厂商内部到底哪里断了,改为直接从我们能确认命中的 ALCS 入口处,插入调用直接把命令送到
uart_imc_output**,见第 5 节。
2.3.1 AI patch的最终方案
2.3.1.1 注入点
sub_2306C48C @ VA 0x2306C48C——这是 ALCS 侧两条 property/set 入口(/sys/{pk}/{dn}/thing/service/property/set 资源和另一个变体资源)汇合后唯一共同经过的函数,调用签名 sub_2306C48C(int devid, void *ctx),其中:
*(ctx+100)= 原始 payload JSON 字符串指针*(ctx+104)= 该字符串长度
这个偏移是从反编译结果里直接读到的(*(_DWORD *)(a2+104) / *(const char **)(a2+100)),不是猜的。
2.3.1.2 补丁结构
- 4 字节跳转钩子(覆盖
sub_2306C48C入口的前两条压缩指令):jal x0, 0x230F0A30,跳到我们自己的代码。 - 跳板(trampoline.S):保存
a0/a1/ra→ 把a1(ctx 指针) 挪到a0作为参数 → 调用curtain_alcs_bridge→ 恢复寄存器 → 原样回放被覆盖掉的那 4 字节原始指令 → 跳回sub_2306C48C+4继续原有逻辑(ALCS 的 200 响应流程完全不受影响)。 curtain_alcs_bridge(curtain_bridge.c):检查 payload 是否匹配已知的 5 种属性前缀,解析出数值,映射成电机 UART 帧,调用uart_imc_output发送。
2.3.1.3 代码存放位置
新代码放在 flash 分区尾部完全空闲区:文件偏移 0xf1a30 起(= VA 0x230F0A30),到分区末尾共 128,464 字节全部是擦除状态的 0xFF,不影响任何现有代码、也不在 SHA-256 哈希覆盖范围内(哈希只覆盖 [0x1000, 0xf1a30))——所以新增代码本身完全不需要参与哈希重算,只有那 4 字节跳转钩子(因为改的是已有代码区域)需要。
2.3.1.4 工具链
./bouffalo/toolchain/bin/riscv64-unknown-elf-gcc(GCC 10.2.0,支持 -march=rv32imac -mabi=ilp32 等多种 RISC-V 变体),配合自定义链接脚本把代码和字符串常量精确固定到目标地址,uart_imc_output 声明为外部符号直接给绝对地址,链接器自动完成所有重定位,不需要手工编码任何机器码(除了 4 字节的跳转钩子,同样用工具链汇编生成,不是手算的)。
5.5 复现步骤
1 | cd firmware_patch |
产出的 final.bin 与实际烧录、已确认工作的 firmware_dump/fw_slotA_patched3.bin 逐字节完全一致(已用 cmp 验证)。
烧录命令:
1 | ~/.venv/bin/bflb-iot-tool --chipname bl602 --interface uart \ |
总结
到此,我已经能成功在局域网控制我家的梦幻帘设备了。已经成功把梦幻帘接入到我家的HA中,然后使用小爱同学进行控制。
这次的任务,AI最让我惊艳的是,在过去,对我来说,patch固件,刷回去,还能让设备正常启用,是一件非常复杂、非常花时间的事情。但是对于AI来说,这却是一件非常轻松容易的事情。
还有一件事,在上一篇文章中,我写了我最初的想法只是让AI辅助我检修电路板,但是这个过程却非常的复杂,至今没有成功。我已经决定放弃了。目前的进度是:很大的可能性是PWM模块坏了,但是,在我不断测试拆元件的过程中,貌似有一块板子坏了。再加上这个PWN模块的印丝模糊,只有存数字,没法看出是什么芯片。如果买错了,还有可能会少板子。最终我在闲鱼上发现了这个尺寸的220V交流转24V的板子,还便宜,我觉得换整块板子了。
使用AI对天猫精灵IoT模块进行逆向分析(二)

