Unlocking a Public Parking Garage with Android Auto: Reverse Engineering Official App
The gate of the public parking garage that I am renting can be opened with an app. However, unlocking a phone, searching the app, choosing the particular parking and pressing “enter by car”. Isn’t that convenient while driving. Let’s see if we can upgrade this user experience.
A couple of weeks ago, I got inspired by greenluigi1’s article1 about getting root access to the infotainment system of Hyundai vehicles. This made me want to find a fun and useful project with some reverse engineering again. As I started renting a parking lot last week, I stumbled upon this opportunity to create something cool.
The parking app
The app that is being provided by the parking company works by simply logging in and pressing a button, which opens the gate for you. There is a validation built in that checks whether you are within a certain distance to the parking garage. I am not sure why they have built in this check, as they are also offering a fallback option by calling a phone number and typing in a code.
With my background as a software engineer, I expected it to be quite a basic app that does some authentication and makes an API-request. Luckily, it turned out to be exactly that. After decompiling the app using javadecompiles, I found a service interface which had all the possible API endpoints listed, including a GET method /api/v3/gate/{gate}/open
.
The next step is finding out where that web server is located. Running a search query with the domain name of the company brought me to a BuildConfig.java
that had a BASE_URL
like https://api-v3.parking-company.com/
. Bingo! Let’s see what we have over there.
That looks like a standard Laravel project, nothing too exciting here. Let’s try one of our previously found API-endpoints. As expected, they result in an error, which is obvious, as there had to be some authentication mechanism. One of the endpoints is oauth/token
, which indicates that oauth is being used. As this is a standard method, it is built in into Postman. The CLIENT_ID
and CLIENT_SECRET
were both also in the BuildConfig.java
which makes it super easy. Filling in my account details got me an access token immediately, which is also automatically applied to the API requests Postman makes. Let’s see if we can fetch some account information from the API!
That returns all my account data, including license plate and phone number. However, it does not tell my anything about my subscription or the gates that I am allowed to open. Let’s give /api/v3/user/{user}/access
a try. This lists my subscription nicely, including the gates that are available.
These are the numbers we need, so let’s see if we can open the gate programmatically. By looking at the service interface, we need to provide a couple of other details, such as: user id, purchase id, coordinates and way. The coordinates are needed to check if we are not too far away from the garage. So we will give the parking company a peace of mind and reassure that we are allowed to open the gate by passing the exact location that got from the garage details. I am not able to find what the way
parameter should be from the code. However, I guessed in
and that seems to be working.
Active, that seems like a success. I didn’t check if the gate actually opened, but I was pretty certain that it would work so I started immediately with the next step: more convenience.
Android auto
Every car with an In-Vehicle Infotainment (IVI) system that is being produced right now, even a Fiat 500, seems to support Android Auto. What I really like about Android Auto, is that it does not matter how crappy the infotainment system is, you will always get the same experience.
So, now we are able to make an API-request programmatically, it should be easy to create an Android Auto app that makes this request once you open it, right?
Full of enthusiasm, I cloned an Android Auto hello-world example. A nice feature of Postman is that you can copy the request into multiple programming languages, including Java OkHttp. That makes life even easier. The access token within the request is valid for 365 days, so I didn’t bother about implementing authentication logic.
Spend one or two hours fine-tuning the app, so that it closes the activity automatically after opening. Tested it in the emulator, where it was working!
The pitfall
On my next trip, I stepped into my car full of excitement and drove to the exit of the garage. However… the app was nowhere to be seen. Reboot, restart car. Other device. No app.
It turns out that Google is fighting the 3rd party app community, as they think it is insecure to have any type of app to run on your car’s head unit. As a developer, you cannot test an Android Auto app on a real car2. The only way to test it, according to Google, is to upload it to the play store in an Alpha channel. Using this method, Google wil test if your app does not distract during driving and fits the Android Auto ecosystem before releasing it.
I am not confident that Google will accept my app. Moreover, my account details are now hard-coded into the app, so I don’t want to upload it somewhere.
Fooling Google
When Google prevents you from doing something, the general answer is rooting. Rooting a device gives you back all the freedom to do whatever you want with your own hardware. As I rooted and flashed many devices in the past, I am certainly familiar with the pros and cons of doing so. Nowadays, I think the need for rooting is minimal, as the standard Android ecosystem has improved heavily over the last decade. Moreover, rooting my device (and also other devices that I want to run the app on) would require a lot of work, not be convenient and introduce security risks.
Luckily, the good old XDA developers forum is also active around creating modifications for the Android Auto ecosystem3. The information around there is a little bit fragmented. However, one app called Fermata Media Player4, which enables you to watch YouTube on an Android Auto headunit, had some interesting information. As this application is not available on the Play Store, they list a couple of methods to install this third-party software.
One of the methods to get third-party applications working without root is using an app called KingInstaller. This app simply lets you select and install an untrusted APK-file, which magically shows up on Android Auto. How does this particular app work if it does not need root? Let’s take a look at the source code.
In Android terms, an Intent is simply an action that is being performed. So as you can see, the android package installer is being called with the APK as data.
Moreover, it adds two extra parameters NOT_UNKNOWN_SOURCE
and INSTALLER_PACKAGE_NAME
. The first parameter specifies that the application should be treated as coming from the app invoking the intent 5, which is KingInstaller in this case. Secondly, the installer package name is set to com.android.vending
. This package is also known as the Google Play store.
It turns out that this is the general way to find out which app store installed the app, from within the app itself 6. This is being used by apps that are available in multiple app stores, to keep track on where they were downloaded from.
Apparently, Google is also using this method to check if an app comes from their app store, which should assure that they have verified and reviewed it. But what surprises me most, is that this mechanism can be fooled by just adding an extra parameter to the intent.
The Android Auto solution that I built by reverse engineering the official app.
Conclusion
I think it is fun to have the ability to find out the inner working of everyday products, especially if you can benefit from these findings. I had expected that most of the time would go into reverse engineering the parking company app, but due to the simplicity of the app and the use of standard authentication, this was fairly easy.
Most time went into setting up an Android Auto development environment and getting the hello-world app to compile after struggling with different Gradle and SDK versions. The restrictions with Android Auto required research, but the actual solution could not be easier.
All in all, I am happy that it is working now, and it actually makes my life easier.
-
https://programmingwithstyle.com/posts/howihackedmycarguidescreatingcustomfirmware/ ↩
-
https://stackoverflow.com/questions/29353302/can-android-auto-apps-be-tested-on-actual-devices ↩
-
https://forum.xda-developers.com/f/android-auto-general.3834/ ↩
-
https://forum.xda-developers.com/t/fermata-media-player-audio-and-video-player-for-android-auto.4079519/ ↩
-
https://www.demo2s.com/android/android-intent-extra-not-unknown-source.html ↩
-
https://www.yellowduck.be/posts/checking-if-android-app-installed-google-play ↩