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

文章目录

iOS逆向时经常会遇到参数为block类型,本文介绍一个lldb script,可快速打印出Objective-C方法中block参数的类型。,然后在 ~/.lldbinit 文件中添加下行内容:
command script import ~/zlldb/main.py,Objective-C type encodings
iOS小技能:lldb打印block参数签名
iOS小技能:lldb打印block参数签名,Objective-C method encodings,iOS小技能:lldb打印block参数签名,main.py,公号:iOS逆向,Chisel_fblldb.py_lldbinit,如果是逆向工作的话,没有代码,那可以断点到 objc_msgSend这行,执行命令 zblock 0x100588080 (block的地址传给 zblock命令),然后block的参数就出来了。,

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

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

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

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

  1. 如果是逆向工作的话,没有代码,那可以断点到 objc_msgSend这行
  2. 执行命令 zblock 0x100588080 (block的地址传给 zblock命令),然后block的参数就出来了。
  3. 根据每一行的type encoding 对照苹果文档ocrtTypeEncodings即可知道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 iOS小技能:lldb打印block参数签名 iOS小技能:lldb打印block参数签名

Objective-C method encodings

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

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)

公号: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

© 版权声明

相关文章