iOS 开发 Objective-C

iOS 底层 day 09 tweak %log logify

2020-08-01  本文已影响0人  望穿秋水小作坊

一、%log 的使用

%log 是 logo 的日志语法,可以 tweak 项目的方法内部,可以帮我们打印出许多信息

比如编写如下 hook 代码:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  %log;
  %orig;
}

我们可以得到如下日志,非常详细:

-[<QQRecommendViewController: 0x1160c5c00> tableView:<UITableView: 0x1169cf600; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x2829c2250>; layer = <CALayer: 0x28276dca0>; contentOffset: {0, -16}; contentSize: {375, 602.5}; adjustedContentInset: {64, 0, 49, 0}> didSelectRowAtIndexPath:<NSIndexPath: 0xc000000000a00116> {length = 2, path = 1 - 5}]

从上面的日志,我们可以获得许多信息:

基于上面的效果,我们有一个大胆的想法,如果我们把一个 '控制器' 里面的所有方法像上面,调用的时候,把详细日志打印出来,那么是不是我们就非常方法追踪我们需要的信息了呢?

二、logify.pl 的使用

基于我们对 %log 的猜想,logify.pl 这个工具已经帮我们实现了该功能。

logify.pl 会把我们指定 .h 文件里面的所有方法,包装打印日志,并且用 %orig 维持原有功能,生成一个 tweak 文件。

执行 logify.pl QQChatViewController.h > QQChatViewController.x 指令,生成 tweak 文件,QQChatViewController.x 部分内容如下:

%hook QQChatViewController
- (void)setNewestFeedRequestID:(long long )newestFeedRequestID { %log; %orig; }
- (long long )newestFeedRequestID { %log; long long  r = %orig; NSLog(@" = %lld", r); return r; }
%end

我们发送一条信息,就能得到如下调用链:

QQChatViewController 调用链

QQChatViewController.x 可能make会遇到的编译错误,我们一般做如下操作:

  1. 删掉 _weak
  2. 删掉 inout
  3. 删掉或者声明协议 @protocol xxxDelegate;
  4. 删掉 -(void).css_destruct{%log;%orig;}
  5. 声明缺失的类信息 @class xxPerson, xxCar;

三、动态调试

  1. 关于 GCC、GDB、LLVM、LLDB
  1. debugserver
  1. Xcode 调试 App 的原理


    Xcode 调试 App 的原理

四、如何让 LLDB 和 debugserver 能调试所有 APP

  1. 找到手机上 /Developer/usr/bin 目录下的 debugserver 可执行文件,导入 Mac 电脑中。
  2. 创建如下授权文件:debugserver.entitlements
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/ PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.springboard.debugapplications</key> <true/>
    <key>run-unsigned-code</key> <true/>
    <key>get-task-allow</key> <true/>
    <key>task_for_pid-allow</key> <true/>
</dict> 
</plist>
  1. 执行 ldid -Sdebugserver.entitlements debugserver 指令,把权限重新签名给 debugserver。
  2. 将 debugserver 放入 iPhone 的 /usr/local/bin 目录下,并 chmod +x debugserver 赋予可执行文件(为什么不覆盖原来 iPhone 上的呢?第一不影响原来 Xcode 的调用,第二该目录不能全局执行,第三该目录是只读目录)
  3. 至此,iPhone 上的 debugserver 配置完毕,原本逻辑是要使用 Xcode 调用 LLDB 来操纵 debugserver 的,但是 Xcode 的弊端是只能调试 Xcode 自己运行的项目,所以我们现在要使用 Mac 终端来控制 LLDB。
Mac 终端来控制 LLDB
  1. iPhone 终端执行 debugserver 192.168.0.187:10011 -a QQ 指令,命令行进入等待 192.168.0.187 来链接的提示:
iPhone:/usr/local/bin root# debugserver 192.168.0.187:10011 -a QQ
debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.87
 for arm64.
Attaching to process QQ...
Listening to port 10011 for a connection from 192.168.0.187...
  1. iPhone 终端执行lldb 进入 lldb 模式:成功链接会如下显示
carrotdeMacBook-Pro:~ carrot__lsp$ lldb
(lldb) process connect connect://192.168.0.67:10011
Process 21025 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x000000019632f0f4 libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap:
->  0x19632f0f4 <+8>: ret    

libsystem_kernel.dylib`mach_msg_overwrite_trap:
    0x19632f0f8 <+0>: mov    x16, #-0x20
    0x19632f0fc <+4>: svc    #0x80
    0x19632f100 <+8>: ret    
Target 0: (QQ) stopped.
(lldb)  

此时,debug 的应用程序会进入断点模式,会卡住。出入 c 回车,即继续。

五、debugserver 和 LLDB 链接可能遇到的问题

  1. debugserver 一输入监听指令,就退出:
iPhone:~ root# debugserver *:10011 -a ting
debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.87
 for arm64.
Attaching to process ting...
Listening to port 10011 for a connection from 127.0.01...
Failed to get connection from a remote gdb process.
Exiting.

解决方案:

上一篇 下一篇

猜你喜欢

热点阅读