两个月前,我为我的联想笔记本电脑(ThinkPad X230T)买了一块新电池。我正要去度假,想要一个电池,可以让我在飞机飞行中使用;到那时,最初的电池只能维持10分钟。我一点也不知道自己即将经历一次冒险。
我安装了新电池,在几小时内一切正常……也就是说,直到我不得不将笔记本电脑插入充电状态。电池没有充电。古怪的我重新启动,却发现BIOS在屏幕上显示了以下消息:
该系统不支持非联想制造或授权的正品电池。系统将继续启动,但可能不会对未经授权的电池充电。
注意:联想对未经授权的电池的性能或安全不承担任何责任,也不对因使用电池而导致的故障或损坏提供任何担保。
“可以不收费”?这是一个相当不确定的信息,但这个电池肯定没有充电,即使在笔记本电脑关闭的情况下。哦,天哪。
当然,在这一点上,除了非正品电池之外,电池也可能存在故障,但我不喜欢联想将我限制为只使用“正品”电池的想法。首先,我手里有一个电池,如果不是这样的话,它可能工作得很好。其次,这意味着联想可以人为地抬高“正品”电池的价格。第三,如果联想停止为我的笔记本电脑更换电池,我确实会留下一台无用的笔记本电脑。
我的第一个调查途径是“嗅探”笔记本电脑和两个电池之间的通信,将替换电池与原始电池进行比较。我很容易在互联网上找到联想电池的pin码,为方便参考,它是:
在本例中,我对通过SMBus引脚、SCL和SDA进行的通信感兴趣。为了嗅探这种通信,我使用了我手头的一个基本逻辑分析仪(一个USBee SX)。方便的是,电池触点中有足够的剩余长度,可以在电池连接到系统时敲出信号,如图所示:
(技巧1:我端对端焊接了两个2针头(),这样,端针可以楔入SDA/SCL触点周围,中间可以穿过狭窄的间隙到达笔记本电脑的外部,逻辑分析仪可以连接到端头。)
(技巧2:VGA接口可以接地,这在探测笔记本电脑时是一个非常有用的技巧。)
USBee SX软件的优点是,只需点击一下,就可以内置I2C/SMBus解码。不过,我觉得输出的可读性不是特别好,所以我用了一个快速的一行程序来清理它(perl-pe的/\n//gs'| sed的/[:space:][]\+//g;s/START/\nSTART/g;s/ACK\([0-9A-F]\)/ACK 0\1/g;s/ACK//g')。我已经上传了原始电池和替换电池的SMBus捕获,供感兴趣的人使用。
现在,对于那些不知情的人来说,大多数现代智能电池都实现了一个称为智能电池规范(SBS)的标准。我们刚刚捕获的通信实际上是基于智能电池规范的,尽管使用了一些特定于供应商的命令。
我已经根据下面的SBS协议对通信进行了解码。我将两个电池交错放置,绿色是原电池,黑色是替换电池。我已经用粗体的红色注释标出了有趣的线条,我将在下面提到。
阅读技术规格信息->;0x0031(支持PEC的SBS 1.1)读取规格信息->;0x0031(支持PEC的SBS 1.1)读取电池模式->;0xe004(无内部充电控制器等)读取电池模式->;0xe005**错误的PEC校验和**(1)读取电池模式->;0xe005(存在内部充电控制器等)(2)写入电池模块0xe004写入电池模块0xe005读取电池模块->;0xe004读取电池模式->;0xe005读取设计容量->;0x1848(62.16Wh)读取设计容量->;0x1314(48.84Wh)读取设计电压->;0x2b5c(11.1V)读取设计电压->;0x2b5c(11.1V)读取制造日期->;0x4308(2013-08-08)读取制造日期->;0x46f2(2015-07-18)读取序列号->;0x036d(877)读取序列号->;0x18c7(6343)读取制造商名称->;“LGC 11”读作制造商名称->;“三洋”(3)读取设备名称->;“LNV-45N1079”读取设备名称->;“LNV-45N1079”读设备化学->;“狮子”读设备化学->;“狮子”
(身份验证顺序1)写入可选MFGFunction4 0x39 0x55 0x48 0x28读取可选MFGFunction4->;“联想日本”0x3b 0x7b 0x8c 0x44写入可选MFGFunction4 0x0f 0x35 0x48 0x28读取可选MFGFunction4->;“”写入可选MFGFunction4 0x10 0x68 0x48 0x28**失败(NACK)**写入可选MFGFunction4 0x10 0x6f 0x48 0x28读取可选MFGFunction4->;“”写入可选MFGFunction4 0x11 0xa3 0x48 0x28**失败(NACK)**写入可选MFGFunction4 0x11 0xb1 0x48 0x28读取可选MFGFunction4->;“写入可选MFGFunction4 0x12 0xe5 0x48 0x28**失败(NACK)**写入可选MFGFunction4 0x12 0xec 0x48 0x28读取可选MFGFunction4->;“”写入选项MFGFunction4 0x14 0x20 0x48 0x28**fail(NACK)**
读取未知0x35->;0x00c0读取未知0x37->;0x01 0x00 0x3A 0x00 0x00 0x01 0xFB 0x01读取可选MFGFunction5->;“1ZL1J38L1W3”读作可选MFGFunction5->;“(4)阅读选项MFGFunction2->;0x0021(33)读取可选MFGFunction2->;0x0021(33)读取可选MFGFunction1->;0x4325(17189)读取可选MFGFunction1->;0x42a3(17059)读取制造商访问->;0x0010读取制造商访问->;0x0018读取电池状态->;0x02a0(充满电等)读取电池状态->;0x02c0(放电等)读取充电电流->;0x0000(0)读取充电电流->;0x0dac(3500mA)读取充电电压->;0x0000(0)读取充电电压->;0x3138(12.6V)读取温度->;0x0bcf(302.3°K)读取温度->;0x0bd5(302.9°K)读取未知0x3b->;0x0bd6(303.0°K)读取未知0x3b->;0x0bc5(301.3°K)读取电压->;0x30fd(12.541V)读取电压->;0x2870(10.352V)读取剩余容量->;0x00c1(1.93Wh)读取剩余容量->;0x0146(3.26Wh)读取满充电容量->;0x00c1(1.93Wh)(5)读取满充电容量->;0x1215(46.29Wh)读取电流->;0x0000(0)读取电流->;0x0000(0)读取RunTimeToEmpty->;0xffff(不适用)读取RunTimeToEmpty->;0xffff(不适用)读取平均电流->;0x0000(0)读取平均电流->;0x0000(0)读取AverageTimeToFull->;0xffff(不适用)读取AverageTimeToFull->;0xffff(不适用)读取平均时间到空->;0xffff(不适用)读取平均时间到空->;0xffff(不适用)读取循环计数->;0x05d5(1493)读取循环计数->;0x0001(1)读取最大错误->;0x0000(0%)读取最大错误->;0x0001(1%)读取相对电量->;0x0064(100%)读取相对电量->;0x0007(7%)读取制造商数据->;0x03 0x32 0x01 0x32 0x00 0x00 0x16 0x10 0x59 0x10 0x8D 0x10 0x08 0x10读取未知0x30->;0x0A 0x7F 0xAE 0x59 0x50 0x5E 0x27 0x00 0x00 0x00 0x00 0x00 0x00
(身份验证序列2)写入未知0x27:0x44 0x91 0x11 0x45 0xB2 0x77 0xFC 0x5C 0x5D 0x00 0xCF 0xE9 0x7B 0x72 0xE1 0x2E 0x03读取未知0x28->;0xA6 0xCB 0x36 0x12 0xEF 0x36 0xF6 0x41 0x9B 0xB7 0xB7 0xDC 0xD5 0x9F 0xD1 0x36 0x5C 0xA0 0x07 0x3F 0xDF 0x4A 0xC6 0x2E 0x00
替换电池有一个错误/功能,它在第一次访问(1)时生成错误的数据包校验和(PEC)。然而,笔记本电脑很高兴再次尝试。
更换的电池报告它有一个集成充电控制器,而原来的电池没有(2)。
更换电池的制造商为三洋,而原电池的制造商为LGC(3)。事实上,联想电池由三洋和LG化学共同生产;我怀疑制造我的备用电池的人恰好是在克隆三洋制造的电池。
原装电池对制造商指定的功能OptionalMfgFunction5做出响应,其外观类似于序列号(4)。
事实证明,所有这些微小的差异都可以忽略。有趣的部分是身份验证序列:
认证顺序1:笔记本电脑使用特定于制造商的命令OptionalMfgFunction4(0x3c)写入4个字节,然后使用相同的命令读取12+4个字节。在这种情况下,传出消息发送一个四字节的质询,响应是字符串“Lenovo Japan”,后跟一个取决于质询的四字节响应(这是质询响应身份验证的一种形式)。
验证序列2:笔记本电脑使用命令0x27写入17字节,使用命令0x28读取8+17字节。智能电池规范中未定义这些命令。再次证明,这是一种质询-响应身份验证。
目前尚不清楚为什么会有两个不同的认证步骤,但也许第一个步骤之前就已经被打破了:毕竟,这是联想和那些有意规避其方案的人之间的猫捉老鼠的游戏。这两种身份验证方案都没有在我的替换电池中实现。
(标记为(5)的线条只是为了提醒大家注意一个尴尬的情况,即我的62Wh原电池在两年后,现在的满容量刚刚低于2Wh。)
现在,我们大致了解了电池是如何通过身份验证的,接下来的问题是我们可能如何绕过这种身份验证。有许多可能的选择。
选项1:仅更换原电池中使用过的锂离子电池,保留原控制器
这是一种常见的电池修复方法。然而,也有一些陷阱。拆开联想电池必然会在一定程度上损坏塑料,因为接缝处既有插销,也有胶水。此外,更换电池时需要小心,因为如果电池电压断开,一些控制器可能会自行损坏(我不知道联想电池是否如此)。有问题的推论是,控制器将记住有关旧细胞的数据,我不确定这可能会产生什么影响。
我决定不走这条路,除非万不得已。在更换电池正常工作后,我确实拆开了原来的电池,以供自己借鉴,我可能会在以后的帖子中对此发表更多评论。
“修改电池上的固件?”,你难以置信地说。是的,事实上,智能电池运行固件,通常这种固件是可更新的。例如,众所周知,TI BQ20Z80电池燃油表芯片具有嵌入式ARC微处理器和闪存,并且经过了充分的逆向工程,因此下载/上传/修改固件实际上是可行的(参见Charlie Millers的Blackhat talk on battery firmware Hacking)。
这有两个角度。首先,如果我们能从正版电池上下载固件,我们或许就能设计出认证算法。其次,如果我们可以将新固件上传到非正版电池,我们就可以在新电池上实现身份验证算法。
此时,我将两个电池的SMBus线路连接到一个微控制器上,这样我就可以独立于笔记本电脑向它们发送命令。我使用Arduino只是因为它是我手边的,尽管任何微控制器(最好是3.3V)都可以正常工作。
不幸的是,我在这方面一无所获:虽然所有标准的SBS命令都有效,但电池都没有响应我尝试的任何TI供应商特定的命令。这让我觉得两者都没有使用TI芯片,或者它们都被很好地锁定。非原装电池以0x2168响应ManufacturerAccess命令0x0001(可能是某种设备ID?),而真正的电池似乎没有以任何有用的方式响应制造过程。
考虑到我不知道两个电池中都有什么芯片——即使我知道,我可能也无法获得足够的信息来破解固件——我决定暂时搁置这个选项。
另一个选择是在笔记本电脑和电池之间添加一个小型嵌入式微控制器,如果电池无法响应认证命令,该微控制器将响应认证命令。(事实上,从严格意义上讲,可能没有必要插手,仅仅坐在那辆公交车上就足够了。)
Thinkpad的迷你PCIe插槽中有一些空闲空间,因此可以将电线从SMBus线路连接到该托架。然而,向笔记本电脑添加额外的电子设备并不理想,目前我们仍然不知道如何实际计算对身份验证挑战的响应。
显然,如果我们能修改笔记本电脑,跳过电池认证,那将解决我们所有的问题。由于电池身份验证即使在笔记本电脑关闭时也会发生,因此进行身份验证的不能是BIOS(BIOS在主系统处理器上运行,在系统关闭时不运行)。因此,身份验证必须由系统的另一部分执行:嵌入式控制器。