文章目录
debugserver 连接APP
$sh usbLogin.sh
链接手机,root# cd /Developer/usr/bin
可以看的目录下有个debugserver,在链接之前可以$ps -A
查看进程。
$ ./debugserver *:12346 -a WeChat
root# ./debugserver
运行debugserver*:端口号
:使用手机的某个端口提供服务-a 进程
:连接的APP (进程ID,进程名称–MachO文件的名称)
LLDB 启动
LLDB 启动原理
- XCode安装程序包里==/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport==目录下,每个版本有个DeveloperDiskImage.dmg安装包,联机调试的时候会安装到手机
$lldb
开启LLDB- lldb连接debugserver,debugserver选择性调试某个App
(lldb) process connect connect://手机IP地址:debugserver服务的端口
连接成功,程序就被断住的。
LLDB下断点
查看手机砸壳状态
root# Clutch -i
;砸壳root# Clutch -b 2
,其中“2”为查看的标示。拷贝MachO文件WeChat.decrypted到电脑桌面
$class-dump -H WeChat.decrypted -o ./Headers/
$sh usbLogin.sh
链接手机,root# cycript -p WeChat
进入cycript(如果连不了去(lldb) command + c
),cy# @import test
加载命令查看当前视图cy# currentVC()
用Hopper软件分析MachO文件WeChat.decrypted, 找当前视图类的onNext方法的地址,加上
(lldb) image list
查看到的进程地址(lldb) b 0x1027DA3A8
下断点,(lldb) breakpoint list
可以查看到新下断点。(lldb) po $x0
输入即下断点的类(lldb) exit
退出LLDB
命令行工具的权限文件
拷贝debugserver,查看文件类型
$file debugserver
其为可执行二进制文件导出权限文件
$ldid -e 可执行文件 > 文件名称.entitlement
打开.entitlement文件添加两个关键字段:
get-task-allow YES
task_for_pid-allow YES签名权限
$ldid -Sdebugserver.entitlement debugserver
拷贝debugserver到root的==/Device/usr/bin==目标了下
root# debugserver
执行
可执行文件
- 创建Single View App,删除界面相关文件,并对main.m删除不需要的代码,添加printf语句,编译找到可执行文件,拷贝到手机==/usr/bin==目录,
$ sh usbLogin
链接手机,到目录下./文件名
执行,发现root# Permission denied
并没有权限,root# chmod +x 文件名
加上权限,便可以执行。 - 命令行参数,其实就是可执行文件的argv[],其中
argv[0]=文件名
反调试ptrace
- debugserver用ptrace(process trace进程跟踪)函数,它提供了一个监听控制另外一个进程,并且可以检查被控制进程的内容和寄存器里面的数据。具体可参照《程序员的自我修养》一书
- 新建命令行工程,
#import <sys/ptrace.h>
输入ptrace函数,去头文件,拷贝头文件内容。张贴到Single View App工程的MyPtraceHeader.h - 调用ptrace函数
ptrace(PT_DENY_ATTACH, 0, 0, 0)
,此时可以联机编译,但是运行会崩溃。但是我们发现,越狱手机可以直接运行,并且控制台设备正常输出内容。这是因为此时此程序不能被Xcode附加调试。同样$sh usbConnet
和$sh usbLogin
链接手机,root# debugserver *:12346 -a 进程ID
出现Segmentation fault
。支付宝、微信做了类似的防护。
破解ptrace反调试
- 添加framework,注入动态库,hook ptrace方法
- 因为ptrace是系统函数,会保留函数符号,需要重新绑定。在注入代码里
#import fishHook.h
- 定义指针,保存原理的函数地址,定义自己的函数,在
+load
时交换,即hook。
//定义指针,保存原来的函数地址
int (*ptrace_p)(int _request, pid_t _pid, caddr_t _addr, int _data);
//定义自己的函数
int my_ptrace(int _request, pid_t _pid, caddr_t _addr, int _data){
if (_request != PT_DENY_ATTACH) {//如果不是拒绝连接,就保持调用
return ptrace_p(PT_DENY_ATTACH,_pid,_addr,_data);
}
//如果是拒绝加载,就不执行直接return
return 0;
}
+(void)load
{
//交换
struct rebinding ptraceBd;//fishHook的绑定结构体
ptraceBd.name = "ptrace";//函数名称
ptraceBd.replacement = my_ptrace;//新函数地址
ptraceBd.replaced = (void *)&ptrace_p;//原始函数地址的指针
//弄一个数组,放fishHook的绑定结构体
struct rebinding bindings[] = {ptraceBd};
//fishHook的重绑定函数
rebind_symbols(bindings, 1);
}
- 注入后又可以正常运行调试了。支付宝,微信如果只是这样的防护那也太low了。你是对的,通过framework防护调试,此方法失效。道高一尺,魔高一丈,神高于一切!
通过framework防护调试
- 动态库加载顺序,决定调用顺序。并且在应用程序调用之前。
- 将反调试内容放置framework,就能防止别人破坏反调试,达到调试应用的目的。
- 通过fishHook反Hook,就是使用最快调用,达到调用自己的目的。通过ptrace,反调用,达到防护效果,使用了一样的原理。