iOS底层原理笔记
端口映射
1 | python tcprelay.py -t 22:10010 // usbmuxd将本地10010端口tcp协议 通过usb转发到iPhone的22端口 |
Cycript 安装和使用
iOS11及以上iOS版本中不能直接使用Cycript,如果想继续使用可使用以下方法
ssh登录iPhone
执行以下命令(如没有安装wget,在Cydia安装)
1
2
3
4
5
6
7
8
9wget [http://apt.saurik.com/debs/cycript_0.9.594_iphoneos-arm.deb ](https://links.jianshu.com/go?to=http%3A%2F%2Fapt.saurik.com%2Fdebs%2Fcycript_0.9.594_iphoneos-arm.deb)
wget [http://www.tateu.net/repo/files/net.tateu.cycriptlistenertweak_1.0.0_iphoneos-arm.deb ](https://links.jianshu.com/go?to=http%3A%2F%2Fwww.tateu.net%2Frepo%2Ffiles%2Fnet.tateu.cycriptlistenertweak_1.0.0_iphoneos-arm.deb)
wget [http://www.tateu.net/repo/files/net.tateu.cyrun_1.0.5_iphoneos-arm.deb](https://links.jianshu.com/go?to=http%3A%2F%2Fwww.tateu.net%2Frepo%2Ffiles%2Fnet.tateu.cyrun_1.0.5_iphoneos-arm.deb)
dpkg -i cycript_0.9.594_iphoneos-arm.deb
dpkg -i net.tateu.cycriptlistenertweak_1.0.0_iphoneos-arm.deb net.tateu.cyrun_1.0.5_iphoneos-arm.deb通过cyrun进入cycript
1
2cyrun -n SpringBoard -e
// -n表示SpringBoard为进程名字,-e表示使cycript能注入到SpringBoard进程中退出cycirpt
1
21. control 加 D,退出cycript
2. 执行 cyrun -n SpringBoard -d,将cycript从之前的进程中抽离出来,才能将cycript注入另一个进程噢。
Cycript使用
打印view层级数
1 | [UIApp.keyWindow recursiveDescription] |
筛选
1 | choose(UIViewController) |
查看对象的缩影成员变量
1 | *对象 |
编译
1 | clang test.c // 编译c语言文件为可执行文件 |
查看文件信息
1 | file Test |
查看可执行文件支持架构
1 | lipo -info Test |
拆分二进制文件架构
1 | lipo Test -thin armv7 -output Test_armv7 |
合并二进制文件
1 | lipo -create Test_arm64 Test_armv7 -output Test2 |
Mach-O基本结构
1 | Header |
验证可执行文件是否被加壳
使用MachOView 查看Load Commands 中LC——ENCRYPTING_INFO 中 Crypt_ID 是否为0 // 0未加密
otool -l Test | grep Crypt // cryptid 为0 则未加密
APP砸壳
APP砸壳使用的工具
Clutch (http://github.com/KJCracks/Clutch/releases)
使用方法:
将Clutch文件拷贝到iPhone的/usr/bin目录
注:如果在iPhone上执行Clutch指令,权限不够,需赋予“可执行权限” chmod +x /usr/bin/Clutch
1
2Clutch - i // 获取加壳应用列表
Clutch -d + 列表序号dumpdecrypted(https://github.com/stefanesser/dumpdecrypted/)
在下载后的dumpdecrypted目录执行
make
,会执行Makefile文件自动编译出dumpdecrypted.dylib动态库将动态库文件拷贝到iPhone上(如果是root用户,建议放/var/root目录)
1
2
3在/var/root目录中执行
DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib app可执行文件路径
脱壳的App会生成在/var/root/目录下
iOS12真的是对逆向不太友好,解决了各种kill 9之类的问题之后,你会发现上面的方法都砸壳失败了。最终使用CrackerXI
解决
flexdecrypt (iOS12之后砸壳可用)
首先连接到越狱的iPhone上,然后使用wget命令下载最新的deb(wget自行安装):
1
iPhone:/tmp root# wget https://github.com/JohnCoates/flexdecrypt/releases/download/1.1/flexdecrypt.deb
然后直接安装:
1
2
3
4
5
6iPhone:/tmp root# dpkg -i flexdecrypt.deb
Selecting previously unselected package flexdecrypt.
(Reading database ... 3858 files and directories currently installed.)
Preparing to unpack flexdecrypt.deb ...
Unpacking flexdecrypt (1.1) ...
Setting up flexdecrypt (1.1) ...安装完之后就可以使用了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16iPhone:/tmp root# flexdecrypt
Error: Missing expected argument '<file>'
OVERVIEW: A tool for decrypting apps and Mach-O binaries. Based on the Flex 3
jailbreak app's source code.
USAGE: flex-decrypt <subcommand>
OPTIONS:
--version Show the version.
-h, --help Show help information.
SUBCOMMANDS:
file (default) Decrypt file.
See 'flex-decrypt help <subcommand>' for detailed help.看描述,flexdecrypt应该不如clutchname智能,因此只能先cd到要砸壳的app目录下,然后再进行砸壳,具体如何找App的路径可以参考之前的博客,这里以砸Quantumult为例:
1
2
3
4
5iPhone:/tmp root# cd /var/containers/Bundle/Application/
iPhone:/var/containers/Bundle/Application/ root# cd 6B8B93D5-DB46-4AAE-A264-F1C93A689B65
iPhone:/var/containers/Bundle/Application/6B8B93D5-DB46-4AAE-A264-F1C93A689B65 root# cd Quantumult.app/
iPhone:/var/containers/Bundle/Application/6B8B93D5-DB46-4AAE-A264-F1C93A689B65/Quantumult.app root# flexdecrypt Quantumult
Wrote decrypted image to /tmp/Quantumult可以看到静态砸壳的速度是很快的,基本秒出,但是只有一行输出,告诉了你脱壳文件的位置,使用scp命令将文件取出:
1
2
3
4
5
6
7
8➜ ~ scp -P 2222 root@127.0.0.1:"/tmp/Quantumult" ~/Desktop
root@127.0.0.1's password:
Quantumult 100% 3235KB 34.9MB/s 00:00
➜ ~ cd Desktop
➜ Desktop otool -l Quantumult| grep crypt
cryptoff 16384
cryptsize 2703360
cryptid 0Frida
可能是iOS12之后最好用的砸壳工具了,具体方法看另一个文档
Clutch 解决iOS 12 中kill 9
iOS12中似乎因为越狱不完美导致自己添加的可执行文件不受信任,报错kill: 9 ,其他可执行文件遇到kill 9 也可按照此方法尝试解决
可执行下面的代码添加信任
1 | safe place to work in |
Theos 使用
安装签名工具
1 | brew install ldid |
配置环境变量
1 | vim ~/.bash_profile |
clone theos
1 | git clone --recursive https://github.com/theos/theos.git $THEOS # $THEOS 是指定安装目录为上面配置的THEOS环境变量 |
编写tweak代码
创建项目
1 | nic.pl # 选择tweak项目 |
配置Makefile
1 | 新增设备ip 端口 |
Logos语法
1 | %hook %end // hook一个类的开始和结束 |
类/协议/方法 未定义报错解决办法
1 | # 声明类 |
添加资源文件
新建layout文件夹
项目安装时会按照layout文件夹中目录结构安装到手机根目录
建议资源文件路径: Library/PreferenceLoader/Preference/XXXX/
1 | // 资源文件推荐路径 /Library/PreferenceLoader/Preferences/ |
logify.pl
可以将一个头文件快速转换成一家包含打印信息的xm文件
logify.pl xx.h > xx.xm
// 打印信息太多,可将%log 换成 NSStringFromSelector(_cmd)
注意点:
删掉__weak
删掉inout
删掉协议 比如
或声明协议 @protocol XXXDelegate, XXXXDelegate; 删掉-(void).cxx_destruct{…}
删除HBLog(@”=0x%x,(unsigned int)r”)或改为HBLog(@”=0x%@,r”)
替换类名为void, 比如将XXPerson *替换为void *
- 或者声明一下类信息@class XXPerson: NSObject;
编译安装
1 | make // 编译Tweak代码为动态库 *.dylib |
插件将安装在/Library/MobileSubstrate/DynamicLibraries文件夹中
- *.dylib -> 编译后的Tweak代码
- *.plist -> 存放着需要hooc的APP ID
iOS 命令行工具开发
命令行工具的本质
- 可执行文件
- 和App内部可执行文件差不多
权限问题
1 | 1.导出权限文件 >覆盖 >> 追加 |
开发方法
修改main函数 return 0
删除UIApplication相关方法
删除其他资源文件
在main函数中编写代码
编译
取出编译好的.app文件中的可执行文件,复制到iPhone即可运行
Xcode 调试
编译器发展历程: GCC->LLVM
调试器发展历程: GDB->LLDB
Debugserver 一开始在Xcode里,当手机连接Xcode时会安装到iPhone上(/Develpoer/user/bin/debugserver)
Xcode调试的局限性: 一般只能调试通过Xcode安装的App
Xcode调试App的原理
Xcode 上的LLDB
将指令传送到手机上的debugserver
,debugserver协助LLDB调试App。
动态调试任意APP
debugserver权限问题
- 默认情况下,/Developer/usr/bin/debugserver缺少一定的权限,只能调试Xcode安装的APP,无法调试其他APP(比如来自APP Store的APP)
- 如果希望调试其他APP,需要对debugserver重新签名,签上2个调试相关的权限
- get-task-allow
- task_for_pid-allow
- run-unsigned-code
- 将重签名的debugserver 放入 /usr/bin 目录
签名方法:
- 通过ldid签名
1 | ldid -e debugserver > debugserver.entitlements # 将debugserver权限导出 |
- 通过codesign签名
1 | 查看权限信息 |
调试方法
让debugserver附加到某个APP进程
1 | 方式一 将debugserver附加在一个已启动的进程上 |
使用LLDB连接debugserver
- 启动LLDB
1 | lldb |
- 连接debugserver服务
1 | (lldb) process connect connect: //手机IP地址: debugserver服务端口号 |
- 使用LLDB的c命令让程序先继续执行
1 | (lldb) c |
- 接下来就可以用LLDB命令调试APP了
- 退出连接
1 | (lldb) process detach |
常用的LLDB命令
1 | debugserver -x auto *:端口号 APP的可执行文件路径 |
获取偏移地址
1 | (lldb) image list -o -f |
遇到的问题
lldb连接debugserver时报错 error: rejecting incoming connection from ::ffff:127.0.0.1 (expecting ::1)
1 | sirde-iPhone:~ root# debugserver_arm64 *:10011 -a neteasemusic |
解决办法
使用ip地址替换 * 和localhost
手机端:
1 | sirde-iPhone:~ root# debugserver 127.0.0.1:10011 -a neteasemusic |
电脑端:
1 | (lldb) process connect connect://127.0.0.1:10011 |
mac lldb提示ImportError: cannot import name _remove_dead_weakref
1 | ➜ ~ lldb |
查看是否安装了python和python@2
1 | brew list |
remove 多余的 python@2
1 | brew remove python@2 --ignore-dependencies |
debugserver 在 iOS 12遇到的坑
因iOS12为不完美越狱,开发中总会遇到各种困难 kill:9,可通过如下方法解决
从/Developer/usr/bin/debugserver取出debugserver (或使用其他工具复制到电脑)
1
2cp /Developer/usr/bin/debugserver /var/root/
scp root@ip:/var/root/debugserver ./对debugserver进行瘦身,抽取arm64架构二进制文件
1
lipo -thin arm64 debugserver -output debugserver_arm64
复制debugserver_arm64到手机usr/bin目录 (可使用其他工具复制)
1
scp debugserver_arm64 root@ip:/usr/bin/debugserver_arm64
用ldid对debugserver进行签名 (也可在在电脑中签名后复制到手机)
1
2// uncOver越狱会提供debugserver.xml在/usr/share/entitlements/debugserver.xml
ldid -S/usr/share/entitlements/debugserver.xml /usr/bin/debugserver_arm64使用inject命令 (貌似是添加信任)
1
inject /usr/bin/debugserver_arm64