此次逆向的apk为tmri_10101_1461033981072_release.apk
首先把apk安装在模拟器上,然后抓包分析网络流量
把apk拖进模拟器中之后安装:
然后设置代理

然后打开apk抓包

虽然app走的是http,但是抓到的包全是乱码,所以app在内部肯定对流量进行了加密操作
1.用jeb做静态分析
用jeb打开此apk之后查看代码
因为在app打开的时候会把系统信息传给服务器,而且访问的链接是writeDeviceInfo
经过我的一番查找,居然在com.tmri.services下面找到writeDeviceInfo这样的函数

右键反编译,打开这个函数:
发现确实是app发送设备信息的代码

然后对代码进行查看,发现类x可能是发送请求的代码,然后点击x后打开继续跟进

看到/m/deviceInfo/writeDeviceInfo
发现自己的猜想确实正确
往下拉继续查看这个类

发现这样的一个函数,其中this.d().a(……)这个函数似乎是在把数据包组装起来准备做发送
然后我注意到这个函数的参数有一个((HttpEntity)v2),这样的东西,我猜测这个可能是发送的http body,然后跟踪v2这个变量,发现在上面
v2 = new f(v0_3, ((Map)v1), null);进行了初始化
现在跟进f类
在f类中找到这样的函数:

d.d(……)这个函数是要发送的明文
那么下面的this.a(v2, this.f);就是加密函数了吧
跟进去之后发现确实是加密的核心函数

其中arg7传入的明文数据,而arg6是传出的密文数据,这个代码的最关键部分在
byte[] v2 = com.tmri.app.services.packet.c.b(com.tmri.app.services.packet.b.b(arg7, com.tmri.app.services.packet.b$a.values()[this.j]), com.tmri.app.services.packet.c$a.values()[this.k]);

而v2就是加密之后的数据
继续跟进com.tmri.app.services.packet.c.b

跟到这一步之后,静态分析就显得有点吃力了,首先
com.tmri.app.services.packet.c.b(com.tmri.app.services.packet.b.b(arg7, com.tmri.app.services.packet.b$a.values()[this.j]), com.tmri.app.services.packet.c$a.values()[this.k]);
这个函数中传入的j和k的值不能确定,进而无法确定这个函数将流量进行了何种的加密方式,所以下面将继续apk的动态分析
2.apk动态分析
这里参考的文章是:http://www.52pojie.cn/thread-502219-1-1.html
首先:用apktool解开app,然后修改AndroidManifest.xml中的 <application android:allowBackup="false" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:name="com.tmri.app.DemoApplication" android:theme="@style/AppTheme" android:debuggable="true">
把android:debuggable="true" 改成true
然后再用apktool打包
再用signapk.jar做个签名
然后用baksmali反编译一下:
baksmali tmri_sign.apk -o SmaliDebug/src
剩下的步骤和http://www.52pojie.cn/thread-502219-1-1.html里面讲的差不多,但是我用的Android Studio,但是步骤也是差不多的,没有多少区别。下面开始正式开始动态调试:
首先运行apk然后,在终端里面输入:adb shell ps
找到apk运行之后的名字,这个apk的名字是:com.tmri.app.main
然后在AndroidManifest.xml找到application这个标签,在这个标签下找到activity标签,然后在这个标签找到
然后在终端运行 android:name字段,这个字段就是app的主activity,这个app的主activity是:com.tmri.app.ui.activity.TmriActivity,在终端运行:adb shell am start -D -n com.tmri.app.main/com.tmri.app.ui.activity.TmriActivity
然后模拟器中出现:

说明成功,然后点击关闭这个窗口
然后再运行这个app,在终端中输入adb shell ps,然后找到这个app的pid,我现在运行的pid是:2166,然后运行:
adb forward tcp:8700 jdwp:2166,将调试进程附到2166这个进程中
然后在android studio中的src目录下找到刚才找到的加密函数,这个函数在com.tmri.app.services.packet的f类中

然后阅读smali代码,找到刚才那个加密函数:

在smali代码中找到在:

然后在这个函数的iget-byte v4, p0, Lcom/tmri/app/services/packet/f;->k:B
下断点,然后在菜单上点run-》debug”debug”

成功后这样的:

现在我的app的状态是:

随便输入一个用户名和密码点登陆:
发现android studio成功的断了下来

在右下角的窗口我添加v0,v1,v2,v3查看各个寄存器的值,然后按下f8单步运行这个apk
然后看到i=0,j=0,k=3
然后我再用jeb找到具体的加密函数,看他到底是怎么加密流量的

这个对应的smali在com.tmri.app.services.packet的c这个类里面:

我在每一个加密函数的入口加一个断点,看看它会用哪个函数进行加密流量:
运行之后看到他运行了invoke-static {p0, v0}, Lcom/tmri/app/services/packet/AesCipherJni;->native_t_set([BI][B
这个函数,对应的java代码是arg3 = AesCipherJni.native_t_set(arg3, arg3.length);
我可以在在右下角的寄存器中看到进入函数的值是:

进入后:


到这里就很明显了,它调用了一个动态链接库进行加密,然后把加密结果再传递出来
我们可以通过jeb的静态分析知道这个这个加密函数调用的是哪个动态链接库:

这个库在lib目录下

这三个目录对应的是cpu的类型,每个cpu类型的目录下都有名字一样的so文件,因为我的模拟器跑着x86的模拟器里面,所以我要分析的动态链接库在x86/ libAesCipher-Jni.so
3.静态分析so文件
静态分析so的软件是ida pro

用ida pro打开要分析的so文件,找到刚才被调用的函数:n_token_set然后打开,按f5做反编译为类c语言代码


慢慢分析一下,终于分析到倒数第二个函数(sub_DB0)的时候我看到了熟悉的东西

openssl的aes加密函数,其中参数a3,a4就是我想要的aes加密密钥key和iv,但是点进去之后,却看不到任何东西,看来只能动态调试了,这里先把sub_DB0的起始虚拟地址和结束虚拟地址找到:分别为:0000DB0和0000EF0

4.动态分析so文件
首先从网上下载gdbserver,上传到手机里面,然后找到用adb shell ps找到app的pid,我现在的pid是2166

然后在gdbserver
目录下运行./gdbserver :23946 --attach 2166

然后再开一窗口运行:
adb forward tcp:23946 tcp:23946
运行这两个指令之后我就能用本地的gdb调试代码了,但是我想用ida pro(破解版,只能在win上跑)提供的方便的功能进行调试,怎么办?于是我就想到了端口转发工具,于是我在网上找的一份这样的开源代码:http://blog.knownsec.com/2012/02/open-source-rtcp/
然后按照说明在本地mac上运行python rtcp.py l:3333 c:127.0.0.1:23946
我实现的调试拓扑

然后在远程的win打开ida pro,选择菜单的debugger->attach->Remote GDB debugger

然后

houstname 填的是我mac的地址,port是mac监听的端口,点击一直点ok,然后成功进入

下面我来寻找动态链接库的基地址,因为我调制的pid是2166,所以,我查看proc的maps文件来找动态链接库的基地址,在终端中运行adb shell cat /proc/2166/maps | grep libAes,

这个程序加载了三次这个动态链接库,但是每个动态链接库的执行权限不同,分别是是r-xp,r—p,rw-p,要调试的动态链接库应该是具有执行权限的,即r-xp,所以调试的基地址是:e2269000,刚才找到的函数的虚拟地址是0000DB0,所以函数在内存中的地址是:基地址+虚拟地址:e2269000+0000DB0= e2269db0
然后跳到e2269db0

然后下断点,然后运行起来,

在手机中输入用户名和密码之后,调试器被断住,断点正好在我下断的e2269db0位置,然后,先不着急按f8调试,先在里面右键,创建函数

然后再右键编辑函数,找到函数结束的地址:为刚才找到的函数结束虚拟地址+基地址:e2269000+0000EF0= e2269EF0,然后修改一下

点确定,然后把光标移到函数中,按下f5
汇编代码变成了类c的语言,

然后找到加密的函数下断点,然后运行起来


看到程序被成功的断下

将鼠标指向a3和a4的位置上,查看他们的地址:

然后找到对应的寄存器或者栈地址,将其显示出来

然后就找到aes加密的key是
95 8A FA EB CA EF A4 96 EC 7B 7E 97 D0 75 EA 48
iv是:
E0 A4 14 94 34 3A 26 1A 35 64 C6 3C 3A F0 43 57

这样,这个app的破解就差不多了
5.收尾
下面要编写流量解密程序,来验证拿到的key和iv是不是正确的,先在下面的两个函数上下断点来看加密之后的数据是什么样的


发现是02 9d 79 2c开头并且以 23 8a d1 88结尾的数据
先设置burp的拦截,然后运行app,这样burp成功拦下app发出的数据

然后保存这段数据为一个文件

然后我用.net写的一个aes解密程序破解成功,

解密程序如下

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;namespace aes
{class AESHelper{/// <summary>/// AES解密/// </summary>/// <param name="Data">被解密的密文</param>/// <param name="Key">密钥</param>/// <param name="Vector">向量</param>/// <returns>明文</returns>public static String AESDecrypt(String Data, byte[] Key, byte[] Vector){Byte[] encryptedBytes = Convert.FromBase64String(Data);Byte[] bKey = Key;Byte[] bVector = Vector;Byte[] original = null; // 解密后的明文Rijndael Aes = Rijndael.Create();Aes.Mode = CipherMode.CBC;Aes.Padding= PaddingMode.Zeros;Aes.BlockSize = 128;try{// 开辟一块内存流,存储密文using (MemoryStream Memory = new MemoryStream(encryptedBytes)){// 把内存流对象包装成加密流对象using (CryptoStream Decryptor = new CryptoStream(Memory,Aes.CreateDecryptor(bKey, bVector),CryptoStreamMode.Read)){// 明文存储区using (MemoryStream originalMemory = new MemoryStream()){Byte[] Buffer = new Byte[1024];Int32 readBytes = 0;while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0){originalMemory.Write(Buffer, 0, readBytes);}original = originalMemory.ToArray();}}}}catch(Exception e){Console.WriteLine("失败"+e.ToString());original = null;return null;}return Encoding.UTF8.GetString(original);}// 把十六进制字符串转换成字节型public static byte[] StringToByte(string InString){string[] ByteStrings;ByteStrings = InString.Split(' ');byte[] ByteOut;ByteOut = new byte[ByteStrings.Length];for (int i = 0; i < ByteStrings.Length; i++){ByteOut[i] = Convert.ToByte("0x"+ByteStrings[i],16);}return ByteOut;}public static byte[] GetPictureData(string imagepath){根据图片文件的路径使用文件流打开,并保存为byte[]   FileStream fs = new FileStream(imagepath, FileMode.Open);//可以是其他重载方法 byte[] byData = new byte[fs.Length];fs.Read(byData, 0, byData.Length);fs.Close();return byData;}static void Main(string[] args){string strkey = "95 8A FA EB CA EF A4 96 EC 7B 7E 97 D0 75 EA 48";string striv = "E0 A4 14 94 34 3A 26 1A 35 64 C6 3C 3A F0 43 57";byte[] key = StringToByte(strkey);byte[] iv = StringToByte(striv);byte[] bfile = new byte[2048];bfile=GetPictureData(@"C:\Users\hehe\apk\333");string pic = Convert.ToBase64String(bfile);string ok = AESDecrypt(pic, key, iv);Console.WriteLine(ok);}}
}

逆向加固的apk详细教程相关推荐

  1. Android Studio打包apk详细教程

    怎么手动打包 项目写完了,现在需要把应用上传到市场,问题出现-怎么把代码变成.apk(Android的可安装文件). 创建签名文件 填写好签名参数 生成APK 注意:签名的密码和密匙的密码注意保管,不 ...

  2. 安卓apk逆向之雷霆解锁VIP会员超详细教程

    本文来自 大神论坛 安卓逆向学习系列. 安卓apk逆向之雷霆解锁VIP会员超详细教程 图1∽10为『永久免费』教程,图11∽13为『免登陆』教程,图14∽24为『修改VIP』教程 逆向该apk使用的工 ...

  3. UE4打包成APK的详细教程(普通安卓应用,VR全景应用尚在探索中,之后若解决会更新)

    因为打包apk的学习过程中没有看到有哪篇文档是把全部流程完整描述出来的(就是给完完全全纯小白的博客,对官方文档的理解也不深的情况下)(也可能是我没搜到过吧)在没理解透的情况下走了很多弯路,这个过程确实 ...

  4. idea 配置mysql逆向_IDEA中Mybatis的MGB使用逆向工程配置的详细教程

    添加依赖 添加generatorConfig.xml文件 在maven的plugins中运行mybatis-generator插件 注意事项: (1).generatorConfig.xml文件需要放 ...

  5. 将 TensorFlow 移植到 Android手机,实现物体识别、行人检测和图像风格迁移详细教程

    2017/02/23 更新 贴一个TensorFlow 2017开发者大会的Mobile专题演讲 移动和嵌入式TensorFlow 这里面有重点讲到本文介绍的三个例子,以及其他的移动和嵌入式方面的TF ...

  6. android平板改成电视盒子,【当贝市场】废旧手机改造成电视盒子详细教程

    原标题:[当贝市场]废旧手机改造成电视盒子详细教程 话说现在的手机配置越来越高,比起盒子也没差到哪儿去,再加上本来也是同属安卓阵营的产品,闲置了可惜,卖了又不值钱,送人也没人要,那么何不废物利用一下呢 ...

  7. Android连接SQLServer详细教程(数据库+服务器+客户端),并在微软Azure云上搭建云服务

    Android连接SQLServer详细教程(数据库+服务器+客户端),并在微软Azure云上搭建云服务 参考博客:http://blog.csdn.net/zhyl8157121/article/d ...

  8. tensorflow的regress(超详细教程)

    tensorflow的regress(超详细教程) 运行结果 代码如下: """ Know more, visit my Python tutorial page: ht ...

  9. 在安卓手机上安装Ubuntu详细教程(无需root)

    在安卓手机上安装Ubuntu详细教程(无需root)    Android系统是基于Linux的,但是要在安卓上安装Linux却没有那么容易.本文法针对安卓手机上安装Ubuntu系统提出了一种方法,安 ...

  10. [安卓开发笔记一]Android开发配置opencv环境超详细教程

    [安卓开发笔记一]Android开发配置opencv环境超详细教程 [更新于 2022年4月] 再次提醒,建议现在看到这篇文章的,仅仅把此文做一个流程参考,4年前android studio就使用cm ...

最新文章

  1. FreeBSD 8.0候选版本RC3发布
  2. 脚手架koa2+mockjs
  3. Servlet--01--概念
  4. YARN编程实例—Unmanaged AM工作原理介绍
  5. PyTorch随笔-2
  6. 一个半路出家的前端工程师的2018 | 掘金年度征文
  7. 10个你必须知道的Python内置函数
  8. 阿里巴巴大规模应用Flink的踩坑经验:如何大幅降低 HDFS 压力?
  9. vue 限制渲染条数_深入理解Vue 的条件渲染和列表渲染
  10. SQL极致优化案例:利用索引特性进行max/min优化
  11. jQuery-选择器-查找标签
  12. 《圈圈教你玩USB》 第三章 USB鼠标的实现——看书笔记(1)
  13. sqlmap详细使用教程
  14. 从0到1开发H5游戏
  15. Django 面试题
  16. android常用机制,11.Android 常见面试题——Binder机制
  17. 证件照修改宽高和体积的工具
  18. Jmeter常用插件下载
  19. Intriguing properties of neural networks——L-BFGS attack
  20. 从前后端分离到前后端整合的“退步”(一)项目结构

热门文章

  1. 详细不啰嗦,电脑重装系统win10教程分享
  2. 计算机科学是ei期刊吗,EI计算机期刊有哪些
  3. Element-Ui 双重el-tabs组件选中第二层时,刷新导致第一层选中样式丢失问题以及解决方法
  4. always@(敏感列表)
  5. STM32 之 HAL库
  6. @Autowired和@Resource的区别
  7. html播放器怎么删除,风行如何完全删除?风行播放器彻底删除图文教程汇总
  8. PS2接口键盘、鼠标改成USB接口
  9. 保利威视云直播的python API
  10. 读书笔记-《启示录--打造用户喜爱的产品》