# IPA Analysis Using MobSF

#### Disclaimer:

I do not own any of the contents of this page, these have been copied from another contributor merely for the purpose of storing this information on my page for reference. The link for original contributor of the information relayed on this page is as follows:

{% embed url="<https://inesmartins.github.io/mobsf-ipa-binary-analysis-step-by-step/index.html>" %}

[MobSF](https://github.com/MobSF/Mobile-Security-Framework-MobSF) is an open source static and dynamic analysis tool for Android and iOS, which can be used to quickly detect major issues on your mobile application.

When scanning an `.ipa`, the "IPA Binary Analysis" section can report multiple issues that can be hard to interpret.

Hopefully this article will help you understand why each vulnerability was reported and how to fix it.

### Getting to the good stuff <a href="#getting-to-the-good-stuff" id="getting-to-the-good-stuff"></a>

`.ipa` files are actually just zipped files that include the application executable and a bunch of other stuff.

When we talk about binary analysis, we're actually just talking about analysing this executable file, so the first thing we need to do is **find it**.

Note that if you don't have access to the `.ipa` you can extract it from the App Store using [ipatool](https://github.com/majd/ipatool):

```
~ brew tap majd/repo
~ brew install ipatool
~ ipatool download --bundle-identifier <app-bundle-id> --email <appstore-account-email> --password <appstore-account-password>
```

So, now that you have your `.ipa` it's time to unzip it and look inside:

```
~ unzip MyApp.ipa
~ cd Payload/
~ cd MyApp.app/
~ file MyApp
MyApp: Mach-O 64-bit executable arm64
```

As you can see above, the app binary is compiled for `ARM` and uses the `Mach-O` file format.

A more thorough analysis of this binary can be done using [otool](https://www.manpagez.com/man/1/otool/). You should become familiar with this tool since it will help us validate and fix most of the issues reported below.

Alternatively, I also recommend [htool](https://h3adsh0tzz.com/projects/htool/), which serves the similar purpose of analysing `Mach-O` binaries.

### ARC <a href="#arc" id="arc"></a>

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-20.12.27.png)

If you're used to working with Swift, then you most likely know `ARC` or "Automatic Reference Counting" simply as [one of the core features](https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html) of the language.

However, `ARC` is actually a feature of the Clang compiler, and unlike with Swift, you can (but [shouldn't](https://stackoverflow.com/questions/8760431/to-arc-or-not-to-arc-what-are-the-pros-and-cons/8760820#8760820)) use Objective-C without using Automatic Reference Counting.

If you've never heard of "Automatic Reference Counting" you should basically know that it "automatically frees up the memory used by class instances when those instances are no longer needed".

The alternative is to leave memory management to the developer, who is always less reliable and can easily make mistakes that can lead to memory corruption vulnerabilities.

So, if your application is written (at least partially) in Objective-C, you should first make sure that the project is configured to use `ARC` by checking the `"Objective-C Automatic Reference Counting"` setting under the `"Build Settings"` tab:

![](https://inesmartins.github.io/content/images/2021/08/image-6.png)<https://advancetechtutorial.blogspot.com/2016/07/xcode-arc-automatic-reference-counting.html>

If this property is set to `No`, you should "Convert" the project, as shown below:

![](https://inesmartins.github.io/content/images/2021/08/image-5.png)<https://stackoverflow.com/questions/8969644/tool-for-transitioning-to-arc/8969662>

You can also check the `"Compile Sources"` section under the `"Build Phases"` tab for the presence of the `-fno-objc-arc` flag, which is used to exclude specific files from using `ARC`, as shown below:

![](https://inesmartins.github.io/content/images/2021/08/flag-1024x434.jpeg)<https://thomashanning.com/how-to-disable-arc-for-objective-c-files/>

Since there are limitations that come with using `ARC`, the adequacy of these exceptions should be evaluated on a case by case basis.

As mentioned above, `otool` can help us understand our binary files a little better.

When it comes to `ARC` we can use this tool to check for the presence of ARC-related symbols, such as `_objc_release`, `_objc_autorelease`, `_objc_storeStrong`, `_objc_retain`, etc.:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-22-at-11.52.58.png)

Note the usage of `otool`'s `-I` and `-v` flags:

```
~ otool
	...
	-I print the indirect symbol table
	-v print verbosely (symbolically) when possible
```

### Code Signature <a href="#code-signature" id="code-signature"></a>

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-20.12.35.png)

From the [Apple docs on Code Signing](https://developer.apple.com/support/code-signing/) we can read:

> Before your app can integrate app services, be installed on a device, or be submitted to the App Store, it must be signed with a [certificate](https://developer.apple.com/support/certificates/) issued by Apple.

Also, from the [iOS Security Guide](https://www.apple.com/mx/privacy/docs/iOS_Security_Guide_Oct_2014.pdf):

> In order to develop and install apps on iOS devices, developers must register with Apple and join the iOS Developer Program. The real-world identity of each developer, whether an individual or a business, is verified by Apple before their certificate is issued.\
> \[...]\
> At runtime, code signature checks of all executable memory pages are made as they are loaded to ensure that an app has not been modified since it was installed or last updated.

So, code signing is simply the process of signing an application with an appropriate certificate that ensures the author's identity and the app content's integrity.

Since this process is required by Apple for most operations, if this section is flagged as "False" by MobSF, it's likely that the file you're analysing was generated via some non-traditional method, which seems worth investigating.

### Encrypted <a href="#encrypted" id="encrypted"></a>

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-20.14.17.png)

Similarly to the previous section, encryption shouldn't be a concern for most iOS developers, since the `App Store` takes care of it during the distribution process.

From [iPhoneDev's Wiki](https://iphonedev.wiki/index.php/Crack_prevention):

> App Store binaries are signed by both their developer and Apple. This encrypts the binary so that decryption keys are needed in order to make the binary readable.

So, when it comes to the MobSF analysis you should keep in mind the origin of the `.ipa` you're testing:

* if you simply download it from the `App Store` (using `ipatool`, for example), then the binary should be encrypted;
* if you get the `.ipa` from any other source, then most likely it's not encrypted.

To confirm the binary's encryption you can use `otool` to look for the `LC_ENCRYPTION_INFO` section:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-22-at-10.32.27.png)

From the [iPhoneDev Wiki](https://iphonedev.wiki/index.php/Crack_prevention):

> iOS can tell the encryption status of a binary via the `cryptid` struture member of `LC_ENCRYPTION_INFO` `MachO` `load` command.\
> If `cryptid` is a non-zero value then the binary in encrypted.

Note that the `cryptsize` indicates the size of the encrypted segment.

Also note the usage of `otool`'s `-l` flag:

```
~ otool
	...
	-l print the load commands
```

### NX <a href="#nx" id="nx"></a>

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-20.14.38.png)

Although the `NX bit` is specific to the `AMD` architecture, people tend to use "NX" as a generic way of referring to the feature that enables you to **specify non-executable memory pages**.

So, in this case, the `NX` section actually refers to the `XN` or "eXecute never" feature, since we're dealing with an `ARM` binary.

In the [iOS Security Guide](https://www.apple.com/mx/privacy/docs/iOS_Security_Guide_Oct_2014.pdf), under "Runtime process security" we can read:

> Further protection is provided by iOS using ARM’s Execute Never (XN) feature, which marks memory pages as non-executable.\
> Memory pages marked as both writable and executable can be used only by apps under tightly controlled conditions:\
> The kernel checks for the presence of the Apple-only dynamic code-signing entitlement. Even then, only a single mmap call can be made to request an executable and writable page, which is given a randomized address.

So, this section should never be flagged by MobSF, as long as Apple continues to use `XN` by default.

### PIE <a href="#pie" id="pie"></a>

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-20.15.40.png)

As explained above, each time you run a "Position Independent Executable" (`PIE`), the binary and all of its dependencies are loaded into random locations within virtual memory, which make ROP attacks much more difficult to execute reliably.

We can check for the presence of the `PIE` flag in our executable with `otool`:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-20.25.18-1.png)

Note the usage of `otool`'s `-h` and `-v` options:

```
~ otool
	...
	-h print the mach header
	-v print verbosely (symbolically) when possible
```

If this flag is not present in the binary, then you need to review your compilation settings.

First, ensure that `"Don't Create Position Independent Executables"`  under `"Build Settings"` is set to `NO`:

![](https://inesmartins.github.io/content/images/2021/08/rHGq2.png)<https://stackoverflow.com/questions/32728783/why-would-xcode-not-use-the-build-configuration-settings-from-my-xcconfig-file>

Then, check that these flags are set:

* In `Other C flags`: `-fPIC`
* In `Other Warning flags`: `-Wl,--emit-relocs` (retains all relocations in the executable file) and `-Wl,--warn-shared-textrel` (warns if the text segment is not shareable).

### Stack Canary <a href="#stack-canary" id="stack-canary"></a>

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-20.19.33.png)

Again we can use `otool` to check whether a binary is using stack canaries by looking for some specific symbols, such as `_stack_chk_guard` and `_stack_chk_fail`:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-22-at-10.44.30.png)

Note the usage of `otool`'s `-I` and `-v` flags:

```
~ otool
	...
	-I print the indirect symbol table
	-v print verbosely (symbolically) when possible
```

If the stack canary is not present, you need to ensure that the `-fstack-protector-all` flag is set under `"Other C Flags"`, on your project's `"Build Settings"` tab, as shown below:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-22.50.58.png)

### Rpath <a href="#rpath" id="rpath"></a>

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-20.15.58.png)

The "Runpath Search Path" instructs the dynamic linker to search for a dynamic library (dylib) on an ordered list of paths ... sort of like how Unix looks for binaries on `$PATH`.

This is an issue because it makes it possible for an attacker to place a malicious dylib in one of the first paths that doesn't contain the library that the linker is trying to locate, therefore hijacking it.

A simple way to check whether or not your application's libraries were compiled using `rpath` is to run `otool` with the `-L` flag, which lists all Mach-O Shared Libraries:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-21.28.28-1.png)

Note that some of the libraries are prefixed with `@rpath`, while others are prefixed by the absolute path.

Also, if you already have access to the full MobSF Static Analysis report, you can simply scroll down to the "Libraries" section and check which are prefixed by `@rpath`:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-21.27.32.png)

If your application uses the [Swift Package Manager](https://www.swift.org/package-manager/), in order to compile the libraries without `rpath` you need to use some hidden build flags. On your local command line run:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-19-at-19.33.44.png)

Note the swift compiler option `no-stdlib-rpath` which disables `rpath` entries during compilation.

Configure your build settings so that the application is built with this configuration flag, e.g.: `swift build -c release -Xswiftc -no-toolchain-stdlib-rpath`.

Alternatively, if your application uses [Cocoapods](https://cocoapods.org/), you can first check the install directory of the pods:

![](https://inesmartins.github.io/content/images/2022/01/Screenshot-2022-01-13-at-13.15.10.png)

And then use the following configuration on your `Podfile`:

```ruby
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['DYLIB_INSTALL_NAME_BASE'] = <your-install-directory>
    end
  end
end
```

So, the result would looks something like this:

![](https://inesmartins.github.io/content/images/2022/01/Screenshot-2022-01-13-at-13.16.08.png)

### Symbols Stripped <a href="#symbols-stripped" id="symbols-stripped"></a>

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-21-at-20.19.40.png)

From Apple's [Building Your App to Include Debugging Information](https://developer.apple.com/documentation/xcode/building-your-app-to-include-debugging-information):

> When Xcode compiles your source code into machine code, it generates a list of symbols in your app—class names, global variables, and method and function names.\
> These symbols correspond to the file and line numbers where they’re defined; this association creates a *debug symbol*, so you can use the debugger in Xcode, or refer to line numbers reported by a crash report.\
> Debug builds of an app place the debug symbols inside the compiled binary file by default, while **release builds of an app place the debug symbols in a companion&#x20;*****Debug Symbol file*** (`dSYM`) to reduce the size of the distributed app.

So, the good thing about these `dSYM` files is that you can store them separately and then use them to [symbolicate](https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report) your logs without actually letting the end user have access to them via App Store:

```
~ symbolicatecrash "<path-to-crash-file>" "<path-to-dSYM file>" > symbolicated.crash
```

By default, `dSYM` files are generate for "Release" builds, which you can check by reviewing your `"Build Settings"`:

* `Generate Debug Symbols` = `YES`
* `Debug Information Format` = `DWARF with dSYM File`

A simple way to check whether or not your application was compiled with debug symbols is to again run `otool` with the `-Iv` flags:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-22-at-11.32.20.png)

Alternatively, you can use `nm`, which "displays the name list (symbol table) of each  object file in the argument list".

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-22-at-11.43.08.png)

If MobSF flags you project as containing debug symbols, please ensure that your project's `"Build Settings"` contain the following `"Release"` configurations:

* `Deployment Postprocessing` = `YES`;
* `Strip Debug Symbols During Copy` = `YES`;
* `Strip Linked Product` = `YES`;
* `Strip Style` = `All Symbols`;
* `Strip Swift Symbols` = `YES`

![](https://inesmartins.github.io/content/images/2022/01/image-1.png)

Finally, note that you can actually manually strip your binary, but as shown below, this invalidates the code signature:

![](https://inesmartins.github.io/content/images/2021/08/Screenshot-2021-08-22-at-11.46.45.png)
