我试图为此寻找解决方案,但无法做到这一点我认为我开始了一个新问题。
我想要做的是还原在特定日期编辑过的文件,以恢复到之前的版本。原因是我的计算机上发现了一个恶意软件,它已经加密了我的所有文件。由于我在桌面上运行了Google云端硬盘应用程序,恶意软件加密了这些文件,谷歌云端硬盘已将其同步到云端......所以目前我在Google云端硬盘中有一堆损坏的文件。
我可以手动进入每个文件"管理修订版"并将其恢复到工作版本,但由于文件数量的原因,这需要花费数小时的时间。
我已经完成了有关可能会被使用的Google Drive API的阅读,但我不是专家程序员,所以我想问一下是否有人有任何建议/知道最好的方法解决这个问题。
干杯, 阿尔弗雷德
答案 0 :(得分:5)
这并不难。我假设文件在相关日期都被感染(因此被编辑),并且自那时起它们还没有被编辑过。如果是这种情况,那么您可以使用https://developers.google.com/drive/v2/reference/files/list https://developers.google.com/drive/web/search-parameters指定 modifiedDate 来查找这些文件。
然后,您可以检索修订Feed [{3}},我猜您在恶意软件日期之前正在寻找最新版本。
然后,您将获取内容并使用它来创建新文件,可能是在新的"未加密的"夹。或者,您可以尝试使用https://developers.google.com/drive/v2/reference/revisions/list删除加密的修订版,从而在其之前公开未加密的修订版。 NB我还没有尝试过这种方法。
如果您之前从未创建过云端硬盘应用,那么您可以获得很多乐趣。预算2-3天进行阅读并使其正常运行。作为骨架,您可能需要查看https://developers.google.com/drive/v2/reference/revisions/delete。我写这篇文章是为了快速解开所有用户的文件。这是一个不同的用例,但是将q=untrashed
替换为q=modifiedDate=yyyy-mm-dd
,并将untrash
替换为get_revisions, delete top_revision
,它距离您想要的距离不是一百万英里。
<强> NB。有点显而易见,但请确保在黑客修订之前备份所有内容。
答案 1 :(得分:3)
我们受到了cerber Ransomware的攻击,它感染了我们的Google驱动器。 我能够创建一个Python脚本,使用Google Drive API来恢复驱动器的转速。代码在这里有指导地再现。不要照原样使用它。 请注意代码顶部的免责声明。 希望它能让你开始完全恢复。
另请注意,要使用Google云端硬盘,您必须使用受感染的帐户登录,并转到https://console.developers.google.com生成client_secret.json文件。将文件放在与此脚本相同的目录中。
运行脚本: %python script_name.py
# This file CHANGES the drive. USE IT AT YOUR OWN RISK. I'M NOT RESPONSIBLE FOR ANY LOSE.
# It removes the revisions of cerber2 encrpted files
# It also renames the file back to what it was before the cerber2 infection
# You will probably have to run it multiple times because it only removes one rev each time.
# Good luck! Hope you get back to a state you were before the infection.
#
from __future__ import print_function
import httplib2
import os
import json
from apiclient import discovery
import oauth2client
from oauth2client import client
from oauth2client import tools
try:
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None
# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/drive-python-quickstart.json
#SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
SCOPES = 'https://www.googleapis.com/auth/drive'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Drive API Python Quickstart'
def get_credentials():
"""Gets valid user credentials from storage.
If nothing has been stored, or if the stored credentials are invalid,
the OAuth2 flow is completed to obtain the new credentials.
Returns:
Credentials, the obtained credential.
"""
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
'drive-python-quickstart.json')
store = oauth2client.file.Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
if flags:
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
def main():
"""Shows basic usage of the Google Drive API.
Creates a Google Drive API service object and outputs the names and IDs
for up to 10 files.
"""
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('drive', 'v3', http=http)
results = service.files().list(
corpus="domain",
spaces="drive",
pageSize=1000,
orderBy="folder,modifiedTime desc,name",
q= "name contains 'DECRYPT MY FILES'",
fields="nextPageToken, files(id, name)"
).execute()
items = results.get('files', [])
if not items:
print('No files found.')
else:
print('Files:')
for item in items:
deleteFile = service.files().delete(fileId=item['id']).execute()
print("file deleted " + item['name'])
results = service.files().list(
corpus="domain",
spaces="drive",
pageSize=1000,
orderBy="folder,modifiedTime desc,name",
#q="modifiedTime > '2016-09-04T12:00:00'",
q= "name contains 'cerber2'",
fields="nextPageToken, files(id, name)"
).execute()
items = results.get('files', [])
if not items:
print('No files found.')
else:
print('Files:')
for item in items:
details = service.files().get(
fileId=item['id'],
fields="lastModifyingUser,name").execute()
#print(details)
if(details['name'].endswith("cerber2")):
print('-------------------------File-------------------------------')
print(details)
revs = service.revisions().list(fileId=item['id'],fields="kind,revisions").execute()
allrev = revs['revisions']
print('==checking old revs==')
if(len(allrev) > 1):
#print(json.dumps(allrev,indent=4))
lastRev = allrev[-1]
if(lastRev['originalFilename'].endswith("cerber2")):
try:
print("removing lastrev of file " + details['name'] + " " + lastRev['id']) # delete the lastRev
revDel = service.revisions().delete(fileId=item['id'],revisionId=lastRev['id']).execute()
print(revDel)
except:
print("trying to remove earlier rev") # in case there are two revs with same time stamp, Google does not return the last rev as the last structure and the script fails
lastRev = allrev[-2]
if(lastRev['originalFilename'].endswith("cerber2")):
try:
print("removing lastrev of file " + details['name'] + " " + lastRev['id']) # delete the lastRev
revDel = service.revisions().delete(fileId=item['id'],revisionId=lastRev['id']).execute()
except:
print("Please handle this file yourself. Unable to remove revisions " + details['name'])
else:
print("lastRev name does not seem infected " + lastRev['originalFilename'])
file = {'name': lastRev['originalFilename']}
# Rename the file.
updated_file = service.files().update(fileId=item['id'],body=file,fields='name').execute()
print("Renamed")
else:
lastRev = allrev[0]
print("rename " + details['name'] + " id=" + item['id'] + " to " + lastRev['originalFilename'])
file = {'name': lastRev['originalFilename']}
# Rename the file.
updated_file = service.files().update(fileId=item['id'],body=file,fields='name').execute()
print("Renamed")
if __name__ == '__main__':
main()
#set PYTHONIOENCODING=utf-8 : You may need to set this in case file names have chars that cannot be printed on the console
答案 2 :(得分:0)
刚才找到了这个答案。 2016年9月基本上使用相同的想法,但在Java中。 完整博客:https://www.tmns.com/cerber3-ransomware-infected/
希望这有助于某人。勒索软件很糟糕。
源代码:
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.*;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.Revision;
import com.google.api.services.drive.model.RevisionList;
import com.google.api.services.drive.Drive.Files;
import com.google.api.services.drive.model.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
public class GDriveList {
/** Application name. */
private static final String APPLICATION_NAME = "Drive API Java Quickstart";
/** Directory to store user credentials for this application. */
private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"),
".credentials/drive-java-quickstart");
/** Global instance of the {@link FileDataStoreFactory}. */
private static FileDataStoreFactory DATA_STORE_FACTORY;
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
/** Global instance of the HTTP transport. */
private static HttpTransport HTTP_TRANSPORT;
/**
* Global instance of the scopes required by this quickstart.
*
* If modifying these scopes, delete your previously saved credentials at
* ~/.credentials/drive-java-quickstart
*/
private static final List<String> SCOPES = Arrays.asList(DriveScopes.DRIVE);
// Arrays.asList(DriveScopes.DRIVE_METADATA_READONLY);
// The DRIVE_METADATA_READONLY scope did not give me enough "power". Switched to "DRIVE".
static {
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}
/**
* Creates an authorized Credential object.
*
* @return an authorized Credential object.
* @throws IOException
*/
public static Credential authorize() throws IOException {
// Load client secrets.
InputStream in = GDriveList.class.getResourceAsStream("/client_secret.json");
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
clientSecrets, SCOPES).setDataStoreFactory(DATA_STORE_FACTORY).setAccessType("offline").build();
Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
System.out.println("Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
return credential;
}
/**
* Build and return an authorized Drive client service.
*
* @return an authorized Drive client service
* @throws IOException
*/
public static Drive getDriveService() throws IOException {
Credential credential = authorize();
return new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME).build();
}
/**
* Retrieve a list of revisions.
*
* @param service
* Drive API service instance.
* @param fileId
* ID of the file to retrieve revisions for.
* @return List of revisions.
*/
private static List<Revision> retrieveRevisions(Drive service, String fileId) {
try {
RevisionList revisions = service.revisions().list(fileId).execute();
return revisions.getRevisions();
} catch (IOException e) {
System.out.println("An error occurred: " + e);
}
return null;
}
/**
* Rename a file.
*
* @param service
* Drive API service instance.
* @param fileId
* ID of the file to rename.
* @param newTitle
* New title for the file.
* @return Updated file metadata if successful, {@code null} otherwise.
*/
private static File renameFile(Drive service, String fileId, String newTitle) {
try {
File file = new File();
file.setName(newTitle);
// Rename the file.
Files.Update updateRequest = service.files().update(fileId, file);
updateRequest.setFields("name");
File updatedFile = updateRequest.execute();
return updatedFile;
} catch (IOException e) {
System.out.println("An error occurred: " + e);
return null;
}
}
public static void main(String[] args) throws IOException {
// Build a new authorized API client service.
Drive service = getDriveService();
String fileId;
String revisionId;
String currentFilename = "";
String originalFilename = "";
String nonCerberName = "";
String cerberFilename = "";
boolean moreThanOneFilename = false;
// Get files in batches of 500.
FileList result = service.files().list()
.setPageSize(500)
.setQ("name contains '.cerber3'")
.setSpaces("drive")
.setFields("nextPageToken, files(id, name)").execute();
List<File> files = result.getFiles();
if (files == null || files.size() == 0) {
System.out.println("No files found."); // And this would be a good
// thing!
} else {
// Decided to put my output in a format that I could later easily
// paste into Excel
// So these are the headers of my CSV file.
// Just remember to start this code with the following command:
// gradle -q run >> output.csv
System.out.println("Filenum, Filename, fileId, revisionId, cerberFilename, originalFilename");
int filenum = 0;
String realFilename = "";
String deleteVersionId = "";
String renameVersionId = "";
String renameFilename = "";
for (File file : files) {
// Note: don't put \n at the end. There will be more stuff
// printed later on.
System.out.printf("%s, %s, %s, ", ++filenum, file.getName(), file.getId());
// Try to get a bit more info in a separate call.
fileId = file.getId();
cerberFilename = file.getName();
moreThanOneFilename = false;
List<Revision> revisions = retrieveRevisions(service, fileId);
if (revisions.size() != 2) {
// This statement will mess up the CSV-style output I'm
// trying to create.
// Talk to someone who cares...
System.out.println("There are " + revisions.size() + " revisions (and not 2), skipping");
} else {
// Loop through all TWO revisions
realFilename = "";
for (Revision listRevision : revisions) {
renameVersionId = "";
deleteVersionId = "";
revisionId = listRevision.getId();
// OK, got the fileID, now the revisionID, now get the
// revision itself.
// Think we already had the revision? Think again. We
// need to retrieve it via
// a separate get(), since we need to tell the API to
// get the originalFilename
// in the return JSON.
Revision revision = service.revisions().get(fileId, revisionId).setFields("id,originalFilename")
.execute();
originalFilename = revision.getOriginalFilename();
if (originalFilename.indexOf(".cerber3") > -1) {
// Yeah, found the encrypted file, let's delete this
// version
// System.out.printf("Going to delete file,
// versionid, originalName: %s, %s, %s\n", fileId,
// revisionId, originalFilename);
deleteVersionId = revisionId;
} else {
// System.out.printf("Going to rename file,
// versionid, originalName: %s, %s, %s\n", fileId,
// revisionId, originalFilename);
renameVersionId = revisionId;
renameFilename = originalFilename;
}
}
// Looped through 2 version, now do the deleting + renaming
// First delete the version
service.revisions().delete(fileId, deleteVersionId).execute();
// Rename the version
File renamedFile = renameFile(service, fileId, renameFilename);
// And complete the CSV-line, started before (already
// printed num, filename, fileid)
System.out.printf(" %s, %s, %s\n", deleteVersionId, cerberFilename, renameFilename);
}
}
}
// Now let's look for the cerber "help" files...
// These files are named either
// @___README___@.html or @___README___@.txt or @___README___@.url
result = service.files().list()
.setPageSize(500)
.setQ("name contains '@___README___@.'")
.setSpaces("drive")
.setFields("nextPageToken, files(id, name)").execute();
files = result.getFiles();
if (files == null || files.size() == 0) {
System.out.println("No cerber files found."); // And this would be a good thing!
} else {
int filenum = 0;
for (File file : files) {
System.out.printf("Going to delete file %s, %s, %s\n", ++filenum, file.getId(), file.getName());
// .delete only works if you are the owner of the file.
// Which, in this case, is exactly what we want.
service.files().delete(file.getId()).execute();
}
}
}
}
答案 3 :(得分:0)
我遇到了同样的问题,勒索软件对PC上的所有文件进行了加密,并且由于我安装了Google Backup&Sync,因此将所有加密的文件推送到Google云端硬盘。
我创建了这个nodejs脚本来删除加密的修订并将文件重命名为原始文件: https://github.com/ronnyvdb/rollbackRevisionsGoogleDrive