一、背景
在「iOS 逆向入门 - TikTok 调试」文章中介绍了使用 MonkeyDev 工具对 TikTok 进行调试。使用同样的方法对抖音进行调试的过程中遇到了几个问题,在这里记录一下。
二、动态库注入失败
按照 TikTok 的方式运行后,发现控制台没有打印 insert dylib success
的信息,猜测动态库注入失败了,果然在编译信息的输出中找到相关错误打印:
在 MonkeyDev 的 change.log 中找到信息,尝试恢复使用 optool 工具注入动态库。
下载 optool 的二进制文件并复制到相应位置,然后修改以下代码:
# 注释原来的 MONKEYPARSER
# "$MONKEYPARSER" install -c load -p "@executable_path/Frameworks/lib""${TARGET_NAME}""Dylib.dylib" -t "${BUILD_APP_PATH}/${APP_BINARY}"
# 修改为 optool
OPTOOL="${MONKEYDEV_PATH}/bin/optool"
"$OPTOOL" install -c load -p "@executable_path/Frameworks/lib""${TARGET_NAME}""Dylib.dylib" -t "${BUILD_APP_PATH}/${APP_BINARY}"
重新编译运行后可发现控制台中出现 insert dylib success
信息,证明动态库已经注入成功。
三、绕过反调试
动态库注入成功后,发现控制台没有了任何输出,且 lldb 已经断开,证明抖音使用了某种反调试手段。
1、反调试常规手段
1)ptrace
ptrace
被常用于防止 lldb 依附,原理是一个进程只能被 ptrace
只能被一次,先于别人调用 ptrace
则可以防止别人依附。
ptrace
有几种方式进行调用:
- 通过
dlsym
调用 - 通过汇编调用;
- 通过
syscall
调用,syscall(26,31,0,0)
。
2)sysctl
通过 sysctl 去查看当前进程的信息,看有没有这个标记位即可检查当前调试状态。
bool isBeingAttach() {
size_t size = sizeof(struct kinfo_proc);
struct kinfo_proc info;
int ret = 0, name[4];
memset(&info, 0, sizeof(struct kinfo_proc));
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PID;
name[3] = getpid();
if (ret == (sysctl(name, 4, &info, &size, NULL, 0))) {
return ret != 0;
}
return (info.kp_proc.p_flag & P_TRACED) ? YES : NO;
}
2、反反调试常规手段
我们知道了反调试的常用函数,我们可以使用 fishhook hook 这些函数,达到反反调试的效果。
MonkeyDev 已经为我们写好了相关实现,我们打开注释即可:
3、进一步
打开上面的注释重新运行后,lldb 依然依附失败,说明抖音有更进一步的反调试手段。
通过网上查阅资料,有以下解题套路:
1)判断反调试代码的位置
Xcode 上添加 AppDelegate 的符号断点:
-[AppDelegate application:didFinishLaunchingWithOptions:]
运行后断点依然失败,证明反调试代码在 didFinishLaunchingWithOptions
之前。
2)利用 IDA 进行分析
把二进制文件拖入 IDA 后进行分析,在 start 函数中的 0x0000000109640CF4~0x0000000109640D00 就是反调试代码,相当于调用了上面提到的 syscall(26,31,0,0)
,最终就是调用了 ptrace
函数。
3)绕过反调试代码
- lldb 中执行
image list -o -f
打印链接的库,其中第一个地址则是 ASLR 的偏移地址。
运行时基地址(0x000000010BEC8D00) = ASLR 偏移地址(0x0000000002888000) + 基地址(0x0000000109640D00)
-
添加地址断点,
breakpoint set -a 0x000000010BEC8D00
; -
断点到该地址后,执行
register write $x1 0
,修改 x1 寄存器值。
继续运行后则发现已经成功依附到 lldb。
ASLR 偏移地址每次 App 运行都会被修改,所以每次运行都要进行上面的操作。