iOS逆向笔记
iOS系统安全架构
- 安全启动链
- 信任链:系统启动 -> boot rom -> LLB -> iBoot -> kernal
- 系统软件授权
- 固件 -> cpu -> itunes ==> 服务器验证
- 低版本服务器返回验证许可,可通过保存shsh绕过验证
- 高版本返回验证许可+随机串
- 固件 -> cpu -> itunes ==> 服务器验证
- 应用代码签名
- 所有可执行代码(动态库,动态资源)运行时验证签名
- 运行时进程安全
- 沙盒:/var/mobile/Containers/Data/Application/[GUID]
- DEP
- ASLR
- 数据加密保护
- 硬件秘钥 + 密码秘钥 -> 类秘钥
- 硬件秘钥 -> 文件系统秘钥
- 类秘钥 + 文件系统秘钥 -> 文件秘钥 => 文件内容
越狱
- Cydia Substrate
- MobileHooker
- MobileLoader
- safe mode
- ssh连接ios设备
openssh
- ssh root@ip
通过usb连接:
usbmuxd -> tcpreplay.py -t 22:xx
brew install libimobiledevice -> iproxy 2222 22
- ssh root@localhost -p xx
- 配置免密码登录越狱设备
ssh-keygen -t rsa -P ''
ssh-copy-id -i /Users/username/.ssh/id_rsa root@ip
或者安装sshpass自己设置密码:
brew install https://raw.githubusercontent.com/kadwanev/bigboybrew/master/Library/Formula/sshpass.rb
- 终端输入中文
cd /var/root
touch .inputrc
echo 'set convert-meta off' >> .inputrc
echo 'set meta-flag on' >> .inputrc
echo 'set output-meta on' >> .inputrc
echo 'set input-meta on' >> .inputrc
- 插件
- ps:安装adv-cmds
- 绕过app签名:安装appsync
- 文件显示:安装apple file conduit 2
- fileza
越狱工具 next.tweakboxapp.com
app文件结构和构建
- 查看符号表:nm -nm
- 依赖库、汇编等:otool -L / -tV
- 从源代码到ipa的构建过程
数据存储
- property list
- plutil -convert xml1 xx -o xx.plist
- User Defaults
- sandbox -> Library -> Preferences -> xx.plist
- Archive
- Database
- sqlite
- keyChain
Runtime
Hook
Method Swizzle
针对objective-C,利用runtime,替换Dispatch table中SEL和IMP的对应关系。
fishhook
rebind_symbols:遍历查找懒加载表和非懒加载表的符号并替换地址。
Cydia Substrate
- MSHookMessageEx -> objC
- replace Objective-C message implementations
- MSHookFunction -> c
- hijack native code to your own implementation
- http://iphonedevwiki.net/index.php/Cydia_Substrate
- MSHookMessageEx -> objC
ARM汇编
push {r0} <==> str r0,[sp,#-4]!
pop {r0} <==> ldr r0,[sp],#4
汇编使用intel模式:https://github.com/vadimcn/vscode-lldb/issues/87
模拟器使用x86架构,32位入栈。64位rdi、rsi、rdx、rcx、r8、r9,多余参数入栈。
真机arm架构,32位r0-3,64位w0-8。
Mach-O
- 文件架构
lipo -info whatsApp
file whatsApp
Header
otool -hv whatsApp
MachOView
- 魔数
- 通用格式:0xcafebabe
- armv7:0xfeedface
- arm64:0xfeedfacf
- 文件类型
- OBJECT:1
- EXECUTE:2
- DYLIB:6
- 魔数
Load commands -> n * Segment
otool -lv whatsApp
- (lldb) image list -e -f
- Load commands -> LC_SEGMENT(_TEXT) -> VM address
- 加载地址 + 段虚拟地址 = 文件加载地址
Data -> n * Section
Mach-O动态链接(延迟加载)
Code Signature
- codesign -dvvvv whatsApp
App签名
- 查看加密标识:
- otool -l whatsApp | grep crypt
- 查看电脑中证书
- security find-identity -v -p codesigning
- 获取描述文件(embedded.mobileprovision)
- 苹果官网获取
- 新建工程真机安装后在包中获取
- 查看:security cms -D -i embedded.mobileprovision
- 拷贝至要签名文件中
- 生成授权文件
- security cms -D -i embedded.mobileprovision > entitlements_full.plist
- /usr/libexec/PlistBuddy -x -c ‘Print:Entitlements’ entitlements_full.plist > entitlements.plist
- 重签名
- codesign -fs “iPhone Developer: xxx(2中证书名)” –no-strict –entitlements=xxx(4中授权文件) Payload/xxx.app
- 如果有extension,可删可重签名
- 如果新加动态库,需要签名
- codesign -fs “iPhone Developer: xxx(2中证书名)” –no-strict –entitlements=xxx(4中授权文件) Payload/xxx.app
- 压缩为ipa
- zip -qr target.ipa Payload
动态库
- clang编译objec并签名,放入Library->load dylibrary->DynamicLibaries中
- 导出和隐藏符号
- static
- export_list
- -fvisibility=hidden
- 函数调用顺序
- __attribute__((constructor))
- main
- __attribute__((destructor))
- 基于c++动态库
- 基于oc动态库
- 注入可执行文件
- LC_LOAD_DYLIB
- 工具: insert_dylib
- 查看:otool -L
应用砸壳
- 查看加壳
- otool -l xx(mach-o) | grep cryptid
- 从itools导出ipa
- 利用scp导出执行文件(打开app,ps找到进程)
- 砸壳工具
- dumpdecrypted
- 查找Document路径:
- cycript -p WeChat
- NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)[0]
- 查找Document路径:
- AloneMonkey/dumpdecrypted
- Clutch
- frida-ios-dump
class-dump
https://github.com/nygard/class-dump
官方工具修正后编译:
// CDObjectiveC2Processor.m 224h
objc2Class.data = value & ~3; //error: value & ~7;
./class-dump mach-o_file -H -o ./Headers
Reveal
cydia中添加BigBoss源安装Reveal2Loader,开启reveal使用
高版本reveal需要将RevealServer(help->show reveal library in finder->ios library)重命名为libReveal.dylib,并和libReveal.plist一同放入ios的Library->MobileSubstrate->DynamicLibraries中
plist文件内容:
{ Filter = { Bundles = ( "bundleID" ); }; }
cycript
静态分析
- 工具
- hopper
- IDA
- arm汇编,结构体!
动态调试
- 处理debugserver
- 下载/Developer/usr/bin/debugserver
- 授权文件entitlements.plist内容:
- com.apple.springboard.debugapplications
- run-unsigned-code
- get-task-allow
- task_for_pid-allow
- 签名
- 上传至/usr/bin/debugserver
- lldb + debugserver
连接
- 映射端口: python tcpreply.py -t 22:2222 1234:1234
- 手机:debugserver *:1234 -a WhatsApp
- pc: llvm –> process connect connect://localhost:1234
调试指令
- image list -o -f
- b -[xx xxx]
- br s -a 0xaaaaaa
- po $r0
- p/x $r0
- x/s $r1
- register read
- memory read
- br list / br com add 1.1 : DONE
or
使用 MokeyDev
定位button的action事件
- 传统:
- [btn allTargets] //xxx
- [btn allControlEvents] //yyy
- [btn actionsForTarget:xxx forControlEvent:yyy]
- 使用chisel:
- pviews
- pactions btn
Theos
- tweak
- 执行$THEOS/bin/nic.pl创建工程
- 编写hook代码
```
%hook ViewController
-(void)clickme:(id)sender{
NSLog(@"Click me hooked !!!");
%log;
%orig; //执行原方法
}
%end
```
- 编译 * make * make package * make install
- iOSOpenDev(13年没更新了)
- MonkeyDev
查看Log输出
安装libimobiledevice工具(需要usbmuxd):
brew install --HEAD libimobiledevice
使用如下命令查看输出Log:
idevicesyslog | grep 'xxx'
或者使用自带的 console.app 程序查看。
Oplayer lite 去广告
- 使用frida-ios-dump砸壳
- 用class-dump导出头文件
- 用reveal定位广告view
- 用xcode lldb调试找到广告的addSubview:调用位置
- 使用hooper静态分析逻辑
- 用Theos写插件改变逻辑去广告
SnapChat 消息
- 使用cycript或者reveal找到view对应的viewcontroller
- 通过theos的logify.pl hook一个类所有方法找到具体调用
- 通过lldb打印具体调用的执行堆栈 – bt
- tweak找不到类可以通过声明@class xxx解决
迁移到非越狱设备
Frida
数据加密
- 字符串加密
- 数据存储加密
- 网络数据加密
反调试与反注入
反调试
ptrace
ptrace(PT_DENY_ATTACH, 0, 0, 0);
void *handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW); ptrace_ptr_t ptrace_ptr = (ptrace_ptr_t)dlsym(handle, "ptrace"); ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
sysctl
使用sysctl获取当前进程,标志位p_flag对比P_TRACED
BOOL isDebuggerPresent(){ int name[4]; struct kinfo_proc info; size_t info_size = sizeof(info); info.kp_proc.p_flag = 0; name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = KERN_PROC_PID; name[3] = getpid(); if(sysctl(name, 4, &info, &info_size, NULL, 0) == -1){ NSLog(@"sysctl error..."); return NO; } return ((info.kp_proc.p_flag & P_TRACED) != 0); }
syscall
syscall(26, 31 , 0, 0, 0);
反反调试
- hook ptrace
- hook dlsym
- hook syscall
- hook sysctl
反注入
编译加入标志位
-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null
原理,增加__RESTRICT这个section
dylib的注入一般是通过DYLD_INSERT_LIBRARIES这个环境变量来实现的,在dyld源码中:
case restrictedBySegment: dyld::log("main executable (%s) has __RESTRICT/__restrict section\n", sExecPath); break;
故存在该分段即可忽略DYLD_开头的环境变量,从而防止dylib注入。
检测加载动态库路径中是否有DynamicLibraries(测试没用)
BOOL isInjected0(){ int count = _dyld_image_count(); if(count > 0){ for(int i=0; i<count; i++){ const char* dyld = _dyld_get_image_name(i); if(strstr(dyld, "DynamicLibraries")){ return YES; } } return NO; } return NO; }
检测是否存在环境变量DYLD_INSERT_LIBRARIES(测试有用)
BOOL isInjected1(){ char* env = getenv("DYLD_INSERT_LIBRARIES"); if(env) return YES; return NO; }
反反注入
修改mach-o文件中__RESTRICT字段中restrict字符串为其他字符串
混淆
- 类名和方法名混淆
宏定义替换
- ios-class-guard
直接替换MachO文件
- 修改 __objc_classname
- 修改 __objc_methname
- OLLVM