[Android Software/Hacking General [Developers Only]] shen747:
Hi Experts / Expert Hackers,

I'm trying to implement the Google Play application silent install feature (similar to appbrain fast web installer) on android.

So far I was able achieve the following :

1. Find out a method to retrieve the Google Play Auth Token (thus granting permission for my application to talk with Google Play application on the Phone). I've listed the code I've used for this below :

Log.i(TAG,"Getting the Google Play Auth Token Using Account Manager : START");
AccountManager accountManager = AccountManager.get(getApplicationContext());
Account[] accArr = accountManager.getAccountsByType("com.google");

for (Account acc : accArr) {
Log.i(TAG, "For Account Name : " + acc.name + " - "+ "Account Type : " + acc.type);
accountManager.getAuthToken(acc, "googleplay", null, this,new AccountManagerCallback<Bundle>() {

public void run(
AccountManagerFuture<Bundle> paramAccountManagerFuture) {
try {
Bundle localBundle = (Bundle) paramAccountManagerFuture.getResult();
String authToken = localBundle.get("authtoken") + "";

Log.i(TAG, "Got AuthToken : " + authToken);

} catch (Exception ex) {
StackTraceElement[] starray = ex.getStackTrace();
StringBuffer bf = new StringBuffer();
bf.append("Error : " + ex.getMessage()).append("\n");
for (StackTraceElement ste : starray) {
bf.append(ste.toString()).append("\n");
}
Log.e(TAG, bf.toString());
}

}

}, null);
}
Log.i(TAG,"Getting the Google Play Auth Token Using Account Manager : END");

2. Find out how to Retrieve the Android-Id of the Phone (This Id as I believe should be used when sending the appInstall request to the GPlay Servers or the Gplay/vending application on the android phone)

Log.i(TAG, "Getting the Android ID Of the Phone : START");

Uri localUri = Uri.parse("content://com.google.android.gsf.gservices");
ContentResolver localContentResolver = getContentResolver();
String[] arrayOfString = new String[1];
arrayOfString[0] = "android_id";
Cursor localCursor = localContentResolver.query(localUri, null,null, arrayOfString, null);
Log.i(TAG, "Column Count : " + localCursor.getColumnCount());
if ((localCursor != null) && (localCursor.moveToFirst())) {
String androidId = Long.toHexString(Long.parseLong(localCursor.getString(1)));
Log.i(TAG, "Received Android ID : " + androidId);

Log.i(TAG,"Other Value in Column : " + localCursor.getString(0));
}

Log.i(TAG,"Getting the Android ID of the Phone : END");

3. Find out the Protocol Buffer Request to be sent to the Google Play servers or the Gplay/vending application on the phone to Initiate the silent application download & install process.

message InstallRequest {
optional string appId = 1;
}
message RequestContext {
required string authSubToken = 1;
required bool isSecure = 2;
required int32 version = 3;
required string androidId = 4;
optional string deviceAndSdkVersion = 5;
optional string userLanguage = 6;
optional string userCountry = 7;
optional string operatorAlpha = 8;
optional string simOperatorAlpha = 9;
optional string operatorNumeric = 10;
optional string simOperatorNumeric = 11;

}
message Request {
optional RequestContext context = 1;
repeated group RequestGroup = 2 {
optional InstallRequest installRequest = 10;
}
}

4.I even used the protobuf compiler and generated the java class for manipulating the above protocol buffer request and filled the above protocol buffer fields with some sample data. See the code below :

public void buildAndSendSilentInstallProtoBuffMessage(String gplayAuthToken, String deviceAndroidId){

try{
/*
* The Root Request Object Assumed to be Holding the Silent Install Request
*/
Request.Builder request = Request.newBuilder();

//Populating the ReequestContext Object
RequestContext.Builder context = RequestContext.newBuilder();

context.setAndroidId(deviceAndroidId);
context.setAuthSubToken(gplayAuthToken);

context.setIsSecure(true);
context.setVersion(1002);
context.setDeviceAndSdkVersion("dream:4");
context.setUserLanguage("en");
context.setUserCountry("us");
context.setOperatorAlpha("Android");
context.setOperatorNumeric("310260");
context.setSimOperatorNumeric("310260");

//Building the Install Request
InstallRequest.Builder installRequest = InstallRequest.newBuilder();
installRequest.setAppId("-2564446724934482383");

//Setting the Install Request to the Request Group
RequestGroup.Builder requestGroup = RequestGroup.newBuilder();
requestGroup.setInstallRequest(installRequest);

//Setting the Request Context to the Main Request Object
request.setContext(context);

//Setting the Request Group to the Request Object
request.addRequestGroup(requestGroup);

The Sample Data for GPlay Token and the Android Id are as follows :

1. Android_ID :

3a0f901831a0f402

2. Google Play AuthToken :

DQAAAMgAAACpOyPf6apRbb0i4qhTVaf0yYoikTAb4TYlHCRLrW4mu5f14j-H35KGmO9TQKUDYCfj3-b-QIH5chfXT3bS02Uxljg7vYt4I-kgXLEJwPcynjugDcJ9fYPOh1c2FnOnywFXXxXw6hcqs5sVnJEt5zW2ditoB5VeeXG9Zfodj9dXKobObi50-XnHoGfWi2b64Uf3EHGdQTsDCMzfZrE4mb22fr9LCW1oZG5tkzwS4KhPBHWMN2fO7w-1IZ4UK5LOI80vPBLjxBaavKAXHoVUHSNV

5. I also did some sniffing using my rooted galaxy nexus phone during Gplay application silent install and found only two HTTP GET Requests.

I tried reproducing the those two Http GET requests captured using Shark for root(using my rooted android galaxy nexus phone) and the 1st Request just downloads the Market File itself (which I was able to save to the SD card of the Phone. But then it has to be installed like any unknown sources application) while the second request returns nothing.

The two get requests captured are shown below :

1. GET REQUEST ONE :

21 0.827240 192.168.135.102 173.194.36.4 HTTP 535 GET /market/download/Download?packageName=com.gau.go.launcherex.theme.appwidget.gopowermaster.futureworld&versionCode=1&token=AOTCm0QRnH3rmypWtCGoAL_SU1BSt311wpyz-_LZTodkUSAlc-f5SrdMiz5WDRDUKMMm6S3plBI9Jbh1tukT1jyCYXLgP4QhVvZvn5JLtZQ&downloadId=-165214892049282883 HTTP/1.1

Which has the following http headers :

Cookie: MarketDA=17214805622679635526\r\n
Host: android.clients.google.com\r\n
Connection: Keep-Alive\r\n
User-Agent: AndroidDownloadManager/4.1.1 (Linux; U; Android 4.1.1; Galaxy Nexus Build/JRO03C)\r\n

2. GET REQUEST TWO :

44 6.595093 192.168.135.102 222.165.163.15 HTTP 608 GET /market/GetBinary/com.gau.go.launcherex.theme.appwidget.gopowermaster.futureworld/1?expire=1346838270&ipbits=0&ip=0.0.0.0&cp=SnpybWlzSFk6OTYzMzg0MTE2NzA1ODEwOTYxMjE&sparams=expire,ipbits,ip,q:,cp&signature=2C0778C4635F6F8AE1DA8479FB08DCB9BC04C2E9.60202D8D4D2FDDA70609A3862A25852F0BAA2766&key=am2 HTTP/1.1

Which has the following http headers :

Cookie: MarketDA=17214805622679635526\r\n
Host: o-o.preferred.slt-cmb2.v12.lscache4.c.android.clients.google.com\r\n
Connection: Keep-Alive\r\n
User-Agent: AndroidDownloadManager/4.1.1 (Linux; U; Android 4.1.1; Galaxy Nexus Build/JRO03C)\r\n

I've been looking into this for about two weeks now but I still couldn't find the following :

1. Whether the AppBrain fast Web Installer uses the protocol buffer to invoke the Gplay (vending application) on the phone or the Gplay servers ?. If so is the above Protocol Buffer Request format correct ??.

2. If the Above Protocol Buffer Request format is correct then to Where in the Phone or Gplay server should I send the Protocol buffer request to to invoke the Silent Application download and installing procedure ?.

I also have a C2DM (now GCM) server and client setup around this task as well. Could anyone point me in the correct direction or give me any clues for solving this ?. Any help is much appreciated :).