Discovering that your car battery monitor is siphoning up your location data

Reverse engineering an Android app for a Bluetooth connected car battery monitor with some startling discoveries ...

Discovering that your car battery monitor is siphoning up your location data

Hello Hacker News, thanks for visiting!

Update: 25th July 2023
The developers have released an update to both App stores in which the AMap SDK has been removed.

This means that the GPS, Wifi and cell phone tower data collection to AMap’s servers hosted in mainland China no has ceased. GPS location data is still sent to a server hosted within Alibaba cloud in Hong Kong. The iPhone app will also resolve and send the user’s street address. See this Twitter thread for further details.


TLDR

  • A Bluetooth enabled battery monitor that records car battery voltages. The hardware requires a smartphone for pairing
  • The product collects GPS co-ordinates, cell phone tower data and nearby Wifi beacons
  • Location data is sent over the Internet to servers in Hong Kong and mainland China
  • App store misleads consumers by stating that no personal data is collected or shared. Since the Android app requires location permissions to use the hardware device, users are effectively forced to continuously broadcast their physical location to 3rd parties in order to use the product.
  • On Android, the application has persistance and will automatically restart when the phone is rebooted

There are no legitimate reason for a car battery monitor application to track it’s user’s location. With over 100,000 downloads on Android alone, this raises significant privacy concerns


In this four part series:

  • Part 1 - This page
  • Part 2 - Reverse engineering the AMap SDK location tracking features
  • Part 3 - Reimplementing BLE functionality
  • Part 4 - Obtaining and modifying the firmware

Within this series of posts, we explore the discovery of an Bluetooth enabled battery voltage product, acquired from a popular electronics retailer in Australia. What started as an initial hunch lead me down rabbit a rabbit hole to discover that the app covertly tracks the users physical location. It collects GPS co-ordinates, neighbouring cell phone tower location data and Wifi access points, sending this data to cloud servers in Hong Kong and mainland China.

At the time of writing, location data is sent to servers related to two seperate corporate entities:
The product / app developer, Leagend, hosted in Alibaba Cloud, Hong Kong
bm2.quicklynks.com / 47.244.125.231
The location services SDK developer, AMap, hosted in Alibaba Cloud, Beijing
dualstack-cgicol.amap.com / 106.11.130.194

Partly responsible for the extensive data collection is an embedded library used, called AMap, which is a “leading provider of digital map in China”.

Acquired by Alibaba, it is stated that “In 2018, Amap became the first Chinese maps service to navigate a path to 100 million daily users”. In part 2 we look under the hood at how AMap is not only collecting the GPS co-ordinates, but also every other possible location data the phone can collect - surveying Wifi and telecommunication cell phone tower data.

The Android application which connects to the battery monitor device, BM2 100K+ downloads, with 1.55K reviews.

2023-06-07 As @XenoKovah highlights, you can map out the coverage of these devices by searching the various BLE advertised device names (battery monitory,ZX-1689,Li Battery Monitor) in WiGLE.net. You can gain an appreciation to just how much coverage these devices have across the whole globe.

The iPhone iOS version can be found here. While I have not peformed any static analysis on the iOS decompilations to date, inspection of the network traffic from the phone reveals that that the Apple iPhone version is also sending location data to remote servers.

Feel free to reach out to me on twitter for partially reverse engineered decompilation of the sources referenced. The subsequent posts should provide enough detail for others to independently verify what is being reported.

In the following Wireshark trace we see along with the battery voltage readings, the latitude and longitude being sent unencrypted, via a HTTP POST to bm2.quicklynks.com:

Product information

I acquired the vehicle battery monitoring Bluetooth device sold under the brand PowerTech from a popular Australian electronics retailer, Jaycar Electronics.

This appears to be a re-branded Bluetooth 4.0 Battery Monitor by a company called Leagend which is available on Amazon for purchase.

2023-06-27 The companies FCC application is registered under SHENZHEN LEAGEND OPTOELECTRONICS CO., LTD, with the device FCC FCC ID 2AU4A-191114.

It’s resold under local brands, for example another popular auto retailer, Repco, sells it under the Century brand.

Other device names are “ZX-1689” and “Li Battery Monitor” which the application looks for in the device name of the advertising BLE beacon which are indentified in part3.

The device is quite simple - you connect it to the terminals of a battery and pair it with your phone. It shows the battery voltage/percentage and allows you to run some crank tests. That’s what’s advertised.

Additionally, the required application runs in the background, effectively turning a smart phone into location scanning device. Having your phone become a continuous Wifi scanner drains the battery - and this isn’t something legitimate application developers want. People do complain about issues caused. Patrick’s review of the BM2 app would agree:

While we can’t explain the legitimate reason a battery voltage monitor would need to know your GPS location, a charitable explanation of the AMap SDK collecting GPS, Wifi and cell tower data is they are attempting to do what Google and Apple already do - build a relational database, mapping phone cell towers and wifi access points to GPS co-ordinates. When a phone has bad GPS signal, knowing the adjacent Wifi access points or phone towers within reception can help increase accuracy.


Some terminology

AMap collects the telecommunication provider’s adjacent cell phone tower location data - Specifically the cell global identity. This is an ID that uniquely identifies a cell, unique across the whole world.

The CGI is made up of:
MCC = Mobile Country Code
MNC = Mobile Network Code
The MCC + MNC make up the PLMN (Public Land Mobile Network) - Identifies the mobile operator (e.g. Telstra, Australia)
LAC = Location Area Code. Set of base stations grouped together in a geographical region
CI = Cell ID. Identifies base station transceiver within a region. Think of this as an ‘antenna’ that your phone is talking to

In 4G, technically TAC (tracking area code) is used. 

Wifi data collection includes:

BSSID MAC address of Wifi access points.
SSID - Access point name


The AMap developers go to lengths to conceal the behaviour, encrypting any data before it touches disk or sent over the Internet. Location data is encrypted with ephemeral AES keys which is then encrypted with a public RSA key. This removes the dependency for certificate pinning and ensures man-in-the-middle inspection of the network traffic is not possible without modifications to the application or obtaining the corresponding private RSA key.

Data privacy

Note: As of 27th of June 2023, the BM2 app developer have updated the privacy statements on both the Google Play and Apple App stores - now mentioning that precise location data is being collected.

The following is stated on the BM2 app Android Play store

One by one, let’s review the statements claimed:

1. No data shared with third parties

  • In addition to your battery statistics (e.g. voltage), the latitude and longitude co-ordinates of your location is sent to the BM2 application cloud servers, quicklynks.com
  • Crash analytics are sent to a 3rd party Chinese company, umeng.com
  • Wifi, cell phone tower and GPS co-ordinates are sent to a Chinese company, AMap

2. No data collected

  • Self explanatory

3. Data is encrypted in transit

  • Data sent to the BM2 cloud servers is unencrypted

How about on the Apple store? take a look

The privacy policy fine print does mention “Hong Kong” and “location information”. We all read the fine print right?

Location and Android permissions

For the application to work, you must give the Android application permissions that let it obtain location information otherwise it won’t work: For Bluetooth scanning, Android requires this permission. At least with the iOS version, you can hit “deny” when it asks for location permissions and the battery monitor device will still work.

To expand on the reason cited, it’s best explained from Android’s developer documentation:

To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs. To access the hardware identifiers of nearby external devices via Bluetooth and Wi-Fi scans, your app must now have the [ACCESS_FINE_LOCATION] or [ACCESS_COARSE_LOCATION] permissions.

I would argue that such a broad permission that covers both Bluetooth, GPS and Cell data offers lower data protections - as it opens up app developers to abuse this permission as we see with the BM2 application that really just requires BLE scanning. BLE scanning can be achieved with just BLUETOOTH_SCAN, available on Android 12+.

💡
Update 2023-06-27 Google provide further guidance here. It is possible to specify ACCESS_FINE_LOCATION with android:usesPermissionFlags set to neverForLocation. This is only for when Bluetooth scan results are used to derive physical location. That does not seem to be the case here though.

The hardware

Our interest lies mostly in the phone applications that interface with the hardware, although it’s customary to at least take a peek inside and explore what the possibilities are for pulling off the firmware.

Not much too it; some voltage regulators and a single SoC - a Texas Instruments CC2541) all in one Bluetooth Low Energy MCU. Datasheet here. Some possible debug ports are spotted:

The CPU is based on an 8 bit Intel 8051. Later revisions of the CC series use ARM cortex architecture.

According to the specifications, the CC series SoCs support on chip debugging via a proprietary interface - No JTAG or SWD to be seen here. This means we will need the CC Debugger or try some custom Arduino implementation, although this specific IC is not supported. As the device supports over-the-air updates, there is a REST endpoint which will return the firmware over HTTP, documented in part 3

It appears there is no shunt or other current sensing circuity. Hardware wise, this really is as simple as it gets.

The test setup

For testing I’m using a small led acid 12v battery with the BM2 battery monitor and a rooted Android handset which will be used for dynamic instrumentation.

Notably, the setup sat on my desk. As we discover in part 2 of this blog post series, the AMap location data is only written to it’s database from memory when it detects you are physically moving. To overcome this and other hurdles, Frida and Objection used extensively to instrument the running software in run time.

Dynamic analysis

Intercepting network traffic

Mitmproxy is a defacto “in the middle” proxy software and it now supports a new mode using wireguard. What this means is it’s extremely trivial (and quick) to peek inside mobile application traffic with minimal configuration. Once the Wireguard application is installed on the handset, simply mitmweb --mode=wireguard and take a scan the QR code on screen by taking an image from the handset. Immediately all traffic from the handset will be sent over a Wireguard tunnel to mitmproxy. Browsing to http://mitm.it then allows you to download a certificate to add to the trust store. With iOS the process is trivial. Android has now made it harder to do, and in this case I had to use a rooted handset.

💡
Note: Since the BM2 does not use HTTPS, there is no need to even install a certificate. What this means is that anyone can independently identify that their latitude and longitude co-ordinates are being sent on either iOS or Android with no modifications to their phone.

After the application connects to the battery monitor device, we see a POST request is sent to http://bm2.quicklynks.com:8080/api/bm2/userDevice/upload?.

Latitude and longitude fields are highlighted in green.

At the time of writing, this server resolves to a host in Alibaba cloud, HK:

$ host bm2.quicklynks.com
bm2.quicklynks.com has address 47.244.125.231
$ curl https://ipinfo.io/47.244.125.231
{
  "ip": "47.244.125.231",
  "city": "Sham Shui Po",
  "region": "Sham Shui Po",
  "country": "HK",
  "loc": "22.3302,114.1595",
  "org": "AS45102 Alibaba (US) Technology Co., Ltd.",
  "timezone": "Asia/Hong_Kong",
}

In this specific request we also see a sample of the battery voltages, the hardware MAC address of the device (nickname and serialNo).

Spoofing GPS co-ordinates

GPS co-ordinates can be spoofed by using the following Frida to dynamically hook into android.location.Location.{getLatitude|getLongitude} methods. Frida will be used extensively in our testing. More on this later.

location.js

const lat = 39.1090;
const lng = -76.7700;

Java.perform(function () {
   var hookedClass = "android.location.Location"
	var Location = Java.use(hookedClass);
	Location.getLatitude.implementation = function() {
      console.log("[+] " + hookedClass + "new lat:" + lat);
		return lat;
	}
	Location.getLongitude.implementation = function() {
      console.log("[+] " + hookedClass + "new lng:" + lng);
		return lng;
	}
})

To invoke: $ frida -U -l location.js -f com.dc.battery.monitor2

Memory analysis

As stated earlier, GPS, Wifi and cell data is gathered by the embedded AMap library. The code is obsfucated to make reverse engineering more time consuming. Anything that touches disk or the network is encrypted serialized binary blobs. This calls for some quick wins with dynamic instrumentation as the code runs on a handset while paired to the hardware battery monitor.

For example, we can peek inside the application’s heap memory. For this we will use a plugin for Objection called Wallbreaker. After some quick analysis of the AMap library we know what class names to find instances in memory (click pictures to expand):

GPS data: 

Telecommunication provider cell data: 

Wi-Fi data (toString enumerated): 

Static analysis

Decompilation

First let’s grab the APK straight off the handset. We could of course get a copy from APK pure too from here

First identify the application name identifier which is com.dc.battery.monitor2:

Obtain the path of the APK and pull it from the device with adb shell pm path then pull it off the phone.

JADX is our choice for the de-compiler, and it’s just great. Opening the .apk and it handles everything in one shot, from decompression to de-compiling the java bytecode into Java.

The very first thing is to check the permissions in AndroidManifest.xml after opening the APK in APK in jadx-gui

The hightlights in green raises a few questions. We have explained why FINE_LOCATION is required, but why would a battery monitor application needs CAMERAIMAGE_CAPTUREACTION_VIDEO_CAPTUREMODIFY_AUDIO_SETTINGS and RECORD_AUDIO ?

At this point it’s possible that this functionality is unused. More investigation is needed here.

Very quickly we see that the decompilation of the java bytecode directly from the APK is going to be problematic. The entrypoint is com.stub.StubApp which has methods names obsfucated with xor encryption which indicates there is more work to do.

<application android:theme="@style/AppTheme" android:label="@string/apk_release_name" android:icon="@mipmap/ic_launcher" android:name="com.stub.StubApp"

Fortunantly it’s obvious that a commercial software packer called qihoo.util has been used. Zimperium has a good writeup on this packer as it’s often found employeed in Chinese based mobile malware. It’s somewhat advanced in the sense that the unpacked software is encrypted and packed into native, compiled library. People have written unpacking tools that claim to handle this packer such as android-unpacker. Given that developers often update and change their packing techniques, the unpacker tools in the public domain can quickly become outdated.

As such we will take much easier approach - by using frida-dexdump it’s possible to dump the original (unpacked) mobile application Dalvik executable bytecode from memory after opening the application on the handset.

💡
Qihoo 360 is not without their own controversy, being “placed on the Bureau of Industry and Security’s Entity List due to U.S. national security concerns”.

After installing dexdump (e.g. pip3 install frida-dexdump), run it after opening the application:

frida-dexdump -U -f com.dc.battery.monitor2 -d

Use dex2jar to covert classes.dex to java bytecode:

./d2j-dex2jar.sh ./com.sec.android.app.samsungapps/classes.dex

We can the use jadx to then decompile into readable java and now have the original application code, method names, variable names for com.dc.battery.monitor2, as no further obfuscation was done outside of the initial packing/encrypting.

The exception here is the amap location services SDK library which was originally obsfucated which will make our time a little harder to reverse these parts. Fortunately class names are recoverable for the AMap related classes by selecting tools -> deobsfucation in JADX.

While the variable or method names are random(ish) strings, the recovered class names are descriptive enough that with some effort the function of the classes and methods is identified with method and variables renamed appropriately by hand.

Next up, in part 2 we will investigate how the embedded AMap SDK is not only sending the GPS co-ordinates, but Wifi and telecommunication cell tower data.