Подтвердить что ты не робот

Как просмотреть скрытые данные приложения на Google Диске?

У меня есть приложение для Android, в котором хранятся мои заметки в скрытых данных приложения. Я хочу экспортировать свои заметки, поэтому вопрос прост:

Как я могу получить доступ к скрытым данным приложения на Google Диске для конкретного приложения?

4b9b3361

Ответ 1

Действительно, Google не позволяет напрямую обращаться к этой скрытой папке приложений.

Но если вы можете получить доступ к секретной/электронной подписи клиента/клиента клиента, которая используется для аутентификации на серверах Google, то да, вы можете в основном эмулировать приложение и получать доступ к скрытым данным на вашем Google Диске, используя API Drive.

Как это работает в Android

Обычно, когда приложение android хочет получить доступ к API Google (например, Drive, игры или вход в Google - не все они поддерживаются), он общается с клиентской библиотекой сервисов Google Play, которая, в свою очередь, получает токен доступа от Google от имени приложения. Этот токен доступа затем отправляется с каждым запросом API, так что Google знает, кто его использует и что ему разрешено делать с вашей учетной записью (OAuth 2.0). Чтобы получить этот токен доступа в первый раз, служба Google Play отправляет запрос POST HTTPS на android.clients.google.com/auth с этими полями (вместе с другими данными):

  • Token - "главный токен", который идентифицирует учетную запись Google и в основном позволяет получить полный доступ к ней.
  • app - имя пакета приложения, например com.whatsapp
  • client_sig - цифровая подпись (отправляется как SHA1)
  • device - устройство Android-идентификатор
  • service - scopes (разрешения), которые приложение хочет иметь

Итак, прежде чем мы сможем использовать API-интерфейс Drive в имени конкретного приложения, нам нужно знать его подпись и токен главной учетной записи. К счастью, подпись может быть легко извлечена из файла .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. Разница в том, что теперь приложение, запрашивающее разрешения, - это приложение "Службы воспроизведения" (com.google.android.gms), а Google также предоставляет дополнительные параметры Email и Passwd для входа в систему. Если запрос будет успешным, мы вернем наш главный токен, который затем может быть добавлен в запрос пользовательского приложения.

Вы можете прочитать этот blogpost для получения более подробной информации об аутентификации.

Объединяя все вместе

Теперь мы можем написать код для аутентификации, используя эти два 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.

ПРИМЕЧАНИЕ. Это неофициальное, хакерское решение, и поэтому у него может быть несколько проблем. Например, токен доступа жив только один час, после чего он не будет обновляться автоматически.

Ответ 2

Пользователь не может напрямую обращаться к данным в скрытых папках приложений, только приложение может получить к ним доступ. Это предназначено для конфигурации или других скрытых данных, которые пользователь не должен напрямую манипулировать. (Пользователь может удалить данные, чтобы освободить пространство, используемое им.)

Единственный способ, которым пользователь может получить доступ к нему, - это использовать некоторые функции, отображаемые конкретным приложением.