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.
jadx we can easily extract the web part of the source code. Cordova apps usually place them under
For the app I’m working on, simply opening
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
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:
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.
Uncaught ReferenceError: device is not defined
Quick Googling gave me this answer:
cordova plugin add cordova-plugin-device
Add Missing Plugins – a better way
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.
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:
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.
So to answer the above questions, here’s the high level process that I usually take:
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
- 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:
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 .