Sometimes I need to get hold of an Android application from the Market for analysis. One way to do this is to manually use the Market on an Android device or emulator, install the App, and then copy it off. For various reasons this isn’t always ideal – I sometimes don’t want to install an App if I don’t know what it does, and I may want to get it a lot faster (i.e. automate it).
In this post I share what worked for me in creating a command line script to login to the Market and download the application’s APK. This isn’t anything particularly new as an unofficial Market API already exists for searching the Market and Tim Strazzere posted some Java source to emulate a download request. However, in Tim’s example you have to manually specify the App’s
assetID and your
authToken which means it isn’t automated. What I wanted was a script which takes a package name as a parameter and downloads it. To achieve this I used the Market API to login, get an
authToken, search for the package, get its
assetID, and then submit a download request.
I’ve documented this for interest, it isn’t supported software and there isn’t much error checking. If you use this it is assumed you know what you are doing.
What was used:
- Linux with PHP including curl support
- Rooted Android phone (I used a spare development phone)
- Temporary GMail account associated with phone
- PHP Android Market API by Splitfeed
- ADB from the Android SDK
I’m using Ubuntu Linux and PHP with curl support. To install it you need something like this:
sudo apt-get install php5-curl
The first step is to get the Android Market
userID which is required in the download request for APKs. I’m not aware of an easy way to get this at the moment but it is simple enough to sniff from the real Market App and only needs to be done once. Tim Strazzere comes to the rescue again with a nice tip for easily sniffing traffic on Android.
Open up the Market App on the device and find an app to install, start the following ADB command and then click install:
adb shell tcpdump -vv -s 0 -w /sdcard/output.cap
After install hit
Ctrl+C to to stop sniffing. Open up the
.cap file in something like wireshark and look for a GET request which contains the
userID parameters and make a note of them. I found that on my phone the GET request was different from the one in Tim’s post, it had extra parameters and when I manually emulated it I was given a 302 redirect to download the file. However, using the older GET request as per Tim’s post and ignoring the extra parameters seems to still work and leads to the direct download of the APK.
Download PHP Android Market API and unzip it somewhere. In the subfolder
examples create a file called
local.php with the following contents (replacing my values with yours):
<?php define('GOOGLE_EMAIL','firstname.lastname@example.org'); define('GOOGLE_PASSWD','yourpassword'); // Use a random number with the same number of digits: define('ANDROID_DEVICEID','0000000000000000'); // Use your real deviceID here that you sniffed: define('ANDROID_REALID','0000000000000000000'); // Use your sniffed userID parameter here: define('ANDROID_USERID','00000000000000000000');
I found that the Market API worked with a fake
deviceID but not my real one, and the APK download request worked with my real
deviceID but not the fake one. I didn’t look into it too much as it seems to work okay as above.
Download test_download.php.txt and save it in the
examples folder as
/Market so this line:
private $authSubToken = "";
public $authSubToken = "";
Okay that is the preparation. We can now use the script to grab any free app from the Market by passing the package name as a parameter. In this example I found a Notepad application on Android Market and saw the package name in the URL was
user@linux:~/market-api/examples$ php test_download.php bander.notepad * About to connect() to android.clients.google.com port 80 (#0) * Trying 22.214.171.124... * connected * Connected to android.clients.google.com (126.96.36.199) port 80 (#0) > POST /market/api/ApiRequest HTTP/1.1 User-Agent: Android-Market/2 (sapphire PLAT-RC33); gzip Host: android.clients.google.com Accept: */* Cookie: ANDROID=DQAAAREDACTED Content-Type: application/x-www-form-urlencoded Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Content-Length: 586 < HTTP/1.1 200 OK < Content-Type: application/binary < Date: Sun, 12 Jun 2011 23:34:37 GMT < Expires: Sun, 12 Jun 2011 23:34:37 GMT < Cache-Control: private, max-age=0 < X-Content-Type-Options: nosniff < X-Frame-Options: SAMEORIGIN < X-XSS-Protection: 1; mode=block < Content-Length: 140 < Server: GSE < * Connection #0 to host android.clients.google.com left intact * Closing connection #0 Downloading Notepad (3073103588488610805) user@linux:~/market-api/examples$ ls -hl *.apk -rw-r--r-- 1 user user 45K 2011-06-13 00:34 bander.notepad.apk
And now we have the APK. The Market API is actually really good and it can also get other data about the app such as author, version, what permissions it needs, screenshots, etc. It would be a fairly trivial enhancement to get the script to save this extra metadata at the same time as the APK if needed.