逆向探探
获取探探”源码"
一个App需要经过开发、编译、签名、生成apk、等一系列步骤后才能上传到应用市场,而逆向就要从apk文件开始说起。本文实验对象通过探探官网下载,应用版本为4.1.1。
逆向的第一步就是反编译。首先了解一下逆向工具 apktool ,按文档介绍运行最简单的命令 “apktool d 探探.apk -o tantan” 后,终端报错 Not a valid dex magic value: cf 77 4c c7 9b 21 01 cd 。字面意思不难看出是dex 的魔数值不正确。说到魔数我最先想到的是 jvm class 的4位魔数0xCAFEBABE ( cafe babe ? ) , 而dex的魔数是由8位组成 ,魔数的前3位分别为 64 65 78转换字符串为dex 第4位为0A 转换字符串为\n,后续三位为版本号 最后一位为0 。查看log后发现是解析到assets/A3AEECD8.dex 后报错,经查询后得知此dex为腾讯X5内核的webview所用, 由于此dex加密后更改了魔数,所以apktool 不能识别。我们想要绕过这个crash需要在命令后拼接 --only-main-classes,大意为仅反编译根目录下的dex,忽略其他文件夹。
为了更方便的回编译(后续会提到),我们还需要忽略资源文件也就是 resources.arsc。原因是无论正编译或是反编译,资源的整合都是由Android提供的扩展工具aapt/aapt2 完成。因为逆向环境和正向开发环境不一致,resources.arsc 解码后会造成部分文件丢失,回编译时aapt/aapt2打包生成的压缩文件与索引不对应导致回编译失败,所以需要在命令后拼接 -r至此 一个完整的反编译命令为 “apktool d 探探.apk -o tantan --only-main-classes -r”
文件&目录名称 | 用途说明 |
---|---|
lib | so 库文件 |
smali_XX | 虚拟机指令,Dalvik字节码 |
resources.arsc | 资源文件集合,由aapt生成 |
AndroidManifest.xml | 服务清单 |
上图是对解码后的探探工程主目录做的简要说明,我们单独分析 AndroidManifest.xml 后可知道探探的包名为 com.p1.mobile.putong ,所以我们需要重点关注此包下的文件夹或文件因为我们阅读的是dalvik字节码,所以需要对其指令集有所了解。 探探的工程“源码”全部都存放于smali_XX 文件中,下面我们以程序入口作为案例梳理一下应用初始化流程。首先打开AndroidManifest.xml 后找到application标签确定源码路径,源码存放于./tantan/smali_classes2/com/p1/mobile/putong/app/TantanApp.smali。
主要分析 application 中onCreate 和 attachBaseContext 两个方法。 代码如下:
第一眼看完后后除了知道这个类名是TantanApp之外,好像无法再获得更多信息。所以分析代码这个步骤完全是考验耐力,不过不要退缩,我们只要遵循一些技巧,就可以大幅减少工作量。由于分析过程比较繁琐,这里就不结合具体代码了,只做一些理论总结: 从目标 API 开始入手,跟踪执行流程、只分析涉及代码块,缩小分析范围、尝试搜索一些关键词或者log 日志 。
切记不要在茫茫代码中迷失自我
入口方法初始化流程如下:
验证逆向思路的可行性
在逆向分析的过程中,我们需要注入自定义的代码,用于辅助定位源码或获取上下文的变量值,方便我们调试应用。首先看下对探探Apk注入方法后的效果:
如图所示,注入分为两部分
在打开启动页时 ,添加了一个广告页。在登录时,对登录方法进行拦截
新增广告页
启动页的源代码码路径为 ./tantan/smali_classes2/com/p1/mobile/putong/account/ui/welcome/WelcomeAct.smali,在 onCreate 生命周期内,跳转一个广告Activity即可。但由于广告Activity没有在 AndroidManifest.xml 中注册,我们选择通过Hook ActivityManagerService、PackageManagerService 等绕过系统检测,此处不对 Hook 的内容与原理做延伸。
登录方法拦截
登录页的源代码路径为 ./tantan/smali_classes2/com/p1/mobile/putong/account/ui/accountnew/loginopt/act/PhoneNumberLoginOptAct.smali。此页面通过分析可以得出是典型的mvp 模式,此Activity 只做数据传递的桥梁,view 是由 l/byb 维护 ,presenter 是由 l/bxt 维护。点击事件在 byb 类下的 protected e()V 中注册,点击登录按钮后事件流转到 byb 类下的 public o()V,在此处我们弹出对应的拦截框即可。并且在此处也可以拿到登录传递的参数,可做进一步的其他分析
登录拦截代码
以登录方法为例,插入代码如下:
回编译
方法插入完成后,下一步就是二次打包也就是回编译。运行命令 “apktool b tantan” 生成新的apk ,因为此时的apk 没有签名无法安装使用,所以在这里我们采用jdk 工具 jarsigner 对新apk 进行签名。在回编译的过程中我们需要注意dex方法数超过65535的问题,在插入代码时我们要尽可能的将新代码分布到多个smali_XX文件夹内以确保单个dex方法数不超过系统限制。重新签名后,新的签名与原探探签名会不一致,这样会导致某些第三方服务异常 例如百度地图、微信登录支付等。解决此问题可以尝试修改sdk 内获取应用签名方法,强制返回探探应用原签名。但有些服务把获取签名方法放到了native 侧,所以需要一些arm 汇编知识修改so,具体方法在此处就不做延伸。
安全漏洞
由于探探的微信或其他第三方平台的key 和 秘钥是明文写到客户端内,所以我们可以自由使用。如果我是一个破坏者我会新建一个工程 ,包名与探探包名保持一致,并且对微信校验签名方法hook ,强制返回探探的应用签名即可使用探探的身份进行微信授权登录等。极端点还可以使用探探的身份做一些违反微信社区要求的操作,这样会导致探探的线上设备全部被微信封禁。
探探网络请求的body 没有做加密,仅做了身份校验操作。利用此特性,灰产可通过网络接口对用户数据读写。模拟客户端真实操作,从而达到非法盈利的目的