Действительно, Google не позволяет вам напрямую обращаться к этой скрытой папке данных приложения.
Но если вы можете получить идентификатор клиента / секрет клиента / цифровую подпись приложения, которые используются для аутентификации на серверах Google, тогда да, вы можете в основном эмулировать приложение и получать доступ к скрытым данным на вашем Google Диске с помощью Drive API .
Как это работает в Android
Обычно, когда приложению Android требуется доступ к Google API (например, к Диску, Игры или вход через Google — поддерживаются не все) он взаимодействует с клиентской библиотекой сервисов Google Play., который, в свою очередь, получает токен доступа от Google от имени приложения. Затем этот токен доступа отправляется с каждым запросом к API, чтобы Google знал, кто его использует и что ему разрешено делать с вашей учетной записью (OAuth 2.0). Чтобы получить этот токен доступа в первый раз, сервис Google Play отправляет запрос HTTPS POST на адрес android.clients.google.com/auth
со следующими полями (вместе с другими данными):
Token
— «мастер-токен», который идентифицирует учетную запись Google и, по сути, обеспечивает полный доступ к ней.
app
— имя пакета приложения, например com.whatsapp
client_sig
– цифровая подпись приложения (отправляется как SHA1).
device
– идентификатор Android устройства.
service
– области (разрешения), которые требуется приложению.
Поэтому, прежде чем мы сможем начать использовать Drive API от имени конкретного приложения, нам нужно знать его подпись и основной токен нашей учетной записи. К счастью, подпись можно легко извлечь из файла .apk
:
shell> unzip whatsapp.apk META-INF/*
Archive: whatsapp.apk
inflating: META-INF/MANIFEST.MF
inflating: META-INF/WHATSAPP.SF
inflating: META-INF/WHATSAPP.DSA
shell> cd META-INF
shell> keytool -printcert -file WHATSAPP.DSA # can be CERT.RSA or similar
.....
Certificate fingerprints:
SHA1: 38:A0:F7:D5:05:FE:18:FE:C6:4F:BF:34:3E:CA:AA:F3:10:DB:D7:99
Signature algorithm name: SHA1withDSA
Version: 3
Следующее, что нам нужно, это мастер-токен. Этот специальный токен обычно получают и сохраняют на устройстве при добавлении новой учетной записи Google (например, при первой настройке телефона), делая аналогичный запрос на тот же URL-адрес. Разница в том, что теперь приложение, которое запрашивает разрешения, является самим приложением сервисов Play (com.google.android.gms
), а Google также предоставляет дополнительные параметры Email
и Passwd
для входа в систему. Если запрос будет успешным, мы вернем наш основной токен, который затем можно будет добавить в запрос пользовательского приложения.
Вы можете прочитать эту запись в блоге, чтобы узнать больше подробная информация о процессе аутентификации.
Собираем все вместе
Теперь мы можем написать код для аутентификации, используя эти два HTTP-запроса напрямую — код, который может просматривать файлы любого приложения с любой учетной записью Google. Просто выберите свой любимый язык программирования и клиентскую библиотеку. Мне было проще использовать PHP:
require __DIR__ . '/vendor/autoload.php'; // Google Drive API
// HTTPS Authentication
$masterToken = getMasterTokenForAccount("[email protected]", "your_password");
$appSignature = '38a0f7d505fe18fec64fbf343ecaaaf310dbd799';
$appID = 'com.whatsapp';
$accessToken = getGoogleDriveAccessToken($masterToken, $appID, $appSignature);
if ($accessToken === false) return;
// Initializing the Google Drive Client
$client = new Google_Client();
$client->setAccessToken($accessToken);
$client->addScope(Google_Service_Drive::DRIVE_APPDATA);
$client->addScope(Google_Service_Drive::DRIVE_FILE);
$client->setClientId(""); // client id and client secret can be left blank
$client->setClientSecret(""); // because we're faking an android client
$service = new Google_Service_Drive($client);
// Print the names and IDs for up to 10 files.
$optParams = array(
'spaces' => 'appDataFolder',
'fields' => 'nextPageToken, files(id, name)',
'pageSize' => 10
);
$results = $service->files->listFiles($optParams);
if (count($results->getFiles()) == 0)
{
print "No files found.\n";
}
else
{
print "Files:\n";
foreach ($results->getFiles() as $file)
{
print $file->getName() . " (" . $file->getId() . ")\n";
}
}
/*
$fileId = '1kTFG5TmgIGTPJuVynWfhkXxLPgz32QnPJCe5jxL8dTn0';
$content = $service->files->get($fileId, array('alt' => 'media' ));
echo var_dump($content);
*/
function getGoogleDriveAccessToken($masterToken, $appIdentifier, $appSignature)
{
if ($masterToken === false) return false;
$url = 'https://android.clients.google.com/auth';
$deviceID = '0000000000000000';
$requestedService = 'oauth2:https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.file';
$data = array('Token' => $masterToken, 'app' => $appIdentifier, 'client_sig' => $appSignature, 'device' => $deviceID, 'google_play_services_version' => '8703000', 'service' => $requestedService, 'has_permission' => '1');
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close",
'method' => 'POST',
'content' => http_build_query($data),
'ignore_errors' => TRUE,
'protocol_version'=>'1.1',
//'proxy' => 'tcp://127.0.0.1:8080', // optional proxy for debugging
//'request_fulluri' => true
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (strpos($http_response_header[0], '200 OK') === false)
{
/* Handle error */
print 'An error occured while requesting an access token: ' . $result . "\r\n";
return false;
}
$startsAt = strpos($result, "Auth=") + strlen("Auth=");
$endsAt = strpos($result, "\n", $startsAt);
$accessToken = substr($result, $startsAt, $endsAt - $startsAt);
return "{\"access_token\":\"" . $accessToken . "\", \"refresh_token\":\"TOKEN\", \"token_type\":\"Bearer\", \"expires_in\":360000, \"id_token\":\"TOKEN\", \"created\":" . time() . "}";
}
function getMasterTokenForAccount($email, $password)
{
$url = 'https://android.clients.google.com/auth';
$deviceID = '0000000000000000';
$data = array('Email' => $email, 'Passwd' => $password, 'app' => 'com.google.android.gms', 'client_sig' => '38918a453d07199354f8b19af05ec6562ced5788', 'parentAndroidId' => $deviceID);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close",
'method' => 'POST',
'content' => http_build_query($data),
'ignore_errors' => TRUE,
'protocol_version'=>'1.1',
//'proxy' => 'tcp://127.0.0.1:8080', // optional proxy for debugging
//'request_fulluri' => true
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (strpos($http_response_header[0], '200 OK') === false)
{
/* Handle error */
print 'An error occured while trying to log in: ' . $result . "\r\n";
return false;
}
$startsAt = strpos($result, "Token=") + strlen("Token=");
$endsAt = strpos($result, "\n", $startsAt);
$token = substr($result, $startsAt, $endsAt - $startsAt);
return $token;
}
И, наконец, результаты -
Files:
gdrive_file_map (1d9QxgC3p4PTXRm_fkAY0OOuTGAckykmDfFls5bAyE1rp)
Databases/msgstore.db.crypt9 (1kTFG5TmgIGTPJuVynWfhkXxLPgz32QnPJCe5jxL8dTn0)
16467702039-invisible (1yHFaxfmuB5xRQHLyRfKlUCVZDkgT1zkcbNWoOuyv1WAR)
Done.
ПРИМЕЧАНИЕ. Это неофициальное, хакерское решение, поэтому оно может иметь несколько проблем. Например, токен доступа активен только в течение одного часа, после чего он не будет обновляться автоматически.
person
Tomer
schedule
07.04.2016