Quickly Printing Block Parameter Signatures in Objective-C Methods with LLDB

About the author. I’m Colin Xiao — an independent reverse engineer, mostly working solo on contract jobs. I dig into compiled code of every kind, including but not limited to: Android and iOS apps, x86/x64/ARM native binaries, packers and obfuscators, DRM and license checks, network protocols and APIs, crypto and signature algorithms, malware, game binaries, and embedded/IoT firmware. I also handle large-scale data collection and vulnerability research. If you have any project in mind, I’d be glad to take it on — whatever it is, as long as it’s within my wheelhouse. Just reach out. You can reach me on X at @colinxiao_lab or on Telegram at https://t.me/ColinXiao666.

This research is published for educational and defensive purposes. The target sample is anonymized throughout.


Quickly Printing Block Parameter Signatures in Objective-C Methods with LLDB

iOS reverse engineering frequently hands you methods whose parameters are blocks. This post introduces an LLDB script that quickly prints the type of a block parameter in an Objective-C method.

Headers dumped with class-dump often contain signatures like:

- (void)doSomethingWithCompletionHandler:(CDUnknownBlockType)arg1;

CDUnknownBlockType is a block-typed parameter. To call this method you need to know its actual type.

I searched around and found a good writeup that uses raw LLDB commands to find the parameter type:

http://www.swiftyper.com/2016/12/16/debuging-objective-c-blocks-in-lldb/

But typing those commands by hand every time is tedious. So I looked for a script and found:

https://github.com/ddeville/block-lldb-script

…but it’s been unmaintained for years and mostly doesn’t work. So let’s try fixing it:

-> debugging .
-> debugging ..
-> debugging ...
-> ....
-> fixed, yeah :)

Install

Clone the LLDB script:

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

Then add this line to ~/.lldbinit:

command script import ~/zlldb/main.py

Usage

Say we have a block method:

@interface Hello : NSObject
@end
@implementation Hello
+ (void)say:(NSString*)text callback:(void(^)(NSString *text,int x, NSString *y, double z, BOOL m))callback {
}
@end

Called like:

[Hello say:@"world" callback:^(NSString *text, int x, NSString *y, double z, BOOL m) {    
}];

Set a breakpoint on that call line. When reversing without source, break on the objc_msgSend line instead:

Breakpoint at the objc_msgSend call

The block is the second parameter, so print $arg4. Then run zblock 0x100588080 (passing the block’s address to the zblock command) and the block’s parameters appear:

zblock output showing the block signature

Match each line’s type encoding against Apple’s docs to learn the block’s parameters:

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

Code

https://github.com/everettjf/zlldb

Since Xcode 11’s built-in LLDB scripts default to Python 3, Facebook’s chisel still had some compatibility issues (maybe resolved by now). zlldb collects the few commands I use most, with Python 3 support (i.e. current Xcode). Besides zblock there are a handful of other simple commands — see the README.

References

  1. http://www.swiftyper.com/2016/12/16/debuging-objective-c-blocks-in-lldb/
  2. https://maniacdev.com/2013/11/tutorial-an-in-depth-guide-to-objective-c-block-debugging
  3. https://github.com/ddeville/block-lldb-script
  4. https://store.raywenderlich.com/products/advanced-apple-debugging-and-reverse-engineering

Enjoy :)


Colin Xiao — I take on contract reverse-engineering work, and writeups like this are how I show what I can do. If you need help with anything in this space — including but not limited to the areas I cover above — I’m available. No project is too big or too small — if it’s reverse engineering and I can do it, I’ll take it. DM me on X (@colinxiao_lab) or Telegram (@ColinXiao666).

Get in touch