iOS小技能:lldb打印block参数签名

简介: iOS逆向时经常会遇到参数为block类型,本文介绍一个lldb script,可快速打印出Objective-C方法中block参数的类型。

前言

iOS逆向时经常会遇到参数为block类型,本文介绍一个lldb script,可快速打印出Objective-C方法中block参数的类型。

zblock <block-address> : print oc block signature, parameter -d for disassemble

I lldb打印block参数签名

1.1 install

cd ~
git clone git@github.com:zhangkn/zlldb.git

然后在 ~/.lldbinit 文件中添加下行内容:command script import ~/zlldb/main.py

1.2 使用

  1. 如果是逆向工作的话,没有代码,那可以断点到 objc_msgSend这行
  2. 执行命令 zblock 0x100588080 (block的地址传给 zblock命令),然后block的参数就出来了。
  3. 根据每一行的 type encoding 对照[苹果文档ocrtTypeEncodings](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html

)即可知道block的参数都有什么。

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html

由于Xcode11内置的lldb script开始默认Python3版本,facebook的chisel还有些支持问题(可能现在解决了)。zlldb就是把我自己常用的几个命令放到了这里,支持Python3(也就是最新版Xcode)。除了zblock外,还有几个简单的命令,大家可以参考README。

Objective-C type encodings

Objective-C method encodings

1.3 Python script

main.py

zblock_print_block_signature
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):
    arch_64 = ['arm64', 'x86_64']
    arch = target.GetTriple().split('-')[0]
    return arch in arch_64

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)

see also

公号:iOS逆向

Chisel_fblldb.py_lldbinit

Chisel is a collection of LLDB commands to assist debugging iOS apps.

https://github.com/kunnan/kunnan.github.io/blob/master/_posts/Debug/2018-07-07-Chisel_fblldb.py_lldbinit.md

目录
相关文章
|
9月前
|
iOS开发
iOS block修饰符用copy还是strong
iOS block修饰符用copy还是strong
103 0
|
12月前
|
iOS开发
iOS URL参数转字典
iOS URL参数转字典
132 0
|
12月前
|
JSON 移动开发 数据格式
iOS url传递JSON格式参数方法
iOS url传递JSON格式参数方法
221 0
|
12月前
|
安全 iOS开发 开发者
ios签名工具永久有效吗?
苹果APP上架难,不用越狱,下载未上架APP!
|
安全 Linux 网络安全
【IOS实用玩机技巧】爱思助手 IPA 签名功能常见问题汇总(iOS上架)
【IOS实用玩机技巧】爱思助手 IPA 签名功能常见问题汇总(iOS上架)
2291 0
【IOS实用玩机技巧】爱思助手 IPA 签名功能常见问题汇总(iOS上架)
|
iOS开发 开发者
iOS开发 - 如何写出漂亮的block
iOS开发 - 如何写出漂亮的block
77 0
|
iOS开发
iOS开发- 关于Block的几种应用
iOS开发- 关于Block的几种应用
93 0
|
存储 iOS开发
iOS小技能: get 和post 布尔值参数处理、按照时间分页的数据重复的处理
1. get 和post 布尔值参数处理:如果后台Bool 参数没有同时支持【 0,1】 ;和【 true false】,get请求的时候就需要特殊处理。 2. 按照时间分页的数据重复的处理
145 0
iOS小技能: get 和post 布尔值参数处理、按照时间分页的数据重复的处理
|
自然语言处理 iOS开发
IOS——Block
IOS——Block
64 0
|
iOS开发
iOS代理 通知 block传值的规范写法
iOS代理 通知 block传值的规范写法
117 0