Apple Inc. (originally Apple Computer Company) was founded back in 1976 to sell one of the world’s first personal computers (PCs) as we know them now. By now, Apple Inc. is an industry giant with a valuation of many billions of dollars. However, not everybody is aware that its modern operating systems (such as macOS, iOS, watchOS, and tvOS) are primarily based on the NeXTSTEP solution developed by the NeXT, Inc., a company founded by Steve Jobs following his resignation from Apple in 1985 and later acquired by Apple in 1997. All modern Apple operating systems are based on a set of components unified as the Darwin operating system, which is based on the XNU hybrid kernel.
Multiple Apple products became famous for their high quality and reliability, with their users enjoying the feeling of security and often strongly believing that there was no malware for Mac. Indeed, the number of malicious samples successfully targeting this platform is significantly lower than Windows. There are multiple reasons for this, including different security and business models, as well as the different markets of these platforms. However, as long as the number of potential targets that use these systems increases, we will also see an increase in effort to develop malware for Apple-driven platforms. Here, we will look at various threats that target users of macOS and iOS operating systems and will learn how to analyze them.
To streamline our learning, the chapter is divided into the following main sections:
In many cases, malware uses design weaknesses in the system architecture in order to achieve its goals. Examples could be unauthorized access to sensitive data, tampering with security measures, or modification of system files to achieve persistence or stealth. Thus, the security model plays a vital role in reducing the attack surface, and in this way, reducing the number of techniques available to malware authors.
Now, let’s take a look at security models introduced in macOS and iOS and see why they are important when we talk about malicious code.
macOS (previously Mac OS X and OS X) has gone through multiple iterations since it was first introduced in 2001. Prior to that, a series of operating systems developed between 1984 to 2001 for the Macintosh family of PC was in use; now, they are known by the colloquial term Classic Mac OS. macOS belongs to the family of Macintosh operating systems derived from NeXTSTEP. This operating system was originally based on Unix (particularly, BSD with the Mach microkernel). Using a Unix-derived architecture was a completely new direction compared to the previous Mac OS solutions.
Apart from traditional C/C++ languages, the main programming languages that Apple supports in their products are Objective-C and Swift (since 2014). Interactions between applications and the OS are possible through the native API, called Cocoa, derived from OPENSTEP; prior to that, the Carbon API was used.
There are multiple mechanisms implemented in the operating system that aim to boost security while always keeping usability in the mind. Let’s go through some of the most important ones.
macOS utilizes several security controls derived from BSD. In particular, it utilizes traditional discretionary access restrictions to system resources and files that are based on user and group IDs. In this case, permissions are granted mainly at the level of folders, files, and apps, and are controlled at many levels, including kernel components. In addition, macOS implements mandatory access controls to power multiple important features, such as sandboxing or System Integrity Protection. System Integrity Protection was introduced in OS X 10.11 and enforces read-only access to specific critical filesystem locations, even for the root user, which are applied to all running processes. The following locations are protected:
Figure 12.1 – No write access for one of the protected directories even with sudo
These paths can be accessed only by the processes signed by Apple as having a reason to work with them, such as Apple software updates. Thus, system files and resources, including kernels, are separated from the user’s app space so that malicious code can’t easily access it. The root user is disabled by default, but it can be enabled in system preferences when necessary.
Tasks and resources are administrated by introducing secure communication channels, called Mach ports. Ports are unidirectional endpoints that connect a client requesting service and a server that provides it, where a resource specified by a port generally has a single receiver and multiple possible senders. Permissions to access a port in particular ways by tasks are called port rights. Ports are an essential part of the macOS inter-process communication (IPC), which includes multiple forms, such as classic message queues, semaphores, or remote procedure calls. Bypassing the associated permissions shouldn’t be possible unless some vulnerability is discovered, such as CVE-2021-30869 used in the DazzleSpy threat.
Let’s take a look at the most common directories that can be found on the modern versions of macOS and learn a bit more about them.
Here are some of the most crucial directories (in terms of malware analysis) and their purpose:
Apart from that, there are various Unix-specific directories, such as /bin, /sbin, /var, /usr, and /tmp.
Apple uses its own Apple FileSystem (APFS) that offers multiple modern features, including strong encryption. All Mac computers are shipped with the FileVault disk encryption system, which utilizes the Advanced Encryption Standard (AES) algorithm to protect critical data. It is also possible to encrypt the whole disk and make it accessible only with valid credentials or a recovery key (FileVault 2). Once the user enables the FileVault feature, authentication is required before using the Target Disk mode, where a device can be attached to another machine and become accessible as an external device (making it possible for attackers to access sensitive data). Newer models of Mac computers are shipped with a dedicated Apple T2 chip (or its successors) and have disk encryption enabled by default. In this case, the optional FileVault provides extra protection by requiring credentials to be provided before decryption – otherwise, encrypted SSDs can be decrypted by simply attaching them to the corresponding Mac. In addition, the Apple T2 security chip enables Secure Boot to implement a chain of trust rooted in hardware, where the software integrity is assured at every next step of booting, making bootkit creation extremely hard.
All Macs are also shipped with the built-in Time Machine backup feature, which allows you to restore files once they are lost or damaged, for example, due to a ransomware attack. In this case, it is also possible to encrypt backups for extra security and use external storage to make them inaccessible to malware (especially wipers and ransomware).
Finally, it is possible to create encrypted disk images using Disk Utility and use them as secure containers for sensitive information. In this case, either 128-bit or 256-bit AES encryption is possible.
All these techniques make it more difficult for attackers to get access to sensitive information.
There are several built-in features available in macOS that ensure that only trusted applications are installed on the system.
One of the first technologies worth mentioning is called Gatekeeper. It gives users direct control over which apps are allowed to be installed. Thus, it is possible to enforce the policy by allowing only apps from the App Store to be used. All apps aiming to appear on the App Store should be signed with a certificate issued by Apple and reviewed by its engineers to ensure that they are generally free of bugs, up to date, secure, and don’t compromise the user experience in any way.
Default Gatekeeper settings also allow applications from outside the App Store that still have a valid developer ID signature, which means the app is signed using a certificate issued by Apple. In addition, it is possible to submit an app to Apple for notarizing. In this case, the files are checked by automatic malware scanning and signature checking; as a result, the ticket is distributed with the app and available online. So, when the user executes such an app, they get a notification that it has been checked by Apple for the presence of malicious functionality. Unsigned applications will be restricted in rights by mandatory access controls and cause alerts.
Another anti-malware feature implemented in Gatekeeper is Path Randomization, as in App Translocation. When apps appear to be less trustworthy, they are placed in the unknown within their developer system location, which supports at most read-only operations – for example, when the apps are executed from the unsigned disk image or from the location where they have been downloaded and unpacked (but not moved yet). The idea here is to prevent malicious apps from self-updating and from accessing data using relative paths. This feature works closely with another one that involves marking files downloaded using quarantine-aware applications with a special extended attribute, com.apple.quarantine. It will ensure that for particularly dangerous file types, the first time the user attempts to open or execute them, they will be treated in a more secure manner. This attribute can be seen when executing the ls –l@ command:
Figure 12.2 – An extended attribute com.apple.quarantine in action
All apps from the App Store are sandboxed and don’t have access to the data of other apps, other than by using dedicated APIs. For apps distributed outside the App Store, this feature is optional but highly recommended.
A non-sandboxed app has the same access rights as the user executing it, which means if it gets compromised by exploiting some vulnerability, the attacker gets user privileges. The way App Sandbox handles this is by only providing an app with the access rights it needs to perform its tasks; additional access may be explicitly granted by a user:
Figure 12.3 – App Sandbox explained
Here are examples of the resources that a sandboxed app has to request explicitly in order to use:
macOS features an embedded antivirus solution called XProtect that detects malware using signatures and can block its installation. This technology aims to prevent infection, but if it happens, another built-in program called the Malware Removal Tool (MRT) is supposed to monitor potential malware activity and remediate infections.
In addition, a built-in firewall can provide network protection. Finally, automatic security updates improve the overall level of system security.
Now, let’s compare it with the iOS setup.
In contrast with macOS, which is mainly developed for PC use cases, iOS was created later to power mobile devices—and this fact affects the security model introduced with it. Other newer operating systems, such as watchOS and tvOS, are extensively based on it, so we will focus mainly on iOS in this chapter.
Similar to macOS, the development can be done in the Objective-C and Swift programming languages, and the API in this case is called Cocoa Touch, which also includes mobile-oriented features, such as gesture recognition. All iOS-powered devices use ARM-based processors.
Now, let’s take a look at the different layers of protection implemented in iOS.
The first thing that is worth mentioning here is the secure boot chain. This means that all components involved in the system code execution are signed by Apple and thus comprise a chain of trust, including the following:
In both recovery and DFU modes, the device can be updated or restored to a valid state of the OS. The difference between them is that the recovery mode works mainly through iBoot, which is essentially a part of the operating system, so it can be updated or modified if necessary. In contrast, the DFU is part of the Read-Only Memory (ROM) and cannot be tampered with.
When available, the secure enclave coprocessor is responsible for cryptographic operations that confirm the integrity and overall data protection. It runs a dedicated updatable Secure Enclave OS that is also verified by the Secure Enclave boot ROM.
As we can see, the startup process ensures that only Apple-signed code can be installed and executed, which serves as protection against bootkits and similar threats. Apart from this, Apple strongly opposes downgrading software to older, less secure versions (either by a user or by an attacker), so it introduces a mechanism called system software authorization that prevents its installation. All system updates can be installed either through iTunes, when a full image of the OS is being downloaded and installed, or through an Over-The-Air (OTA) mechanism, where only components related to updates are used.
In terms of encryption, Apple introduced several important features to make it both extremely robust and highly productive. Each iOS device has its Unique ID (UID) and Group ID (GID) to be used in cryptographic operations, where the UID is unique to the device and the GID is shared across all processors of the same type. These values are fused or compiled into the Secure Enclave and CPU during manufacturing; each device gets its own values that are not accessible directly by either software, firmware, or through debugging interfaces (such as JTAG). Cryptographic keys are generated inside the Secure Enclave utilizing a true Hardware Random Number Generator (HRNG), which are generally more secure than Pseudo-Random Number Generators (PRNGs). In addition, a dedicated technology called Effaceable Storage is responsible for securely erasing saved keys once they are no longer needed. File encryption is implemented based on the technology called Data Protection. It generates a new 256-bit AES key for each file created on the device. On newer devices, AES-XTS encryption mode is used, while older devices feature AES-CBC mode. This per-file key is then wrapped (encrypted) with the corresponding class key, which varies for different types of data and is handled differently according to it. Here are the classes supported at the moment:
Finally, the wrapped key is stored in the file’s metadata, which is encrypted using the filesystem key. While the class keys are encrypted/wrapped using UID and some of them with the passcode, the filesystem key is wrapped using the effaceable key stored in the Effaceable Storage. Once the effaceable key is deleted (for example, using a remote wipe or the Erase All Content and Settings options), it makes the content of all files inaccessible by any means.
When the user sets a passcode, Data Protection becomes enabled automatically. As it is connected to the device’s UID (which we now know is not accessible), it is impossible to brute-force passcodes without the device being physically present. There are several other mechanisms implemented to complicate brute-forcing, for example, a large count of iterations to slow it down, time delays, or automatic data wiping after entering several consecutive invalid values. Other authentication mechanisms, such as TouchID and FaceID, work closely with this technology.
All sensitive data that belongs to apps can be stored in the iOS keychain, which is an SQLite database where values are encrypted using the AES-256-GCM algorithm. This keychain also introduces its own classes to handle different types of data. This way, developers can prevent access to certain data under particular circumstances, for example, when the device is locked. Keychain items can be shared by several apps, but only when they come from the same developer. Finally, all class keys for file protection and keychain are administrated using keybags. There are several types of them used at the moment in iOS:
Saved user passwords are kept in the dedicated storage, called the Password AutoFill keychain. In addition, the iCloud keychain mechanism is responsible for synchronizing credentials across multiple devices. Together, these technologies provide functionality to generate strong passwords, fill in credentials on the websites and apps of your choosing, and securely share them.
It is impossible for apps to access credentials without explicit user consent. In addition, you may need approval from the application or website developer. This approach makes unsolicited data access much more difficult.
iOS requires all code running on the device to be signed using a valid Apple-issued certificate, to ensure its integrity and that it comes from a trusted source. Unlike macOS, this rule is enforced, and the sideloading of apps outside the App Store is not supported for purposes other than app development. A notable exception to this rule is code signed with Enterprise Program certificates, which mainly aim to allow the distribution of proprietary software for internal use or intra-organization beta testing. Later, we will see how this technology can be misused by malware. Usually, this is done using MDM; in this case, a special enterprise-provisioning profile is created on the device.
Once the developer joins the Apple developer program, their identity needs to be verified before the certificate can be issued. Since 2015, there is also an option for developers to sign their code for free, but it has multiple limitations, such as a short expiration date, lack of access to certain features for apps, and a small number of devices on which the app can be executed. In addition, all app code must be verified by Apple to confirm that it is free of obvious bugs and doesn’t pose a risk to users. While it frameworks can be loaded inside the apps, the system validates the signatures of all loaded libraries at launch time using team identifiers.
It may be quite difficult for the attacker to obtain a full valid certificate, but even in the case of success, Apple has an option to promptly revoke the compromised entry and thus protect the majority of devices.
All apps are sandboxed, so they can only access the resources necessary to perform their function. They run under the non-privileged mobile user and there are no APIs that allow self-privilege escalation. Each app has its own directory to store files and can’t gather or alter information associated with other applications – only apps that belong to the same App Group and come from the same developer can access a limited set of shared items.
The following directories are commonly used by sandboxed apps:
The exact location at which apps are installed varies among the different versions of iOS.
There are dedicated APIs that can be used to allow safe interaction between apps. In addition, the apps’ extensions (signed executables shipped with the app) can be used for inter-process communications as well; in this case, each extension has its own address space. All this makes it very difficult for attackers to access or tamper with sensitive information, or to affect the system.
The way that third-party apps can access sensitive data is controlled by mechanisms called entitlements. These are digitally signed credentials, associated with apps, for handling privileged operations. Beyond this, features such as Address Space Layout Randomization (ASLR), ARM’s Execute Never (XN), and stack canaries are used to provide protection against exploits that leverage memory-corruption vulnerabilities. Finally, the entire partition that stores the operating system is mounted as read-only to prevent tampering.
One last thing worth mentioning is the Apple FairPlay DRM protection, which may also be used to apply encryption to the app once it is downloaded so that the encrypted block can be decrypted only on the approved device that is requesting it. It may complicate the life of reverse-engineers doing a static analysis of the sample, as the decrypted version needs to be obtained first, so this is worth keeping in mind.
Now, it is time to dive deeper into the various file formats widely used in Apple operating systems to manage executables.
Knowing about file formats and their structure is important for static analysis, as it becomes possible to know exactly where to search for particular artifacts of interest. In terms of dynamic analysis, knowledge about the structure is particularly useful, as this way, we know how to run the sample properly and the order in which the code is going to be executed, so we won’t miss an important part of the functionality.
This format is the main executable format on macOS and iOS operating systems. It has pretty much the same role as PE on Windows or ELF on Linux-based systems. It is also used to store object code, shared libraries, and core dumps. There are two types of these files: thin and fat.
This is the most common type of Mach-O file. It is composed of the following parts:
struct mach_header {
unsigned long magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
unsigned long filetype; /* type of file */
unsigned long ncmds; /* number of load commands */
unsigned long sizeofcmds; /* the size of load commands */
unsigned long flags; /* flags */
};
The difference between 32-bit and 64-bit versions of this header lies mainly in the extra reserved field added to the end of this structure, and the slightly different magic values used: 0xfeedface for 32-bit and 0xfeedfacf for 64-bit.
struct segment_command {
unsigned long cmd; /* LC_SEGMENT */
unsigned long cmdsize; /* size of section structs */
char segname[16]; /* segment name */
unsigned long vmaddr; /* memory address of this segment */
unsigned long vmsize; /* memory size of this segment */
unsigned long fileoff; /* file offset of this segment */
unsigned long filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
unsigned long nsects; /* number of sections in segment */
unsigned long flags; /* flags */
};
The same fields are used within 32-bit and 64-bit architectures (LC_SEGMENT and LC_SEGMENT_64 commands, respectively) – the difference will only be the sizes of the fields.
It is followed by a set of structures that describe the sections:
struct section {
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
unsigned long addr; /* memory address of this section */
unsigned long size; /* size in bytes of this section */
unsigned long offset; /* file offset of this section */
unsigned long align; /* section alignment (power of 2) */
unsigned long reloff; /* file offset of relocation entries */
unsigned long nreloc; /* number of relocation entries */
unsigned long flags; /* flags (section type and attributes) */
unsigned long reserved1; /* reserved */
unsigned long reserved2; /* reserved */
};
In terms of malware analysis, another load command that might be of interest to an analyst is LC_LOAD_DYLIB, which is responsible for loading additional libraries.
The files that implement this format contain machine code associated with one platform only. At the moment, it is ARM for iOS and x86-64 or ARM for macOS; older versions of macOS were based on PowerPC and later, IA-32 architectures.
The format has undergone a few changes with the introduction of Mac OS X 10.6, which made newer executables incompatible with older versions of the OS. These changes included the following:
Fat binaries (also known as multi-architecture binaries or universal binaries) are quite unique, as they are used to store code for several different architectures. The format includes a custom fat header, followed by a set of Mach-O files:
Figure 12.4 – A fat Mach-O executable file
Here is the header structure:
struct fat_header { unsigned long magic; /* FAT_MAGIC */ unsigned long nfat_arch; /* number of structs that follow */ };
The magic value, in this case, is 0xcafebabe.
This header is followed by several fat_arch structures, whose amount is equal to the value specified by the nfat_arch field:
struct fat_arch { cpu_type_t cputype; /* cpu specifier (int) */ cpu_subtype_t cpusubtype; /* machine specifier (int) */ unsigned long offset; /* file offset to this object file */ unsigned long size; /* size of this object file */ unsigned long align; /* alignment as a power of 2 */ };
All these structures can be found in the officially published Apple source code.
Figure 12.5 – IDA confirming which thin Mach-O file in the fat binary should be analyzed
Usually, it makes sense to stick to the architecture that the engineer is most comfortable working with.
Bundles are directories that store everything that the app needs in order to successfully perform its operations. It allows related files to be grouped together and distributed as a single entity. In the case of both macOS and iOS systems, they generally include the following:
The most common extension associated with application bundles here is .app. The file hierarchy is slightly different for iOS and macOS; for the former, all required files are located in the root folder, while for the latter, they are located in the dedicated Contents folder, with the code located in the MacOS subdirectory and resources in the Resources subdirectory inside it. Other common standard subdirectories used are PlugIns, Frameworks, and SharedSupport.
As has already been mentioned, Info.plist provides important app-related metadata to the system at runtime. The required values are slightly different for macOS and iOS; let’s go through the most important of them.
Here is a list of important values with a brief explanation for each:
Now, let’s take a look at the fields for iOS apps:
Figure 12.6 – A CFBundleExecutable field in the Info.plist file of an AceDeceiver threat
Besides XML and JSON, .plist files can also be encoded using the binary format. In this case, they will look as follows:
Figure 12.7 – A binary-encoded .plist file of the ZergHelper threat
The standard file tool will display the following message for such files:
Info.plist; Apple binary property list
To convert them to a human-readable format, use the standard plutil tool: plutil -convert xml1 Info.plist.
These files commonly have the .pkg file extension and are used to group and store related files together, preserving the file hierarchy. Then, they can be extracted and installed using the installer application on macOS. Internally, they implement eXtensible ARchive (XAR) format. The content can be explored and extracted using a standard macOS xar tool:
Figure 12.8 – The content of the .pkg file listed using the xar tool
Important note
It is not recommended to use 7-Zip for extraction in this case, as it doesn’t see all the files present in the archive compared to the xar tool, which may lead to some artifacts that are important from the analysis perspective being overlooked. Figure 12.9 is an example of the incomplete data visible when using 7-Zip.
Figure 12.9 – 7-Zip only displaying a subset of the files present in the archive compared to the xar tool
Aside from looking for Mach-O executables in the Payload directory, also check the PackageInfo file, as it may point to scripts that will be executed during the installation, commonly located in the Scripts archive. Another place to check is the Distribution file if present, as it may contain executable JavaScript code.
This is another common way to distribute applications for macOS; the corresponding disk image files generally have the .dmg file extension. They can be used as a mountable disk or volume for storing files of various types. The native format used for this nowadays is the Universal Disk Image Format (UDIF), but prior to that, the New Disk Image Format (NDIF) was used. It also supports compression and encryption. Rather than a header, they can be recognized by a trailer, which contains a magic four-byte koly value at its start. In order to get access to the files inside, the disk image can be mounted or converted using standard tools bundled with Apple operating systems, such as the hdiutil console. On other operating systems, it is possible to use tools such as dmg2img to convert these files into a non-proprietary disk image format and then mount them as usual. Alternatively, they can be unpacked using tools such as 7-Zip.
iOS App Store Package is a format used in iOS to distribute archived apps. The file extension used in this case is .ipa. All .ipa files should contain the Payload directory with the .app bundle directory inside, which may also contain various metadata for iTunes and the App Store. In terms of implementation, the ZIP format is used here, which means that these files can be unpacked using any standard tools able to handle ZIP files.
Now that we are familiar with the most common file types used in Apple systems, let’s explore their APIs.
Apple provides a rich set of APIs to developers that aim to let them perform any task in a robust and secure way. The NS prefix commonly used in names stands for NeXTSTEP – the platform that they were originally designed for. The CF prefix is an abbreviation of the Core Foundation framework, which is a C API for macOS and iOS. The reason they co-exist and sometimes provide similar functionalities is mainly historical, as this is the result of merging the Classic Mac OS toolbox and OPENSTEP specification. There is even a special term for using the corresponding logic interchangeably: toll-free bridging.
Here are some examples of classes commonly misused by malware:
Low-level functionality can also be implemented using classes from the Streams, Sockets, and Ports group, such as InputStream and its counterpart, CFReadStream. Another option is the NSWorkspace class from AppKit, which can be used to manipulate files and access their metadata. Beyond this, it is also possible to work with files using certain NSString methods; for example, stringWithContentsOfFile.
In disassembly, things will look a little bit different. Particularly, the objc_msgSend function will appear quite often, as it is used by the compiler to interact with instances of classes by sending messages and receiving the results. In order to figure out the actual functionality, we need to map selector arguments to the corresponding human-readable values, a job generally done by disassemblers and decompilers. Here is how it may be presented in the debugger:
Figure 12.10 – An example of XcodeGhost’s disassembly in IDA preparing a web request
We have already learned enough about how malware samples may look, so now let’s explore what their most common functions would be.
Regardless of the targeted architecture, generally, malware has to go through the same stages in order to achieve its goals; however, the implementation can be quite different. Let’s go through the most important of them.
To begin, let’s talk about jailbreaks in greater detail. Jailbreaking generally applies to iOS mobile devices and involves obtaining elevated privileges in order to remove certain software restrictions. There are multiple reasons why users may want to do this to their devices:
While the terms jailbreaking and rooting are often used interchangeably, jailbreaking is actually a broader term, as it also involves unlocking the bootloader in order to modify the operating system, for example, to allow easy app sideloading (that is, the installation of unsigned apps or apps distributed outside the App Store).
There are several common types of jailbreaks for iOS, based on the way the kernel is patched:
Older jailbreaking tools, such as JailbreakMe, could even be used over the internet by downloading a specifically-crafted PDF exploit that targeted the Safari browser. Newer tools, such as unc0ver and Chimera, are generally distributed as IPA files that can be installed on a device by signing them with a free developer certificate associated with the owner of the device and manually approving them in the device settings. Once the exploit has been successfully applied and elevated privileges are obtained, usually, the Cydia package manager is installed. In addition, many users install OpenSSH in order to be able to get access to a full-fledged console. So, common malware checks for an existing jailbreak involve looking for the presence of Cydia or sshd files in the filesystem.
As we can see, generally, there is no obvious solution for generic malware to silently apply a jailbreak when running either on the device itself or the connected PC without interaction with a legitimate user. Thus, many malware families prefer to either target already-jailbroken devices or rely on other techniques in order to achieve their goals.
As we know now, the application-related policies are quite different for macOS and iOS. If macOS still makes it possible for users to install programs outside the App Store, lower their security settings to allow unsigned applications, and create programs that don’t incorporate App Sandbox, all this is not possible on iOS without jailbreaking the device. Thus, the common penetration vectors differ for these operating systems.
As the App Store infrastructure is quite well-protected against malicious apps, especially because of the obligatory signing of quite expensive certificates that can be promptly revoked, therefore deactivating the corresponding threat on the vast majority of devices, mass malware authors rarely follow this path. Still, there are some exceptions to this rule, for example, when malware authors get access to stolen certificates or inject malicious functionality into legitimate software. An example of this could be an XcodeGhost threat that managed to get access to developers’ machines via a compromised Xcode IDE downloaded from a third-party website and injected malicious logic into legitimate iOS apps. Another approach was chosen by the authors of XcodeSpy and XCSSET threats, which embedded into distributed Xcode projects and executed payloads when the developer would build them.
A creative way to bypass the revocation of malicious apps was used by the authors of AceDeceiver, who managed to upload their app to the App Store by checking the physical location and presenting benign functionality to users located outside of China. The attackers managed to intercept the authorization token used by the Apple FairPlay DRM technology, which is unique to each app but the same for all devices. Eventually, this token allowed the attackers to perform FairPlay MITM attacks – when a client running on the connected PC can use it to install an app to non-jailbroken iOS devices, even after the actual app was removed from the App Store. Another app that managed to bypass the Apple review was ZergHelper. In order to install apps on non-jailbroken devices, it implemented a part of the Xcode functionality responsible for automatically obtaining free developer certificates. Originally intended to be used to sign apps that can run only on the personal developer’s device, in this case, they were used to sign unwanted apps on the fly, before installing them on the victim’s device associated with the requested certificate:
Figure 12.11 – ZergHelper dynamically obtaining developer certificates
One more notable example is WireLurker, distributed via Chinese app stores where it trojanized hundreds of apps. In this case, even if the device wasn’t jailbroken, it was possible to collect some basic information about the system and install unwanted apps signed with Enterprise Program certificates.
Overall, many iOS threats primarily target jailbroken devices to be able to get access to sensitive information or required system features – on modern systems, there is no easy way to elevate privileges from the device itself, so users commonly jailbreak their own devices by manually signing jailbreaking apps using their own certificates and allowing them access to the device settings. Cydia repositories are among the most common places where malware authors host their brainchildren. A notable exception to this rule was the Pegasus malware, which leveraged a zero-day exploit that targeted the Safari browser, so it was enough for users to click on the phishing link in order to get infected.
For macOS, attackers these days mainly focus on simpler options, such as hosting malicious apps on third-party websites, application stores, or torrent networks and relying on social engineering techniques to trick users into installing them. In the case of the KeRanger threat, a legitimate website was compromised and the corresponding software was trojanized. The use of exploits that target browsers is quite rare nowadays. In addition, just as with Windows users, it is possible to get infected by opening a Microsoft Office document that contains a malicious macro and allowing it to be executed. In some cases, malware authors may still prefer to propagate through the App Store using stolen certificates to bypass Gatekeeper. This particularly applies to malware families that don’t care whether they are detected and deleted in a day or two, as their aim is to affect as many users as possible in a very short time. A good example is ransomware, whose job is done as long as it manages to encrypt a victim’s files and then deliver instructions on how to pay a ransom.
Once the first-stage malware enters the targeted machine, it generally needs to settle down, deliver, and configure additional modules (commonly by downloading or extracting them from its body), and then make sure it will survive the system reboot. That’s what execution and persistence stages are mainly about.The deployment mechanisms vary for macOS and iOS systems. Let’s take a look at each of them in greater detail.
There are multiple places where malware can hide from the user on the macOS system. Here are some of the most common locations:
Persistence is commonly achieved by adding the corresponding .plist file to one of the following locations:
Figure 12.12 – Malware establishing persistence by copying its .plist file to /Library/LaunchDaemons/
Figure 12.13 – The WireLurker threat using the /System/Library/LaunchDaemons path
Persistence can be also achieved by various other means such as using the cron tool or performing dylib hijacking, where the malicious dynamic library (dylib) is placed in a path that a legitimate victim application searches for and loads at runtime.
Now, let’s take a quick look at how things are organized in iOS.
For non-jailbroken devices, malware often hides in trojanized legitimate software packages (clean software with inserted malicious code). For the end user, the app looks and behaves as expected, while simultaneously performing malicious actions in the background.
For jailbroken devices, malware has access to multiple locations throughout the system, so in this case, the choice depends mainly on the preferences of the attackers.
As with macOS, persistence can be achieved by placing a .plist file in one of the .../Library/LaunchDaemons directories.
Now, let’s talk about the actual negative effects that malware may cause. In many cases, the motivation behind the attack can be the same whether it occurs on a mobile device or a PC. Nowadays, both provide access to a large amount of sensitive information and have enough computational power to perform actions that malware authors may be interested in.
To begin, most of the malware types affecting Mac users strongly resemble the threats targeting Windows users – the difference is mainly in the scope and implementation. Thus, macOS Terminal actually uses Unix shells, so malware can create shell scripts and utilize the various commands that we discussed in the previous Chapter 11, Dissecting Linux and IoT Malware. Here are some of the other commands that are commonly misused on Mac computers:
Meanwhile, the following entries can be used to set a custom search engine:
In addition, unlike many Linux distributions, modern macOS is shipped with Python, so malware can rely on its presence as well.
Figure 12.14 – Python code used by the CookieMiner malware
Now, let’s go through some of the recent examples of malware categories commonly targeting Mac users:
Figure 12.15 – MaMi malware installing a custom root certificate
Figure 12.16 – The KeRanger malware preparing a ransom-related note
The KeRanger threat was signed with a valid certificate to bypass Gatekeeper and used a C&C located in the Tor network. A more creative way to do this was used by the Safari-get authors. The idea was to make a system unusable, for example, by opening multiple windows, providing a contact number falsely associated with a legitimate organization (such as Apple), and then charging money to resolve the issue. The interesting part is that all this could be done after the victim just visited a specifically-crafted website, which either created multiple mail drafts or opened iTunes using <a href=”mailto:...” and <a href=”itunes:...” attributes.
A more recent example of ransomware malware is EvilQuest.
It’s worth mentioning that the number of threats successfully targeting iOS devices is significantly lower than on macOS, thanks to the strong security architecture enforced on it. Over the last few years, there were very few big incidents involving malware for this platform. Here are some of the most notorious ones:
Apart from using traditional malicious code that executes on the system, there are other attack vectors that can be used to access sensitive information or enable surveillance. While not all of them involve using malicious software as we know it, it is still important to be aware of them, as in many cases, they may be the actual reason for a system compromise. Here is a list of the most notorious examples for macOS and iOS.
There are multiple types of attack that can be performed once the attacker gets physical access to the device. They are commonly known as evil maid attacks, based on the scenario where a hotel maid can subvert unattended devices left in the room. Many of them have been addressed over the last few years. Let’s have a look at the most common techniques:
These techniques generally require physical access to the device. Many of them are known under the umbrella term of malicious charger attacks, as they can be performed once the mobile device is connected (using its physical port) to malevolent hardware:
Here are some notable exceptions that don’t rely on physical access:
Even though the number of malicious samples targeting macOS and iOS users is significantly lower than for other more prevalent platforms, such as Windows and Android, we can still distinguish between the generic and more advanced techniques implemented. They involve non-standard or difficult-to-implement approaches that usually aim to complicate the analysis and to prolong the infection.
Some malware families that target macOS and iOS incorporate universal techniques to complicate analysis and detections that work for most other platforms as well. Here are some examples:
Figure 12.17 – A list of antiviruses to search for in CrescentCore malware
Figure 12.18 – Custom xor-based encryption used in Pirrit malware
Now, let’s talk about other techniques.
Apart from using macros in MS Office documents, there is another, less common way to execute code. In this case, attackers rely on the DDE functionality. One way to do so is to use the DDEAUTO statement (currently disabled by default). Another option recently used to spread the cross-platform Adwind RAT is to abuse the function logic implemented in Microsoft Excel. Please refer to Chapter 10, Scripts and Macros – Reversing, Deobfuscation, and Debugging, for more information. Attackers can always try to utilize social engineering tricks in order to make the user enable any required functionality.
This technique can be used to hide a newly created user from the configuration and login screens. The idea here is to set a Hide500Users property within the /Library/Preferences/com.apple.loginwindow.plist file. In this case, all users with a UID lower than 500 won’t be present on these screens. An example of a threat that uses this technique to hide an illegitimate user is Pirrit malware.
AppleScript was originally developed to automate certain tasks within Apple systems. However, its functionality is commonly misused by various malware families as well. For example, the aforementioned Pirrit threat managed to use it to inject JavaScript payloads into browsers. To perform code injection, the osascript command-line tool can be used. Here are snippets with examples for different browsers:
tell application "Safari" to do JavaScript "<payload>" in current tab of first window
tell application "Google Chrome" to execute front window's active tab JavaScript "<payload>"
Besides this, it is possible to use osascript for other purposes; for example, CookieMiner used it to set up environments before delivering other modules, as you can see in the following figure:
Figure 12.19 – The first-stage payload of the CookieMiner threat misusing the osascript functionality
Finally, malware can use so-called run-only AppleScript scripts, which are the compiled versions of the original scripts without their source code. The standard file extension for them is .scpt. OSAMiner is an example of a malware family utilizing them. Unfortunately, the standard osadecompile tool cannot decompile run-only scripts, so other tools such as applescript-disassembler and aevt_decompile have to be used to present the script’s functionality in a human-readable form.
This technique is found when infostealers target jailbroken iOS devices. The idea here is to intercept certain APIs in order to get access to sensitive data before it gets encrypted or after it has been decrypted. One example could be KeyRaider targeting SSLRead and SSLWrite from the itunesstored process with the help of Cydia Substrate, otherwise known as MobileSubstrate:
Figure 12.20 – A parsed .plist file from one of KeyRaider’s modules
There are other techniques that are not common among macOS malware developers and serve more as features of certain malware families. For example, while most threats that target Apple systems rely on Bash, AppleScript, and Python for scripting, the Silver Sparrow malware prefers to use JavaScript instead, misusing the installation-check element in the standard Distribution XML file present in .pkg samples:
Figure 12.21 – The Silver Sparrow threat using JavaScript code during its installation
Another interesting example is the Bundlore threat, which is distributed in the form of .dmg files that don’t contain executables as they are. Instead, the next-stage payload is dynamically decrypted and loaded using an embedded bash script, as you can see in the following figure:
Figure 12.22 – Bundlore using an embedded script to decrypt the next-stage payload
Sometimes, malware developers get quite creative at introducing new ways to run their malware. For example, the authors of the LoudMiner threat have the whole VM running with the help of QEMU to mine cryptocurrency and utilize their victim’s resources.
Finally, let’s briefly mention the topic of rootkits.
It might be surprising to some people, but rootkits targeting macOS do exist. One of the most notable examples in this category of threats is the Rubylin rootkit. Among its features is the ability to hide files, directories, and processes, as well as users and ports from particular tools. Most of the techniques used in this case are different implementations of the approaches that we covered in Chapter 7, Understanding Kernel-Mode Rootkits, dedicated to Windows kernel-mode threats, but this time for the XNU kernel. As there are pretty much no notorious malware families that extensively use these techniques for malicious purposes, it falls outside the scope of this book. If you’re curious, you can find more information about its internals by reading the Phrack article, Revisiting Mac OS X Kernel Rootkits, in issue 69.
Now that we know enough about how macOS and iOS are organized and what their executable files look like, let’s talk about how to analyze the malware targeting them.
As we know now, the most common programming languages that are used to write code for Apple platforms are Objective-C and Swift. The disassembly will look different depending on which language the malware author chooses, but in both cases, pretty much the same tools can be used for analysis.
Let’s take a look at the options available on the market in order to facilitate the reverse-engineering of macOS and iOS programs.
For engineers who don’t have immediate access to a Mac computer or a VM available to run malware on, it is beneficial that most of the static analysis tools are available on multiple platforms, so the analysis can be performed on other operating systems as well.
Before any actual malicious code can be analyzed, it first needs to be obtained. Here is how it can be done, depending on the way it is distributed:
Figure 12.23 – Looking inside the DMG file
While it is possible to extract some files from .deb packages using this tool, a more reliable way here is to use the standard ar tool with the x argument, ar x <sample>.deb. As we have already mentioned, for .pkg archives, the xar tool is highly recommended over 7-Zip.
Here is a list of tools commonly used to work with the disassembly of samples:
Figure 12.24 – An example of the disassembled Mach-O file for the ARM platform in radare2
In order to load a 64-bit ARM Mach-O sample (either as a standalone thin file or as part of a fat binary), use -a arm -b 64 arguments.
The following are the auxiliary tools and libraries for static analysis:
Apart from this, many basic universal tools, such as file, strings, or nm, can be used to extract information from executables.
While static analysis tools are pretty much the same for macOS and iOS files, the dynamic analysis toolset varies drastically due to different security models implemented in both operating systems. It is possible to install macOS on the virtual machine, but for iOS, having a real device is usually the only reliable option.
Dynamic analysis of executables for macOS is quite straightforward and doesn’t involve any special extra steps.
Performing step-by-step debugging is extremely useful in many cases, for example, when we have to deal with obfuscated code and understand the logic behind certain operations. Luckily, there are multiple powerful tools available that make this possible:
In case the other fields are incorrect (for example, left untouched and this way, associated with a local file, rather than a remote machine), modern versions of IDA will ask whether it should copy the file specified in the Input file field to the remote computer:
Figure 12.25 – Debugging WireLurker targeting macOS remotely in IDA located on a Windows machine
These tools have already been described in detail in Chapter 11, Dissecting Linux and IoT Malware, and all that knowledge can be applied here as well.
Commonly referred to as behavioral analysis, running malware in a real or simulated environment with various monitors to track system changes can provide a quick and valuable insight into malware functionality. In addition, it may be useful to change the behavior of the executed sample on the fly. Here are some of the most popular tools that make it possible on macOS:
Important note
In order to make this tool work, you may need System Integrity Protection (SIP) to be temporarily turned off. Follow the latest documentation for your version of macOS (and VM if applicable) to do so correctly and safely. You can run the csrutil status command to check whether it is currently enabled.
Beyond these, there are multiple standard macOS tools that can be used to monitor system activity, such as lsof or fs_usage for file operations.
Figure 12.26 – Using the fs_usage tool for behavioral analysis
All these tools are pretty easy to set up and start using – just follow the latest official documentation for them.
In terms of network analysis, this can be easily done on the device itself. In this case, popular solutions such as Wireshark and tcpdump can be used. To intercept and decode HTTPS traffic, Fiddler and the commercial Charles proxy can be used. In addition, it is always possible to redirect the traffic of interest (for example, by setting up a proxy or performing DNS hijacking) to a MITM solution, such as Burp Suite.
More stringent security controls and App Sandbox on iOS generally prevent researchers from performing analysis straight away, so often the use of jailbroken devices with the Cydia package manager installed is preferred here. Its name derives from Cydia pomonella, known as the codling moth, a major pest in the apple industry. Cydia provides an alternative app market with lots of tools that are useful for reverse-engineering purposes.
Besides Cydia, it makes sense to get OpenSSH (if it is not already installed) because it enables the engineer to execute commands on the testing device from the connected PC.
The first thing that may be tricky is to deliver malware to the testing system. The following tools should be used on the PC that the jailbroken device is connected to:
Figure 12.27 – The interface of the Cydia Impactor tool
In order to use this tool, there is no need to install Cydia Extender; if you don’t have a paid developer account, simply drag and drop the required .ipa file over its interface. Then, the tool will ask for an Apple ID and the corresponding password. Keep in mind that this should be not the main set of credentials used to log in to the Apple website but an app-specific password that can be generated at https://appleid.apple.com.
If the developer certificate hasn’t been recently approved, it should be done on the device by going to Settings | General and then either selecting the Profiles or Device Management option (the exact name may vary depending on the iOS version). There, it is possible to manually approve the loaded app, which requires an internet connection.
Now, let’s talk about debuggers.
The list of the most common debuggers in this case is pretty much the same as for macOS. The main difference here will be in the setup, as iOS is used to power mobile devices, and it is generally more convenient to perform debugging on the PC:
As we know now, as part of the copyright protection measures implemented in iOS, apps that come from the official App Store are encrypted. While this technology is supposed to fight piracy, it may also complicate malware analysis. Here are some of the best tools that can be used to decrypt samples:
Now, what about monitoring apps running in memory?
It is also possible to set up monitoring tools for iOS, even though it may require some non-standard approaches. Luckily, there are multiple existing tools that make this possible:
Alright, what about analyzing network activity?
Apple provides a Remote Virtual Interface (RVI) mechanism for use on the Mac connected to the device via USB. Once created using the rvictl tool, the interface can be used with tcpdump on the Mac to record the mobile device’s traffic. In addition, just as with macOS, it is possible to redirect required network traffic to a MITM solution of your choice and review or modify it if necessary.
Now we know what tools we should use at different stages of the analysis, let’s summarize the steps that we may need to go through to define the workflow.
When analyzing malware that is targeting Apple systems (whether it be macOS or iOS), the following workflow can be used:
Continue the analysis using references to strings as landmarks, keeping the markup accurate. Also, carefully review the code close to the sample’s entry point, as it may contain arguments that parse functionality.
All this information will allow you to confirm the exact purpose and type of the malware (at this stage, we already know how they look), which is extremely useful for estimating the risks and losses involved.
Choose your analysis strategy depending on the questions that need to be answered, and the time and setup available. Some steps may be modified or completely omitted if they fall outside the scope of the report that needs to be delivered.
In this chapter, we learned about the security models of macOS and iOS to understand potential attack vectors, and dived deeper into the file formats used on these operating systems to see what malicious samples may look like. Then, we went through the tools available to analyze malware that targets macOS and iOS users and provided guidelines on how they can be used. After this, we put our knowledge into practice and went through all the major attack stages generally implemented by malware, from the initial penetration to the action phase, and learned how they may look in real-life scenarios. Finally, we covered the advanced techniques utilized by more high-profile malware families.
Equipped with this knowledge, you now have the upper hand in analyzing pretty much any type of threat that targets these systems. As a result, you can provide better protection from unwarranted cyberattacks and mitigate further risks.
In Chapter 13, Analyzing Android Malware Samples, we are going to cover another popular mobile operating system, Android, and we will learn how to deal with the malware that targets it. Read on!