fl3xbl0w project logo

Bowflex Curiosities - fl3xbl0w

Released on May 28, 2022

Reverse engineering project. It started with the Bowflex Treadmill 22 but ended up being generalized for any Android machine sold by Nautilus Inc. (Nautilus, Bowflex, Schwinn).

The /sdcard/Pictures/nautilus File

When decompiling NautilusLauncher, you can see references to that specific path:

// path: com/nautilus/nautiluslauncher/LauncherService.java
public void run() {
  if (!new File("/sdcard/Pictures/nautilus").exists()) {
    LauncherService.access$000(LauncherService.this).disableAdbDebug();
    LauncherService.access$000(LauncherService.this).enterKioskMode();
    return;
  }
  LauncherService.access$000(LauncherService.this).enableAdbDebug();
}
// path: com/nautilus/nautiluslauncher/MainActivity.java
protected void onCreate(Bundle bundle) {
  // ...
  if (!new File("/sdcard/Pictures/nautilus").exists()) {
    this.mPlatformControl.disableAdbDebug();
    this.mPlatformControl.enterKioskMode();
  } else {
    this.mPlatformControl.enableAdbDebug();
  }
  // ...
}

The effect of placing the file in its place is that NautilusLauncher will activate adb after each restart. If the file is NOT in place, NautilusLauncher will ACTIVELY DISABLE adb (if it was previously enabled).

The /sdcard/Nautilus/redbend/Credentials.txt File

It seems that Red Bend Software (acquired by Harman, now I understand why so many references to KNOX) is providing OTA services for Nautilus hardware. I found some references to that file within com.redbend.client.apk.

package com.redbend.client;
public class Ipl {
  protected static final String AUTO_SELF_REG_FILE_PATH = "Credentials.txt";
  // ...
  public static int iplGetAutoSelfRegDomainInfo(Context context, String[] strArr) {
    // ...
    File file = new File("/sdcard/Nautilus/redbend/");
    if (!file.exists()) {
      file.mkdirs();
    }
    copyAssets(context, "Credentials.txt", file.getCanonicalPath());
    bufferedReader = new BufferedReader(new FileReader(new File(file.getAbsoluteFile(), "Credentials.txt")));
    // ...
  }
  // ...
}

Also in com.redbend.client.ClientService we can find:

// ...
public class ClientService extends SmmService {
  // ...
  @Override // com.redbend.app.SmmService, android.app.Service
  public void onCreate() {
    // ...
    if (Ipl.iplGetAutoSelfRegDomainInfo(this, strArr) == 0) {
      sendEvent(new Event("D2B_AUTO_SELF_REG_INFO").addVar(new EventVar("DMA_VAR_AUTO_SELF_REG_DOMAIN_NAME", strArr[0])).addVar(new EventVar("DMA_VAR_AUTO_SELF_REG_DOMAIN_PIN", strArr[1])));
      }
    // ...
  }
  // ...
}

Given that information, we can label the content in the file /sdcard/Nautilus/redbend/Credentials.txt as:

First line: DOMAIN_NAME
Second line: DOMAIN_PIN

DOMAIN_PIN appears to be a real pin code as it is a six-digit number.

There are some credentials within the “Red Bend Network” to associate a machine with a specific brand/product for OTA updates. I hope those credentials are IDENTICAL across all Nautilus hardware. The file is included within the com.redbend.client APK and is extracted upon installation.

I found references to com.redbend.client here, and I thought it was quite funny to see it crashing in a car. I hope it doesn’t fail that often in our machines as well.

Bluetooth Heart Rate Monitor

This one was quite straightforward to decipher. The Bluetooth name appears as CL831-xxxxxxx (number hidden) from CHILEAF.

When scanned through nRF Connect, the device’s MAC address and some key data were exposed:

Heart Rate:
UUID: 0x180D
Heart Rate Measurement
UUID: 0x2A37

It seemed pretty standard, and a post from the Home Assistant Community had already figured this out (not the same model, but it seems the Heart Rate Monitor uses a standard protocol). I have created an ESPHome configuration file here as a proof of concept:

Screenshot of Home Assistant showing a heart rate sensor
Content translated by gpt-4-1106-preview

©2022-2024 Sebastian Barrenechea. All rights reserved.

Built with Astro v4.15.9.