APP爬虫初阶课程笔记(上)

发布时间 2023-05-08 16:11:11作者: z5onk0

此笔记内容全部来源于r0ysue大佬的《APP爬虫入门课程》,干货满满,内容硬核详实,我的笔记只是自己学后的心得体会,实际课程内容远多于此,建议大家感兴趣的都去找r0ysue买一个vip会员,你值得拥有~

101 环境

虚拟机配置

用虚拟机的原因

  • 不会破坏主机
  • 拍快照,试错成本低
  • 重新解压虚拟机,获得纯净环境

修改系统时间

dpkg-reconfigure tzdata

设置鼠标滚轮

链接

安装工具

  • jnettop、htop
  • QtScrcpy
  • wifiadb
  • genymotion&translation
  • kali-linux
  • termux

Android Studio

  • 第一次同步很慢,可以设置代理

  • 只建议在linux上编译安卓程序

  • platform目录下自带adb,只需加入系统路径即可

wifi感叹号问题

  • “已连接,但无法访问互联网”开机后wifi有感叹号,部分网站无法访问
在手机的shell里以root用户执行: 
#settings put global captive_portal_http_url https://www.google.cn/generate_204 
#settings put global captive_portal_https_url https://www.google.cn/generate_204 
#settings put global ntp_server 1.hk.pool.ntp.org 
#reboot 
后续只要把时区调对,时间会自动同步的。

书籍

  • 《第一行代码》
  • 《零基础学安卓》
  • 《精彩编程200例》
  • 《安卓项目开发实战入门》
  • 《疯狂安卓讲义》(难度高)
  • 《安卓应用防护和安全分析》

102 基础知识

开头

  • APP加载过程
  • so加载过程
  • APP四大组件
  • 安卓系统架构

终端命令

  • 安卓本质上是linux系统
  • neofetch查看系统信息
  • net hunter进入安卓的kali子系统
  • ps -e
  • ps -T -p + 进程号:查看线程
  • netstat -tunlp|grep 7001:查看端口对应的进程号
  • netstat -alpe |grep -i https/22:查看当前正在运行的进程
  • tree -Nucfh树状排列
  • 在termux中通过pkg install htop安装htop命令

adb命令

  • adb shell

  • adb connect ip

  • adb devices

  • adb -s ip:port shell

  • adb shell dumpsys activity top

  • adb input

  • adb logcat

  • adb shell screencap:截屏

termux

  • 宝藏APP,为安卓系统提供了一系列命令
  • /data/data/com.termux/files/usr/bin
  • 需要赋予APP应用存储权限

Genymotion

  • 精简版的安卓系统,删了很多库

103 刷机

pixel2刷机

刷机准备

  • lineage zip
  • twrp img
  • magisk zip(github上下的是APK,需要把后缀改为zip)

刷机步骤

  • 首先需要一个底包,这里我用的出厂自带的google官方系统,没有重新刷入

  • 手机上打开usb调试,关闭屏幕超时锁屏,打开OEM锁

  • 手机完全关机,按住向下键重启(或者通过adb reboot bootloader 命令),进入bootloader,注意要确保bl锁处于unlocked状态

  • 当bootloader屏幕上显示Start时,用下面命令刷入twrp,很快(fastboot和adb都在Android Studio的Sdk工具包里)

    fastboot flash recovery recovery.img

    但这个命令在pixel2手机上执行会报错,因为pixel2手机是ab分区,没有独立的recovery分区,只能刷到boot分区中,所以将命令改为

    fastboot flash boot recovery.img

  • 刷完后手机重启,进入bootloader,按两下向下键,选择进入recovery模式,选择Advanced->adb sideload,用adb刷入lineage包,时间比较长,屏幕上会有红色报错,不用管

    adb sideload lineage-signed.zip

  • 用adb将magisk.zip push到sdcard目录下,然后进入recovery模式的install选项,选择安装magisk,安装完后重启设备

    • 解决红色报错的办法:安装包时把usb线拔掉,防止自动挂载system分区
  • 重启进入lineage os后,安装magisk.apk,至此手机成功获得root权限

104/105 动静态分析

动静态分析

静态

  • jadx(稍弱)/jeb/gda轮换着看
  • 得到包下面的类,名字以内存里的为主,在内存中确认有没有这个类

动态

  • frida server+objection

  • 调系统库用objection,快速定位

  • 定位到非常小的范围内,定位算法才用smali

  • hook toString

命令

frida server启动

frida-server -l 0000:8888

objection启动

objection -N -h host -p port -g package explore

objection查看日志

cat .objection/objection.log | grep com.example.demo10

pyenv切换

  • 用pyenv切换下环境

    pyenv local 版本号

wallbreaker插件

# 加载
-P ~/.objection/Plugins
# 使用
Plugin wallbreak classdump

查看端口

netstat -aple 
netstat -tuulp
lsof -p
ps -e

106 自动化分析和定位

objection免root调试

  • 用objection重打包APK,将frida-gadget.so注入APK中

    proxychains4 objection patchapk --architecture armeabi-v7a --use-aapt2 --source hello2.apk
    
  • 再用objection连接frida

    objection explorer
    

objection内存漫游

# 内存搜索模块
memory list modules
# 内存搜索导出库
memory list exports so库
# 在堆上查找类的实例
android heap search instances bitmap类 
# 主动调用类的方法,在google devloper上找类方法
android heap execute hash getHeight --return-string
# 调用带参的方法

objection组件控制

# 查看任务
jobs list
# 切换activity
android intent launch_activity 类名

objection远程调用

  • objection内置flask,提供rpc调用接口,可直接使用curl控制手机

  • objection上开发flask端口

    objection --api-port 8000 explore --enable-api
    
  • curl远程调用api

    curl -s "http://127.0.0.1:8888/rpc/invoke/androidHookingListActivities"
    
  • 可上传执行脚本,可调用带参函数,更多例子见rpc接口

objection脱壳

  • 无法对加壳的程序重打包,必须要root才能启frida

  • 多运行一会,等待APP进入自己的主程序

  • 将dexdump放到plugin目录下

    git clone https://github.com/hluwa/frida-dexdump ~/.objection/plugins
    
  • 启用脱壳

    # 加载
    -P ~/.objection/Plugins
    # 使用
    plugin dexdump dump
    

107 去升级重打包

wallbreaker搜索类

# 搜索类实例
plugin wallbreaker objectsearch 类名
# 打印实例信息
plugin wallbreaker objectdump 实例编号

定位升级弹窗的方法

  • 搜索字符串不科学
  • 用动态调试的方法,hook弹窗的api,打印调用栈,找到主程序中弹窗的代码逻辑

objection启动时hook

  • frida有两种模式:spawn和attach

  • objection启动时如果没有找到类名,则以spawn模式启动,通知Zygote孵化进程,如果找到类名则attach

  • 加上参数,用来一启动即hook

    --startup-command "YOUR CMD"
    

apktool打包解包

# 解包
apktool d apk
# 打包
apktool b apk

自签名

  • 安卓系统对签名的校验很弱

keytool生成证书

keytool -genkey -alias hello -keyalg RSA -validity 20000 -keystore hello.keystore

jarsigner自签名

jarsigner -verbose -keystore hello.keystore -signedjar demo_signed.apk demo.apk hello.keystore

安卓包管理命令

am

pm

108 带壳去升级重打包

三代壳

  • 一代壳:整体性的壳,用工具可脱完全
  • 二代壳:函数式的壳,脱完后只能看到函数名,没有函数体
  • 三代壳:vmp、ollvm

APK安全性校验

  • 大部分APK都带安全性校验,重打包、脱壳后APK会失效

判断函数能否被hook

# 把所有类中能被hook的打印出来
android hooking list classess

如何选择需要objection注入的类

  • 通过top查看活跃进程
  • 通过 frida-ps -U查看活跃进程

dexdump脱壳的三种模式

objection内启用插件

dexdump插件目录下运行main.py

  • 先运行frida-server
  • 再运行main.py,会自动判断前台进程,对前台进程内存进行扫描dump

frida-dexdump

pip install frida-dexdump
frida-dexdump -U -f pkgname

脱壳后如何找到包含mainactivity的dex文件

  • du -h *选最大的文件
  • grep -rn -i MainActivity搜索包含的文件

定位目标函数方法

  • 先尝试hook弹窗的类,定位到dialog类

  • 所见即所得:点击弹窗周围无用,猜测调用了setConceled API

  • hook函数,证实调用,打出调用栈,找到程序中调用的逻辑

  • 修改原有逻辑,重打包

Android弹窗API

  • 查看android develop官网

PopupWindow类

dialog类

AlertDialog类

新建window

新建Activity

APK带壳重打包的方法

dexump去壳

  • 将生成的dex文件从大到小命名为classes.dex, classes2.dex, classess3.dex ...

apktool解包

# 保留dex解包
apktool -s -d packagename
# 将去壳的dex全部替换到解包的dex文件

apktool封包并签名

  • 签名后运行APK观察是否正常

apktool解包,修改dex文件

apktool封包并签名

109 APP加固

安卓原生和linux原生

  • 所谓原生程序,指更接近接近解释器
  • 安卓原生就是libart.so来解释、linux原生就是CPU直接解释

加固技术发展

  • 静态混淆

  • 动态加载

    • 安卓动态加载dex:链接
  • native加固

    • 使用libsecshell.so等
  • 核心数据、功能云端化

  • 反调试、反反编译

加固技术手段

一代整体壳

  • 文件落地加载、不落地加载

二代代码抽取

  • 对抗:dexdump主动加载
  • 对抗:FART

dex保护

  • dex vmp虚拟机保护:自编译一个dalvik解释器,执行效率很低

  • java2c:用NDK编写应用

native保护

  • ollvm:通过编写 PASS 来控制中间代码以达到混淆的目的

  • 自定义elf格式,用专门的linker加载so

  • 段加解密

动态调试对抗类名、函数名混淆

  • 静态搜索关键字
  • 通过objection查看类的结构和属性,进行确认

201 Xposed介绍

Xposed和Frida对比

  • xposed直接替换art虚拟机,更持久和稳定,但只能hook java层
  • frida本质是ptrace,注入到进程中,能hook so层

Xposed衍生品

  • edXposed
  • virtual app
  • 平头哥
  • 太极

Xposed安装

  • 先root,推荐SuperSU
  • apk(需要科学)或者zip安装
  • 下载插件
    • gravitybox
    • Xdebuggable
    • justtrustme

202 手调Smali

Android Studio带源码调试

Jeb无源码调试

快捷键

Java和Smali间切换
  • tab键
断点
  • ctrl+b
交叉引用
  • x
类方法搜索
  • 选择环绕搜索

无源码调试

  • 定位包和类
# 搜索包
pm list packages | grep 包名
# 搜索类
dumpsys activity top grep 包名
  • 调试模式启动APP,并停留在启动入口

adb shell am start -D -n 包名 ./.mianactivity

  • jeb拖入APK,选择debug->start,附加到APP进程

  • 改局部变量类型,辅助分析

debug模式

debug模式和普通模式的区别
  • 区别在于启动过程,能否在创建界面时调试,即能否附加onCreate
若APK不是debug模式
  • 法一:重打包,改mainfest为debug,不一定成功
  • 法二:用xposed的xdebuggable插件,hook系统对debug的校验

其他Jeb相关

改局部变量类型,辅助分析

  • $1是内部类

  • objdump不包含基类方法和属性,jeb看到的是全的

  • apktool分割成多个单独的smali类

smali和frida调试的选择

Smali调试的场景:小项目、抠算法细节、全是本地变量、变形的标准算法

Frida调试的场景:大项目、快速定位、各种执行流、API过滤和trace

DDMS

  • Android 开发环境中的Dalvik虚拟机调试监控服务

An error has occurred.See the log file错误

  • as自带jdk很老,做个软链接过去
ln -s /root/Desktop/android-studio/jre /root/Android/Sdk/tools/lib/monitor-x86_64
./monitor

辅助增强工具

  • 监控线程和进程、内存情况

dumpview

  • 获取组件类及ID,帮助frida定位

view的继承关系

methodprofile

  • 函数trace记录

203 Frida开发和调试

模拟器vs真机

  • 模拟器是精简版系统,很多api都没有,没有so层
  • 利用的时候可以用模拟器,逆向分析和抓包的时候用真机

Frida环境

  • BlissRoms给N5安装android 10

pyenv安装

0. 首先请确保系统已经是root用户、并且默认shell切换为了bash: https://t.zsxq.com/UFa6my3
1. git clone GitHub - pyenv/pyenv: Simple Python version manage... ~/.pyenv
2. 在~/.bashrc文件的最后加上:
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"
4. sudo apt-get update; sudo apt-get install make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
5. 重启(必须)
6.pyenv install 版本号

frida安装

# 指定安装frida版本
pip install frida==12.8.0

# 上frida github查看对应tools版本
pip install frida-tools==

# 上pypi objection,找frida发布后最近一次的objection
pip install objection==

frida常用命令

# 查看前台应用
frida -H host:port -F

frida开发

js开发

1. git clone https://github.com/oleavr/frida-agent-example.git
2. cd frida-agent-example/
3. npm install
4. 使用VSCode等IDE打开此工程,在agent下编写typescript,会有智能提示。
5. npm run watch会监控代码修改自动编译生成js文件
6. frida -U -f com.example.android --no-pause -l _agent.js

python开发

  • 调用frida接口

204 抓包环境配置及原理

抓包环境配置

  • 物理机和手机连接同一wifi
  • 虚拟机设置桥接网卡(不复制网络),一定要桥接wifi网卡

wifi http代理抓包

  • wifi设置代理
  • 应用层抓包,容易被api检测

vpn代理抓包

  • 网络层抓包,位于路由表第一条,所有流量都走vpn虚拟网卡

postern全局代理配置

  • 设置代理服务器ip和端口
  • 配置代理规则
  • 开启vpn

burp和charless抓包

  • 应用层抓包的核心原理是中间人代理
  • 设置代理服务器

抓http和https

  • ssl是会话层,http可以放到ssl中
  • 关闭ssl:不解密抓包,可以抓到http明文和https的密文
  • 打开ssl:尝试解密,此时未放入charless签发证书,抓https会失败

205 https抓包实战

http的危险性

  • 明文可能被窃听

  • 通信方可能伪装

    • 运营商劫持http包,插入广告信息
    • 运营商劫持dns,返回错误结果GTW
  • 报文可能被篡改

    • IOT渗透测试:升级包覆盖原有固件,留下后门
    • 就算做了签名,签名本身也可能被篡改

网页:客户端校验服务器

app:还有服务器校验客户端:将app的证书导入到charless,伪装成客户端

https=http+加密+认证+完整性保护

ssl

  • https是披着ssl外衣的http
  • 刚开始的认证阶段速度慢,后续可以保持一段时间用session key通信
  • ssl提供加密和证书

证书机制

混合加密机制

双向绑定

ssl pinning

  • 极少见,再代码中对证书再进行校验

charless抓https包

  • 插入中间人,分割成两端独立的https通信,需要证书保持三者的session key一致,才能通信

  • charless开启代理服务,socks比http/https更强

  • 手机连接代理

手机导入charless证书

  • 手机浏览器输入Charles的证书下载地址chls.pro/ssl
  • 下载证书并安装到手机中
  • 将用户证书安装到系统目录中
cd /data/misc/user/0/cacerts-added
mount -o remount,rw /
cp * /etc/security/cacerts/
mount -o remount,ro / 
  • 重启

charless添加app证书

  • 两种方法获取app证书文件

    • 解包apk,搜索p12结尾的文件
    • hook打开文件的api,找到文件路径
  • 获取证书解密公钥

    • frida hook脚本,不同框架使用不同的api
  • 将证书文件和公钥添加到charless中

抓国外APP的科学方法

  • charless选择外部代理,连接科学链路

206 基于hook的抓包

缺点:不如抓包软件全面
优点:无视证书、基于HOOK直接得到参数、打调用栈得到参数的构成和来源

hook抓包的步骤

  • 通过objection打印所有类
  • 在objection目录下cp日志
  • grep搜索常用安卓网络通信方法类,猜测可能用到的框架
    • httpurlconnection
    • okhttp
  • hook网络方法类定位请求地址与参数

frida批量hook的方法

objection批量hook

  • objection打印所有类
  • excel生成批量语句,按照制表符分割导出为txt
  • objection -c txt批量hook

zentracer批量hook

  • 基于pyqt和frida

记录trace的工具

  • zentracer
  • ddms:用于录制函数调用,不推荐
  • android开头的类属于安卓系统提供的java库,也可以引入第三方java库,都被打包到了dex文件中

推荐的hook抓包工具

OkHttpLogger

  • 用于抓OkHttp框架的java API

ssl_logger

  • 链接

  • hook libssl的read和write,在加密前和解密后获取明文数据

  • tcpdump抓的是加密过的流量

  • 抓取日志中搜索grep - 100 phone_num

207 FRIDA基本使用

FRIDA的两种操作模式

命令行

  • REPL交互式控制台界面
# HelloWorld.js
# 到java虚拟机中打印helloworld
Java.perform(function(){
	console.log("HelloWorld!")
})

# perform和performnow的区别
虚拟机起来,类加载器还没起来就执行的是performnow

# USB、前台进程
frida -UF -l HelloWorld.js

# 使用es语法
es6的箭头表达式要加--runtime=v8

# 查看手机的执行引擎
Script.runtime

RPC

  • 通过python脚本调用frida的方法
  • objection本质是一个python rpc
import frida

#device = frida.get_device_manager().add_remote_device("")
device = frida.get_usb_device()
print(device.get_frontmost_application())

pid = device.get_frontmost_application().pid
session = device.attach(pid)

with open("HelloWorld.js") as f:
	script = session.create_script(f.read())
script.load()

input()

FRIDA操作APP的两种模式

attach

  • 可以指定pid
  • attach前台进程
  • 用于有壳的APP

spawn

  • frida -U -f 包名

  • spawn时可能会遇到对象未创建的问题

  • --no-pause恢复主线程执行,或者手动%resume

FRIDA三板斧

  1. 先hook、看参数和返回值:定位:命令行
  2. 再构造参数、主动调用:利用:命令行
  3. 最后配RPC导出结果:规模化利用:PYTHON
  • hook类、方法、返回值和参数,不能hook语句
  • frida的核心是反射

java类加载器和反射

  • 正常加载:第一次使用该类,new一个对象就可以分为两个过程:加载并初始化类和创建对象。
  • 反射机制:Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
  • 动态加载(热加载):Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
  • 反射的应用场合:类的名称放在XML文件中,属性和属性值放在XML文件中,需要在运行时读取XML文件,动态获取类的信息

208 FRIDA hook

objection定位

  • 用于定位,所见即所得

  • 确定类是否被加载、对象是否被创建、方法是否被调用,再挂frida脚本

Frida hook

  • frida可以热部署,js保存后立即生效
  • 打印调用栈,参数和返回值
function main(){
	Java.perform(function(){	//只要是java代码都要跑在perform里
		Java.use("类名").dip2px.implementation = function(args){	替换原函数的实现
			var result = this.dip2px(args)	//主动调用原函数
			console.log("args==>", args)	//打印参数			
	  console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));	//打调用栈
			return result
		}
	}
}
setImmediate(main)
  • 修改参数、返回值,注意重载函数需要用overload标明哪一个
function main(){
	Java.perform(function(){	
		Java.use("类名").setText.overload("java.lang.CharSequence").implementation = function(args){	
			# js字符串和java字符串要转换
			var javaString = Java.use("java.lang.String")
			var newString = javaString.$new("z5onk0")
			var result = this.setText(newString);
			return result
		}
	}
}
setImmediate(main)

objection和frida联合调试

  • 可以同时用,但不能同时hook函数

  • objection主动调用,动态方法要找到实例

android heap search instances 类名
android heap execute hash 方法名
  • frida hook自吐,此时的调用栈会不一样

hook的时候两个原则:

离数据越近越好

离动作越近越好

hook用不上Java.choose的
hook函数时不分动静态

hook不上的问题

  • 对于大的基础库,hook可能会崩溃
  • 换进程,换安卓系统

查看APP崩溃日志

  • logcat | grep 进程名

混淆后的hook

  • 方法名直接复制黏贴、先编码再解码
  • 参考

209 FRIDA主动调用和批量自动化

主动调用

访问静态域静态方法

  • 静态域和静态方法可以直接在Java.use后访问

    Java.use("类名").静态变量名.value
    Java.use("类名").静态方法名(参数)
    
  • android.os.Build用来改机,改序列号,改系统名,手机信息,从设置APP里进去权限较高

访问动态域动态方法

  • 动态域动态方法需要通过Java.choose枚举实例后访问

    Java.choose("类名", {
    	onMatch:function(instance) {
    		console.log("instace text is ==>", instance.text.value);
    		instance.clear("123");
    	}, onComplete:function(){
    		console.log("Search Complete!")
    	}
    }
    
  • 或者通过new构造一个实例来访问

  • 实例方法内存中唯一份,hook时不用Java.choose枚举

模拟点击

  • 调用安卓系统的shell命令
# input是shell命令,keyevent是模拟按键
function subCommand(){
	Java.perform(function(){
		var process = Java.use("java.lang.Runtime").getRuntime().exec("input keyevent 25")
		console.log("subcommand success process is :", process)
	})
}

挂脚本

  • js中导出rpc函数
rpc.exports = {
	subcommand: subCommand
}
  • python中调用rpc函数
command = ""
while 1 == 1:
	command = input("Enter command:\n1: Exit\n2: Call secret function\nchoice:")
	if command == "1":
		break
	elif command == "2":
		script.exports.subcommand()

重启应用

pid = device.spawn(["包名"])
device.resume(pid)
time.sleep(1)
session = device.attach(pid)

RPC多机器批量调用

  • frida通过网络连接多台机器,挂python脚本rpc
  • 在数组中枚举ip、script

远控内网机器

  • 用nps做内网穿透,将frida_server端口映射到vps,python链接vps端口实现远控

  • 只需在一台内网机器上部署nps客户端,可以搭建多条隧道,映射多台内网机器

打造4g代理

  • 手机通过4g/5g信号与基站的交换机进行数据传输

  • 内网手机上开启http/socks代理

  • 将内网手机的代理端口映射到vps外网端口

  • 通过requests/scrapy访问该vps端口