# Objective-C .dylib Reverse Engineering "gigavaxxed" with Binary Ninja & LLDB

### \[UPDATE] - source code now available [here](https://github.com/cr7pt0pl4gu3/Apple-Framework-Decorator).

### First, the results, then - many words

PS. Warning, this post contains lots of black & unfunny IT humor.

#### The complexity of this technique

Just press a button (yep, that's it):

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2FhtrHjJo43mVnLzkCH69u%2Fimage.png?alt=media&#x26;token=964d9fea-4712-4674-ac5e-1d1667784863" alt=""><figcaption></figcaption></figure>

#### With vs Without

**Without the plugin (Pseudo C)**

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2F01IZno09gZoOeavsikIe%2Fimage.png?alt=media&#x26;token=530f603a-275e-477a-9543-c6cfd2dc1d6e" alt=""><figcaption></figcaption></figure>

**With the plugin (Pseudo C)**

Note that selectors are displayed as comments, before the objc\_msgSend call. Objective-C classes, strings, protocols, etc are displayed as well:

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2Fxeo0r3EMOTCUwuHX39GS%2Fimage.png?alt=media&#x26;token=cd8be806-6b0d-4de0-9820-a3bd80d63e0c" alt=""><figcaption></figcaption></figure>

**Without the plugin (Disassembly)**

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2FlVc572tmU5w80tAhloz6%2Fimage.png?alt=media&#x26;token=3bedf377-8969-461e-ae5c-06cbe33e3320" alt=""><figcaption></figcaption></figure>

**With the plugin (Disassembly)**

Honestly, the annotations & namings are close to being perfect:

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2FM9Pibc0yxLcKVRnmGOn8%2Fimage.png?alt=media&#x26;token=b5cc465a-b17a-400a-af1f-d653032501d7" alt=""><figcaption></figcaption></figure>

#### Impressive, but I use [iDa pRo](https://hex-rays.com/ida-pro/)

Good luck on that (7.7.211224 [IDA Freeware](https://hex-rays.com/ida-free/) below):

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2Ftda1cbpJOhQqcfowEfyu%2Fimage.png?alt=media&#x26;token=d74ae0c2-6fa5-4388-a065-ae56cc4ea2ec" alt=""><figcaption></figcaption></figure>

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2FEBjwwyavQRU8oAdoF3TZ%2Fimage.png?alt=media&#x26;token=254a1fae-a701-4962-9796-e0437ef7d78a" alt=""><figcaption></figcaption></figure>

### Backstory

This story happened in April 2022, while I was attending the Program Analysis for Vulnerability Research training by [Margin Research](https://margin.re) & [Vector35](https://vector35.com). That was just after I did [Reverse Engineering and Demystifying \*OS Private Frameworks](https://blog.cryptoplague.net/main/research/macos-research/reverse-engineering-and-demystifying-os-private-frameworks) for my university classes.

I was sitting in my chair thinking about reverse engineering one of Apple's Private Frameworks (you read it right, "thinking"). Casually loaded it in [Binary Ninja](https://binary.ninja), selected the [Objective-Ninja](https://github.com/jonpalmisc/ObjectiveNinja) workflow, and got greeted with this:

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2F6P07Nq1wvfVKSaGXoqbv%2Fimage.png?alt=media&#x26;token=00a0e7ec-8086-4157-9abc-7d01db3748f7" alt=""><figcaption></figcaption></figure>

I was devastated. My life was ruined. I wanted to die.

Jokes aside, I thought that I needed to link the .dylib with my [Xcode](https://developer.apple.com/xcode/) project, resolve the method that I want to look at during the runtime with [LLDB](https://lldb.llvm.org), STEAL the information from it, and apply that in my beloved [Binary Ninja](https://binary.ninja) manually. *That is a Sisyphean labor*.

Of course, [LLDB](https://lldb.llvm.org) is great when it comes to resolving some of the important Objective-C runtime information, such as selectors or NSStrings for example:&#x20;

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2FbMslxNRAU66pw8OZ1EoB%2Fimage.png?alt=media&#x26;token=aa9e3b37-42b5-4d53-9685-831ca2e02d49" alt=""><figcaption></figcaption></figure>

If only I could apply all this information to my reverse engineering tool of the choice...

### An idea comes to mind

Static analysis or dynamic analysis, reverse engineering theory... No! I will choose my own destiny. I will make a plugin. A plugin that makes my static analysis "gigavaxxed" with the power of dynamic analysis.

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2F0XVE9kh6peJWhJB33TEb%2Fimage.png?alt=media&#x26;token=6912ff91-3370-4600-975f-09a28742d5de" alt=""><figcaption></figcaption></figure>

*Note:* [*Binary Ninja*](https://binary.ninja) *has an AMAZING set of APIs. Refer to the* [*docs*](https://api.binary.ninja) *for more information on them.*

For a given .dylib function or a .dylib itself, my plugin compiles an [Xcode](https://developer.apple.com/xcode/) project with an altered code that will resolve the function's pointer. Then, it is analyzed in [LLDB](https://lldb.llvm.org) and the runtime information from that is propagated to the [Binary Ninja](https://binary.ninja), where comments are added and variables are renamed (effectively enhancing our static analysis).

### Time - before one runs away

One would say, "It will take a huge amount of time".

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2FG51IEa5ZqnbrDNHYME9f%2Fimage.png?alt=media&#x26;token=5f526f58-d5ca-4881-845e-cb36538f2ea7" alt=""><figcaption></figcaption></figure>

I would answer, YES. Dynamic analysis ([LLDB](https://lldb.llvm.org)) itself is costly, not even taking the [Xcode](https://developer.apple.com/xcode/) project building & running into account. Moreover, the *Big O notation* would probably have died from a heart attack if my python code was ever EXPOSED to it.

BUT, the time spent is **WORTH IT**. The plugin also runs on a separate thread so it won't bother your analysis.

For example, the time needed to decorate the whole ***TCC.Framework*** C-like export table using my plugin (tests were done on my M1 MacBook with *99999* Safari tabs open, PyCharm running, and Burp Suite + Chromium devouring my RAM and CPU in the background):

x86\_64: **137** functions decorated, **17.85** minutes elapsed.

arm64: **137** functions decorated, **11.87** minutes elapsed.

Clearly shows why arm64 is the future.

Funnily, it also triggered this alert (if somebody could explain to me what happened, I would be very grateful):&#x20;

<figure><img src="https://750590561-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqEHYs3J0lebZbZucvZkw%2Fuploads%2F0nf8e0hlAhzY1SAITP0b%2Fimage.png?alt=media&#x26;token=ad88cd1a-ece0-48bf-9698-3a5e8e58157e" alt=""><figcaption></figcaption></figure>

All I was doing is resolving the function's pointer, attaching to it with [LLDB](https://lldb.llvm.org) and breaking at main:

```objectivec
#import <Foundation/Foundation.h>
#impjort <objc/runtime.h>
    
extern id TCCAccessSetForBundleIdAndCodeRequirement();
    
int main(void) {
    NSLog(@"POINTER:%p", TCCAccessSetForBundleIdAndCodeRequirement);
}
```

*TCCAccessSetForBundleIdAndCodeRequirement* is also mentioned by [Wojciech Reguła](https://twitter.com/_r3ggi) [here](https://wojciechregula.blog/post/play-the-music-and-bypass-tcc-aka-cve-2020-29621/). Amusing that only resolving that function's pointer triggers such a pop-up.

What about the Objective-C methods? I used the following technique:

```objectivec
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

int main(void) {
    Class c = NSClassFromString(@"AMFIPathValidator_ios");
    void* p = method_getImplementation(class_getClassMethod(c, @selector(validateWithError:)));
    if (p == NULL) {
        void* p = method_getImplementation(class_getInstanceMethod(c, @selector(validateWithError:)));
        NSLog(@"POINTER:%p", p);
    }
	else {
        NSLog(@"POINTER:%p", p);
    }
}
```

Benchmark of ***AppleMobileFileIntegrity.Framework***:

x86\_64: **99** methods decorated, **5.93** minutes elapsed.

Impressive!

### Automation is the key

I coded this simple [LLDB](https://lldb.llvm.org) python script to dump the function and save the PRECIOUS runtime information:

```python
def dump(debugger, command, result, internal_dict):  
    debugger.HandleCommand('break set -n main')  
    debugger.HandleCommand('run')  
    f = open("dump.txt", "w")  
    debugger.SetOutputFileHandle(f, True)  
    debugger.HandleCommand('disas -a 0x7ffb15479824')
```

For the [Binary Ninja](https://binary.ninja), I created my LLDBDecorator class which inherits from [BackgroundTaskThread](https://api.binary.ninja/binaryninja.plugin-module.html?highlight=backgroundtaskthread#binaryninja.plugin.BackgroundTaskThread) to enable threading:

```python
class LLDBDecorator(BackgroundTaskThread):  
    def __init__(self, bv, fnc=""):  
        self.functions = []  
        self.results = 0  
        self.bv = bv  
        self.fnc = fnc  
        self.progress_bar = ""  
        BackgroundTaskThread.__init__(self, self.progress_bar, True)  
  
    def run(self):  
        start = time.time()  
        res = self.lldb_decorate()  
        end = time.time() - start  
        log_info("[Vulnerizer] [Objective-C] - LLDB decoration ended, {} decorated, {:2f} seconds elapsed".format(res, end))
```

I also coded the ldb\_decorate method to set everything up, automate [Xcode](https://developer.apple.com/xcode/) + [LLDB](https://lldb.llvm.org) routines and populate [Binary Ninja](https://binary.ninja) with results:

```python
def lldb_decorate(self):
	# ...
```

We can ABUSE python "TeMpLaTeS" (f-strings) for the changes in code:

```python
code = f"""#import <Foundation/Foundation.h>  
#import <objc/runtime.h>  
  
int main(void) {{  
    Class c = NSClassFromString(@"{class_name}");  
    void* p = method_getImplementation(class_getClassMethod(c, @selector({selector_name})));  
    if (p == NULL) {{  
        void* p = method_getImplementation(class_getInstanceMethod(c, @selector({selector_name})));  
        NSLog(@"POINTER:%p", p);    }}  
    else {{  
        NSLog(@"POINTER:%p", p);    }}  
    // NSLog(@"%@", [c performSelector: @selector({selector_name})]);  
}}"""
```

```python
dump_py = f"""
def dump(debugger, command, result, internal_dict):  
    debugger.HandleCommand('break set -n main')    debugger.HandleCommand('run')    f = open("{os.path.join(dirname, 'dump.txt')}", "w")  
    debugger.SetOutputFileHandle(f,True)    debugger.HandleCommand('disas -a {pointer}')"""
```

I also added an option for C-like imports (as shown during the TCC benchmark):

```python
elif self.fnc == "exports":  
    exports = 1  
    for sym in self.bv.get_symbols_of_type(SymbolType.FunctionSymbol):  
        if sym.binding == SymbolBinding.GlobalBinding:  
            self.functions.append(self.bv.get_functions_by_name(sym.name)[0])
```

### Code

Unfortunately, at the end of the day, my MacBook overheated, malfunctioned, started to burn, and exploded. This is so sad and that is why I couldn't provide the full codebase.

Well, jokes aside, this is still very much work-in-progress and I cannot provide the project code in the state it is right now (please do not HACK and EXPOSE me). I am also confident that many Security Researchers are more experienced than I am, so re-implementing this project shouldn't take a lot of time given the effort and information above (personally did it in two days).

In the worst case, DM me on [Twitter](https://twitter.com/cr7pt0pl4gu3) for the source code.

### Grand Finale

Thank you for reading this and I hope you learned something new or at least explored an interesting case study that may push you to your great ideas.

I may also do a second take on this project if it interests people.
