• LLDB调试详解--逆向开发


    一、前言

    今天讲述在苹果日常开发中一个装逼神器LLDB,是Xcode内置的动态调试工具. 在iOS系统程序开发中,会经常需要代码调试的追踪, 最常用的也是LLDB(low level debugger) .LLDB能更好的辅助开发者通过各种手段如修改变量进行测试,甚至能协助开发同学来定位bug. 

    LLDB是新一代高性能的调试器, 也是Mac OSX上Xcode的默认调试器, 支持在桌面和iOS设备模拟器上调试C,OC和C++以及Swift.

    二、帮助

    LLDB命令的格式如下:

    <命令名称> <命令动作> [-可选项 [可选项的值]] [参数1 [参数2...]]

    LLDB命令是由各部分空格分割, 如果参数是包含空格, 则需要双引号括起参数,如果参数本身中包含双引号或反斜杠, 就需要使用反斜杠来进行转义.

    LLDB命令是非常多的, 完全记录下来是不可能的, 而且还没有必要. 可以利用help命令查看相关LLDB命令的用法.如下:

      

    三、LLDB常见命令

     3.1 breakpoint指令

    示例Demo1 

      func test1(str: String) {
            self.test2(str: str)
        }
    
        func test2(str: String) {
            self.test3(str: str)
        }
    
        func test3(str: String) {
            print(str)
        }
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            self.test1(str: "zxy")
        }

    通过breakpoint set -n 某函数名,来给某函数设置断点

    通过breakpoint list 打印出断点列表

     如果想一次性来设置多个断点,也可以使用命令

     breakpoint set -n 某函数名, -n 某函数名, -n 某函数名……

    但是这样设置就会将这几个断点设置为一组,与上面不一样,一个个设置的.

    breakpoint delete来删除所有上次设置的断点

    breakpoint disable 断点Id: 将设置过的断点禁用,再次打印出breakpoint list 发现断点式disable的

    breakpoint set -r “字符串” 会遍历整个工程,只要含该字符串的方法、函数都会下断点

    breakpoint set -f 类名 -l 断点行数 会给该类名的具体行数加断点 

    breakpoint set -file 类名 --selector 方法名 会给该类名的具体方法加断点

     breakpoint command add 标号 :断点之后执行相应命令,以Done结束,类似于Edit breakpoint

    总结如下:

    3.2 流程控制

    在Xcode调试Debugger时,经常有看到界面

    对应的解释和意义如下图:

     对应的命令如下

     3.3 打印命令

    p语句动态执行语句,可以查看基本数据的类型值, 如果用p命令查看的是对象的话, 只会返回对象的指针地址, p后面可以接变量、常量还可以接表达式

    po语句: 打印对象的desc信息, 打印对象. 

    p和po的区别在于po会输出对应的值, p会返回返回值的类型及命令结果的引用名

    expression语句: 和p语句意思是一样的

     上面有&0,&1这样的符号,是指对象的一个引用. 在控制台上可以用这个符号来操作对应的对象.

    示例2

    -(NSMutableArray<Person *> *)models{
        if (!_models) {
            //arrayWithCapacity 节约内存。容量就是真实的内存中占用的大小。
            _models = [NSMutableArray array];
        }
        return _models;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        Person * p1 = [[Person alloc] init];
        p1.name = @"one";
        p1.age = 1;
        Person * p2 = [[Person alloc] init];
        p2.name = @"two";
        p2.age = 2;
        Person * p3 = [[Person alloc] init];
        p3.name = @"three";
        p3.age = 3;
        
        [self.models addObject:p1];
        [self.models addObject:p2];
        [self.models addObject:p3];
    }

     3.4 frame、bt、 up、 down

    frame select 断点排序值 

    frame variable :查看参数

    bt:查看堆栈

     再看示例1,点击test1,test2,test3 。对test1设置断点

    可以通过up和down命令来查看步骤

    up:向上查看

    down:向下查看

     3.5 thread、target

    thread info: 输出当前的线程

    thread return :不再执行下面的代码

    target stop-hook add -o  "frame  variable": 断点进入之后做的操作,这里是打印参数

    3.6 image指令 

     image lookup -address 查找崩溃信息

     image lookup -name 查看方法的来源

     image lookup -type 查看成员,可以查看某个类class的所有成员变量以及属性

     总结图如下:

    四、ASLR

    4.1 概述

    ASLR(Address space layout randomization) 是一种针对缓冲区溢出的安全保护技术,通过对栈、堆、共享库映射等线性区布局的随机化,通过增加攻击者预测目的预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到组织溢出攻击的目的。

    ASLR并不是苹果Mac与iOS特有的,其他主流的操作系统也已经实现了ASLR。

    4.2 讲解

    4.2.1 demo1代码

    - (void)viewDidLoad {
        [super viewDidLoad];
    }
    
    - (void)eatWithObjc:(NSString *)objc {
        NSLog(@"吃到了%@",objc);
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        [self eatWithObjc:@"小蘑菇炖鸡"];
    }
    
    @end

    运行App,然后利用Hopper disassembler v4查看eatWithObjc()函数的文件地址

    然后打开MachOView查看可执行文件,pagezero为MachO首地址

     通过image list 查看功能模块的地址,第一个为MachO地址

     然后我们讲解一下内容,基本概念

     4.2.2 demo2代码

    将断点断在a = 20,下面找一下全局变量放的位置。打印全局常量a在内存中的地址,以及MachO可执行文件的地址

     将两个地址相减,得到文件的偏移地址。0x0000000106ce8db0 - 0x0000000106ce5000 = 0x3DB0

    然后打开MachOView查看

    全局常量为10,找到MachOView的offset为0x3DB0,看Data LO为10,完美。

    过掉断点,发现a = 20了,再次查看内容,发现也已经为20

     五、Cycript

    Cycript 是由Cydia创始人Saurik推出的一款脚本语言,其混合了OC、JavaScript语法的解释器,也就意味着可以在一个命令中使用OC或者JavaScript,甚至两者并用,能够挂钩正在运行的进程,能够在运行时修改很多东西。

    提到解释器,我们来普及两个概念

    高级语言分为两个部分,解释型语言和编译型语言

    解释型语言:Python:直接将源代码放进内存里面

    编译型语言:OC:将源代码编译成可执行文件,运行在设备上

     

     总结

     LLDB功能是非常强大的, 上面仅仅是介绍了一些简单常用的命令, 还可以做进一步的探索. 下一篇我们将继续讲述LLDB的高级用法的操作, 使用LLDB操作指令可是开发装逼的一种神器, 快使用起来吧. 希望本篇博客对大家理解使用LLDB有所帮助,如果觉得还不错,给个点赞撒!!!

  • 相关阅读:
    【C++基础汇总】参数传递
    常用VC快捷键
    美股交易规则
    xpath 总结1
    【字符集】字符集和编码知识【转】
    【字符集】ASCII 表
    【win32编程学习】常用技巧总结
    【win32编程学习】 调用dll
    【win32编程学习】 创建自己的dll
    充实的生活
  • 原文地址:https://www.cnblogs.com/guohai-stronger/p/11940433.html
Copyright © 2020-2023  润新知