A forum for reverse engineering, OS internals and malware analysis 

Forum for analysis and discussion about malware.
 #30472  by mhanne
 Thu Jun 15, 2017 12:18 pm
I think this is just a test sample for OS/X ransomware.
I made a quick look on the malware and here's my findings:

1. The malware gets the Primary MAC Address using the following using API IOServiceMatching("IOEthernetInterface") and given the iterator it will use the API's IORegistryEntryGetParentEntry(infService, "IOService", &controllerService) and IORegistryEntryCreateCFProperty(controllerService, CFSTR("IOMACAddress"), *kCFAllocatorDefault_ptr, 0LL) to return the mac address.

Snippet:
GetMacAddress()
Code: Select all
_BYTE *__cdecl GetMacAddress()
{
  signed int counter; // [rsp+4h] [rbp-1Ch]@3
  _BYTE *result; // [rsp+8h] [rbp-18h]@1
  char tmp_result[6]; // [rsp+12h] [rbp-Eh]@2
  unsigned int intFIterator; // [rsp+18h] [rbp-8h]@1
  kern_return_t kernResult; // [rsp+1Ch] [rbp-4h]@1

  kernResult = 0;
  result = malloc(6uLL);
  kernResult = FindEthernetInterfaces(&intFIterator);
  if ( !kernResult )
  {
    kernResult = getMacAddress(intFIterator, tmp_result, 6LL);
    if ( !kernResult )
    {
      for ( counter = 0; counter < 6; ++counter )
        result[counter] = tmp_result[counter];
    }
  }
  IOObjectRelease(intFIterator);
  return result;
}
FindEthernetInterfaces
Code: Select all
kern_return_t __fastcall FindEthernetInterfaces(__int64 matchingServices)
{
  __int64 _propertyMatchDict; // [rsp+0h] [rbp-20h]@2
  __int64 matchingDict; // [rsp+8h] [rbp-18h]@1

  matchingDict = IOServiceMatching("IOEthernetInterface");
  if ( matchingDict )
  {
    _propertyMatchDict = CFDictionaryCreateMutable(
                           *kCFAllocatorDefault_ptr,
                           0LL,
                           kCFTypeDictionaryKeyCallBacks_ptr,
                           kCFTypeDictionaryValueCallBacks_ptr);
    if ( _propertyMatchDict )
    {
      CFDictionarySetValue(_propertyMatchDict, CFSTR("IOPrimaryInterface"), *kCFBooleanTrue_ptr);
      CFDictionarySetValue(matchingDict, CFSTR("IOPropertyMatch"), _propertyMatchDict);
      CFRelease(_propertyMatchDict);
    }
  }
  return IOServiceGetMatchingServices(*kIOMasterPortDefault_ptr, matchingDict, matchingServices);
}
getMacAddress
Code: Select all
  while ( 1 )
  {
    infService = IOIteratorNext(v11, v3);
    if ( !infService )
      break;
    v3 = "IOService";
    v6 = IORegistryEntryGetParentEntry(infService, "IOService", &controllerService);
    if ( !v6 )
    {
      v3 = CFSTR("IOMACAddress");
      v5 = IORegistryEntryCreateCFProperty(controllerService, CFSTR("IOMACAddress"), *kCFAllocatorDefault_ptr, 0LL);
      if ( v5 )
      {
        v16 = 0LL;
        v15 = 6LL;
        v13 = 0LL;
        v14 = 6LL;
        v18 = 6LL;
        v17 = 0LL;
        v3 = 0LL;
        CFDataGetBytes(v5, 0LL, 6LL, v10);
        CFRelease(v5);
      }
      IOObjectRelease(controllerService);
    }
    IOObjectRelease(infService);
  }
2. It will look for the file "PANW_Top_Secret_Sauce.jpg" in the current directory, this is the one to be encrypted.:
Code: Select all
const char *__fastcall getFileToDecrypt(char **curDir, __int64 len)
{
  char *buff; // ST30_8@10
  const char *result; // rax@13
  const char *v4; // [rsp+38h] [rbp-438h]@7
  struct dirent *dp; // [rsp+40h] [rbp-430h]@2
  DIR *dir; // [rsp+48h] [rbp-428h]@1
  const char *_result; // [rsp+58h] [rbp-418h]@8
  char *filepath[129]; // [rsp+60h] [rbp-410h]@7
  __int64 v9; // [rsp+468h] [rbp-8h]@1

  v9 = *__stack_chk_guard_ptr;
  dir = opendir_INODE64(curDir, len);
  if ( dir )
  {
    while ( 1 )
    {
      dp = readdir_INODE64(dir);
      if ( !dp )
        break;
      if ( strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..") )
      {
        if ( !strcmp(dp->d_name, "PANW_Top_Secret_Sauce.jpg") )
        {
          buff = malloc(0x400uLL);
          __snprintf_chk(buff, 0x400uLL, 0, 0xFFFFFFFFFFFFFFFFLL, "%s/%s", curDir, dp->d_name);
          _result = buff;
          goto return;
        }
        __snprintf_chk(filepath, 0x400uLL, 0, 0x400uLL, "%s/%s", curDir, dp->d_name);
        v4 = getFileToDecrypt(filepath, 1024LL);
        if ( v4 )
        {
          _result = v4;
          goto return;
        }
      }
    }
    closedir(dir);
    _result = 0LL;
  }
  else
  {
    _result = 0LL;
  }
return:
  result = *__stack_chk_guard_ptr;
  if ( *__stack_chk_guard_ptr == v9 )
    result = _result;
  return result;
}
3. It also check if the file is running inside virtual machine (VirtualBox VMware) using the command ioreg -l | grep -e Manufacturer -e 'Vendor Name' | grep -e 'Parallels' -e VMware -e Fusion -e 'Virtual Box'
Code: Select all
 strCommand = "ioreg -l | grep -e Manufacturer -e 'Vendor Name' | grep -e 'Parallels' -e VMware -e Fusion -e 'Virtual Box'";
  pStream = popen(
              "ioreg -l | grep -e Manufacturer -e 'Vendor Name' | grep -e 'Parallels' -e VMware -e Fusion -e 'Virtual Box'",
              "r");
  if ( pStream )
  {
    v1 = BUFSIZE;
    if ( fgets(v10, BUFSIZE, pStream) )
    {
      v15 = 999;
      v11 = 1;
    }
    else if ( pclose(pStream) )
    {
      v2 = printf("Command not found or exited with error status\n", v1);
      v15 = -1;
      v11 = 1;
      v8 = v2;
    }
4.The malware will generate the key by creating a buffer with a size of 256 that contains [0-0x100] (like buffer[0]=0 buffer[1] = 1 etc) and swapping the value based on MAC Address. (I can't explain it well, english is not my native language. can someone explain this? hehe)
Code: Select all
__int64 __fastcall generateKey(char *buff, char *mac, int len)
{
  __int64 result; // rax@4
  signed int i; // [rsp+4h] [rbp-1Ch]@1
  signed int counter; // [rsp+4h] [rbp-1Ch]@4
  unsigned __int8 x; // [rsp+Bh] [rbp-15h]@4
  int _len; // [rsp+Ch] [rbp-14h]@1

  _len = len;
  for ( i = 0; i < 256; ++i )
    buff[i] = i;
  buff[256] = 0;
  result = buff;
  buff[257] = 0;
  counter = 0;
  x = 0;
  while ( counter < 256 )
  {
    x += mac[counter % _len] + buff[counter];
    swap(&buff[counter], &buff[x]);
    result = (counter++ + 1);
  }
  return result;
}
5. Once the key is generate, it will now encrypt the data using the key. see the encryption algorithm below:
Code: Select all
__int64 __fastcall generateEncryptedData(char *key, char *buffRead, char *newEncData, int fsize)
{
  __int64 result; // rax@2
  int i; // [rsp+10h] [rbp-20h]@1
  int size; // [rsp+14h] [rbp-1Ch]@1
  char *_newBuff; // [rsp+18h] [rbp-18h]@1

  _newBuff = newEncData;
  size = fsize;
  for ( i = 0; ; ++i )
  {
    result = i;
    if ( i >= size )
      break;
    key[257] += key[++key[256]];
    swap(&key[key[256]], &key[key[257]]);
    _newBuff[i] = key[(key[key[257]] + key[key[256]])] ^ buffRead[i];
  }
  return result;
}
6. It also generates an identifier for the encrypted file based on getMD5(generateID(MAC Address)):
Code: Select all
_DWORD *__fastcall generateID(__int64 mac)
{
  _DWORD *result; // rax@7
  signed int j; // [rsp+28h] [rbp-88h]@3
  signed int i; // [rsp+2Ch] [rbp-84h]@1
  _DWORD *v4; // [rsp+30h] [rbp-80h]@1
  char _key[104]; // [rsp+40h] [rbp-70h]@1
  __int64 v6; // [rsp+A8h] [rbp-8h]@1

  v6 = *__stack_chk_guard_ptr;
  memcpy(_key, key, 0x64uLL);
  v4 = calloc(4uLL, 5uLL);
  for ( i = 0; i < 5; ++i )
  {
    for ( j = 0; j < 5; ++j )
      v4[i] += *&_key[20 * j + 4 * i] * *(mac + j);
    v4[i] %= 0xFBu;
  }
  result = *__stack_chk_guard_ptr;
  if ( *__stack_chk_guard_ptr == v6 )
    result = v4;
  return result;
}
That's all.
 #30496  by tWiCe
 Sat Jun 24, 2017 10:19 am
4.The malware will generate the key by creating a buffer with a size of 256 that contains [0-0x100] (like buffer[0]=0 buffer[1] = 1 etc) and swapping the value based on MAC Address. (I can't explain it well, english is not my native language. can someone explain this? hehe)
It's initialization of RC4 context.
5. Once the key is generate, it will now encrypt the data using the key. see the encryption algorithm below:
It's plain RC4 encryption.

Important fact why you couldn't call it's malware - It encrypts only one file with the specific name "PANW_Top_Secret_Sauce.jpg". Nothing more.