This loader is strongly associated with the NullMixer pay-per-install service which uses SEO poisoning to place it's loader in high ranked Google searches. According to a Kaspersky post about NullMixer the SEO poisoned terms often relate to “cracks” and “keygens”.

The LegionLoder (aka Satacom) itself is used to deliver malware payloads but also contains a built-in crypto stealer detailed in this DeepInstinct post.



  • packed ddc2b05410808c6a42584aec972332a8e7ca155cb7dcad4fb68167d39130ce09 UnpacMe

    • unpacked 2ff7169de9b8737c232ef3410736167129a02ffe3cbb953e528fb88c8f665660
  • packed 0302f9e68aba7f9c2e9a80d959431b68eab2991e9489887fca727c2a3d493bff UnpacMe

    • unpacked cc1087c4b35d8e6a4f1b88c2eaf0870b7630e53bad8d188283543a3df312188d
  • packed 296a4593d0619126d9b6dc61dcc9c608699ae89af1849378ec3d9347795a0db1UnpacMe

    • unpacked 8fbf21e9ecaa64b8f71904791380a3efa08f71f18f18fc9f7e171de2c5a946fc

String Decryption (hex strings)

  • hex decode
  • rc4 decrypt with hard coded key
from malduck import rc4

key = bytes.fromhex('f74b76852a9cbfd407365cfdcf2ead7e9e483d51865a585ed17ec67e620b3c3a')
data = '759e021374ebbd9ed98899a2'
enc_data = bytes.fromhex(data)
rc4(key, enc_data)
ss = ['2ad14e587eebf5',

for s in ss:
    enc_data = bytes.fromhex(s)
    print(enc_data | refinery.rc4(key) | bytes)

Binary Refinery Decrypt

Attempt to perform the same decryption with binary refinery.

import refinery

enc_data | refinery.rc4(key) | bytes

String Decryption (base64 strings)

  • base64 decode
  • xor decrypt with stack string
import base64
from malduck import xor
b64_string = 'c21pZXt/cw=='
enc_str = base64.b64decode(b64_string)
xor(b'KCQ', enc_str)

Dumpulator Decrypt

Attempt to perform the same decryption with dumpulator.

from dumpulator import *

def main():
    dp = Dumpulator("/tmp/2ff-malware.dmp", trace=False, debug_logs=False, quiet=True)
    init_function = 0x4056E0
    map_ptr = dp.call(init_function)
    print(f"string map: {hex(map_ptr)}")
    decrypt_function = 0x401270
    buf_ptr = dp.allocate(1024)
    for i in range(6):
        dp.call(decrypt_function, [i, buf_ptr], regs={'rcx': map_ptr})

if __name__ == "__main__":
string map: 0xbb75e8
Mozilla/5.0 (Windows NT 6.3; Trident/7.0; Touch; rv:11.0) like Gecko


The packer uses many obfuscation techniques to prevent detection of its stub including the addition of junk API calls.

IDA Python NOP Patch

To remove the packer junk code we can use the following script. Simply highlight the junk code and run the script to replace it with null bytes.

import idaapi

_, start, end = idaapi.read_range_selection(None)
for ea in range(start, end):
     idaapi.patch_byte(ea, ord('\x90'))

Packer ID

Thanks to mishap for the IOC. The following binary string can be used to locate packers that have a hard coded payload size that matches the samples analyzed. NOTE this is only useful for finding packers with the same payload (for further research) and is not a generic IOC for this packer.

{C7 05 ?? ?? ?? ?? E0 0E 00 00}

Many of the samples also include the PE metadata which identify the payload name as fork5.dll. This is another IOC that can be used to identify one version of the packer. It is not a generic IOC for this packer.