一、LLDB 原理
我们调试工程的时候使用LLDB, 其原理如下:
LLDB原理
其中, debugserver
原本是不存在与非越狱手机的, Xcode在首次安装APP到手机的时候向该手机安装了debugserver
. 该debugserver
来自于Xcode包中的设备支持文件--DeviceSupport
中.
二、越狱设备中不通过Xcode调试APP
设备中安装debugserver的两种方式:
1. 通过Xcode安装
通过Xcode安装的
debugserver
在手机的路径为:Developor/usr/bin/debugserver
通过Xcode安装的
debugserver
只能调试你自己的APP
2. 拷贝debugserver到手机
① 拷贝手机中的debugserver
文件到电脑, 导出权限文件
ldid -e dubugserver > debugserver.entitlements
② 修改权限--修改权限后才能调试所有APP
可以用Xcode打开权限文件, 在里面添加
<key>com.apple.springboard.debugapplications</key>
<true/>
<key>get-task-allow</key>
<true/>
<key>task_for_pid-allow</key>
<true/>
<key>run-unsigned-code</key>
<true/>
③ 重签权限文件
ldid -Sdebugserver.entitlements debugserver
④ 拷贝重签的deubgserver
到手机. 可以拷贝到/usr/bin/
目录下, 这样就全局可用了. 另外, /developer
目录是不可写的.
⑤ 给debugserver
可执行权限
chmod +x debugserver
3. 开启LLDB调试
-
debugserver
链接要调试的APP
iPhone# debugserver IP:PORT -a 进程名称/进程ID
也可以写为
iPhone# debugserver *:PORT -a 进程名称/进程ID
其中*表示接收来自任何IP的数据, 也可以指定IP, PORT为将监听的本机端口,接收来自Mac的命令.
- 开启
LLDB
lldb
- LLDB链接debugserver
(lldb) process connect connect://手机IP:debugserver服务端口
4 . 继续调试
刚链接成功的时候, 进程是被停止的, 使用LLDB命令c
开始调试
- 退出
exit
三、反调试
使用ptrace
函数反调试
debugserver
之所以可以调试APP, 是依赖一个系统函数ptrace
(process trace 进程跟踪). 此函数提供了一个进程监听控制另外一个进程, 并且可以检查被控制进程的内容和寄存器里面的数据. 可以用来实现断电调试和系统调用跟踪. iOS中没有提供此函数的头文件, 但不是私有API.
可以创建一个macOS工程或命令行工程导入头
#import <sys/ptrace.h>
然后在iOS工程中创建一个头文件, 进入sys/prance.h
头文件, 复制其内容到我们的iOS工程我们创建的头文件中.
/**
* request: 要做的事情
* pid: 要监听/操作的id
* addr: 为request代表的操作提供的地址
*/
ptrace(int _request, pid_t _pid, caddr_t _addr, int _data)
request
的值可以是:
#define PT_TRACE_ME 0 /* child declares it's being traced */
#define PT_READ_I 1 /* read word in child's I space */
#define PT_READ_D 2 /* read word in child's D space */
#define PT_READ_U 3 /* read word in child's user structure */
#define PT_WRITE_I 4 /* write word in child's I space */
#define PT_WRITE_D 5 /* write word in child's D space */
#define PT_WRITE_U 6 /* write word in child's user structure */
#define PT_CONTINUE 7 /* continue the child */
#define PT_KILL 8 /* kill the child process */
#define PT_STEP 9 /* single step the child */
#define PT_ATTACH ePtAttachDeprecated /* trace some running process */
#define PT_DETACH 11 /* stop tracing a process */
#define PT_SIGEXC 12 /* signals as exceptions for current_proc */
#define PT_THUPDATE 13 /* signal for thread# */
#define PT_ATTACHEXC 14 /* attach to running process with signal exception */
#define PT_FORCEQUOTA 30 /* Enforce quota for root */
#define PT_DENY_ATTACH 31
#define PT_FIRSTMACH 32 /* for machine-specific requests */
其中#define PT_DENY_ATTACH 31
表示拒绝调试. 那么只要在工程中调用如下代码就可以阻止调试:
+ (void)load {
ptrace(PT_DENY_ATTACH,getpid(),0,0);
}
使用sysctl
函数反调试
通过sysctl
函数可以得知APP是否被调试, 当我们发现APP被调试时, 可以执行exit
.
#import <sys/sysctl.h>
bool isDeebuger() {
// 控制码
int name[4]; // 里面放字节码, 查询信息
name[0] = CTL_KERN; // 内核
name[1] = KERN_PROC; // 查询进程
name[2] = KERN_PROC_PID; // 通过id查询, 传递的参数是进程id
name[3] = getpid(); // 拿到当前进程id
struct kinfo_proc info; // 结束进程查询结果的结构体
size_t info_size = sizeof(info); // 结构体的大小
int error = sysctl(name, sizeof(name)/sizeof(*name), &info, &info_size, 0, 0);
if (!error) {
// p_flag 的值转换为二进制, 假如从低位到高位第12位的值为1(0x800), 则正在被调试
if (info.kp_proc.p_flag & P_TRACED) {
return true;
} else {
return false;
}
}
return false;
}
使用sysctl
函数检测APP是否被调试, 最好是每隔一段时间检测一次.
反反调试
针对
ptrace
和sysctl
的反反调试参考MonkeyDev
. 使用的是fishhook
. 但是如果你的反调试代码是通过framework
优先加载的, 那么这里的反反调试无效.
网友评论