Reverse engineering a BLE clock

Decompiling the Mobile App

This APK file contains the Dalvik bytecode that Android executes, but you can decompile it into Java source code using the powerful jadx [5] decompiler, which comes in a command-line version as well as in a graphical interface. You will need the 64-bit version of Java 8 or later to run jadx.

Download the latest release of jadx from GitHub and unpack the ZIP file. Then start the graphical interface by running ./bin/jadx-gui from the command line inside the unpacked directory.

Select the base.apk file you downloaded. The program now decompiles the app and shows a tree structure of its packages and Java files at the left.

Follow the Breadcrumbs

You are now ready to search for the time setting command. Look again at the Bluetooth log in Wireshark. You already figured out the meaning of the written value in the packet that sets the time, but where's it written? Click on the Handle drop-down in the details pane. It shows a service UUID, 000102030405060708090a0b0c0d1910, and a characteristic UUID, 000102030405060708090a0b0c0d2b11. These two values are the first breadcrumbs to follow.

In jadx, open the Navigation | Text search menu. Be patient: jadx now starts decompiling the whole app. When it's ready, paste one of the UUIDs in the search field. This won't result in a match for both UUIDs, but if you search with just 0001, you see that the UUIDs are definitely in the code as a string with delimiters.

When reverse engineering BLE connections, the characteristics are always more interesting than the services, because those are the actual containers for data. Services are just lists of characteristics. If you enter the characteristic UUID as 00010203-0405-0607-0809-0a0b0c0d2b11 in the search field, you find one occurrence:

public final UUID f4476c = UUID.fromString("00010203-0405-0607-0809-0a0b0c0d2b11");

This means that code that uses this UUID refers to it by its name f4476c. Open the text search menu again and search for f4476c. There's only one other occurrence:

BluetoothGattCharacteristic characteristic = service.getCharacteristic(aVar.f4476c);

A few lines later this characteristic is used as follows:

characteristic.setValue(bArr);

Here, the value in bArr is written to the characteristic. This bArr is an argument to the method where this piece of code comes from, and this method is called mo4745d. So, that's the next breadcrumb. Search for this name in the text search menu to see where this method is called. This gives eight results (Figure 4), so look at each result and try to figure out what they're doing.

Figure 4: Following breadcrumbs in the decompiled code.

Finding the Right Code

After following all the breadcrumbs, you find the code in Listing 1, which immediately shows the structure that you had figured out: a header byte, the year, month, day, hour, and then minute, which confirms that after this comes the seconds. Then comes the day of the week, and the 1 that you couldn't identify turns out to be a value for the 24-hour format. My clock was showing the time on its display in 24-hour format, but apparently this bit changes the format to a 12-hour clock using AM/PM.

Listing 1

Decompiled Code for Setting the Time

01 public void mo4809a(boolean z) {
02   byte[] bArr;
03   if (mo4825v()) {
04     if (z) {
05       bArr = new byte[10];
06       Time time = new Time();
07       time.setToNow();
08       bArr[0] = -91;
09       bArr[1] = (byte) (time.year % 2000);
10       bArr[2] = (byte) (time.month + 1);
11       bArr[3] = (byte) time.monthDay;
12       bArr[4] = (byte) time.hour;
13       PrintStream printStream = System.out;
14       printStream.println(DateFormat.is24HourFormat(this) + "24 Hour" + time.hashCode());
15       bArr[5] = (byte) time.minute;
16       bArr[6] = (byte) time.second;
17       int i = time.weekDay;
18       bArr[7] = i == 0 ? 7 : (byte) i;
19       bArr[8] = DateFormat.is24HourFormat(this);
20       bArr[9] = 90;
21     } else {
22       Time time2 = new Time();
23       time2.setToNow();
24       bArr = new byte[]{-91, (byte) (time2.year % 2000), (byte) (time2.month + 1), (byte) time2.monthDay, (byte) time2.hour, (byte) time2.minute, (byte) time2.second, 90};
25     }
26     if (mo4826w() != null) {
27       mo4745d(bArr);
28     }
29   }
30 }

You also see that this code supports another time setting command structure, without the day of the week or 24-hour format. This presumably is for another type of clock without those capabilities.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Bluetooth LE

    Bluetooth Low Energy is ideal for networking battery-powered sensors. We show you how to use it on the Raspberry Pi.

  • Bluetooth Security

    Is your address book open to the world? Is your mobile phone calling Russia? Many users don’t know how easy it is for an attacker to target Bluetooth.

  • Bluetooth Hacks

    The user rules in Linux – if you know where you’re going. This month the trail leads deep into the Linux Bluetooth stack.

  • Adding a Bluetooth Speaker to Linux
  • Bluetooth Mobile Phones

    It is becoming increasingly common for new generation mobile phones to have an integrated Bluetooth interface. This article explores how to access your Bluetooth phone using Linux.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News