EvilQuest macOS Ransomware

8 minute read

Mac OS Malware Analysis

This won’t be just an analysis of the “EvilQuest” ransomware, I will be explaining in detail some internals and things that are done in different ways between Mac & windows Os.


In the last few days, I spent some time learning about MacOs’ malware, Studying File Format for Mach-O executables, and more about the environment itself.

I am new to this area and I know that I may be missing some important internal stuff for MacOs until the time of writing this blog post but I was shocked by what I will mention here.

I am running this version of Mac Os

Error loading

It was a standard installation process means that it contains all the defaults.

But when I downloaded the “EvilQuest” sample the was nothing preventing me from doing that and also nothing preventing the ransomware from infecting the device, although the sample has a high score on virus total.

Error loading

File Structure

We are presented with an x64 Mach-O file.

Error loading

A Mach-O file consists of three major regions — a header, load commands, and segments.

You can use the built-in tool otool to parse object files.” for more options use the man page”

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; /* size of all load commands */
    unsigned long flags; /* flags */

Error loading

Load Commands:

Variable size commands that specify the layout and linkage characteristics of the file. Can specify the initial layout of the file in virtual memory, location of the symbols table, initial execution state of the main thread, names of shared libraries for imported symbols, and more…

there is a big number of load commands so you can find more about them in the resources.

As an example of what you can find in “Load Commands” for our malware, Here are the two commands shown the first on is showing where are the main of the file is, and the second one shows what libraries needed by the file.

Error loading


Segments are somehow the same concept of dividing the content of the file into Code and data and applying specific write, read, and execute permissions to each one.

Code Analysis

I am using Ida pro in a Remote debugging session to analyze the sample.

Args Check

The file starts by checking the arguments supplied and based on that it initializes some local variables.

Error loading

there is three command line arguments:

  • –silent
  • –noroot
  • – ignrp


The file then starts a function that checks if it’s running inside a VM

Error loading

It’s a simple implementation of checking for VM using execution time. “Actually this implementation never catched my VM” I think this because it’s not implemented for our VMs but it’s for sandboxes that speed up any delay.

Error loading

Enum user Info

After that, there is a function called “user_info” that gets the “HOME” path and the “UID” of the user.

Error loading

Enumerating Privileges

The file is then called a function called “extract_ei” the function takes two arguments one of them is a path to itself.

Error loading

Then the start in that function is with a call to “stat$INODE64”, and by searching on the man page we can find that this a function to get info about the file passed as an argument to it. the returned structure is the following…

 struct stat64 {
         dev_t           st_dev;           /* ID of device containing file */
         mode_t          st_mode;          /* Mode of file (see below) */
         nlink_t         st_nlink;         /* Number of hard links */
         ino64_t         st_ino;          /* File serial number */
         uid_t           st_uid;           /* User ID of the file */
         gid_t           st_gid;           /* Group ID of the file */
         dev_t           st_rdev;          /* Device ID */
         struct timespec st_atimespec;     /* time of last access */
         struct timespec st_mtimespec;     /* time of last data modification */
         struct timespec st_ctimespec;     /* time of last status change */
         struct timespec st_birthtimespec; /* time of file creation(birth) */
         off_t           st_size;          /* file size, in bytes */
         blkcnt_t        st_blocks;        /* blocks allocated for file */
         blksize_t       st_blksize;       /* optimal blocksize for I/O */
         uint32_t        st_flags;         /* user defined flags for file */
         uint32_t        st_gen;           /* file generation number */
         int32_t         st_lspare;        /* RESERVED: DO NOT USE! */
         int64_t         st_qspare[2];     /* RESERVED: DO NOT USE! */

Then opening a handle to itself.

The file then locks itself for other threads and parses the returned state.


The file then calls a function called “ei_persistence_main” that likely does the persistence but before that it performs some anti-debugging by checking for a debugger or it’s being traced or unwanted processes.

Error loading

  • Check if the process is being debugged

Let me explain how this happens in Mac Os

Error loading

Sysctl is a function used to read kernel parameters which has info about the process then uses the “and” operation to check for the bit that indicates debugging if it’s set.

  • The second is to check if being traced.

Error loading

calling this function will terminate the process if it’s traced which is what debuggers do. So I patched the call for it.

  • The next one is killing unwanted processes

there is a function called “kill_unwanted” that takes an array of encrypted data that will be decrypted to names which the file checks if it’s presented in the processes returned by the call to “Get_process_list” function.

Error loading

These names are

Little Snitch

In the next function, the file copies an executable to a hidden file in the “/Users/$USERNAME/Library”

Error loading

Error loading

Then changing its execution permissions.

Error loading

And then copying itself to the Library folder

Error loading

It checks if the folder exists before doing that and creates it if it’s not.

Error loading


After that, there is a call to a function “install_deamon” the deamon in Unix systems is a process running in the background like the service in the windows world.

But how that happens?!.

Error loading

Inside each user’s home there is a folder called “LaunchAgents” and another one for all the machine users in the global Library folder called “LaunchDeamons” these folders contain files that each one has info about the files that will run as deamon, this files that store that info are “pslist” files, and its content is XML looks like this.

Error loading

After that, it forks the deamon as a new process using “launchctl” utility with the command line “–silent”

So I will run it again passing this parameter.

Actual capapilities

As we discovered that the malware executes it self after persistence with the parameter “–silent” so we will trace the execution.

The same checks that done before it is executed

The trick here is that the file keeps forking itself many times and checks for that number inside the “check_if_running” function, so we need to spoof that result to continue to the actual functionality.

Error loading


The malware starts to decrypt its C2 domain in the function “eiht_get_update” which in our sample is


the site is up at the time of the analysis but there is no response for the first request that hits the “/ret.txt” on the C2.

Error loading

Error loading

the malware checks if there is a response and because there wasn’t it decoded another URL

Collecting Host Info

After that, the malware starts to collect some info about the host in the function “ei_get_host_info” and sends them to the decrypted IP.

the collected info are:

  • uname
  • language
  • username
  • hostname

Error loading

Stealing files

Before the encryption starts the attacker tries to exfiltrate files that seem to be important in the thread created to start the function “ei_forensic_thread” by packing the file and sending it.

Error loading

Encrypting process

The file checks if there is a specific time passed from the initialization of the timers and if that happens it will start the encryption process in the function called “ei_carver_main”

Error loading


  1. Creates a temporary filename by calling a function named make_temp_name
  2. Opens the target file for reading
  3. Checks if the target file is already encrypted with a call to a function named is_carved, which checks for the presence of 0xddbebabe at the end of the file
  4. Opens the temporary file for writing
  5. Reads 0x4000-byte chunks from the target file
  6. Invokes a function named tpcrypt to encrypt the 0x4000 bytes
  7. Writes out the encrypted bytes to the temporary file
  8. Repeats until all bytes read and encrypted from the target file
  9. Invokes a function named eip_encrypt to encrypt keying information, which is then appended to the temporary file
  10. Writes 0xddbebabe to the end of the temporary file
  11. Deletes the target file
  12. Renames the temporary file to the target file

After the encryption process ends the code starts to decode the ransom note content

Error loading

Then showing it on the screen of the device with an alert.

Error loading