声明:案例分析仅供学习交流使用,勿用于任何非法用途。如学习者进一步逆向并对版权方造成损失,请自行承担法律后果,本人概不负责。

简介

很多软件在保护文件安全、用户隐私时,都会对本地文件数据进行加密处理。本次逆向的apk就对关键数据进行了加密,并对加解密代码提供了一定程度的保护。

目标

写一个小工具解密数据。

逆向流程

找到解密函数

首先从data目录找到文件:data2.8.0。内容是经过加密的。

通过jadx搜索“data2.8.0”没有任何线索,进一步扩大范围搜索“data”,本来有些担心这个词语过于普遍导致结果太多,但没想到还真找到一个很可疑的“data+版本号”格式的字符。

追踪进com.vv.test.ChannelDatas,恰好可以看到第一个函数貌似就是在读取加密文件。

经过分析,该方法功能确实是读取文件后解密。

public ChannelDatas(Context context) {this.mySettings = new MySettings(context);//这里是在生成之后AES解密用的key//pmd5(string)是取md5//SplashActivity.sKey是动态生成的密匙//getSettingStr("rand")是从SharedPreferences取"rand"String substring = AES.pmd5(SplashActivity.sKey + new MySettings(PlayerActivity.context).getSettingStr("rand")).substring(7, 7 + 16);try {//读取文件this.jsonString = ChannelManager.readfile(context, FILE_DATA);//文件内容做变换this.jsonString = this.jsonString.substring(64);this.jsonString = this.jsonString.substring(64);this.jsonString = this.jsonString.replace("f", "#");this.jsonString = this.jsonString.replace("b", "f");this.jsonString = this.jsonString.replace("#", "b");this.jsonString = this.jsonString.replace("t", "%");this.jsonString = this.jsonString.replace("y", "t");this.jsonString = this.jsonString.replace("%", "y");//变化后使用AES解密this.jsonString = AES.Decrypt(this.jsonString, substring);//解密后Base64解密一道再解压一次得到this.jsonString = new String(gzuncompress(Base64.decode(this.jsonString, 0)), "UTF-8");} catch (Exception e) {e.printStackTrace();new MySettings(PlayerActivity.context).saveVersion(0);Toast.makeText(PlayerActivity.context, "解析节目数据失败!请重新启动软件!", 1).show();}
}/*** AES解密工具* str为要解密的内容,str2为密匙*/
public static String Decrypt(String str, String str2) throws Exception {if (str2 == null) {try {System.out.print("Key为空null");return null;} catch (Exception e) {System.out.println(e.toString());return null;}} else if (str2.length() != 16) {System.out.print("Key长度不是16位");return null;} else {SecretKeySpec secretKeySpec = new SecretKeySpec(str2.getBytes("utf-8"), "AES");Cipher instance = Cipher.getInstance("AES/ECB/PKCS5Padding");instance.init(2, secretKeySpec);try {return new String(instance.doFinal(Base64.decode(str, 0)), "utf-8");} catch (Exception e2) {System.out.println(e2.toString());return null;}}
}/*** 解压方法*/
public static byte[] gzuncompress(byte[] bArr) {byte[] bArr2 = null;ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(bArr.length);Inflater inflater = new Inflater();try {inflater.setInput(bArr);byte[] bArr3 = new byte[256];while (!inflater.finished()) {byteArrayOutputStream.write(bArr3, 0, inflater.inflate(bArr3));}bArr2 = byteArrayOutputStream.toByteArray();byteArrayOutputStream.close();} catch (Exception e) {e.printStackTrace();} catch (Throwable th) {inflater.end();throw th;}inflater.end();return bArr2;
}

分析关键参数

当然,到这里还没结束,那就是SplashActivity.sKey和getSettingStr(“rand”)还没拿到,"rand"好办,直接从SharedPreferences.xml文件里可以读到,SplashActivity.sKey还挺费工夫的。由于混淆的厉害,就拿Dalvik看吧。

摘出真正在生成sKey的部分:

L_0x0106:
...java.lang.StringBuilder r9 = new java.lang.StringBuilderr9.<init>()int r10 = sig android.support.v4.media.TransportController.m88(r9, r10) //r9.append(r10)java.lang.String r10 = appnameokhttp3.Route.m286(r9, r10) //r9.append(r10)java.lang.String r10 = packagenameokhttp3.Route.m286(r9, r10)com.setting.MySettings r10 = r1.mySettingsjava.lang.String r10 = com.vv.test.ChannelData.m226(r10) //r10.getSign();okhttp3.Route.m286(r9, r10)java.lang.String r9 = okhttp3.internal.connection.RouteDatabase.m303(r9) //r9.toString();java.lang.String r9 = android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder.m44(r9) //md5(r9) sKey = r9java.lang.StringBuilder r9 = new java.lang.StringBuilderr9.<init>()java.lang.String r10 = sKeyandroid.support.v4.media.MediaMetadataCompatApi21.Builder.m82(r9, r10) //r9.append(r10)java.lang.String r10 = appnameokhttp3.Route.m286(r9, r10)java.lang.String r10 = packagenameandroid.support.v4.media.MediaMetadataCompatApi21.Builder.m82(r9, r10)java.lang.String r9 = android.support.v4.media.session.PlaybackStateCompat.Builder.m106(r9) //r9.toString();java.lang.String r9 = android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder.m44(r9)sKey = r9
...

其中关键的是sig和getSign()。sig生成也比较麻烦:

getSign()是native方法,使用ida静态分析可以看到逻辑如下:

开始Hook

上面两个函数我就不一点点分析了,有兴趣的盆友可以进一步挖掘,我在这里就直接开挂(Xposed Hook)给出答案了:

public class XposedInit implements IXposedHookLoadPackage {@Overridepublic void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {XposedBridge.log("hook init ---"+lpparam.packageName);if (lpparam.packageName.equals("com.vv.com")) {XposedBridge.log("hook start com.vv.com");//拿到com.vv.test.SplashActivity类final Class<?> splashActivityClass = XposedHelpers.findClass("com.vv.test.SplashActivity", lpparam.classLoader);//Hook com.vv.test.SplashActivity的onCreate()方法XposedHelpers.findAndHookMethod("com.vv.test.SplashActivity", lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {//onCreate()方法执行完后@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {super.afterHookedMethod(param);//打印SplashActivity.skeyString skey = String.valueOf(XposedHelpers.getStaticObjectField(splashActivityClass,"sKey"));XposedBridge.log("skey:" + skey); //d3ba4001c159be6c4087fd3679a4a74d}});return;}}
}

获得sKey之后就能写出文件解密工具了:

public static String runDecrypt() {String rand = "13ae41c997b396765bd57e3f8786dbf7";String sKey = "d3ba4001c159be6c4087fd3679a4a74d";String substring = MyTool.md5(sKey + rand).substring(7, 7 + 16);String resData = FileUtils.loadFile("./files/data2.8.0", "utf-8");resData = resData.substring(64);resData = resData.substring(64);resData = resData.replace("f", "#");resData = resData.replace("b", "f");resData = resData.replace("#", "b");resData = resData.replace("t", "%");resData = resData.replace("y", "t");resData = resData.replace("%", "y");try {resData = Decrypt(resData, substring);resData = new String(gzuncompress(Base64.decode(resData, 0)), "UTF-8");if (StringUtils.isNotBlank(resData)) {FileUtils.forBufferedWriter(resData, "./files/data.txt", false);}return resData;} catch (Exception e) {e.printStackTrace();}return "";
}

执行后即可获得解密后文本:

相关资料

Android studio 3.0编写Xposed HOOK登录框

Android逆向:通过Xposed解密柠某直播本地数据相关推荐

  1. 【Android逆向】XPOSED+反射大师脱壳实战

    目录 前言 一.环境搭建 1.Android模拟器 2.XPOSED 3.反射大师 二.脱壳步骤 1.安装目标apk 2.查壳 3.脱壳 总结 前言 Android APK加壳已经非常普遍了,Andr ...

  2. Android逆向分析案例——某点评APP登陆请求数据解密

    今天,七夕,单身23载的程序汪,默默地写着博客~ 上一次的逆向分析案例中讲了如何去分析某酒店的APP登陆请求,为了进一步学习如何逆向分析以及学习其他公司的网络传输加解密,本次案例将继续就登陆请求的数据 ...

  3. Android逆向 某州 解密sign字段 so层 算法分析 Unidbg模拟执行

    跟着龙哥学 SO逆向入门实战教程一:OASIS 前言 功力不及龙哥百分之一文笔也是实力也是, 仅作为个人记录学习过程. 龙哥博客传送门 1. 需解密对象 "sign" 字段 跟着龙 ...

  4. Android逆向--APP通信解密技巧

    一.市场总下载量:2266.43万 漏洞流程 1.分析报文可见正常攻击操作已经无法进行 2.请求和返回内容全部加密 请求包 userId=17060370&token=twZoW57%252F ...

  5. Android逆向工具xposed和mt管理器进行应用脱壳和去广告

    1.下载安卓模拟器,使用网易木木模拟器,官网下载就行,然后打开root和应用兼容性,否则无法使用xposed . 下载之后模拟器版本为 2.下载xposed,官网 https://repo.xpose ...

  6. Android逆向之玩转Xposed模块以劫持登录为例(实战篇)

    上一篇文章<Android逆向之玩转Xposed模块以劫持登录为例(Demo篇)>自编自导了一款劫持登录的Xposed模块,如果仅满于破解自己的APP是多么的悲哀,毕竟市场上的app都是经 ...

  7. Android逆向-Xposed Hook基础 游戏

    首先上游戏安卓包: 链接:https://pan.baidu.com/s/1fNe29ZwOhOvywcvjzVrcug 提取码:a21f 附上xposed的github地址:https://gith ...

  8. Android逆向之旅—Hook神器Xposed使用详解

    一.前言 关于Xposed框架相信大家应该不陌生了,他是Android中Hook技术的一个著名的框架,还有一个框架是CydiaSubstrate,但是这个框架是收费的,而且个人觉得不怎么好用,而Xpo ...

  9. xposed安装,与android逆向工程之xposed的hook

    Xposed installer安卓安装和使用 文章目录 Xposed installer安卓安装和使用 (一)Xposed installer安卓安装 0.百度网盘-我所用的apk(3.1.5)和z ...

最新文章

  1. jQuery运行方式818
  2. mysql数据库帐户_MySQL数据库用户帐号管理基础知识详解
  3. Linux零拷贝的原理
  4. java北大青鸟试题_10个常见2020春招Java面试题及注意事项!
  5. python 模块
  6. (37)FPGA花样流水灯设计(第8天)
  7. 电动汽车告急?特斯拉、蔚来之后 一辆比亚迪新能源车突然自燃...
  8. 使用XPathExpression类对XML文件进行排序
  9. fckeditor异常总结---org.apache.commons.fileupload.FileUploadException
  10. Asp.net安全相关注意的几个问题
  11. 移动web中的幻灯片切换效果
  12. ROS:ModuleNotFoundError: No module named ‘rospkg‘
  13. 2022年焊工(初级)考试及焊工(初级)考试内容
  14. Springboot - 构建基于XML交互的Restful应用程序
  15. Windows版变色龙
  16. LaTeX 文字带边框
  17. BZOJ 2101: [Usaco2010 Dec]Treasure Chest 藏宝箱( dp )
  18. Clustering - Choosing the number of clusters
  19. Flutter 桌面应用调研
  20. 【技术分享】Windows10下安装Nvidia显卡驱动及cuda和cudnn

热门文章

  1. java核心技术卷I-映射
  2. HTML背景墙上加图标,背景墙挂件—背景墙上放一些什么挂件好
  3. future的简单实现
  4. 高斯多种备份/迁移方式
  5. android顶部按钮图片,安卓动态改变button顶部图片即drawableTop属性
  6. 解析儿童编程中的基本概念与目标
  7. #### mysql联合索引 注意事项 ####
  8. 复制带随机指针的链表<难度系数⭐⭐>
  9. AI数学基础——经验分布,熵
  10. 答一位网友《SBO有哪样的几种开发方式》