Posts Reversing MacOS Malware(TinyShell)

Reversing MacOS Malware(TinyShell)

In my journey of learning macOS/Apple Security, I’ve decided to create a blog post about things I have learned. This might not be useful to most researchers since they probably know more . But this blog post are just resources for me and any beginner interested in macOS security.

For my first post, I will document my step in reversing a simple yet interested malware, TinyShell. It’s important to note, I used Mitten Mac ’s post as a reference. I focus more on using advanced static and dynamic analysis.


Before looking at the diadsembler code, I ran codesign to get some basic info about signing certificate. This would usually provided you with the developer Identifier, format type(app bundle or command line), Authority and so on.
fig1 Figure 1

Now for the good part. Using hopper. To get a better idea of what the malware does, I switched to the pseudo code mode. This is what the main function looks like.

fig2 Figure 2

The first thing that caught my eyes was the _MyDecode call but before jumping ahead, we can see that there’s a ptrace call which suggest anti debugging capabilities. I tried looking for what 0x1f means but couldn’t find where it is defined in the linux/BSD kernel. According to Mitten Mac and just thinking as a developer, the hex means ptrace_deny_attach. Pretty straight forward name.

Next is an if statement checking if the user that ran the program has the UID of 0 which is root. The check is done twice, reason: not really sure. In side of the if statement is a call to a new function, _MyDecode. The arguments are a random series of characters and symbol, 0x2 and 0x4. Based on the name, it is safe to assume this is a decoding function for strings. Here’s the content of fig3 Figure 3

The important aspect of this function is the xoring of r14 and r15. We can see that those values are the second and third argument passed to the function. Taking a step back to the main function, those values are 0x2 and 0x4. To decode the encoded strings, I have decided to use a debugger and write a simple python script to replicate the function.

Python script

This is the easy part since the encoding is a simple xor. My python solution is below:

def MyDecode(encoded, key1, key2):
    decode = ""
    for char in encoded:
        temp = (ord(char) + key1) ^ key2
        decode += chr(temp)
    print("Decoded string: " + decode)

encoded_string = input("Enter encoded string: ")
MyDecode(encoded_string, 0x4, 0x2)

Not the best code but it works 😉

fig4 Figure 4


To execute the malware, we have to strip off the revoked signature, quarantine flag and nop the PTRACE call. If not, macOS will pop a warning saying “It is a known malware and will delete it”. Run the commands below

If you wojld like to learn more about quartine, read my other blog about apple's defense system.

  • codesign - - remove-signature
  • xattr -d
  • chmod +x to make it executable

Here’s how to nop the ptrace call, fig5a fig5b Figure 5(Images from Mitten Mac)

After that, we set a breakpoint at the end of the _MyDecode function. At that point, the encoded string would have been decoded and be stored at the r15 or rdx register. fig6 Figure 6

In the debugger console, we can print the register by using x/s $rdx. Since I’m not running the malware as root, the instructions in the if block will be the path. That’s why we see /Users/%@/Library/Fonts/.cache fig7

I ran it couple of time until I hit the breakpoint and I found more interesting strings. fig8 Figure 7

Based on those strings, it is easy to say that they are configuration strings for the victim to properly communicate with the attacker’s server. It is important to note that all of these are being read from /Users/%@/Library/Fonts/.cache. This would be different if we are running as root.

I will stop here for now. Next time, I will figure out the config format for the malware and attempt to do dynamic analysis.

This post is licensed under CC BY 4.0

Trending Tags