App爬虫综合方案分析

前言

最近公司让我研究研究app爬虫,没办法那就撸起袖子就是干,N个夜晚的奋战,N种方案的尝试。最终想写下本文来记录一下!也让有相同需求的小伙伴少走一些冤枉路!本来是想以某红书作为案例来记录下,但律师函警告劝退!

反编译

已经不是什么新鲜事了,网上工具很多,自己常用的也就下面这几个:

  • apktool:资源文件获取,可以提取出图片文件和布局文件进行使用查看
  • dex2jar:将apk反编译成java源码(classes.dex转化成jar文件)
  • jd-gui:查看APK中classes.dex转化成出的jar文件,即源码文件

个人比较喜欢 jd-gui 直接看源码,至于怎么使用自行百度,本文不做过多讲解。

脱壳

你以为反编译后就一定能拿到源码?想多了 很多公司为了安全都会对app混淆和加固后进行上架。

整体加固技术的原理 大概就是替换application/classes.dex、解密/动态加载原classes.dex、调用原application相关方法、将原application对象/名称设置到系统内部相关变量四大环节。其中最为关键的一步就是解密/动态加载原classes.dex,通过加密编译好的最终Dex源码文件,然后在一个新项目中用新项目的application启动来解密原项目代码并加载到内存中,再把当前进程替换为解密后的代码,能够很好地隐藏源码并防止直接性的反编译。

参考链接:https://juejin.im/post/5d8ae282518825095f10112a

常见的加固厂商比如,腾讯,360,乐固等等一大堆。免费的,收费的满天飞。

如果你运气好可能用一些第三方的脱壳工具(Fdex2、dexdump、Zjdroid)可能可以脱壳。

如何分辨应用是否被加固了呢?
  • 看反编译后的代码量,比如就2-3个包,class 还就一两个。
  • 加固后一般会有代表性的so,在lib里面。如:360--libjiagu.so。

看多了自然就知道了。

脱壳方式

使用 Fdex2dexdumpZjdroid不过大多可能是浪费时间,那还有没别的方法呢?

肯定有的,hook libart.so系列的方法,至于为什么这种方式可以成功呢,大概的原理就是:你代码肯定是要通过Android虚拟机的,里面引入了art虚拟机,必然经过,然后hook拿到。(可能有问题,还请大佬纠正)

我所熟知的就fridaDump,吹一波frida真的很好用。也有一些大佬用frida dump 写了一些工具,这里就不多说了,自行百度,实践才是根本!

为什么互联网大厂都不给app加壳?

当你多逆向看的应用多了,你会发现到为什么那么多大厂不加壳呢?加壳的大多数是二三线的小厂。

看一下加固的利弊可能就明白了。

利:

  1. 保护自己核心代码算法,提高破解/盗版/二次打包的难度

  2. 缓解代码注入/动态调试/内存注入攻击

弊:

  1. 影响兼容性

  2. 影响程序运行效率.

  3. 部分流氓、病毒也会使用加壳技术来保护自己

  4. 部分应用市场会拒绝加壳后的应用上架

为了性能。兼容行和hotfix等大厂放弃了加壳,但他们会增加别的地方的逆向难度,比如:给so的sign等算法增加难度......

逆向分析

逆向分析才是app爬虫重中之重,你至少得对这个app有一定的了解才行,不然属实无从下手啊。

抓包

抓包的话也有好几种

  • 基于代理方式的:Fiddler、Charles、Mitmproxy(推荐) 都差不多其实,mitmproxy支持写python脚本对数据进行处理
  • VPN转发:PacketCapture、mitm-vpn-helper

还有什么tcpdump啥的就不提了。

如果你有过抓包的经验,不知道你发现没有有些app你是抓不到包的,甚至一抓包直接断网。这是为什么呢?

罪魁祸首:ssl-pinning

它是在开发时就将服务端证书一块打包到客户端里。这样在HTTPS建立时与服务端返回的证书比对一致性,进而识别出中间人攻击后直接在客户端侧中止连接。

办法总比困难多,既然你校验证书,那我hook 掉 返回 true 不就行了。

基于xposed的:JustTrustMe、TrustMeAlready 模块。frida也能实现,但是对比xposed来说不能持久化。

这样就能保证100%抓得到包吗?

不一定,有的业务会做双向证书验证,一般用于跟支付相关的业务,再则根本不走tcp协议。

Smali解读

Dalvik虚拟机加载的是dex文件,Dex文件是Dalvik虚拟机的可执行文件格式,dex文件很难看懂,baksmali和smali是对Dex文件的反汇编器和汇编器,通过对Dex文件反编译得到smali文件,smali文件是对Dalvik虚拟机字节码的一种解释(也可以说是翻译),并非一种官方标准语言。通过对smali文件的解读可以获取源码的信息。

原文链接:https://blog.csdn.net/qq_32113133/article/details/85163277

smali解读的话可以看看上面的文章,不过不是很推荐下特别大的功夫在上面,像jadxdex2jar这类工具可以直接将smali转换为java代码,不过注意并不是100%准确的,有10%语法还原错误,遇到这种就建议纯看+工具参考了。

smali 动态调试 (不推荐,你可以了解一下有这个东西就算了,我反正感觉不太行)

C/C++

说到c/c++我其实不了解,不过没关系,搞爬虫问题不大。android 目录(lib)下的一大堆libxxx.so是什么呢?

Linux下的.so是基于Linux下的动态链接,其功能和作用类似与windows下.dll文件。都是c/c++ 的产物。

我并不建议下太多的功夫在so的逆向上(你NB就当我i没说)。

你得先去了解c/c++,然后o-llvm 还有 IDA使用等等,况且so还有混淆,校验等手段,难上加难。

所以我选择不搞,**不逆向那我有办法去调用so吗?**有,一般就3种:

  • 自己写个app去模拟
  • Unicorn
  • frida 调用 (推荐)
Hook

Hook 又叫“钩子”,它可以在事件传送的过程中截获并监控事件的传输,将自身的代码与系统方法进行融入。这样当这些方法被调用时,也就可以执行我们自己的代码,这也是面向切面编程的思想(AOP)。其实你可以简单的理解 **就是把一个原有的方法用自己写的方法给替换掉。**还不明白可以看看文末链接。

这里就安利下面两款hook框架,因该是暂时用的比较多的(android方面)需要root

firda

frida是平台原生appGreasemonkey,说的专业一点,就是一种动态插桩工具,可以插入一些代码到原生app的内存空间去,(动态地监视和修改其行为),这些原生平台可以是WinMacLinuxAndroid或者iOS。而且frida还是开源的。

xposed

通过替换 /system/bin/app_process 程序控制 Zygote 进程,使得 app_process 在启动过程中会加载 XposedBridge.jar 这个 Jar 包,从而完成对 Zygote 进程及其创建的 Dalvik 虚拟机的劫持。
Xposed 在开机的时候完成对所有的 Hook Function 的劫持,在原 Function 执行的前后加上自定义代码。

frida和xposed区别

在我看来各有各的好处,两个框架都需要root,frida提供免rootfrida-gadget 的方式注入。

xposed:

  • 可持久化,模块安装好激活就行。
  • 对native不太友好
  • 每次修改必须重启生效(有解决办法,不过麻烦)

frida:

  • 全平台
  • 支持natice hook
  • 采用JavaScriptAPI 来编写脚本
  • 不能持久化,每次得启动frida-server 连接数据线
  • 修改代码不需要重启

总体来说,frida除了持久化无所不能。

如何让frida脱离数据线也能运行?

网上一堆说用frida-gadget简直误人子弟,我们先来看看frida -help

Usage: frida [options] target

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -D ID, --device=ID    connect to device with the given ID
  -U, --usb             connect to USB device
  -R, --remote          connect to remote frida-server
  -H HOST, --host=HOST  connect to remote frida-server on HOST
  -f FILE, --file=FILE  spawn FILE
  -F, --attach-frontmost
                        attach to frontmost application

注意到没有 frida -H显示连接远程的 frida-server,那么肯定就有这个功能

接着尝试firda -H 192.168.1.12:27042 xxx.js报错:frida.ServerNotRunningError: unable to connect to remote frida-server

明明就是这个地址和端口,frida-server也启动了,但是为什么呢?

罪魁祸首是防火墙android 也是系统,也有防火墙,这是只需要 adb shell 进去关闭防火墙就行

adb shell
su
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
ip6tables -P INPUT ACCEPT
ip6tables -P OUTPUT ACCEPT
ip6tables -P FORWARD ACCEPT

你可以使用telnet测试,防火墙关闭以后telnet 192.168.1.12 27042,还是不通?为什么呢

再来adb shell 进入手机查看一波frida-server开放是端口有没问题。

好家伙一看frida-server绑定了ip,127.0.0.1:27042只允许你本机访问,那怎么办呢?

端口转发 开一个0.0.0.0:xxxx 将请求转发到127.0.0.1:27042上就好了。

可以参考 bilibili-爬虫不看学历大佬编译好的

实践是真理,我说明行得通就欧克!

爬虫开发

整个爬虫唯一的痛楚就在于 加密算法的实现,现在90%以上的app至少都做了类似sign 这样的加密算法。

加密算法的实现
  • 手动重现sign/加密算法:需要重现java方法和so函数。
  • 代码注入调用: 通过frida 调用。

我个人比较偏向于frida ,去逆向so和定位分析java代码成本有点大,耗时还不一定成功。

如果app的加密算法没有用到so(很少)你也可以考虑xposed+andserver这种方式。

自动化

这种方式不推荐,但也有人用。一般用以这自动化测试工具来操作UI然后用中间人攻击方式截取数据。主要是自动化很不稳定。

虽然不建议但还是罗列一下

操作ui:

  • appnium
  • airtest 网易的 比appnium好点
  • 基于AccessbilityServiceauto.js一类的脚本

数据截取:

  • ui读取数据(基本没人这么搞吧)
  • 代码调用监听(hook)xposed
  • 网络监听 mitmproxy

END

还是一句话,实践才是根本。

参考链接

常见 app 加固厂商脱壳方法研究

Android Apk加固厂商特征,Apk加固哪家强

理解 Android Hook 技术以及简单实战

Android Hook 机制之简单实战

FRIDA-API使用篇