[Introduction]
As everybody know, the Amazon AppStore for Android in Europe doesn't have a section in its website were users can see the Apps and the Free App of the Day, the only way to do so is to open the "Appstore" on the device itself.
There was no known methods or workarounds to allow us to get the app name, well, until now...
Today I went ahead with some tools and intercepted the traffic that the Amazon Appstore does to its servers and ended up finding the requests/responses, and I made a simple PHP page on my PC to grab the output from amazon and show it locally.
Update
This also works with US Amazon Store, no more need to read values with regexp from the website
Japan Appstore is supported too, China should work (right parameters but is not responding correctly).
[How I did it]
Amazon Appstore on Android uses uses SSL for its calls, and I needed a tool to allow me decrypt SSL traffic. Luckily I have already used such a tool at my job (No, I don't work at three letter agencies), it is a Proxy server that can decrypt then re-encrypt SSL traffic with a custom CA certificate, which is Charles Proxy, you can download a 30 days trial (that work for 30 minutes each time). I installed it on my PC and started it, by default it listens on port 8888.
To intercept the http traffic of the Appstore, I set up my device to use a proxy server (Under the WiFi connection advanced settings, select "Proxy settings" to Manual, and enter the IP and port of the proxy).
Charles Proxy can show SSL traffic simply by decoding the SSL traffic on its part (as if it was the client requesting the data), then re-encrypt it with its own certificate and pass it to the real client as if it was the server.
BUT, to allow this to work, without Android going and refusing connections to the strange CA authority, you need to install CharlesProxy CA on the Android device to let the device recognize it as a good certificate: grab the CA cert file from CharlesProxy website and install it in your device.
Now when you open the Amazon AppStore app om the device, Charles Proxy will show all the calls to/from Amazon, all in the clear.
Appstore does few calls: getCategories, getDynamicWidgets, getFeaturedApplication, getRankedAsins, getRecommendations, search
The most important part for the Free App of the Day is the call to https://mas-ext-eu.amazon.com/getFeaturedApplication
In the Request, there is a json string of the device properties, and the Response is a json object with the App of the Day, and the 8 (or so) features apps of the day/week.
Charles Proxy shows also the complete header used for the request and response, so I used php cURL to replicate the exact header. If you follow the howto guide, you will see that in the request there are some other headers (X-ADP-Request-Digest, Session-ID, X-ADP-Authentication-Token), they seem to be device/account dependent (all Base64 encodes with some encryption), but the server responds correctly even without those extra headers, making the call anonymous (like this they don't have the account information to block it).
This can be made into a library to do calls the Amazon AppStore (how legal is it? need to check Amazon Usage policy), but I have so many projects at the moment, so I will leave it to you ;)
[Sample Code]
Here is a sample PHP function that I made to extract the "App of the Day". As you see, you can set the country to use by changing the $storeCounty parameter, I have the pfm code for 5 countries now: France, Italy, Germany, Spain, UK. I am not sure if this is enough to change the outcome of the server, I can test only for italy. but putting other countries it seems to respond with descriptions in the selected country, and selecting UK will show the price in GBP instead of EUR.
Sample response for calling this function:
Enjoy the hacking !!!!
As everybody know, the Amazon AppStore for Android in Europe doesn't have a section in its website were users can see the Apps and the Free App of the Day, the only way to do so is to open the "Appstore" on the device itself.
There was no known methods or workarounds to allow us to get the app name, well, until now...
Today I went ahead with some tools and intercepted the traffic that the Amazon Appstore does to its servers and ended up finding the requests/responses, and I made a simple PHP page on my PC to grab the output from amazon and show it locally.
Update
This also works with US Amazon Store, no more need to read values with regexp from the website
Japan Appstore is supported too, China should work (right parameters but is not responding correctly).
[How I did it]
Amazon Appstore on Android uses uses SSL for its calls, and I needed a tool to allow me decrypt SSL traffic. Luckily I have already used such a tool at my job (No, I don't work at three letter agencies), it is a Proxy server that can decrypt then re-encrypt SSL traffic with a custom CA certificate, which is Charles Proxy, you can download a 30 days trial (that work for 30 minutes each time). I installed it on my PC and started it, by default it listens on port 8888.
To intercept the http traffic of the Appstore, I set up my device to use a proxy server (Under the WiFi connection advanced settings, select "Proxy settings" to Manual, and enter the IP and port of the proxy).
Charles Proxy can show SSL traffic simply by decoding the SSL traffic on its part (as if it was the client requesting the data), then re-encrypt it with its own certificate and pass it to the real client as if it was the server.
BUT, to allow this to work, without Android going and refusing connections to the strange CA authority, you need to install CharlesProxy CA on the Android device to let the device recognize it as a good certificate: grab the CA cert file from CharlesProxy website and install it in your device.
Now when you open the Amazon AppStore app om the device, Charles Proxy will show all the calls to/from Amazon, all in the clear.
Appstore does few calls: getCategories, getDynamicWidgets, getFeaturedApplication, getRankedAsins, getRecommendations, search
The most important part for the Free App of the Day is the call to https://mas-ext-eu.amazon.com/getFeaturedApplication
In the Request, there is a json string of the device properties, and the Response is a json object with the App of the Day, and the 8 (or so) features apps of the day/week.
Charles Proxy shows also the complete header used for the request and response, so I used php cURL to replicate the exact header. If you follow the howto guide, you will see that in the request there are some other headers (X-ADP-Request-Digest, Session-ID, X-ADP-Authentication-Token), they seem to be device/account dependent (all Base64 encodes with some encryption), but the server responds correctly even without those extra headers, making the call anonymous (like this they don't have the account information to block it).
This can be made into a library to do calls the Amazon AppStore (how legal is it? need to check Amazon Usage policy), but I have so many projects at the moment, so I will leave it to you ;)
[Sample Code]
Here is a sample PHP function that I made to extract the "App of the Day". As you see, you can set the country to use by changing the $storeCounty parameter, I have the pfm code for 5 countries now: France, Italy, Germany, Spain, UK. I am not sure if this is enough to change the outcome of the server, I can test only for italy. but putting other countries it seems to respond with descriptions in the selected country, and selecting UK will show the price in GBP instead of EUR.
PHP Code:
function getFeaturedApp($storeCounty = 'IT') {
$path = "/getFeaturedApplication";
$timeout = 10;
$devInfo['deviceInfo'] = array('deviceDensityClassification'=>'320',
'ref'=>'unknown',
'model'=>'GT-I9300',
'osVersion'=>'16',
'deviceType'=>'A3GFS040JDOGQR',
'manufacturer'=>'samsung',
'carrier'=>'Vodafone'
);
$data = json_encode($devInfo);
$amazonStore['IT'] = array('host'=>'https://mas-ext-eu.amazon.com','pfm'=>'APJ6JRA9NG5V4', 'cor'=>'IT');
$amazonStore['FR'] = array('host'=>'https://mas-ext-eu.amazon.com','pfm'=>'A13V1IB3VIYZZH', 'cor'=>'FR');
$amazonStore['DE'] = array('host'=>'https://mas-ext-eu.amazon.com','pfm'=>'A1PA6795UKMFR9', 'cor'=>'DE');
$amazonStore['ES'] = array('host'=>'https://mas-ext-eu.amazon.com','pfm'=>'A1RKKUPIHCS9HS', 'cor'=>'ES');
$amazonStore['UK'] = array('host'=>'https://mas-ext-eu.amazon.com','pfm'=>'A1F83G8C2ARO7P', 'cor'=>'UK');
$amazonStore['JP'] = array('host'=>'https://mas-ext-fe.amazon.com','pfm'=>'A1VC38T7YXB528', 'cor'=>'JP');
$amazonStore['CN'] = array('host'=>'https://mas-ext-fe.amazon.com','pfm'=>'AAHKV2X7AFYLW', 'cor'=>'CN');
$amazonStore['US'] = array('host'=>'https://mas-ext.amazon.com','pfm'=>'ATVPDKIKX0DER', 'cor'=>'US');
$host = $amazonStore[$storeCounty]['host'];
$requestData = array(
"Accept-Language: en-US",
"x-venezia-pfm: " . $amazonStore[$storeCounty]['pfm'],
"User-Agent: VeneziaAndroid/release-4.5",
"x-venezia-cor: " . $amazonStore[$storeCounty]['cor'],
"Content-Length: " . strlen($data),
"Content-Type: text/plain; charset=UTF-8",
"Host: mas-ext-eu.amazon.com",
"Connection: Keep-Alive",
"Accept-Encoding: gzip");
$tuCurl = curl_init();
curl_setopt($tuCurl, CURLOPT_URL, $host . $path);
curl_setopt($tuCurl, CURLOPT_PORT , 443);
curl_setopt($tuCurl, CURLOPT_HEADER, 0);
curl_setopt($tuCurl, CURLOPT_POST, 1);
curl_setopt($tuCurl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($tuCurl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($tuCurl, CURLOPT_POSTFIELDS, $data);
curl_setopt($tuCurl, CURLOPT_HTTPHEADER, $requestData);
curl_setopt($tuCurl, CURLOPT_ENCODING , "gzip");
$tuData = curl_exec($tuCurl);
if(!curl_errno($tuCurl)){
$info = curl_getinfo($tuCurl);
} else {
die ('Curl error: ' . curl_error($tuCurl));
}
curl_close($tuCurl);
return $tuData;
}
// set response header to display text in Plain mode
$retJsonData = getFeaturedApp('IT');
$jsonObject = json_decode($retJsonData);
$freeApp = $jsonObject->asinDetails;
echo $freeApp->title;
echo $freeApp->developer;
echo $freeApp->developerVersion;
Code:
stdClass Object
(
[application] => stdClass Object
(
[asin] => B00634GHJA
[isCompatible] => 1
)
[asinDetails] => stdClass Object
(
[asin] => B00634GHJA
[averageRating] => 0
[contentType] =>
[deliveryType] =>
[developer] => ERCLab
[developerId] =>
[developerPronunciation] =>
[developerVersion] => 2.5.1
[gameCircleIntegration] => Array
(
)
[isAvailable] => 1
[isCompatible] => 1
[isTestDriveEnabled] => [listPrice] => 1.58[listPriceCurrencyCode] => EUR
[logo] => http://ecx.images-amazon.com/images/I/81kftwGhUiL.png
[mainProductImageUrl] => http://ecx.images-amazon.com/images/I/81kftwGhUiL.png
[ourPrice] => 0.00
[ourPriceCurrencyCode] => EUR
[productVersion] => 4
[promoImage] => http://ecx.images-amazon.com/images/I/81ip82-8FOL.jpg
[purchaseVerifications] => Array
(
)
[releaseDate] => 12/03/2011
[releaseDateMs] => 1322910000092
[reviewCount] => 0
[title] => Photo Transfer App
[titlePronunciation] =>
[zeroesListPrice] =>
[zeroesOurPrice] =>
[zeroesRewardAmount] =>
)
[cursor] =>
[featureAsinsTitle] => Cibo e cucina
[featuredAsins] => Array
(
[0] => stdClass Object
(
[asin] => B008SD6KAU
[averageRating] => 4.25
[contentType] =>
[deliveryType] => default
[developer] => Banzai
[developerId] =>
[developerPronunciation] =>
[developerVersion] => 1.2.6
[gameCircleIntegration] => Array
(
)
[isAvailable] => 1
[isCompatible] => 1
[isTestDriveEnabled] => [listPrice] => 0.00[listPriceCurrencyCode] => EUR
[logo] => http://ecx.images-amazon.com/images/I/31bTM0D8hJL.png
[mainProductImageUrl] => http://ecx.images-amazon.com/images/I/31bTM0D8hJL.png
[ourPrice] => 0.00
[ourPriceCurrencyCode] => EUR
[productVersion] => 1
[promoImage] =>
[purchaseVerifications] => Array
(
)
[releaseDate] => 09/17/2012
[releaseDateMs] => 1347876000709
[reviewCount] => 8
[title] => GialloZafferano: le Ricette della Cucina Italiana
[titlePronunciation] =>
[zeroesListPrice] =>
[zeroesOurPrice] =>
[zeroesRewardAmount] =>
)
[1] => stdClass Object
(
[asin] => B0075CJ1NI
[averageRating] => 2.3333333333333
[contentType] =>
[deliveryType] => default
[developer] => Icona
[developerId] =>
[developerPronunciation] =>
[developerVersion] => 1.4.1
[gameCircleIntegration] => Array
(
)
[isAvailable] => 1
[isCompatible] => 1
[isTestDriveEnabled] => [listPrice] => 0.00[listPriceCurrencyCode] => EUR
[logo] => http://ecx.images-amazon.com/images/I/A15yPxy5GOL.png
[mainProductImageUrl] => http://ecx.images-amazon.com/images/I/A15yPxy5GOL.png
[ourPrice] => 0.00
[ourPriceCurrencyCode] => EUR
[productVersion] => 3
[promoImage] =>
[purchaseVerifications] => Array
(
)
[releaseDate] => 03/04/2012
[releaseDateMs] => 1330858800467
[reviewCount] => 6
[title] => Ricette al contrario
[titlePronunciation] =>
[zeroesListPrice] =>
[zeroesOurPrice] =>
[zeroesRewardAmount] =>
)
[2] => stdClass Object
(
[asin] => B004VOJT0I
[averageRating] => 0
[contentType] =>
[deliveryType] => default
[developer] => Allrecipes.com
[developerId] =>
[developerPronunciation] =>
[developerVersion] => 2.1.2
[gameCircleIntegration] => Array
(
)
[isAvailable] => 1
[isCompatible] => 1
[isTestDriveEnabled] => [listPrice] => 0.00[listPriceCurrencyCode] => EUR
[logo] => http://ecx.images-amazon.com/images/I/71x6qwAy0EL.png
[mainProductImageUrl] => http://ecx.images-amazon.com/images/I/71x6qwAy0EL.png
[ourPrice] => 0.00
[ourPriceCurrencyCode] => EUR
[productVersion] => 5
[promoImage] => http://ecx.images-amazon.com/images/I/81-4ifkmwzL.png
[purchaseVerifications] => Array
(
)
[releaseDate] => 05/08/2011
[releaseDateMs] => 1304848800296
[reviewCount] => 0
[title] => Allrecipes.com Dinner Spinner for Android
[titlePronunciation] =>
[zeroesListPrice] =>
[zeroesOurPrice] =>
[zeroesRewardAmount] =>
)
[3] => stdClass Object
(
[asin] => B00AAGSMMC
[averageRating] => 0
[contentType] =>
[deliveryType] => default
[developer] => aufeminin.com
[developerId] =>
[developerPronunciation] =>
[developerVersion] => 1.5
[gameCircleIntegration] => Array
(
)
[isAvailable] => 1
[isCompatible] => 1
[isTestDriveEnabled] => [listPrice] => 0.00[listPriceCurrencyCode] => EUR
[logo] => http://ecx.images-amazon.com/images/I/81r7eU8T1DL.png
[mainProductImageUrl] => http://ecx.images-amazon.com/images/I/81r7eU8T1DL.png
[ourPrice] => 0.00
[ourPriceCurrencyCode] => EUR
[productVersion] => 0
[promoImage] => http://ecx.images-amazon.com/images/I/913v9f9VI9L.png
[purchaseVerifications] => Array
(
)
[releaseDate] => 01/08/2013
[releaseDateMs] => 1357642800671
[reviewCount] => 0
[title] => Cucina alfemminile
[titlePronunciation] =>
[zeroesListPrice] =>
[zeroesOurPrice] =>
[zeroesRewardAmount] =>
)
[4] => stdClass Object
(
[asin] => B009NE5BDA
[averageRating] => 0
[contentType] =>
[deliveryType] => default
[developer] => Gambero Rosso
[developerId] =>
[developerPronunciation] =>
[developerVersion] => 1.0
[gameCircleIntegration] => Array
(
)
[isAvailable] => 1
[isCompatible] => 1
[isTestDriveEnabled] => [listPrice] => 4.99[listPriceCurrencyCode] => EUR
[logo] => http://ecx.images-amazon.com/images/I/61jRrZ%2BrVEL.png
[mainProductImageUrl] => http://ecx.images-amazon.com/images/I/61jRrZ%2BrVEL.png
[ourPrice] => 4.99
[ourPriceCurrencyCode] => EUR
[productVersion] => 0
[promoImage] =>
[purchaseVerifications] => Array
(
)
[releaseDate] => 11/12/2012
[releaseDateMs] => 1352718000925
[reviewCount] => 0
[title] => Ristoranti d'Italia 2013 del Gambero Rosso
[titlePronunciation] =>
[zeroesListPrice] =>
[zeroesOurPrice] =>
[zeroesRewardAmount] =>
)
[5] => stdClass Object
(
[asin] => B00A27PIFS
[averageRating] => 4
[contentType] =>
[deliveryType] => default
[developer] => Soneso
[developerId] =>
[developerPronunciation] =>
[developerVersion] => 1.0
[gameCircleIntegration] => Array
(
)
[isAvailable] => 1
[isCompatible] => 1
[isTestDriveEnabled] => [listPrice] => 0.89[listPriceCurrencyCode] => EUR
[logo] => http://ecx.images-amazon.com/images/I/81tw38xmFxL.png
[mainProductImageUrl] => http://ecx.images-amazon.com/images/I/81tw38xmFxL.png
[ourPrice] => 0.89
[ourPriceCurrencyCode] => EUR
[productVersion] => 0
[promoImage] => http://ecx.images-amazon.com/images/I/81v5d6IGnKL.png
[purchaseVerifications] => Array
(
)
[releaseDate] => 12/08/2012
[releaseDateMs] => 1354964400186
[reviewCount] => 1
[title] => Chiedilo alla Nonna
[titlePronunciation] =>
[zeroesListPrice] =>
[zeroesOurPrice] =>
[zeroesRewardAmount] =>
)
[6] => stdClass Object
(
[asin] => B00846HN02
[averageRating] => 0
[contentType] =>
[deliveryType] => default
[developer] => Sluice LLC
[developerId] =>
[developerPronunciation] =>
[developerVersion] => 1.5
[gameCircleIntegration] => Array
(
)
[isAvailable] => 1
[isCompatible] => 1
[isTestDriveEnabled] => [listPrice] => 0.79[listPriceCurrencyCode] => EUR
[logo] => http://ecx.images-amazon.com/images/I/71HgPlx%2Bv5L.png
[mainProductImageUrl] => http://ecx.images-amazon.com/images/I/71HgPlx%2Bv5L.png
[ourPrice] => 0.79
[ourPriceCurrencyCode] => EUR
[productVersion] => 1
[promoImage] =>
[purchaseVerifications] => Array
(
)
[releaseDate] => 06/17/2012
[releaseDateMs] => 1339927200939
[reviewCount] => 0
[title] => Grill-It!
[titlePronunciation] =>
[zeroesListPrice] =>
[zeroesOurPrice] =>
[zeroesRewardAmount] =>
)
[7] => stdClass Object
(
[asin] => B009NE5BDA
[averageRating] => 0
[contentType] =>
[deliveryType] => default
[developer] => Gambero Rosso
[developerId] =>
[developerPronunciation] =>
[developerVersion] => 1.0
[gameCircleIntegration] => Array
(
)
[isAvailable] => 1
[isCompatible] => 1
[isTestDriveEnabled] => [listPrice] => 4.99[listPriceCurrencyCode] => EUR
[logo] => http://ecx.images-amazon.com/images/I/61jRrZ%2BrVEL.png
[mainProductImageUrl] => http://ecx.images-amazon.com/images/I/61jRrZ%2BrVEL.png
[ourPrice] => 4.99
[ourPriceCurrencyCode] => EUR
[productVersion] => 0
[promoImage] =>
[purchaseVerifications] => Array
(
)
[releaseDate] => 11/12/2012
[releaseDateMs] => 1352718000925
[reviewCount] => 0
[title] => Ristoranti d'Italia 2013 del Gambero Rosso
[titlePronunciation] =>
[zeroesListPrice] =>
[zeroesOurPrice] =>
[zeroesRewardAmount] =>
)
)
)