如何在Google云端硬盘中查看隐藏的应用数据? [英] How can I see hidden app data in Google Drive?

查看:322
本文介绍了如何在Google云端硬盘中查看隐藏的应用数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Android应用程序,用于将我的笔记存储在隐藏的应用程序数据中。我想导出我的笔记,所以问题很简单:



如何访问Google云端硬盘中隐藏的特定应用的应用数据?

解决方案

确实,Google不允许您直接访问这个隐藏的应用程序数据文件夹。但是,如果您可以亲自使用应用程序的客户端ID /客户端密钥/数字签名(用于对Google服务器进行身份验证),那么可以,基本上可以模拟使用Drive API访问Google云端硬盘中的隐藏数据。

Android的工作原理



通常,当Android应用程序想要访问Google API(例如驱动器时,游戏或Google登录 - 并非全部都支持),它会与 Google Play服务客户端进行通信库,然后代表应用程序从Google获取访问令牌。然后,该访问令牌随每个请求一起发送到API,以便Google知道谁在使用它以及他可以对您的帐户执行哪些操作( OAuth 2.0 )。为了第一次获得此访问令牌,Google Play服务会使用这些字段向 android.clients.google.com/auth 发送HTTPS POST请求(以及其他细节):


  • 令牌 - 标识Google的主令牌账户,并且基本上允许对其进行完全访问。

  • client_sig - 应用程序的数字签名(以SHA1形式发送)

  • device - 设备的 Android ID

  • service - 应用程序希望拥有的作用域(权限)



所以在我们开始使用Drive API之前特定应用的名称,我们需要知道其签名和我们帐户的主令牌。幸运的是,签名可以很容易地从 .apk 文件中提取:

 壳>解压whatsapp.apk META-INF / * 
存档:whatsapp.apk
充气:META-INF / MANIFEST.MF
充气:META-INF / WHATSAPP.SF
充气: META-INF / WHATSAPP.DSA
shell> cd META-INF
shell> keytool -printcert -file WHATSAPP.DSA#可以是CERT.RSA或类似的
.....
证书指纹:
SHA1:38:A0:F7:D5:05:FE: 18:FE:C6:4F:BF:34:3E:CA:AA:F3:10:DB:D7:99
签名算法名称:SHA1withDSA
版本:3

接下来我们需要的是主令牌。当添加新的Google帐户时(例如首次设置电话时),通常会通过向相同的URL发出类似的请求来接收和存储此特殊令牌。不同之处在于,现在要求获得权限的应用程序是Play服务应用程序本身( com.google.android.gms ),Google也会给出额外的电子邮件 Passwd 参数进行登录。如果请求成功,我们将取回我们的主令牌,然后可以将其添加到用户的应用请求中。



您可以阅读此博文,了解有关认证过程的更多详细信息。



把它们放在一起



现在,我们可以直接编写一个使用这两个HTTP请求的验证代码 - 可以使用任何Google帐户浏览任何应用的文件。只需选择您最喜欢的编程语言和客户端库。使用 PHP ,我发现它更简单:

require __DIR__。 /vendor/autoload.php; // Google Drive API

// HTTPS身份验证
$ masterToken = getMasterTokenForAccount(your_username@gmail.com,your_password);
$ appSignature ='38a0f7d505fe18fec64fbf343ecaaaf310dbd799';
$ appID ='com.whatsapp';
$ accessToken = getGoogleDriveAccessToken($ masterToken,$ appID,$ appSignature);

if($ accessToken === false)return;

//初始化Google Drive客户端
$ client = new Google_Client();
$ client-> setAccessToken($ accessToken);
$ client-> addScope(Google_Service_Drive :: DRIVE_APPDATA);
$ client-> addScope(Google_Service_Drive :: DRIVE_FILE);
$ client-> setClientId(); //客户端ID和客户端密码可以留空
$ client-> setClientSecret(); //因为我们伪造一个Android客户端
$ service = new Google_Service_Drive($ client);

//打印最多10个文件的名称和ID。
$ optParams = array(
'spaces'=>'appDataFolder',
'fields'=>'nextPageToken,files(id,name)',
'pageSize '=> 10
);
$ results = $ service-> files-> listFiles($ optParams);

if(count($ results-> getFiles())== 0)
{
printNo files found.\\\
;
}
else
{
printFiles:\\\
;
foreach($ results-> getFiles()as $ file)
{
print $ file-> getName()。 (。$ file-> getId()。)\\\
;
}
}

/ *
$ fileId ='1kTFG5TmgIGTPJuVynWfhkXxLPgz32QnPJCe5jxL8dTn0';
$ content = $ service-> files-> get($ fileId,array('alt'=>'media'));
echo var_dump($ content);
* /

函数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\\\
Connection:close,
'method'=>'POST',
'content'=> http_build_query($ data),
'ignore_errors'=> TRUE ,
'protocol_version'=>'1.1',
//'proxy'=>'tcp://127.0.0.1:8080',//用于调试的可选代理
/ /'request_fulluri'=> true

);
$ context = stream_context_create($ options);
$ result = file_get_contents($ url,false,$ context);
if(strpos($ http_response_header [0],'200 OK')=== false)
{
/ *处理错误* /
print'请求时发生错误访问令牌:'。 $结果。 \r\\\
;
返回false;


$ startsAt = strpos($ result,Auth =)+ strlen(Auth =);
$ endsAt = strpos($ result,\\\
,$ startsAt);
$ accessToken = substr($ result,$ startsAt,$ endsAt - $ startsAt);

return{\access_token\:\。$ accessToken。\,\refresh_token\:\TOKEN \,\ token_type \:\Bearer \,\expires_in\:360000,\id_token\:\TOKEN \,\created\:。时间() 。 };
}

函数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\\\
Connection:close,
'method'=>'POST',
'content'=> http_build_query($ data),
'ignore_errors'=> TRUE ,
'protocol_version'=>'1.1',
//'proxy'=>'tcp://127.0.0.1:8080',//用于调试的可选代理
/ /'request_fulluri'=> true

);
$ context = stream_context_create($ options);
$ result = file_get_contents($ url,false,$ context);
if(strpos($ http_response_header [0],'200 OK')=== false)
{
/ *句柄错误* /
print'试图在尝试时发生错误登录: ' 。 $结果。 \r\\\
;
返回false;


$ startsAt = strpos($ result,Token =)+ strlen(Token =);
$ endsAt = strpos($ result,\\\
,$ startsAt);
$ token = substr($ result,$ startsAt,$ endsAt - $ startsAt);

返回$ token;
}

最后,结果 -

 文件:
gdrive_file_map(1d9QxgC3p4PTXRm_fkAY0OOuTGAckykmDfFls5bAyE1rp)
数据库/ msgstore.db.crypt9(1kTFG5TmgIGTPJuVynWfhkXxLPgz32QnPJCe5jxL8dTn0)
16467702039不可见(1yHFaxfmuB5xRQHLyRfKlUCVZDkgT1zkcbNWoOuyv1WAR)
完成。

注意:这是一种非官方的哈克解决方案,因此它可能会有几个问题。例如,访问令牌只存活一小时,之后不会自动刷新。


I have an Android app that stores my notes in hidden app data. I want to export my notes so the question is simple:

How can I access the hidden app data in Google Drive for a specific app?

解决方案

Indeed, Google does not let you access this hidden app-data folder directly.

But, if you can get your hands on the app's client ID/client secret/digital signature that is used for authentication against Google's servers - then yes, you can basically emulate the app and access the hidden data in your Google Drive using the Drive API.

How it works in Android

Usually, when an android application wants to access a Google API (such as Drive, Games or Google Sign-In - not all are supported) it communicates with the Google Play services client library, which in turn obtains an access token from Google on behalf of the app. This access token is then sent with each request to the API, so that Google knows who is using it and what he is allowed to do with your account (OAuth 2.0). In order to get this access token for the first time, the Google Play service sends an HTTPS POST request to android.clients.google.com/auth with these fields (along with other details):

  • Token - a "master token" which identifies the Google account and basically allows full access to it
  • app - the application package name, such as com.whatsapp
  • client_sig - the application's digital signature (sent as SHA1)
  • device - the device's Android ID
  • service - the scopes (permissions) that the app wants to have

So before we can start using the Drive API in the name of a specific app, we need to know its signature and our account's master token. Fortunately, the signature can be easily extracted from the .apk file:

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

The next thing we need is the master token. This special token is normally received and stored on the device when a new google account is added (for example, when first setting up the phone), by making a similar request to the same URL. The difference is that now the app that's asking for permissions is the Play services app itself (com.google.android.gms), and Google is also given additional Email and Passwd parameters to log in with. If the request is successful, we will get back our master token, which could then be added to the user's app request.

You can read this blogpost for more detailed information about the authentication process.

Putting it all together

Now, we can write a code for authentication using these two HTTP requests directly - a code that can browse any app's files with any Google account. Just choose your favorite programming language and client library. I found it easier with PHP:

require __DIR__ . '/vendor/autoload.php'; // Google Drive API

// HTTPS Authentication
$masterToken = getMasterTokenForAccount("your_username@gmail.com", "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;
}

And finally, the results -

Files:
gdrive_file_map (1d9QxgC3p4PTXRm_fkAY0OOuTGAckykmDfFls5bAyE1rp)
Databases/msgstore.db.crypt9    (1kTFG5TmgIGTPJuVynWfhkXxLPgz32QnPJCe5jxL8dTn0)
16467702039-invisible (1yHFaxfmuB5xRQHLyRfKlUCVZDkgT1zkcbNWoOuyv1WAR)
Done.

NOTE: This is an unofficial, hacky solution, and so it might have a few problems. For example, the access token is alive only for one hour, after which it won't be refreshed automatically.

这篇关于如何在Google云端硬盘中查看隐藏的应用数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆