000yesnt.github.io

Analyzing a companion app for a cheap Chinese IR camera

I recently got recommended a video by Dmytro Engineering about his journey with reverse engineering the Xinfrared Xtherm II T2S+. In it, he mentions how the app requests an insane amount of permissions (a short list is in his blog post), including a few used by malware, such as SYSTEM_ALERT_WINDOW, WRITE_SETTINGS, CALL_PHONE and others.

While his video was interesting, I was left wondering how exactly this permission abuse is used in practice. He theorizes that maybe an incompetent developer slapped on permissions until the app stopped complaining. I think that is indeed the case, and I will describe why in this post.

Because I don’t have the camera, I can’t test the app extensively. Most of my conclusions are drawn from static analysis. Also, while I did my research, I may have missed or misunderstood some things. I’m not an Android RE pro, I just like poking around apps for fun

The Android permission model

To understand how severe this really is, one must first understand how Android permissions work.

Before an app can take a certain protected action, it must declare in its manifest the permission for it. This prevents apps from having full control over the device and allows the user to inspect, and in some cases control, what an app does to the system.

There are three main types of permissions:

Android categorizes permissions into different types, including install-time permissions, runtime permissions, and special permissions. Each permission’s type indicates the scope of restricted data that your app can access, and the scope of restricted actions that your app can perform, when the system grants your app that permission. (source, emphasis mine)

Most permissions that users consider sensitive can only be enabled with an user interaction and can be rejected if the user wishes to do so. Just because it’s in the manifest doesn’t mean the app will have the permission right away.

Regardless of the permission type, it must be declared in the manifest. If a permission that isn’t there is requested, the app will crash. Because of this, some developers declare permissions without ever requesting or using them - perhaps for planned features or as a precaution.

The app’s permissions

This is a non-exhaustive list, here’s all of them from the manifest itself. There are a lot of duplicates, but in total <uses-permission> is used 47 times.

Most of them are runtime permissions. But how many of them does the app actually request and use?

Analyzing the decompiled code

The app has no obfuscation whatsoever. JADX can decompile the entire app flawlessly - no “code decompiled incorrectly” errors that usually plague its output. Using JADX’s search, I looked for any code containing the word “permission” and found a class conveniently named “Permission”

As I wasn’t familiar with how apps request permissions (there are various ways), I thought checking the usage of CAMERA would be a good way to find out where they are requested. Indeed, it leads me to this bit of code:

The rest of the code isn’t too important, it basically checks if the app has the needed permissions and requests them if it doesn’t. But now that we know how the app makes the request, we can search for places where the function is called, and subsequently what runtime permissions the app uses.

Out of all the declared permissions, the only ones the app requests are:

CALL_PHONE???

Why does this app need to make calls? I investigated further.

The method this call is made from is an on click event handler:

If the app can make calls, it runs the following code:

So it seems to read the text of an UI element and use it as a phone number. I located three_img2_value inside res/layout/java_login.xml

Googling the phone number, it seems to be a Chinese hotline for Xinfrared customer support.

How can the user reach this login screen? com.infiRay.Xtherm.ui.Personal_Center is referenced in com.infiRay.Xtherm.ui.Set (conflicts with the built-in type and confuses JADX, lol) as a login page. Set is then referenced in the main activity, in a bit of code that runs when the settings button is pressed. So, judging purely by static analysis, you can call Xinfrared by going into the app’s settings and finding a login button somewhere.

Is that it?

Not quite. I found some other worrying stuff.

Conclusions

The fact the app declares so many permissions but uses very few of them and the numerous duplicate <uses-permission> tags in the manifest brings me to three theories:

  1. A case of a clueless developer pasting random shit from Github, ChatGPT or Stack Overflow in a lazy attempt at getting the app to run.
  2. A developer wanting to get past the Play Store’s verifications for sensitive permissions early so they can do bad stuff later. I don’t think this applies here, since the app can be downloaded directly from their website.
  3. A side effect of how the Android build system merges library manifests into the main app manifest. Can be ruled out as <uses-permission> is merged during app build, which should hide duplicate permissions from libraries. The duplicates must’ve been added manually.

I think this is a good example of how not to work with Android permissions. If the Play Store listing was still up, all those permissions would likely be visible under the app’s details. It’s not a good look for your product when your basic camera app wants to change system settings.

As for whether or not the app is safe to insall, I’d say right now there’s no cause for concern for the average user, but caution is still necessary. Again, an app update can change how the permissions are used. No one knows when, or if, Xinfrared might upload a trojan intentionally or by accident.