美文网首页
Mac调试工具LLDB和Frida

Mac调试工具LLDB和Frida

作者: CoderShmily | 来源:发表于2024-06-12 13:32 被阅读0次

    LLDB

    // 运行app
    lldb /Users/mac/Desktop/MacTest.app
    lldb /Users/mac/Desktop/confuse_mac.app
    
    // 2个打印的地址相差0x100000000 调试mac应用好像没用,直接用IDA Hopper显示的地址就行
    // IDA官网的免费版本不支持arm (下载windows破解wine打包的网上IDA Pro 8.3版本)导致之前看到的函数地址和Hopper不一样
    image list 打印的基地址: 0x102a94000
    image list -o -f打印的地址: 0x002a94000 
    // 直接打印第1个镜像
    po _dyld_get_image_vmaddr_slide(0)
    
    // 默认是没运行 r运行
    r
    
    // 暂停
    ctrl + c
    
    // 继续运行
    c
    
    // 断点 -a的0x可以省略
    b -[ViewController getString:]
    b +[ViewController hello]
    b [AFZLanguageDecemberSplints lowFileElectrodes:]
    br s -a 100002e84
    br s -a  0x100000000+0x100017458
    
    // 条件断点
    breakpoint set --name lowFileElectrodes:
    breakpoint modify -c '(BOOL)objc_msgSend((id)$x2, @selector(isEqualToString:), @"token")'
    breakpoint modify -c '(BOOL)objc_msgSend((id)$x2, @selector(containsString:), @"设备%d名称:%@ 到期时间:%@,允许版本:%@")'
    
    // 列出所有断点
    br list
    
    // 删除断点 指定br list列出的序号可以删除
    br delete 2
    
    // 打印堆栈
    bt
    
    // frame select堆栈ID
    // 展示当前作用域下的参数和局部变量:frame variable
    //反汇编地址: dis -s +地址  当我们调试过程中遇到crash,我们可以通过:dis -s +地址 命令来反汇编地址,来排查导致crash的具体原因。
    
    // 写入内存指令临时覆盖掉逻辑
    register read x0
    register write x0 0
    po (char *)0x000060000374ca80
    po $x0
    // 每次断点都执行一下po $x0
    target stop-hook add -o "po $x0"
    
    hread step-over 、 next 、n 单步运行,把子函数当做整体一步执行
    thread step-in 、step、 s 单步运行,遇到子函数会进入子函数
    thread step-inst-over、 nexti、 ni 单步运行,把子函数当做整体一步执行
    thread step-inst、 stepi 、si 单步运行,遇到子函数会进入子函数
    thread step-out 、finish 直接执行完当前函数的所有代码,返回到上一个函数(遇到断点会卡
    

    LLDB自定义打印方法和Block参数 脚本放到最后面

    参考 自定义打印方法参数的LLDB命令lldb快速打印Objective-C方法中block参数的签名

    • 若是自动加载,需要vim ~/.lldbinit,然后里面就输入以下命令
    command script import ~/custom.py
    
    • 若是临时加载,只需在LLDB模式下输入command script import ~/custom.py

    // Debug是文件名,objargs_func是文件下边的方法名就是具体lldb参数实现,最后的objargs是lldb 环境敲得命令

    def __lldb_init_module(debugger, internal_dict):
        debugger.HandleCommand('command script add -f Debug.objargs_func objargs')
    

    LLDB插件Chisel

    // Chisel是Facebook发布的一个lldb插件,能够帮助调试 
    使用说明 https://www.jianshu.com/p/290e81b632e6
     brew install chisel
    1. 找到fblldb.py:/usr/local/Cellar/chisel/版本号/libexec/fblldb.py
    2. 找到~/.lldbinit文件,然后进行编辑,在末尾添加
    command script import /usr/local/Cellar/chisel/1.8.1/libexec/fblldb.py
    
    

    搜索字符串

    // 查找文件中的字符串  查找指定目录及其子目录中的所有文件,并检查每个文件是否包含字符串 "用户到期",如果包含,则输出文件名
    find /Users/mac/Desktop/confuse_mac.app/Contents -type f -exec sh -c 'strings "$1" | grep "用户到期" && echo "$1"' sh {} \;
    
    // 查找文件 查找当前目录及其子目录中所有名字叫做 CoreRepairCore.framework 的文件或目录 将标准错误输出(文件描述符 2)重定向到 /dev/null,从而忽略并不打印权限不足的错误信息。
    find ./ -name "CoreRepairCore.framework" 2>/dev/null
    
    // 从指定目录中查找所有不是 .DS_Store 的文件,并将它们复制到 ./11 目录下
    find ./ -d -type f -not -name .DS_Store -exec cp {} ./11 \;
    

    恢复符号表

    原理 iOS符号表恢复&逆向支付宝

    // 为了堆栈可以看到裁去符号表的方法名
    // 原版的restore-symbol有问题 用https://github.com/HeiTanBc/restore-symbol 我自己也fork这个了 教程在readme有写
    // 如果是FAT二进制 可以用lipo瘦身只要arm64 我的电脑M2 是arm64
    lipo /Users/mac/Desktop/confuse_mac.app/Contents/MacOS/confuse_mac -thin arm64 -output confuse_mac_arm64
    
    // restore-symbol clone的目录restore-symbol
    ./restore-symbol /Users/mac/Desktop/confuse_mac.app/Contents/MacOS/confuse_mac_arm64  -o /Users/mac/Desktop/confuse_mac.app/Contents/MacOS/confuse_mac_symbol
    
    // 恢复符号表后要改名替换原来的confuse_mac二进制 然后confuse_mac.app无法打开的情况重新签名
    sudo codesign --remove-signature "/Users/mac/Desktop/confuse_mac.app" && sudo codesign -f -s - --timestamp=none --all-architectures --deep "/Users/mac/Desktop/confuse_mac.app" && sudo xattr -cr "/Users/mac/Desktop/confuse_mac.app"
    

    常用修改二进制

    // return 0
    6a 00 58 c3  
    // nop
    90 90
    

    Frida

    frida-trace "confuse_mac" -m "*[AFZUserSecretariesHappen *]"
    frida-trace "confuse_mac" -m "*[AFZLanguageDecemberSplints lowFileElectrodes:]"
    frida-trace "confuse_mac" -m "*[AFZNetworkSuppliesQualifica lowFileElectrodes:]" -o run.txt // 输出日志到
    frida-trace "confuse_mac" -m "*[* armsWindlassAnchor:]" -o run.txt
    
    
    frida-trace "confuse_mac" -m "*[AFZLanguageDecemberSplints lowFileElectrodes:]" -m "*[* objectForKeyedSubscript:]" -m "*[* objectForKeyedSubscript:]" -o run.txt
    
    打印堆栈 在onEnter函数插入打印
    log('\tBacktrace:\n\t' + Thread.backtrace(this.context,Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n\t'));
    
    var after = new ObjC.Object(retval); // 打印出来是个指针时,请用该方式转换后再打印
    log(`after:${after}`);
    
    方法调用时
    onEnter(log, args, state) {
        var self = new ObjC.Object(args[0]);  // 当前对象
        var method = args[1].readUtf8String();  // 当前方法名
        log(`[${self.$className} ${method}]`);
    
        var isData = false;
    
        // 字符串
        // var str = ObjC.classes.NSString.stringWithString_("hi wit!")  // 对应的oc语法:NSString *str = [NSString stringWithString:@"hi with!"];
        // args[2] = str  // 修改入参
    
        // array
        // var 
    
        // 数组
        // var array = ObjC.classes.NSMutableArray.array();  // 对应的oc语法:NSMutableArray array = [NSMutablearray array];
        // array.addObject_("item1");  // 对应的oc语法:[array addObject:@"item1"];
        // array.addObject_("item2");  // 对应的oc语法:[array addObject:@"item2"];
        // args[2] = array; // 修改入参
    
        // 字典
        // var dictionary = ObjC.classes.NSMutableDictionary.dictionary(); // 对应的oc语法:NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
        // dictionary.setObject_forKey_("value1", "key1"); // 对应的oc语法:[dictionary setObject:@"value1" forKey:@"key1"]
        // dictionary.setObject_forKey_("value2", "key2"); // 对应的oc语法:[dictionary setObject:@"value2" forKey:@"key2"]
        // args[2] = dictionary; // 修改入参
    
        // 字节
        var data = ObjC.classes.NSMutableData.data(); // 对应的oc语法:NSMutableData *data = [NSMutableData data];
        var str = ObjC.classes.NSString.stringWithString_("hi wit!")  // 获取一个字符串。 对应的oc语法:NSString *str = [NSString stringWithString:@"hi with!"];
        var subData = str.dataUsingEncoding_(4);  // 将str转换为data,编码为utf-8。对应的oc语法:NSData *subData = [str dataUsingEncoding:NSUTF8StringEncoding];
        data.appendData_(subData);  // 将subData添加到data。对应的oc语法:[data appendData:subData];
        args[2] = data; // 修改入参
        isData = true;
    
        // 更多数据类型:https://developer.apple.com/documentation/foundation
    
        var before = args[2];
    
        // 注意,日志输出请直接使用log函数。不要使用console.log()
        if (isData) {
            // 打印byte对象
          var after = new ObjC.Object(args[2]); // 打印NSData
          var outValue = after.bytes().readUtf8String(after.length()) // 将data转换为string
          log(`before:=${before}=`);
          log(`after:=${outValue}=`);
        } else {
            // 打印字符串、数组、字段
          var after = new ObjC.Object(args[2]); // 打印出来是个指针时,请用该方式转换后再打印
          log(`before:=${before}=`);
          log(`after:=${after}=`);
        }
    
        // 如果是自定义对象时,使用以上方法无法打印时,请使用以下方法:
        // var customObj = new ObjC.Object(args[0]); // 自定义对象
        // // 打印该对象所有属性
        // var ivarList = customObj.$ivars;
        // for (key in ivarList) {
        //   log(`key${key}=${ivarList[key]}=`);
        // }
    
        // // 打印该对象所有方法
        // var methodList = customObj.$methods;
        // for (var i=0; i<methodList.length; i++) {
        //   log(`method=${methodList[i]}=`);
        // }
      },
    
    
    方法返回时
    onLeave(log, retval, state) {
        // 字符串
        var str = ObjC.classes.NSString.stringWithString_("hi wit!")  // 对应的oc语法:NSString *str = [NSString stringWithString:@"hi with!"];
        retval.replace(str)  // 修改返回值
        var after = new ObjC.Object(retval); // 打印出来是个指针时,请用该方式转换后再打印
        log(`before:=${retval}=`);
        log(`after:=${after}=`);
    
        // 其他数据类型,请往上看
      }
    

    LLDB自定义脚本

    # zlldb_block.py lldb快速打印Objective-C方法中block参数的签名
    import lldb
    import optparse
    import shlex
    
    # https://everettjf.github.io/2020/02/11/print-block-in-lldb/
    # github.com:everettjf/zlldb.git
    ###### Init ###### 
    
    def __lldb_init_module(debugger, internal_dict):
        debugger.HandleCommand('command script add -f zlldb_block.cmd_ztest ztest')
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zdebug zdebug')
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zdoc zdoc')
    
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zpvc zpvc')
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zpview zpview')
    
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zp1 zp1')
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zp2 zp2')
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zp3 zp3')
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zp4 zp4')
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zp5 zp5')
    
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zmemory zmemory')
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zdis zdis')
        debugger.HandleCommand('command script add -f zlldb_block.cmd_zblock zblock')
    
        print('zlldb loaded')
    
    ###### Dev Help ###### 
    
    def cmd_ztest(debugger, command, result, internal_dict):
        print('zlldb test')
    
    def cmd_zdebug(debugger, command, result, internal_dict):
        import pdb; pdb.set_trace()
        print('zdebug')
    
    def cmd_zdoc(debugger, command, result, internal_dict):
        import os
        os.system("open https://lldb.llvm.org/python_reference/lldb.{}-class.html".format(command))
    
    ###### Util ###### 
    
    def exec_expression(interpreter, expression, print_when_noresult=None):
        res = lldb.SBCommandReturnObject()
        interpreter.HandleCommand(expression, res)
        if res.HasResult():
            print(res.GetOutput())
        else:
            if print_when_noresult is not None:
                print(print_when_noresult)
    
    ###### View / ViewController Print ###### 
    
    def cmd_zpvc(debugger, command, result, internal_dict):
        # expression -lobjc -O -- [UIViewController _printHierarchy]
        res = lldb.SBCommandReturnObject()
        interpreter = debugger.GetCommandInterpreter()
        expression = 'expression -lobjc -O -- [UIViewController _printHierarchy]'
        interpreter.HandleCommand(expression, res)
        if res.HasResult():
            print(res.GetOutput())
        else:
            print('No result')
    
    def cmd_zpview(debugger, command, result, internal_dict):
        # expression -lobjc -O -- [(id)[[UIApplication sharedApplication] keyWindow] recursiveDescription]
        res = lldb.SBCommandReturnObject()
        interpreter = debugger.GetCommandInterpreter()
        expression = 'expression -lobjc -O -- [(id)[[UIApplication sharedApplication] keyWindow] recursiveDescription]'
        interpreter.HandleCommand(expression, res)
        if res.HasResult():
            print(res.GetOutput())
        else:
            print('No result')
    
    ###### Parameter Print ###### 
    
    
    def cmd_zp1(debugger, command, result, internal_dict):
        interpreter = debugger.GetCommandInterpreter()
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg1', 'no result for arg1')
    
    def cmd_zp2(debugger, command, result, internal_dict):
        interpreter = debugger.GetCommandInterpreter()
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg1', 'no result for arg1')
        exec_expression(interpreter, 'expression -O -- (char*)$arg2', 'no result for arg2')
    
    def cmd_zp3(debugger, command, result, internal_dict):
        interpreter = debugger.GetCommandInterpreter()
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg1', 'no result for arg1')
        exec_expression(interpreter, 'expression -O -- (char*)$arg2', 'no result for arg2')
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg3', 'no result for arg3')
    
    def cmd_zp4(debugger, command, result, internal_dict):
        interpreter = debugger.GetCommandInterpreter()
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg1', 'no result for arg1')
        exec_expression(interpreter, 'expression -O -- (char*)$arg2', 'no result for arg2')
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg3', 'no result for arg3')
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg4', 'no result for arg4')
    
    def cmd_zp5(debugger, command, result, internal_dict):
        interpreter = debugger.GetCommandInterpreter()
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg1', 'no result for arg1')
        exec_expression(interpreter, 'expression -O -- (char*)$arg2', 'no result for arg2')
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg3', 'no result for arg3')
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg4', 'no result for arg4')
        exec_expression(interpreter, 'expression -lobjc -O -- (id)$arg5', 'no result for arg5')
    
    ###### Memory Print ######
    
    def cmd_zmemory(debugger, command, result, internal_dict):
        cmd_args = shlex.split(command)
    
        usage = "usage: %prog <address> <size=8>"
        parser = optparse.OptionParser(prog='zmemory', usage=usage)
        
        try:
            (options, args) = parser.parse_args(cmd_args)
        except:
            print("error parse parameter")
            return
        
        if len(args) == 0:
            print("You need to specify the name of a variable or an address")
            return
    
        address = int(args[0],0)
        size = 8
        if len(args) == 2:
            size = int(args[1],0)
    
        print("address: 0x%x" % (address))
        print("size: 0x%x" % (size))
    
        interpreter = debugger.GetCommandInterpreter()
        exec_expression(interpreter, 'memory read --size %d --format x 0x%x' % (size, address), 'no result')
        
    
    ###### Disassemble ######
    
    def cmd_zdis(debugger, command, result, internal_dict):
        cmd_args = shlex.split(command)
    
        usage = "usage: %prog <address> <size=8>"
        parser = optparse.OptionParser(prog='zmemory', usage=usage)
        
        try:
            (options, args) = parser.parse_args(cmd_args)
        except:
            print("error parse parameter")
            return
        
        if len(args) == 0:
            print("You need to specify the name of a variable or an address")
            return
    
        address = int(args[0],0)
        instruction_count = 20 
        if len(args) == 2:
            instruction_count = int(args[1],0)
    
        print("address: 0x%x" % (address))
        print("instruction_count: %d" % (instruction_count))
    
        interpreter = debugger.GetCommandInterpreter()
        disass_cmd = "disassemble --start-address 0x%x -c %d" %(address, instruction_count)
        exec_expression(interpreter, disass_cmd, 'no result')
        
    
    ###### Block ###### 
    
    '''
    struct Block_literal_1 {
        void *isa;
        int flags;
        int reserved; 
        void (*invoke)(void *, ...);
        struct Block_descriptor_1 {
            unsigned long int reserved;
            unsigned long int size;
            void (*copy_helper)(void *dst, void *src);
            void (*dispose_helper)(void *src);
            const char *signature;
        } *descriptor;
    };
    '''
    def zblock_print_block_signature(debugger, target, process, block_address):
        pointer_size = 8 if zblock_arch_for_target_is_64bit(target) else 4
        # print("pointer size = {0}".format(pointer_size))
        # print("block address = %x"%(block_address))
    
        flags_address = block_address + pointer_size    # The `flags` integer is after a pointer in the struct
        
        flags_error = lldb.SBError()
        flags = process.ReadUnsignedFromMemory(flags_address, 4, flags_error)
    
        if not flags_error.Success():
            print("Could not retrieve the block flags")
            return
        
        block_has_signature = ((flags & (1 << 30)) != 0)    # BLOCK_HAS_SIGNATURE = (1 << 30)
        block_has_copy_dispose_helpers = ((flags & (1 << 25)) != 0) # BLOCK_HAS_COPY_DISPOSE = (1 << 25)
    
        
        if not block_has_signature:
            print("The block does not have a signature")
            return
        
        block_descriptor_address = block_address + 2 * 4 + 2 * pointer_size # The block descriptor struct pointer is after 2 pointers and 2 int in the struct
        
        block_descriptor_error = lldb.SBError()
        block_descriptor = process.ReadPointerFromMemory(block_descriptor_address, block_descriptor_error)
        if not block_descriptor_error.Success():
            print("Could not read the block descriptor struct")
            return
        
        signature_address = block_descriptor + 2 * pointer_size # The signature is after 2 unsigned int in the descriptor struct
        if block_has_copy_dispose_helpers:
            signature_address += 2 * pointer_size   # If there are a copy and dispose function pointers the signature
        
        signature_pointer_error = lldb.SBError()
        signature_pointer = process.ReadPointerFromMemory(signature_address, signature_pointer_error)
        
        signature_error = lldb.SBError()
        signature = process.ReadCStringFromMemory(signature_pointer, 255, signature_error)
    
        if not signature_error.Success():
            print("Could not retrieve the signature")
            return
        
        print("Signature Address: 0x%x" %(signature_address))
        print("Signature String: %s" %(signature))
    
        escaped_signature = signature.replace('"', '\\"')
    
        method_signature_cmd = 'po [NSMethodSignature signatureWithObjCTypes:"' + escaped_signature + '"]'
        debugger.HandleCommand(method_signature_cmd)
    
        docurl = 'https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html'
        print('Type Encodings Ref: %s' % (docurl))
    
    def zblock_disass_block_invoke_function(debugger, target, process, block_address, instruction_count):
        pointer_size = 8 if zblock_arch_for_target_is_64bit(target) else 4
        
        invoke_function_address = block_address + pointer_size + 2 * 4  # The `invoke` function is after one pointer and 2 int in the struct
        print("Invoke address: 0x%x" % (invoke_function_address))
        
        invoke_function_error = lldb.SBError()
        invoke_function_pointer = process.ReadPointerFromMemory(invoke_function_address, invoke_function_error)
        if not invoke_function_error.Success():
            print("Could not retrieve the block invoke function pointer")
            return
        
        disass_cmd = "disassemble --start-address " + str(invoke_function_pointer) + " -c " + str(instruction_count)
        debugger.HandleCommand(disass_cmd)
    
    def zblock_arch_for_target_is_64bit(target):
        # like: x86_64h, x86_64
        arch_64 = ['arm64', 'x86_64']
        arch = target.GetTriple().split('-')[0]
        for arch64_item in arch_64:
            if arch in arch64_item:
                return True
        return False
    
    def cmd_zblock(debugger, command, result, internal_dict):
        cmd_args = shlex.split(command)
    
        usage = "usage: %prog arg1 [--disass -d] [--number-instructions -n]"
        parser = optparse.OptionParser(prog='zblock', usage=usage)
        parser.add_option('-d', '--disass', action='store_true', dest='disass', default=False)
        parser.add_option('-n', '--number-instructions', dest='numberinstructions', default=20)
        
        try:
            (options, args) = parser.parse_args(cmd_args)
        except:
            print("error parse parameter")
            return
        
        if len(args) == 0:
            print("You need to specify the name of a variable or an address")
            return
        
        number_instructions = options.numberinstructions
        should_disass = options.disass
        
        target = debugger.GetSelectedTarget()
        process = target.GetProcess()
        thread = process.GetSelectedThread()
        frame = thread.GetSelectedFrame()
    
        variable_arg = args[0]
        address = int(variable_arg,0)
        if address == 0: 
            print("invalid address")
            return
    
        print("Block address: 0x%x" % (address))
        
        zblock_print_block_signature(debugger, target, process, address)
    
        if should_disass:
            zblock_disass_block_invoke_function(debugger, target, process, address, number_instructions)
    
    
    # lldb_debug_extension.py  自定义打印方法参数的LLDB命令
    import lldb
    import re
    
    def __lldb_init_module(debugger, internal_dict):
        debugger.HandleCommand('command script add -f lldb_debug_extension.objargs_func args')
    
    # 格式化输出
    def __format_output(return_obj):
       output = return_obj.GetOutput()
       return None if not output else output.replace('\n', '').replace('\r', '')
    
    # 打印各个参数
    def __print_arg(interpreter, return_obj, sequence):
        """
        打印函数的第几个参数,传入1打印第一个,以此类推
        """
        register = '$x%s' % str(sequence + 1)
        # 参数值
        interpreter.HandleCommand('po %s' % register, return_obj)
        arg_value = __format_output(return_obj)
        # 参数类型
        interpreter.HandleCommand('po [%s class]' % register, return_obj)
        arg_type: str = __format_output(return_obj)
        # 不是oc对象类型,是基本数据类型
        if not arg_type:
            interpreter.HandleCommand('p %s' % register, return_obj)
            p1 = re.compile(r'[(](.*?)[)]', re.S)  # 提取括号里面的参数类型
            arr = re.findall(p1, __format_output(return_obj))
            arg_type = arr[0]
            print("第%s个参数:【类型:%s】【值:%s】" % (sequence, arg_type, arg_value))
            return
        # 是oc对象类型,判断是不是block类型
        interpreter.HandleCommand('po (BOOL)[%s isKindOfClass: [NSBlock class]]' % register, return_obj)
        is_block = __format_output(return_obj)
        if not is_block == 'YES':  # 如果不是block
            print("第%s个参数:【类型:%s】【值:%s】" % (sequence, arg_type, arg_value))
            return
        # block的处理方式
        interpreter.HandleCommand('x/4xg %s' % register, return_obj)
        descriptor_address = __format_output(return_obj).split(' ')[-1]
        offset = 3 if 'Global' in arg_type else 5
        interpreter.HandleCommand('x/%sxg %s' % (str(offset),descriptor_address), return_obj)
        sign_address = __format_output(return_obj).split(' ')[-1]
        interpreter.HandleCommand('x/s %s' % sign_address, return_obj)
        sign = __format_output(return_obj).split(' ')[1]
        print("第%s个参数:【类型:%s】【签名:%s】" % (sequence, arg_type, sign))
    
    
    # 定义打印参数的函数
    def objargs_func(debugger, command, exe_ctx, result, internal_dict):
        """
        人性化的方式打印objc_msgSend的各个参数
        """
        interpreter = debugger.GetCommandInterpreter()
        # 保存结果
        return_obj = lldb.SBCommandReturnObject()
        # 处理命令
        interpreter.HandleCommand('po $x0', return_obj)
        print("方法调用者:%s" % __format_output(return_obj))
        interpreter.HandleCommand('x/s $x1', return_obj)
        method_name: str = __format_output(return_obj).split(' ')[1][1:-1]
        print("方法名:\t    %s" % method_name)
        args = method_name.split(':')[:-1]
        if not len(args):  # 如果没有参数
            return
        for index, arg in enumerate(args):
            sequence = index + 1
            __print_arg(interpreter, return_obj, sequence)
    
    
    

    相关文章

      网友评论

          本文标题:Mac调试工具LLDB和Frida

          本文链接:https://www.haomeiwen.com/subject/aptnqjtx.html