通过 disassemble manucaftures 库从蓝牙 le scale 获取重量数据

Posted

技术标签:

【中文标题】通过 disassemble manucaftures 库从蓝牙 le scale 获取重量数据【英文标题】:Get weight data from bluetooth le scale by disassemble manucaftures library 【发布时间】:2020-12-24 22:24:40 【问题描述】:

一位朋友有一个带有蓝牙乐的身体秤。为了保存他的体重测量值,他必须在手机上打开 Manufactures 应用程序。所以我们尝试使用他的树莓派来完成工作。我们发现,秤通过广告发送数据。秤永远无法连接,您可以同时使用不同的手机接收数据。在测量过程中,应用程序显示的值与秤的显示相同。你知道,如果你站在秤上,数值会上下波动,直到测量完成。这种“上下移动”也可以在手机上看到,如果您同时使用多个手机,也可以在手机上看到。所以我认为这是一个事实,数据是通过 BLe 广告传输的。它们只能在制造商数据中,例如如下所示:

starts always with:
0f ff ac a0 db 58 e2 53 91 a0

and then:

88,30kg
20 c9 f8 42 0d b0
20 c9 f8 78 0d a6

88,35kg
20 c9 f9 b4 0d a3
20 c9 f9 88 0d b7

88,40kg
20 c9 f9 e6 0d b5
20 c9 f9 e6 0d b5

2,15kg
a0 c8 ab 40 0d a0

0,00kg
a0 c8 a0 a0 0d b5

但无论我如何尝试,我都无法将这些数据计算到给定的重量。我在大端、小端、其他单位(如磅、盎司甚至石头)中进行了尝试。我找不到一个公式来计算每个已知重量的数据。有趣的是,零是“a0 c8 a0 a0 0d b5”。测量时第一个字节为20,完成后,秤会发送多个第一个字节为a0的广告包。我认为这会说“最终价值”。无论如何,第五个字节总是 0d。第二个字节在权重较高时从 c8 变为 c9。我认为是 50 或 60 公斤。 因为我找不到解决方案,所以我尝试了其他方法。我反编译了 android 应用程序以查找解析广告包的部分。不幸的是,该应用程序加载了一个本地库来执行此操作。看来制造商真的很想保密。我试图将他们的图书馆用于我的一个目的。但看起来我需要一个头文件才能在我自己的 Java 应用程序中使用该库。所以我最后的机会是拆解图书馆,我做了什么。我使用了objdump。我从 Java 代码中知道,我需要的功能是

private native List<Map<String, Object>> decode(byte[] bArr, int i, int i2, Object obj);

我可以在转储文件中找到这个函数/子程序。但我不明白如何使用它。我观看了汇编程序的视频教程系列,这真的很有趣,但它并没有真正帮助我。我假设您可以以某种方式查看数据的来源(解码参数),如何处理和返回它们(例如保存到内存中)。我还发现了一个“BleBroadcastScaleProtocol16decodeWeightData”-Function,但仍然存在同样的问题。我现在的问题是:是否有真正的机会,可以通过这种方式完成?转储文件有 10MB 的文本。有人知道怎么做,或者以前做过类似的事情吗?我为此工作了几个月,每向前迈出一步就会让我后退两步。

我把转储文件放在我的云盘上,也许有人会看看。

Dump File

编辑: 我使用我的 Raspberry Pi 向 Manufactures App 发送广告。我使用来自 bluez 的示例广告脚本。 如果我在制造商数据的前两个字节上发送带有 Service-ID FFB0 和“aca0”的广告,应用程序会将 pi 识别为“Insmart”规模。 我还可以将体重数据发送到应用程序。如果我发送“(ac a0 db 58 e2 53 91 a0) a0 c8 a0 a0 0d b5" 应用程序显示 0。 我玩了一下,发现最后四位是校验和,通过将所有十六进制值加在一起计算得出,并取摘要的最后四位。 重量数据必须在 2. 到 4. 位(c8 - 秒 a0)中的某个位置。我编写了一个脚本来从偏移量中获取 16 位并打印出十六进制值。作为输入数据,我使用 c8a0a0 (=0)。偏移量为 1(取 16 位,从位 2 开始)打印出“0x9141”。 在第二个脚本中,我可以输入一个十六进制值,它将与默认值“c8a0a0”合并。所以我可以输入 9142 并将其放在一起作为制造商数据发送的数据。 9142 是 c8a120,除了 9143 什么都不做的是 c8a1a0。该值为 0.25 公斤。当我将第一个值 (9143) 增加 2 时,它将在应用程序中添加 0,25kg。有时它会增加 0.3 公斤。这适用于 917f / c8bfa0 / 7,95kg。如果我去 9181 / c8c0a0 它会跳到 24,55kg。 i 可以继续以 0,25 公斤的步长达到 9195 / c8caa0 / 27,15 公斤。在 9197 / c8cba0 上,它更改单位并显示 4:4.4st:lb。 如果我按 1 计数,则应用程序大部分时间都会因其他值(9144、9146、9148...)而崩溃 有人认出其中的模式吗? 我也开始尝试不同的偏移量,但看起来不太有希望。

编辑2: 4:4.4st:lb 等于 27.397kg。下一步是 4:5.0st:lb 27,67kg。所以在这一点上它是线性的。但是缺少 8 - 24 公斤的范围

Here are the scripts that i use

【问题讨论】:

我假设这与您使用非常相似的广告数据提出的另一个问题有关。该广告似乎确实具有 UUID 为“FFB0”的 GATT 服务。我还找到了秤的说明,上面写着“秤一次只能连接一台设备,请不要同时在其他设备上打开应用程序”。我想知道您将其视为不可连接的原因是否是因为它已在其他地方连接? 我发现nRF Connect App的通用工具非常擅长分析设备nordicsemi.com/Software-and-tools/Development-Tools/…在树莓派上,使用chromium浏览器可以使用URLchrome://bluetooth-internals/#devices来扫描和分析设备。您可能还对以下文章感兴趣,他们讨论了对协议进行逆向工程medium.com/@urish/… 是的,这个问题与我的另一个问题有关。该规模确实可以同时与多个设备一起使用。在 Android-Sourcecode 中是一个文件“BleHandle.java”,可以导入“ICBleProtocol.java”。在这个文件中有一个名为“onDiscoverPeripheral”的函数。当我手动使用此功能时,使用我的广告数据我得到“ICDeviceCommunicationTypeBroadcast;”。 CommunicationTypeConnected 也存在,但似乎适用于其他设备。我们还尝试关闭所有手机(不仅仅是禁用蓝牙),但电子秤始终无法连接。 在我看来,制造商使用 UUID“FFB0”来识别设备类型,或者他们可能为不同的设备使用相同的固件,只是稍微定制一下。 Android-App 的源代码也很连贯,函数名称和 if/else 语句中存在拼写错误,什么都不做。而且看起来制造商确实没有使用任何标准。但我会看看你的链接,试图找出更多的东西。到目前为止谢谢你 我现在确定,体重数据是通过广告传输的。我能够在应用程序中将我的树莓派注册为比例并向应用程序发送虚假测量值。看起来最后一个字节是校验和。如果我将 1 添加到 mac 地址之后的任何字节,我也必须将 1 添加到最后一个字节。应该不难弄清楚校验和是如何计算的。 【参考方案1】:

更新: 根据您提供的数据,我认为您已经找到了可以找到权重值的模式。貌似可以以C8A0A0为起始值(0kg)从第2个字节到第4个字节提取重量值。

要得到权重值,可以用C8A0A0减去第2-4个字节的值。然后将答案除以 1000。

以下示例基于您的数据。括号内的是您观察到的公斤值。

(0.25公斤) C8A1A0 - C8A0A0 = 100HEX => 256DEC => 0.256kg

(7.95公斤) C8BFA0 - C8A0A0 = 1F00HEX => 7936DEC => 7.936kg

(88.3公斤) C9F842 - C8A0A0 = 157A2HEX => 87970DEC => 87.97kg C9F878 - C8A0A0 = 158D8HEX => 88280DEC => 88.28kg

(88.35公斤) C9F9B4 - C8A0A0 = 15914HEX => 88340DEC => 88.34kg C9F988 - C8A0A0 = 158E8HEX => 88296DEC => 88.296kg

(88.40公斤) C9F9E6 - C8A0A0 = 15946HEX => 88390DEC => 88.39kg

(2.15公斤) C8AB40 - C8A0A0 = AA0HEX => 2720DEC => 2.72kg

请尝试更多数据,如模拟发送C9B210,看看是否能得到更接近70kg的重量值。

上一个答案: 也许广告中没有重量数据。在您的描述中,我不清楚您是否试图以标准方式连接到蓝牙电子秤。您可以使用 nRF 或 Lightblue 应用程序来完成。 这是一般程序:

    打开应用程序。让它检测蓝牙秤。 连接到设备。确保电子秤未连接到其他应用(例如它自己的应用)。 您将看到服务和特征的 UUID。 找到具有“通知”和“指示”特征的 uuid,并订阅所有具有该特征的 uuid。 在刻度中的值发生变化时查找这些特征的日志。这很可能是您看到体重数据的地方。

根据您的体重秤的功能,您可能需要在体重秤处于活动状态且尚未确定最终值时执行所有这些步骤,以便蓝牙通信正在进行。您可以通过在操作应用程序时不断进出秤来做到这一点。

【讨论】:

我确定重量数据在广告中。我可以自己向应用程序发送广告并“模拟”规模。我已经编辑了我的问题,所以有更多信息。是的,过去我们尝试以各种方式连接到电子秤。我们创建 hcidumps 以查看您是否已将某些东西发送到秤以使其可连接,关闭任何电话/设备。但是秤永远无法连接。 在您编辑问题并显示更多数据后,我似乎找到了一种模式。我更新了我的答案。 看起来很有希望。但看起来它不适用于每个值。我将一些数据发送到应用程序并获取此值:pastebin【参考方案2】:

我们终于弄清楚了如何获取重量数据。正如我所建议的,重量数据在第二到第四个字节中,如下所示:c9 f8 42。 但是要获得正确的数据,您必须做一些奇怪的事情:您必须像这样替换十六进制字符串的第三个和第五个“字符”:

0 1 2 3 4 5 6 7 8 9 a b c d e f Normal
a b 8 9 e f c d 2 3 0 1 6 7 4 5 Icomon

例如,c8a0a0 (=0,00kg) 将变为 0xC80000。 将其转换为整数并减去 0xC80000,除以 1000 即可。在此示例中,它只是 0,但我使用我们尝试的每个值。

我真的不知道这是否与 Big/little Endian 或 MSB/LSB 恶作剧有关,或者它是否只是一个非常简单的“加密”但它完全有效。

感谢任何人帮助我们,我们在这里得到了一些新的想法,是我们找到答案的原因

这是我们用来解码数据的 python 文件:

#!/usr/bin/env python3
import sys
# 0 1 2 3 4 5 6 7 8 9 a b c d e f normal people
# a b 8 9 e f c d 2 3 0 1 6 7 4 5 Icomon
def main():
  hex_code = sys.argv[1]
  ic = ['a','b','8','9','e','f','c','d','2','3','0','1','6','7','4','5']

  i=0
  out=''
  for byte in hex_code:
    if i in [2, 4]:
      index = int(f'0xbyte', 16)
      out = out+ic[index]
    else: out=out+byte  
    i=i+1
  value = round((int(f'0xout', 16)-0xc80000)/1000,2)
  value=round05(value)
  print(value)

def round05(number):
  return (round(number * 20) / 20)

main()

编辑: 好吧,现在我知道“恶作剧”只是异或。

【讨论】:

我现在才重新审视这个。哈哈。我几乎明白了。我的建议是 (value - 0xC8A0A0) / 1000,如上所述。事实证明,正确的方法是将值异或:(value XOR 0xC8A0A0) / 1000

以上是关于通过 disassemble manucaftures 库从蓝牙 le scale 获取重量数据的主要内容,如果未能解决你的问题,请参考以下文章

disassemble_section

disassemble_section

Radare2 Disassembler 你如何组织可视面板(V!)?

Win#password;;processon #clone;;disassemble;;source find

Hopper Disassembler系列之Sublime Text 3 爆破

如何在VS2012中使用IL Disassembler中查看项目编译生成的程序集