That battery monitor that spied on it's users. What happened after it was exposed?

That battery monitor that spied on it's users. What happened after it was exposed?
8th May 2024 - The following is an "archive" of the investigation done live over X / Twitter to find out what changes had been made after my expose on a popular car battery monitor which you can read here. At the time of the original postings, it had garnished over 1.1 million impressions.
TLDR; The developer removed the 3rd party library that was siphoning up cell tower and Wi-Fi data. It sill collected GPS data. The privacy disclosure statements on the app store were fixed to tell the truth on what they were collecting.

4:18 PM 路 Jul 23, 2023

This invasive Bluetooth car battery monitor was found to be sending the following location data to China.

- Wifi devices
- Cell phone towers

The Apple and Google app stores said no personal data was collected.

A new update has emerged. Let's see what was changed

4:29 PM 路 Jul 23, 2023

Before we begin the investigation, a coverage map of where these devices have been found across planet earth.

Collected Bluetooth beacon data from reveals they are everywhere. There are likely hundreds of thousands of these roaming about.

5:07 PM 路 Jul 23, 2023

The first thing we notice is that the 'Data safety' on the Google Play store has been updated.

Also the Apple 'App Privacy' statement.

This was done after my blog post exposing the device was published.


What else was changed ?

5:27 PM 路 Jul 23, 2023

"Security update, it is recommended that all users update".

I plan to look at both the iOS and Android apps in this Twitter thread.

Android is probably going to be easier, so let's start with that, then move to iOS.

Let's update then.

6:03 PM 路 Jul 23, 2023
Loading up the APK into JADX to decompile the bytecode into Java, it's apparent they are still using the Qihoo packer as before.

The actual code we want to encrypted. Although Qihoo is an advanced (native) packer, there is a trivial way to obtain what we want - pull the decrypted Dalvik executable directly off the Android device after it's decrypted - using a Frida script.

@Zimperium have a really nice write up on the Qihoo packer:

Dissecting mobile native code packers. A case study. - Zimperium
As mobile malware advances to the levels of desktop malware, it鈥檚 not uncommon to stumble upon protected APKs while analysing malware. Most of the times,

6:27 PM 路 Jul 23, 2023

The Android manifest declares permissions used - not much has changed here. Not a good look, although note that a declaration here does not mean the permission is actually used at run time.

It's a battery monitor app. Why did they leave all this in? CAMERA, RECORD_MEDIA_

6:50 PM 路 Jul 23, 2023

Well this is disappointing, although somewhat expected. Despite being on Android 12+, the app is forcing me to grant it precise location permissions to discover the device over BLE.

I literally cannot use the hardware unless I give it access to my location. Sinister.


7:00 PM 路 Jul 23, 2023

In the video above, permissions to discover "nearby devices" was granted, yet the app refuses to pair unless precise location is granted.

Things have improved on newer devices although it's up to the developer to make the effort as demonstrated:

7:09 PM 路 Jul 23, 2023

I'm going to use a quick and dirty Frida script to invoke at runtime and fake the GPS location before continuing.

What latitude / longitude should we set?

Wrong answers only.

7:47 PM 路 Jul 23, 2023

To intercept HTTP/S traffic, initially went with Burp Suite which acts as a HTTP proxy.

Can't see requests to their servers. It seems that the analytics libraries used obey the global HTTP proxy server settings but not the main code.

MITMProxy solves the issue.

8:01 PM 路 Jul 23, 2023

t seems that a new API endpoint has been added:
/v2/ encrypted payload? (jdata).
/v1/ sends GPS data as before to Hong Kong

No reqs to AMap so far. This was the 3rd party lib that was sending cellid,wifi and gps data to servers in mainland China

Time to dig into the code.

8:26 PM 路 Jul 23, 2023

Interesting. Pointed out in my blog was that the AMap location SDK had used asymmetric crypto for POST data within HTTPS, avoiding having to do cert pinning. Also code obfuscation.

The prior BM2 app lacked both of these. Now it seems they have taken note

8:43 PM 路 Jul 23, 2023

One major improvement in the new "security update" version - The use of the location services SDK, AMap, appears to be completely removed.

That was the code that was turning the phone into a cell phone tower & wifi scanner and sending to China
Now GPS data only sent to Hong Kong

9:16 PM 路 Jul 23, 2023

From earlier we know /v2/userDevice/upload might be what we are looking for. It seems o.a() encrypts the parameters with a public RSA key of 2048 bits. At least it's not 512 which is what AMap used (crackable in a few days).

9:24 PM 路 Jul 23, 2023

We can see what arguments are passed and what's returned by the encryption method o.a() in real-time.

Right mouse click in JADX and select "Copy as frida snippet" and paste into a Frida session.

It really could not be any easier.

9:41 PM 路 Jul 23, 2023

Repairing the BLE device triggered the HTTP req.

Plain-text values are passed as an JSON string that includes lat/lng.

Returned value is matched with the encrypted jdata value the POST request over HTTPS to /v2/userDevice/upload.

Confirms what we already knew really.

10:16 PM 路 Jul 23, 2023

What could trigger the location lat/lng to be sent over the Internet -

In addition to pairing, a Bluetooth characteristics event notification, such as a reported change in voltage.

And the app runs all the time, in the background.

10:22 PM 路 Jul 23, 2023

Should observe this dynamically to verify, although for now I'm kind of ready to move on from Android.

Next up is iOS !

The first thing to do is to actually grab the software - not as easy as on Android.

Time to grab a jail broken iPhone.

10:53 PM 路 Jul 23, 2023

The very first thing that stands out is that the iOS app pairs immediately to the BLE device and at the same time asks for access to your location.

It's not at all required - select don't allow and things work as normal.


11:11 PM 路 Jul 23, 2023

The app is respecting the iOS HTTP proxy settings - so back to Burp Suite for TLS MITM it is.

The new /api/v2/ endpoints are being captured with the encrypted jdata parameter. We want to see what's inside these encrypted blobs.

11:29 PM 路 Jul 23, 2023

Apple uses Fairplay DRM - Apps downloaded are encrypted with a public key associated to your Apple account.

Using a Frida script (or any other tool), the unencrypted .ipa package can be obtained. In this case, pulled from working memory.

11:57 PM 路 Jul 23, 2023

Unzipping the .ipa, CFBundleExecutable in Info.plist provides us the (obvious) executable name which is immediately loaded into Ghidra for decompilation.

Descriptive class and member names. Could be relatively straight forward

Starting with the XREFs for the v2 API:

11:57 PM 路 Jul 23, 2023

Starting to go in circles. It's ObjC decomplication - need to think about a smarter approach.

What about searching strings for an RSA public key?
It matches the same one we found in the Android resources file. Should bring us close to where we need to be looking.

12:39 AM 路 Jul 24, 2023

Since the API endpoint is the likely the same for Android, a guess that RSA::encryptString:publicKey: is a candidate to hook into to follow the same approach as we did earlier - try to print the arguments and return value and match against the network traffic capture.

12:52 AM 路 Jul 24, 2023

The first two parameters can be ignored (class name and method selector). The third is likely the string to be encrypted and the fourth we already know is the public RSA key. Modifying some boiler plate Frida code..

1:08 AM 路 Jul 24, 2023


The EXACT residential address (street number, street address) of where I am sitting now is populated into the JSON string that is encrypted and sent out.

How could this have happened?


1:21 AM 路 Jul 24, 2023

Perhaps this is how it's doing it: Sending a request to with the lat and lng values.

It's been around 9 hours straight today on this thread - will park things for now and continue on later to tie up this loose end.

4:28 PM 路 Jul 24, 2023

I've been pondering my response on discovering the iPhone app was sending out street/postal addresses.

To the mind, GPS co-ordinates are just digits.
A residential address feels more real - personal.

Effectively though, they are equivalent. That's the key point.

8:33 PM 路 Jul 25, 2023

I just rebooted the Android phone and noticed that there was abnormal traffic.

The (Android) app appears to have a persistence mechanism and will start silently in the background when you (re)boot your phone.

Does this mean it can track you all the time?

9:54 PM 路 Jul 25, 2023

You have to delete the app completely.

The Android permissions manager said location services was last accessed after I *knew* I had closed the app.

But had it really been closed?

No - the Bluetooth beacon library is configured to always start the app on boot.

10:29 PM 路 Jul 25, 2023

Could the developers plead ignorance?

I'll let you decide.

If a user had run the app just once, it could continue running non-stop for years, secretly tracking their every move.

Android beacon library: how to disable run at startup
It seems that importing android beacon library (2.9) aar file force an application to have 鈥渞un at startup鈥 permission (adds a receiver in the manifest: org.altbeacon.beacon.startup.
Android Beacon Library
Android Beacon Library : An Android library providing APIs to interact with Beacons
Note that the the contents of the tweets from here are mostly captured in this blog post:

1:36 PM 路 Jul 27, 2023

It's time to dig into the actual hardware and try to grab the firmware directly off the device.

Previously I had pulled it apart and documented that it uses a Texas Instruments CC2541 MCU

An unpopulated 5 pin header exposed.

1:49 PM 路 Jul 27, 2023

The CC25xx is an all in one Bluetooth Low Energy SoC based on the Intel 8051. It has a proprietary interface for flashing and debugging needing a CC-DEBUGGER.

I'm almost certain this is what the five exposed pins are for, so I ordered one.

1:58 PM 路 Jul 27, 2023

The exact number of pins for this exposed unpopulated header matches minimum number of connections required to interface the debugger to the microcontroller - 5.

GND, Vdd, debug clock, debug data, and RESET.

I've highlighted the pins in green.

2:17 PM 路 Jul 27, 2023

Using a multimeter in continuity mode, each exposed pinhole can be tracked a pin on the integrated circuit.

Likely used to flash and test the device during production.

A potential hurdle for us is if they enabled the security feature to lock read / debug access.

2:39 PM 路 Jul 27, 2023

I wanted to make sure the flash programmer would be setup correctly, so had also ordered a CC2540 evaluation USB dongle to test the debugger and software with.

Turns out the latest s/w no longer supports the Intel based MCUs. Only the newer ARM based ones.

Fortunately someone had archived the old supported version on Github.

3:51 PM 路 Jul 27, 2023

Soldered up all the connections as per the datasheet. Checked for any shorts many times.

Paranoid here because last time I connected h/w to a USB port, I blew the whole computer up.

4:09 PM 路 Jul 27, 2023

On hitting the reset button, the CC Debugger's status light turns from red to green. This is a good sign.

Also.. computer still running. Also a good sign.

4:24 PM 路 Jul 27, 2023

Looks like it it's working

Patiently waiting ...

4:57 PM 路 Jul 27, 2023

The emitted flash dump is in encoded Intel HEX (the prefixed '':" is the giveaway.

I've colour coded it's structure below (thanks Wikipedia).

There are plenty of tools out there to convert this back into a binary blob.

5:34 PM 路 Jul 27, 2023

Was really hoping Ghidra would support this architecture. Unfortunately there is no support for 8 bit CPUs.

Googling around, Radare2 looks to support the 8051.

Take a look at the path in this person's Stack Overflow question. Look familiar ??

5:46 PM 路 Jul 27, 2023

... it's the name of the phone app that pairs to the device.

So someone has been down this path before. User Rune on Jan 8, 2018.

Could this person be why the there is an anti-piracy check in the app?

8:10 PM 路 Jul 27, 2023

As @marunmagesh and @atc1441 pointed out, Ghidra certainly does support the 8051 architecture.

I think the base address & memory map needs to be tweaked to get successful decompilation.

Next I'm going to try patching the firmware to check if there is write protection

8:26 PM 路 Jul 27, 2023

The easiest way to confirm we can modify the firmware OK is to modify the device name in the BLE advertising beacon.

Then we can just listen the new one advertised over the air.

I'm sure many of you can think of more appropriate names we can give this device by now.

8:38 PM 路 Jul 27, 2023

Perhaps not the most creative change, but it will serve to demonstrate the objective.

Almost forgot to update the last byte which is the checksum of the byte array.

Quick and easy way:

9:05 PM 路 Jul 27, 2023

And it worked!

The new firmware flashed successfully.

Hitting scan on the mobile Bluetooth scanner, nRF Connect, a new device appears in our midst.

'B痰a痰t痰t痰e痰r痰y痰 HaxRob Monitor'

9:49 PM 路 Jul 27, 2023

The mobile app supports OTA update functionality.

Updating over Bluetooth would be a more user friendly alternative way to patch.

I wonder though, what's stopping anyone else from driving around in their car and updating other people's devices?

"war patching"

10:09 PM 路 Jul 27, 2023

The app works by performing BLE scanning and looking for specific device names such as "Battery Monitor" or "ZX-1689" (found in Germany).

BLE message are encrypted with AES-128 CBC. The IV is all zeros due to a bug in the code.

The decryption key is "leagend每镁1882466".

11:19 PM 路 Jul 27, 2023

Jan Andreasen 
What is ZX-1689 a reference to? A chip?

Unsure - perhaps the model ID of a rebranded device sold exclusively in Germany.