> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/sast-and-sca/ocular/tutorials/investigate-obj-c.md).

# Investigate an Application with an Objective-C Frontend

This article will walk you through investigating an application with an Objective-C frontend using Ocular.

## Sample Application <a href="#sample-application" id="sample-application"></a>

For the examples to follow, we will be working with the [Mach-O Browser](https://github.com/dcsch/macho-browser) application, whose repository you can clone via GitHub.

```
// clone the project
git clone https://github.com/dcsch/macho-browser.git

// navigate into the working directory and build
cd macho-browser

// build
xcodebuild OTHER_CFLAGS=-flto OTHER_LDFLAGS=-flto CODE_SIGN_IDENTITY="-" DEVELOPMENT_TEAM="" -configuration Debug

// navigate into the folder with the build files
cd "Build/Mach-O Browser.build/Debug/Mach-O Browser.build/Objects-normal/x86_64/"
```

![](/files/CRrxFX9wuboXxDrdB2dv)

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

Once you've successfully built macho-browser, you can transform it to a Code Property Graph (CPG):

```
/Users/<username>/.shiftleft/ocular/llvm2cpg.sh --output=/tmp/macho.cpg.bin.zip *.o
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

If you're not using the default install location for Ocular, you may need to change **/.shiftleft/ocular** to the appropriate path.

Once you have the CPG, start Ocular:

```
sl ocular
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

When prompted, load the CPG you generated:

```
ocular> importCpg("/tmp/macho.cpg.bin.zip")
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

Run `workspace` to ensure that your CPG has been loaded. If `loaded` is `true`, you're ready to proceed with your investigative queries.

```
ocular> workspace
res0: Workspace =
 _________________________________________________________________
 | name                     | overlays                    | loaded|
 |================================================================|
 | macho.cpg.bin.zip        | semanticcpg(l),dataflow(l)  | true  |
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

## Investigative Queries <a href="#investigative-queries" id="investigative-queries"></a>

The following examples will walk you through the basics of querying the CPG to gather information about your application.

* Identify functions with more than 4 parameters: `cpg.method.where(_.parameter.size > 4).l`
* Sort methods by the number of callers and exclude the first 1000 results: `val methodList = cpg.method.map(x => (x.start.callIn.size, x.name)).l.sorted.reverse.take(1000)`
* Filter for methods that have callers: `methodList.filter(_._1>0).sorted`
* Filter for methods that do *not* have callers: `methodList.filter(_._1==0)`
* Get all of the hard-coded literals in the code: `cpg.literal.code.l`
* Get all types and associated properties/members in the code: `val typesList = cpg.typeDecl.map { t => (t.name, t.start.member.name.l) }.l`
* Identify the call site to `malloc` where the first argument contains an arithmetic expression: `cpg.call("malloc").filter(_.argument (1).arithmetics ).l`

## Querying for Method-Specific Information <a href="#querying-for-method-specific-information" id="querying-for-method-specific-information"></a>

Let's say that you're interested in a class called **LoadCommand** and how it is used. You can declare variables containing the class name for easy reuse:

```
val className="LoadCommand"
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

You can pick a class and observe its methods:

```
cpg.typeDecl.name(className).method.fullName.p.sorted
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

The result will look something like the following:

```
result: List[String] = List(
 "+[LoadCommand loadCommandWithData:offset:]",
 "-[LoadCommand .cxx_destruct]",
 ...
)
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

You can get a list of all Objective-C classes (the convention is that class names start with an uppercase later):

```
cpg.typeDecl.name("[A-Z][A-Za-z]*").name.p.sorted

res11: List[String] = List(
  "ANY",
  "AlignmentFormatter",
  "CGPoint",
  "NSObject",
  ...
)
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

You can find where a method is called:

```
cpg.method.fullNameExact("-[LoadCommand initWithData:offset:]").caller.fullName.p

result: List[String] = List("+[LoadCommand loadCommandWithData:offset:]")
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

Get subclasses in it's type hierarchy:

```
cpg.typeDecl.name(className).derivedTypeDecl.name.p

result: List[String] = List("SymbolTableLoadCommand", "SegmentLoadCommand")
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

Get superclasses in its type hierarchy:

```
cpg.typeDecl.name("LoadCommand").baseTypeDecl.name.p

result: List[String] = List("NSObject")
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

Get all of the **NSObject** subclasses:

```
cpg.typeDecl.name("NSObject").derivedTypeDeclTransitive.name.p

result: List[String] = List(
 "Symbol",
 "Section",
 ...
)
```

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)

## Example: Protecting Against the Billion Laughs Attack <a href="#example-protecting-against-the-billion-laughs-attack" id="example-protecting-against-the-billion-laughs-attack"></a>

iOS offers you two SDK options for parsing XML: [NSXMLParser](https://developer.apple.com/documentation/foundation/nsxmlparser?language=objc) and [libxml2](http://xmlsoft.org/).

If you're using [NSXMLParser](https://developer.apple.com/documentation/foundation/nsxmlparser?language=objc), you should enable the [`shouldResolveExternalEntities` property](https://developer.apple.com/documentation/foundation/nsxmlparser/1414143-shouldresolveexternalentities?language=objc) to protect yourself against the [Billion Laughs Attack](https://en.wikipedia.org/wiki/Billion_laughs_attack):

```
// Verify that the NSXMLParser has been imported and shouldResolveExternalEntities has been enabled
cpg.typeDecl.name(".*NSXMLParser.*").member.name(".*shouldResolveExternalEntities.*").l

// [OR] Verify that, if shouldResolveExternalEntities is set, it is associated to the type NSXMLParser
cpg.method.name(".*shouldResolveExternalEntities.*").where(_.astParentFullName.contains("NSXMLParser")).l
```

![](/files/CRrxFX9wuboXxDrdB2dv)

![](/files/DfHDmRpYn5HJOmhRtTva) ![](/files/P5vj8JOtHNJWVEvAqKym)
