Cordova allows you to develop cross-platform mobile apps using web technologies. Traditional way of decompiling Android apps using tools like jadx wouldn’t give you much useful information when dealing with Cordova apps, since most of the logic and interface is implemented in HTML and Javascript.
In theory web apps should be much easier to reverse engineer because there’s technically no “compiling" process, more information is preserved from the original source code. Unless the developer uses an obfuscater, the original program symbols (function names, variable names, etc) are preserved in the final app package. And, because they’re just web technologies, we should be able to just debug them using modern browsers’ amazing debugging tools.
In practice, we need a way to extract the web app part out before we can do anything with it. This doesn’t seem to be a common operation so google doesn’t give you a straight answer, but now I’ve figured it out and find it quite easy.
Note that I have no experience in Android app development, nor Cordova, so there might be more straightforward ways to do things that I don’t know. But so far these methods have served my needs well.
Extracting
Using apktool
or jadx
we can easily extract the web part of the source code. Cordova apps usually place them under resources/assets/www
.
For the app I’m working on, simply opening index.html
in a normal browser will lead to it running infinite loop in Javascript.
Running in Browser
To make the app run under normal browser, I took idea from Cordova’s app development tutorial.
First create an empty app project:
cordova create hello com.example.hello HelloWorld
cd hello
Add browser and Android platform. Some plugins will fail to install if android platform wasn’t added:
cordova platform add browser
cordova platform add android
Copy the extracted source files from the app over:
cp -r ~/apk/targetapp/resources/assets/www .
Run in browser:
cordova run browser
This should allow the app to at least start initializing, though if the app uses any Cordova plugins that we haven’t installed yet there will be an error and the initialization would fail. Next step would be to install missing plugins.
Add Missing Plugins
In this step, we need to look at the error messages from the browser console to see what plugins are missing. Below is my example, but each app will use different plugins so the process will vary.
Error: Uncaught ReferenceError: device is not defined
Quick Googling gave me this answer:
cordova plugin add cordova-plugin-device
Add Missing Plugins – a better way
I noticed www/plugins/
contains all plugin files, and the directory names are conveniently the name of the plugin. So I can just use xargs to install all of them:
ls www/plugins/ | xargs cordova plugin add
This way all plugins included in the app are installed.
Remote Debugging with Chrome
If you connect the phone running the app to you computer and enable Android’s USB debugging, you can use Chrome’s built-in inspector at chrome://inspect to remote debug the app. This only works for apps that declares themselves to be “debuggable" in AndroidManifest.xml. However, if the app is not debuggable, you can still use this Xposed module to make the WebView debuggable without needing to modify the app.
Errors
If an app fails to load in browser, check browser console for error messages. This section notes all error messages I’ve encountered and the solutions.
“Could not find cordova.js script tag. Plugin loading may fail."
I noticed in index.html
there was this line:
<script type="text/javascript" src="cordova.93551f4e1f7af4ca1581.js"></script>
And in www/
both cordova.xxx.js
and cordova.js
exist.
So I simply changed the src in index.html to cordova.js
and the app loaded successfully.
Analyzing API Usage
One important part of security auditing apps is to see what system APIs it accesses, under what condition, and what it does with the obtained data.
In Cordova, most system API access require plugins. The app logic in Javascript would call respective plugins’ Javascript API, and in turn call the Java part of the plugin, then from there call system Java APIs.
So to answer the above questions, here’s the high level process that I usually take:
- Use
jadx
to look for Java code that calls interesting system APIs - Note down the Java package name containing the code block of interest, for example: org.apache.cordova.file.FileUtils or com.rohithvaranasi.callnumber.CFCallNumber
- Google for these plugins’ documentation on their Javascript API. Using the above plugins as examples, I found:
- cordova-plugin-file : https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/
- CordovaCallNumberPlugin: https://github.com/rohfosho/CordovaCallNumberPlugin
- Read their documentation and look for the global object name encapsulating the plugin’s functions, or the function names of interest. For example, CordovaCallNumberPlugin offers only one function here:
window.plugins.CallNumber.callNumber
- Go back to the app’s Javascript source code, grep for use of
CallNumber.callNumber
TODO: Tweak CORS
If the app wants to send any HTTP request to external servers (other than localhost, most likely due to the app calling API servers), in the browser it will fail from CORS requirements.
I didn’t investigate to fix this because I didn’t need to inspect the server response. But this should be fixable by tweaking the CORS header sent by cordova run browser
.