# RH-android备份文件迁移 **Repository Path**: long-yucheng/rh-android-backup-file-parsing ## Basic Information - **Project Name**: RH-android备份文件迁移 - **Description**: 睿海小项目:解析电脑助手备份得到的数据并迁移 - **Primary Language**: C++ - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2022-05-27 - **Last Updated**: 2022-08-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: JSON, 备份, 安卓, Hash ## README # 安卓数据PC端迁移 ## 项目背景 大多数品牌手机都有自己的电脑助手,比如vivo的电脑端助手:[互传](https://es.vivo.com.cn/),通过互传助手可以备份手机数据,但是备份得到的数据并不是直接可分析的。 ### 小例子 比如我们对联系人进行备份后,会产生相应的备份文件,如`BackupFiles\联系人\NEX S-1654746915003`文件夹下有一个无后缀的字符串文件:`1a73af9e7ae00182733b2292511b814be66f065f`,同路径下还有个`db\000003.log`文件,这是互传助手的日志文件,打开后有很多乱码,但其中有一个字符串是我们需要的: ```json {"filename":"contact","hash":"1a73af9e7ae00182733b2292511b814be66f065f"} ``` 这个是通讯录(contact)文件的哈希计算值,很明显就是刚刚那个无后缀文件名,一般来说我们只需要给这个文件人为加上后缀就可以看到里面存的数据: 1. 通讯录、短信、通话记录等是以`.xml`或`.txt`文件解析 2. 应用数据(QQ、微信等)是以`.zip`或`.tar`文件解析 一般地,我们并不是只备份一个通讯录,而是所有数据一起备份,在备份路径下就会得到很多上述的无后缀文件,那如何区分这些后缀文件是什么呢?一般地: 1. 大多数APP,比如爱奇艺: ```json "filename":"app_com.qiyi.video.data" "hash":"38a696065acd2ee3b5a3f7a4dc42a36058493bfb" ``` 2. 媒体文件, > 图片: ```json "filename": "***.jpg" "hash": "2982bb14d880acbab4c758d99fb44bd8823120bf" ``` > 视频: ```json "filename": "***.mp4" "hash": "131231231280acbab4c758d99fb44bd8823120bf" ``` 3. 其他 ```json "filename": "***" "hash": "***" ``` 备份助手会在`db\000003.log`文件写入所有备份信息,通过查找这些hash值,就可以得知是什么文件,进而下一步处理。 从上面得知,备份一项数据就会得到一个该数据的文件,这个文件以hash字符串命名,这个文件一般是压缩文件或者文本形式的文件,把这个文件添加上后缀,再通过解压或者其他操作就可以得到文件里的内容。 ## 使用方式 ### 1、编译 本项目的编译环境是visual studio 2022,可以直接生成解决方案然后执行。注意,有个头文件`json.hpp`是用于处理json数据的,这个需要提前下载并引用它:[官方文档](https://github.com/nlohmann/json)。 ### 2、输入参数 本项目导出的可执行文件是以动态库`.dll`方式,最终由C#调用,调用的时需要传入一个窗口句柄、一个json字符串,一个int型停止标志等参数: ```C++ extern "C" { __declspec(dllexport)int _stdcall mainEntry(HWND ExHwnd, char* inputJson, char* mainPath, char* backupPath, char* casePath, int UIStop); } ``` 这个输入的json字符串格式为: ```json { "type": 0, "mainPath": "F:/***", "backupPath": "F:/New_Task/datafromvivo/Allfiles/iQOO Z1-1653974992223", "casePath": "F:/***", "appListInfo": [ { "com": "cn.myhug.baobao", "icom": "cn.myhug.baobao", "comex": "", "cn": "抱抱直播", "en": "cn.myhug.baobao", "media": " / sdcard / Android / data / cn.myhug.baobao", "oldapk": "", "cmd": "", "total": "PackageTotal, cn.myhug.baobao", "isGetClone": "", "HisuitVer": "101" } ], "language": 1, "readmode": 0 } ``` 参数解释: 1. `type`:用于标识手机品牌 2. `mainPath`:用于存放的主路径,这里是主控平台的路径 3. `backupPath`:备份文件所在的路径,这个路径下存放了若干无后缀的哈希字符串文件 4. `casePath`:案件的所在目录,一般是mainPath路径下的一个子目录 5. `appListInfo`:存放需要转移的备份数据包名相关信息,有若干个 6. `language`:提示消息的中英文标识 7. `readmode`:专家版读取或普通读取标识(专家版读取backupPath下所有的信息,普通版则按照appListInfo列表读取) ### 3、测试 一个简单的测试代码: ```C++ int(*moveBackupData)(HWND ExHwnd, char* inputJson, char* mainPath, char* backupPath, char* casePath, int UIStop); int test(char* inputJson, char* mainPath, char* backupPath, char* casePath) { HMODULE hdll = LoadLibrary(L"RH_PC_Backup.dll"); if (hdll != NULL) { (FARPROC&)moveBackupData = GetProcAddress(hdll, "mainEntry"); if (moveBackupData != NULL) { int ret = moveBackupData(NULL, inputJson, mainPath, backupPath, casePath, 0); std::cout << ret << std::endl; } else { std::cout << "moveBackupData is null" << std::endl; } } else { std::cout << "Load moveBackupData failed" << std::endl; } FreeLibrary(hdll); return 1; } ``` 解释: 1. 声明函数指针,这与动态库中的要调用的函数参数形式相同,`int(*moveBackupData)(HWND ExHwnd, char* inputJson, char* mainPath, char* backupPath, char* casePath, int UIStop);` 1. 加载动态库:`LoadLibrary(L"RH_PC_Backup.dll")` 2. 绑定入口函数指针:`(FARPROC&)moveBackupData = GetProcAddress(hdll, "mainEntry");` 3. 传入参数,执行:`int ret = moveBackupData(NULL, inputJson, mainPath, backupPath, casePath, 0);` 4. 最后释放动态库:`FreeLibrary(hdll);` ## 说明 1. `hash`值命名的无后缀文件里保存了备份出来的数据,只要人为加上后缀(如`.zip`),就可以看到里面的内容,这个项目的流程就是把这些无后缀文件加上后缀,再解压移动到新的目录中去; 2. 备份助手的`db\000003.log`文件存放了hash值对应的数据包名,这个log文件里存放了本次备份的所有信息,当备份文件量较大时,需要从log文件中解析出无后缀文件是属于哪一类,比如上百张图片,几十个APP等,每一张图片就会有一个无后缀文件,每一个APP也会有一个无后缀文件; 3. 这里用了字典来存放数据包名和哈希值,格式为: ```C++ std::unordered_map < std::string, std::string> appName2Hashval; // app 字典:{应用名:应用名哈希值} std::unordered_map < std::string, std::string> imageName2Hashval; // image 字典:{图片名:图片名哈希值} std::unordered_map < std::string, std::string> videoName2Hashval; // video 字典:{视频名:视频名哈希值} ``` 4. 采用了自定义的结构体存放输入的参数: ```C++ typedef struct appInfo { std::string com; std::string icom; std::string comex; std::string cn; std::string en; std::string meida; std::string total; std::string isGetClone; }appInfo; typedef struct MapStruct { int _language; int _mode; int _type; char _mID[0x40];; std::unordered_map myMapStruct; }MapStruct; ``` 5. 日志文件会保存在`mainPath`下的`...\ectLog\applog\`,以日期命名; 6. 有的压缩包文件需要移除文件地址的头若干位内容,否则解压会失败,相关函数封装在: ```C++ void Phone::DecryTar(std::string filePath, std::string tarPath, std::string tarName, bool need7zip) ``` 7. 本项目基于C++11。