破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷

UT181A是优利德门下旗舰级手持数字万用表,主打数据记录(Data Logging)功能,支持USB联机通讯。基本评测可以看我前面发的文章。前文说到,其官方或第三方软件功能有限,缺少最重要的导出功能。另外,数据传输的速度也比较慢。

所以,欲对其协议进行分析,方便扩展、改进、和其它设备(比如树莓派)连接、等等。

本文的破解/破译方法及结论应该适用于UT171系列;UT71系列也可以参考。对破译其它联机通讯的设备也有借鉴意义。

可行性分析

UT181A使用了Silicon Labs HID-to-UART接口模块CP2110. 在操作系统里呈现为一个HID设备,这样的好处是不用装驱动。既然它最终表现为UART协议,应该比较容易重写其通讯协议。其实UT71系列也是类似的方案(HID转UART),只不过用的南京沁恒的模块。

找了一个CP2110的代码在Linux下试了下,可以对UT181A进行基本的连接设置。但因为会话层的协议未知,所以尝试读写操作时没反应。

为了得到会话的详情,最直接和万能的办法是用USB Sniffer。 试了一下Free USB Analyzer,可以看到一些数据,但不能解码为UART层的数据。从USB到HID,再到UART,实际上是隔了两层,需要层层剥壳,还是有点繁琐。Free USB Analyzer的HID解码,是解为键盘/鼠标数据的;也许它的收费版可以解码为UART。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第1张图片
用Free USB Analyzer截获UT181A通讯

不过我还有另一条完全不同的思路,也许会更简单。

API Hook

十几年前,我用过这种方法对SCSI设备的通讯进行劫获。这些设备的通讯软件,通常会有一个通讯模块(动态库),提供诸如Send/Receive的API。所以,只要自己写一个提供同样API的动态库取代原有的动态库,但在每个API的实现上,还是转到原动态库上,就可以实现钩子(Hook)的效果。这样截获的数据块是应用层/会话层的,比数据链路层/驱动层的数据有更好的可读性。同时,还可以根据API的调用顺序,得到和设备的交互流程,比如:初始化时要进行哪些设置,通讯参数,等等。

查看UT181A软件的目录,果然有两个这样的动态库。用dumpbin /exports查看其API,初步判断应该只要替换SLABHIDtoUART.dll 就可以了。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第2张图片
UT181A使用的动态库及API

从版本信息上,可以看到这个动态库来自Silicon Labs。到其网站上找到了CP2110/4 的SDK,用SDK里的动态库替换这两个动态库,64位版崩溃,换32位版,果然可以运行。

其实优利德使用的版本较老(2010年的1.4),SDK里的版本是2017年的6.7。其中,API数目由42增加到了58。不管怎样,能跑。这样就容易开展下一步的工作了。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第3张图片
CP211x SDK里的动态库及API

有了SDK就有了头文件,有头文件就可以写出八股文一样的代码了。弄两行脚本,自动生成大部分苦力代码。。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第4张图片
HookAPI实现代码示意

很快,就有了一个“山寨”动态库。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第5张图片
自己实现的SLABHIDtoUART.dll及API

正版的要改名;山寨版要记住它名字。——活都找它干。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第6张图片
HookAPI的文件名替换

弄好了,发现山寨版的比老正版的API都少了2个。能跑,就没深究了,毕竟优利德的软件不会用到所有API。

看看Log文件,API的调用一目了然。这样,我们就有了一个坚实的基础。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第7张图片
通过HookAPI截获的API调用序列

CP211x SDK

发现CP211x的SDK里还提供了Linux版Library(-lslabhidtouart -lslabhiddevice)的源代码及例子。

这两个Library和Windows的SLABHIDtoUART.dll,SLABHIDDevice.dll对应。于是,重写通讯协议就更容易了。对Makefile略做修改后,可以在Intel和ARM(树莓派)架构下编译、运行。

直接用SDK里的例子做个测试,发出第一条命令”AB CD 04 00 05 01 0A 00”后,就可以源源不断地收到数据了。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第8张图片
CP211x SDK里例子和UT181A通讯

后续的工作就是根据API Hook的Log,给UT181A发不同的命令,研究其反应,搜集更多的数据,以便发现数据的模式(Pattern)。

协议解码

起始码、长度字

上图中,通过观察每个输入/输出的数据包,发现会间隔地出现”AB CD”。用这两个字节对包进行分隔后,数据看起来更有规律,然后可以看出接下来两个字节应该是包的长度。长度可以和起始字起到相互验证/确认的作用。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第9张图片
基本的会话数据

结束码/检验字

对收到的数据包与其实际意义进行初步的对应后,发现最后两字节是多余的。推测应该是校验字。在CRC在线计算网站上对包中的数据做CRC计算,发现与任何一种CRC编码都不能匹配。

其实,对收到的数据,可以忽略这个校验码,因为USB协议保证了数据不会出错,除非是软件层发生了错误。但后来发现,对发送的命令,也多了两个字节。如果万用表那端要对它收到的数据做校验,主机端则必须生成校验码了。

下图的命令中,带有参数。9字节长的包中有一个参数,13字节长的包有2个参数。根据参数的变化,可以观察出最后两字节的变化规律。观察9字节长的包,发现最后两字节是在参数上增加了0x11,但这显然不能解释13字节长的包。进一步的分析发现,原来这个校验就是最简单的“校验和”,即把前面的所有字节(除起始码”AB CD”外)相加。对于长达2258字节的包也是这样,只不过高位溢出忽略。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第10张图片
观察结束码

浮点数的表示

理论上,测量值可以用整数或小数表示,小数又可以用定点或浮点。

可以用程控电源输出不同的电压来联机测量,观察数据的变化规律。当然,也可以直接猜一猜,反正就只有3种可能。下图是一个例 子。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第11张图片
记录列表及浮点值

图中标示了27.0, 27.1, 27.2。

不太像整型,直接拿浮点试一试。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第12张图片
浮点数测试代码

运气不错,就是普通的浮点。同时,可以看出,二进制的数据并不是万用表或软件界面上显示的值,而是看起来有着“更高精度”的原始数据。当然,这个“更高精度”应该是无意义的。事实上,每个数值后面还有一个字节(10/20/30),应该是用于描述其精度(有效位)的。

日期/时间的表示

最后剩下的,也是最难的,就是日期时间了。时间戳也是增加UT181A价值的地方。像UT71D虽然也记录数据,但测量值没有时间戳,只有序号。

抓取采样数据进行分析,每个数据包最大是2258字节,250个采样,所以每个采样用了9个字节:4字节浮点值,1字节描述精度,还有4字节就是时间了。是的,只有4字节,用来表示年/月/日/时/分/秒。——够吗?

在采集的数据中,每个采样对应于什么时间是已知的。取一段连续的采样数据,观察其变化规律。尤其是分钟,小时,日期和月份发生变化时,看数据如何变化。如下图。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第13张图片
时间数据观察

理论上,这种时间的表示可以用一个整型,像Unix时间戳那样。但分析上面的变化规律,看起来像是位域表示法。据此推演,结果如下。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第14张图片
UT181A的时间的表示法

由于年份使用的6 bit,需要固定加上2000。所以,这意味着UT181A只能用到2063年(的最后一天)。当然,这总比用Unix时间戳编码要好一点,因为后者只能用到2038年。

传输速度

非常遗憾,波特率只能设置为9600。通过API调用,设置更高的波特率是成功的。但传输中得到的数据是乱的。

在树莓派上测试传输133685个采样,耗时1401秒,传输速度为95.42采样/秒。这与PC上的速度(自己写的代码或官方软件)是一致的。

树莓派

在Debian系的Linux上(Ubuntu或树莓派),CP2110都被识别为HID设备,不需要安装驱动即可使用。而且,树莓派的ARM和Intel都是小字节序,所以不用改代码,重新编译一下就可以运行。

下图是在树莓派上(远程)编译、运行。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第15张图片
在树莓派上编译运行UT181A通讯程序

上一张和树莓派的合影。

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第16张图片
UT181A与树莓派

2063年测试

在2016年2月12日,据披露,如果把苹果iPhone、iPad等设备的系统时间设置为1970年1月1日,随后重启设备,它会直接变砖。

心怀忐忑与好奇,我决定确认一下2063年12月31日的问题,于是准备把时间设置到那天的最后一分钟。

但优利德的工程师似乎看穿了我的心思:时间只能设置到2060年!

破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷_第17张图片
UT181A的时间只能设置到2060年

等了1分钟后,时间变成了2061年。

但,如果我想看它出洋相,需要等上3年!——太狡猾了!

结语

通过API Hook的手段,在Windows上截获了 CP2110的通讯详情,破译了UT181A命令和数据的编码方式,重写了主要的会话过程,实现了:实时联机采集数据、传输离线采集的数据并保存为CSV的功能。代码可以在Linux PC和树莓派上运行(理论上,也可以移植到Windows上)。

受硬件限制,不能设置非9600的波特率,所以不能提高传输速度。

“致命缺陷”是:由于时间的编码方式, UT181A只能使用到2063年。

参考

  1. UT181A的基本评测
  2. 一个Free的USB Sniffer软件: Free USB Analyzer
  3. ut71dmm,针对UT71C开发,但我在Ubuntu和树莓派上试过,UT71D和UT181A都用不了。
  4. CP211x SDK, 选CP2110/4 Software package for Windows, 6.7.4
  5. CP2110 API文档
  6. 在线CRC计算
  7. 苹果确认iPhone/iPad时间设置不对会变砖

你可能感兴趣的:(破译优利德旗舰万用表UT181A通讯协议,连接树莓派,发现致命缺陷)