Monday, March 18, 2019

Analysis of BlackMoon (Banking Trojan)'s Evolution, And The Possibility of a Latest Version Under Development

BlackMoon, also known as KrBanker, is a banking trojan that mainly targets South Korea. I thought this family was dead since time ago (around 2016), however these previous days I got a couple of rencent samples that, after unpacking them and performing a quick analysis, I noticed they were BlackMoon. Virustotal's first submission date for one of these samples is 2018-06-18. First submission date for the other one is 2018-11-01. After digging a bit more into this malware family, my conclussion was that probably there is a latest version of BlackMoon that is under development. I explain it in this post, that I hope you enjoy.


  • Original Packed Sample: C38E54342CDAE1D9181EC48E94DC5C83
  • Automatic Generated Report: PepperMalware Report
  • Virustotal First Submission: 2018-11-01 07:03:51
  • Unpacked Banker Module: 4634F4EF94D9A3A0E2FCF5078151ADB2
  • Related links: 



  • Analysis


    • 1. Loader
      • 2.1. Packer
      • 2.2. Process Injection
    • 2. Main Module
      • 2.1. Persistence
      • 2.2. Encrypted Strings
    • 3. Evolution
      • 3.1. Encrypted Strings Evolution
      • 3.2. BlackMoon Versions: Latest Version Under Development?
      • 3.3. BinDiff
        • 3.3.1. 2016-03-03 -> 2016-05-05 Statistics
        • 3.3.2. 2016-05-05 -> 2018-06-18 Statistics
        • 3.3.3. 2018-06-18 -> 2018-11-01 Statistics
        • 3.3.4. 2016-03-03 -> 2016-05-05 Differences
        • 3.3.5. 2016-05-05 -> 2018-06-18 Differences
        • 3.3.5. 2018-06-18 -> 2018-11-01 Differences
    • 4. Conclusions
    • 5. Yara Rules and Scripts
      • 5.1. BlackMoon Yara Rule
      • 5.2. Script to Extract BlackMoon Encrypted Strings
    • 6. Other notes
      • 6.1. Another sample dated 2018 suspicious of being BlackMoon

    1. Loader


    1.1. Packer

    Most of the analyzed samples's packers are wellknown packers such as PeCompact, Aspack, Fsg or Nspack:


    Sample  FirstSeen   Packer 
     09beec989993806345254ca9adcdb034f8649d8a9633bbe8933a52f5093e8be1  2018-11-01  PeCompact 
     80ea86d195bbc4384a1b9a77a2d477e2c4e6dc6d48f3f80447877dbbe41a4e40  2018-06-18  Aspack
    2de1e47c650c0a8865ecc7e7b68379ca071062c0873f46a4addb1aa13b8d48dc 2016-03-03  Fsg
    5f17cf9aee107458995c434d21263528132b5d0ab8a20121d3de48478ec6c467 2016-02-28  PeCompact
    47434c9c2e887ba6f47a31e757b4ac0c0e648dfee9f93e38bd49e1c17f660dcf 2016-03-05  PeCompact
    2012486d87dcc3362745c6f8f178b9be5417c595e79c452a20729d2e60ec814b 2016-03-08  Aspack
    05afd7bbf6efa14102f72bad0e3a0686af6522b25228ab760ef57e8d6df36ed1 2016-03-05  Fsg
    5e1ca094e11b2dcfdd4c729e2eaf1bdfd0ec84067a39f1c3a233bfff1ff6dcb5 2016-03-20  PeCompact
    406c50ed0333d2023de55ce798a4e7d5fa6e45df65c16733ef48961e94277807 2016-04-08  Aspack
    4844e92d76b2158be2b5468b70e2d0898f9ba2287a02b2b0aa7af2a2113d4970 2016-03-02  PeCompact
    7351373a50acbaa4bb3fa622b0573f473289d745ba717551c82abbe398c1c1ff 2016-03-10  Nspack
    09a5dc4f9544f7bbc898d205f1e14518606e158f4a7c7126d7eb604ec9ec5c74 2016-04-09  PeCompact
    224ead790d3bab7ede11252728d47e21f0d0274767aa3e6a16628e8970a0149f 2016-02-28  PeCompact
    00eae37eaaee93b8155e6bad95564c3d95d71e7397653ffcbae4f95614ffa723 2016-05-05  PeCompact


    1.2. Process Injection

    Most of the analyzed samples follow the same strategy, they launch an executable (I think it is choosen randomly) from %system32% folder and they inject the new process (hollow process). The unpacked code will be executed in the context of the new process. Some of the executables that we have seen the malware launchs are: wmiprvse.exe, dwwin.exe, comp.exe, cacls.exe, etc...


    Sample FirstSeen Hollowed Process
     09beec989993806345254ca9adcdb034f8649d8a9633bbe8933a52f5093e8be1 2018-11-01system32\wmiprvse.exe
     80ea86d195bbc4384a1b9a77a2d477e2c4e6dc6d48f3f80447877dbbe41a4e40 2018-06-18system32\wmiprvse.exe
    2de1e47c650c0a8865ecc7e7b68379ca071062c0873f46a4addb1aa13b8d48dc2016-03-03system32\dwwin.exe
    5f17cf9aee107458995c434d21263528132b5d0ab8a20121d3de48478ec6c4672016-02-28system32\comp.exe
    47434c9c2e887ba6f47a31e757b4ac0c0e648dfee9f93e38bd49e1c17f660dcf2016-03-05system32\comp.exe
    2012486d87dcc3362745c6f8f178b9be5417c595e79c452a20729d2e60ec814b2016-03-08system32\cacls.exe
    05afd7bbf6efa14102f72bad0e3a0686af6522b25228ab760ef57e8d6df36ed12016-03-05system32\cacls.exe
    5e1ca094e11b2dcfdd4c729e2eaf1bdfd0ec84067a39f1c3a233bfff1ff6dcb52016-03-20system32\cacls.exe
    406c50ed0333d2023de55ce798a4e7d5fa6e45df65c16733ef48961e942778072016-04-08system32\cacls.exe
    4844e92d76b2158be2b5468b70e2d0898f9ba2287a02b2b0aa7af2a2113d49702016-03-02system32\comp.exe
    7351373a50acbaa4bb3fa622b0573f473289d745ba717551c82abbe398c1c1ff2016-03-10system32\cacls.exe
    09a5dc4f9544f7bbc898d205f1e14518606e158f4a7c7126d7eb604ec9ec5c742016-04-09system32\cacls.exe
    224ead790d3bab7ede11252728d47e21f0d0274767aa3e6a16628e8970a0149f2016-02-28system32\comp.exe


    2. Main Module


    2.1. Persistence

    The malware installs itself under a HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run's subkey. For most of the older samples, the run subkey is a 8-length combination of lowercase and uppercase letters and numbers. However the analyzed samples that date 2018, install themself in the subkey with fixed name 000C29FC2AB3.


    SampleFirst SeenRun Subkey
    09beec989993806345254ca9adcdb034f8649d8a9633bbe8933a52f5093e8be12018-11-01000C29FC2AB3
    80ea86d195bbc4384a1b9a77a2d477e2c4e6dc6d48f3f80447877dbbe41a4e402018-06-18000C29FC2AB3
    2de1e47c650c0a8865ecc7e7b68379ca071062c0873f46a4addb1aa13b8d48dc2016-03-0306iSwa6C
    5f17cf9aee107458995c434d21263528132b5d0ab8a20121d3de48478ec6c4672016-02-28kC6MOsu8
    47434c9c2e887ba6f47a31e757b4ac0c0e648dfee9f93e38bd49e1c17f660dcf2016-03-05R3tP5nj1
    2012486d87dcc3362745c6f8f178b9be5417c595e79c452a20729d2e60ec814b2016-03-0866qscw4Q
    05afd7bbf6efa14102f72bad0e3a0686af6522b25228ab760ef57e8d6df36ed12016-03-05W60u80qO
    5e1ca094e11b2dcfdd4c729e2eaf1bdfd0ec84067a39f1c3a233bfff1ff6dcb52016-03-20uki4Kk2o
    406c50ed0333d2023de55ce798a4e7d5fa6e45df65c16733ef48961e942778072016-04-0835V5Bj9b
    4844e92d76b2158be2b5468b70e2d0898f9ba2287a02b2b0aa7af2a2113d49702016-03-02AAAC2kY8
    7351373a50acbaa4bb3fa622b0573f473289d745ba717551c82abbe398c1c1ff2016-03-101Lf9Tn7B
    09a5dc4f9544f7bbc898d205f1e14518606e158f4a7c7126d7eb604ec9ec5c742016-04-095jNh7p11
    224ead790d3bab7ede11252728d47e21f0d0274767aa3e6a16628e8970a0149f2016-02-28j3pVbRJ5
    00eae37eaaee93b8155e6bad95564c3d95d71e7397653ffcbae4f95614ffa7232016-05-05000C29FC2AB3


    Curiously, the sample 00eae37eaaee93b8155e6bad95564c3d95d71e7397653ffcbae4f95614ffa723 that dates 2016-05-05 (from the older samples, one of the newest), installs itself under the same subkey 000C29FC2AB3.

    In addition, these samples that create the subkey with name 000C29FC2AB3, they create a mutex named M_Test too (the other samples don't create this mutex).


    2.2. Encrypted Strings

    Most of the important strings of BlackMoon are encrypted.

    Here is a capture of the code responsible for decrypting the strings from the sample 09beec989993806345254ca9adcdb034f8649d8a9633bbe8933a52f5093e8be1:




    To compose the definitive key that the malware uses to decrypt the strings, it carries an string that is the first part of the key, and then it appends 6 additional characters to that first part of the key. In the capture, the definitive key to be used would be "7ac13b3aa82136afa3090c5137B8a195".

    Encrypted strings are like this:




    The algorithm used to decrypt each string is rc4(unhexlify(rc4(unhexlify(encrypted_string), key)), key):



    3. Evolution


    3.1. Encrypted Strings Evolution

    We have extracted the strings from samples from different dates, to compare them:


    Date 2016-02-28:
    Sample 5f17cf9aee107458995c434d21263528132b5d0ab8a20121d3de48478ec6c467:



    Date 2016-03-03:
    Sample 2de1e47c650c0a8865ecc7e7b68379ca071062c0873f46a4addb1aa13b8d48dc:

     

    Date 2016-05-05:
    Sample 00eae37eaaee93b8155e6bad95564c3d95d71e7397653ffcbae4f95614ffa723:




    Date 2018-06-18:
    Sample 80ea86d195bbc4384a1b9a77a2d477e2c4e6dc6d48f3f80447877dbbe41a:

     

    Date 2018-11-01:
    Sample 09beec989993806345254ca9adcdb034f8649d8a9633bbe8933a52f5093e:



    In the section 2.1 (about persistence), we had already noticed that most of the samples from 2016 create a 8 bytes length subkey under the registry \Run key, with a combination of lowercase and uppercase letters and numbers. 

    However a sample dated 2016-05-05 and the newer samples dated 2018 create a subkey under \Run with name 000C29FC2AB3. In addition these samples create a mutex with name M_Test (this mutex is not created by the 2016's samples).


    If we take a look at the lists of strings, the sample dated 2016-05-05 and the samples dated 2018, all of them have similar lists of encrypted strings, where strings are ordered in similar order (thought they are not totally identicals).


    The other samples dated 2016 contain another lists of strings, identical between them, but different from the lists of the samples dated 2018.



    3.2. BlackMoon Versions: Latest Version Under Development?

    Having in mind the IoCs collected in the previous sections, we can conclude that there is a first version of BlackMoon malware, whose samples are dated around 2016, and other version that could be under development, whose samples we have one of them dated 2016-05-05, and other two dated 2018-06 and 2018-11.

    Version 1:
    • Persistence: 8 bytes length subkey under registry \Run key, with a combination of lowercase and uppercase letters and numbers
    • Encrypted strings: "http://", "/ca.php", "?m=", "&h;=", "GET", "?p", "POST", "users.qzone.qq.com", "GET /fcg-bin/cgi_get_portrait.fcg?uins=", etc...
    • Samples dated 2016

    Version 2 - probably under development version:
    • Persistence: subkey under \Run with name 000C29FC2AB3
    • Mutex: M_Test
    • Encrypted strings: "ScriptControl", "Language", "VBScript", "ExecuteStatement", "Function MACAddress()", "Dim mc,mo", "Set mc=GetObject(\"Winmgmts:\").InstancesOf(\"Win32_NetworkAdapterConfiguration\"), "For Each mo In mc", etc...
    • A sample dated 2016-05-05, other 2 samples dated 2018
    We have only 3 samples that we have classified as version 2. Probably they are quite similar, but we must have in mind that the lists of encrypted strings for these samples are not totally identical. However, the Run key 000C29FC2AB3 and the mutex M_Test, make us to think these 3 samples are the same version.

    From my point of view, these 3 newer samples could be a version that is under development. Because of that, each version 2's sample is a bit different from the others. And because of that, the name M_Test for the mutex and the non-random name for the \Run subkey.

    3.3. BinDiff

    Lets compare with BinDiff the following samples (once they are already unpacked) trying to understand the evolution of this malware:

    Version1:
    • 2de1e47c650c0a8865ecc7e7b68379ca071062c0873f46a4addb1aa13b8d48dc
    • 2016-03-03
    • Original sample packed with Fsg
    Version2:
    • 00eae37eaaee93b8155e6bad95564c3d95d71e7397653ffcbae4f95614ffa723
    • 2016-05-05
    • Original sample packed with PeCompact
    Version2:
    • 80ea86d195bbc4384a1b9a77a2d477e2c4e6dc6d48f3f80447877dbbe41a
    • 2018-06-18
    • Original sample packed with AsPack
    Version2:
    • 09beec989993806345254ca9adcdb034f8649d8a9633bbe8933a52f5093e
    • 2018-11-01
    • Original sample packed with PeCompact

    3.3.1. 2016-03-03 -> 2016-05-05 Statistics: 345 matching functions


    3.3.2. 2016-05-05 -> 2018-06-18 Statistics: 591 matching functions


    3.3.3. 2018-06-18 -> 2018-11-01 Statistics: 1743 matching functions


    I think the most interesting indicator about similarity, at least in this case, is the number of matching functions because the unpacked modules were dumped with Volatility's procdump command, with --memory --unsafe modificators. Probably most of the primary and secondary unmatched functions are due to residual parts of the code of the packer in memory and maybe due to recompilations of the code with newer versions of the runtime.

    If we compare the paired functions, we find that most of the changes between versions are due to ligth modifications, small fixes, etc... as we will see in the following sections.

    3.3.4. 2016-03-03 -> 2016-05-05 Differences:

    For example, here is a function from the sample dated 2016-03-03 compared to the same function from the sample dated 2016-05-05, where we can see that small changes were done in this function: 


    Another function. In this case a larger part of code was removed from the function in the newer version:



    Btw, in the case of 2016-03-03 -> 2016-05-05, most of the matching functions are ubicated in totally different addresses:


    Probably, in spite of the fact that the code doesn't change a lot and there are a lot of matching functions, a code refactorization was done from version 1 to the first samples of version 2 (around 2016-05).

    3.3.5. 2016-05-05 -> 2018-06-18 Differences:

    In this case, in addition to the similarity between functions pairs, lot of the matching functions are ubicated in the same offset into the unpacked sample:


    This makes us to think both binaries are quite similiar, in spite of the fact that we find minimal changes like in this function:


    However, there are other functions with more important changes that make us to think that there have been at least a minimal development between both samples (manual modifications on the code: improvements or fixes, not only recompilation + repacking):


    3.3.5. 2018-06-18 -> 2018-11-01 Differences:

    Again, lot of the matching functions ubicated in the same offset, and minimal changes between paired functions. And again, some parts of the code with more important changes that suggest a minimal development by the authors between the first and the second sample:



    4. Conclusions


    From my point of view, there are two main versions of BlackMoon family.

    Samples from the first version date first half-year of 2016.

    Around May-2016, a new version was started. In the sample that dates 2016-05-05 we can appreciate a code refactorization and more important changes in the code. In addition, we can find changes in the behavior, such as the non-random subkey under the \Run registry key, named 000C29FC2AB3, and the non-random mutex created by the malware with name M_Test.

    There are minimal changes between the sample that dates 2018-06-18 and the samples that dates 2016-05-05, and again minimal changes between the samples that dates 2016-11-01 and the sample that dates 2018-06-18. However, there are enough changes between these version 2's samples to appreciate that a development was done by the authors, there must be modifications of the source code between them (not only recompilation + repacking).

    My conclussion is, there is a version of the BlackMoon that is under development. We can find quite recent samples (based on the VirusTotal first seen date) of this version under development. I can't say totally sure if the code of that recent samples were modified and compiled in 2018 or previously (in spite of the fact that I think the code was recently modified and it is currently evolving, maybe that samples were only repacked or their bytes lightly modified, or maybe VirusTotal didn't see these samples before).

    In addition to the larger changes from the first version to the second version, we can appreciate an evolution of the code of the second version: from the sample 00eae37eaaee93b8155e6bad95564c3d95d71e7397653ffcbae4f95614ffa723 (May-2016), to the sample 80ea86d195bbc4384a1b9a77a2d477e2c4e6dc6d48f3f80447877dbbe41a (June-2018), and to the sample 09beec989993806345254ca9adcdb034f8649d8a9633bbe8933a52f5093e (November-2018). So, from my point of view, it seems there are enough evidences to think that there is a BlackMoon version that is under development and currently evolving.

    5. Yara Rules and Scripts


    5.1. BlackMoon Yara Rule

    Unpacked module:

           
    rule blackmoon_unpacked {
    strings:
            $code1 = { 89 45 ?? 68 01 01 00 80 6A 00 68 ?? 00 00 00 68 01 00 00 00 BB ?? ?? 00 00 E8 ?? ?? ?? ?? 83 C4 10 }
            $code2 = { FF 75 ?? FF 75 ?? FF 75 ?? FF 75 ?? FF 75 ?? FF 75 ?? FF 75 ?? B9 ?? ?? 00 00 E8 }
    condition:
            (all of them)
    }
    


    5.2. Script to Extract BlackMoon Encrypted Strings

    The following script extracts and decrypts the encrypted strings from a BlackMoon unpacked sample:

    python strings_decryptor.py <path to unpacked blackmoon>

           
    
    import os
    import sys
    import binascii
    import traceback
    
    #################################################
    
    def rc4(data, key):
        x = 0
        box = range(256)
        for i in range(256):
            x = (x + box[i] + ord(key[i % len(key)])) % 256
            box[i], box[x] = box[x], box[i]
        x = 0
        y = 0
        out = []
        for char in data:
            x = (x + 1) % 256
            y = (y + box[x]) % 256
            box[x], box[y] = box[y], box[x]
            out.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256]))
        return ''.join(out)
    
    #################################################
    
    def findencstrings(s):
        l = []
        laststr = ""
        for i in range(0, len(s)):
            if s[i] in "0123456789ABCDEF":
                laststr += s[i]
            else:
                if ord(s[i])==0 and len(laststr)>=6: l.append(laststr)
                laststr = ""
        return l
    
    #################################################
    
    def decstr(s, k, k2):
        sorig=s
        try:
            if len(s)%2: s = s[0:-1]
            s = binascii.unhexlify(s)
            s = rc4(s, k+k2)
            step1 = s
            if len(s)%2: s = s[0:-1]
            s = binascii.unhexlify(s)
            s = rc4(s, k+k2)
            return True, s
        except Exception as e:
            return False, "ERROR:" + repr(e) + ", string:" + sorig
    
    #################################################
    
    def findkey1(s):
        l = []
        laststr = ""
        for i in range(0, len(s)):
            if s[i] in "0123456789abcdefABCDEF":
                laststr += s[i]
            else:
                if ord(s[i])==0 and len(laststr)>=20 and len(laststr)<=30 and not len(laststr)%2 and laststr not in l: l.append(laststr)
                laststr = ""
        if len(l): return l
        return None
    
    #################################################
    
    def findkey2(s):
        key=""
        for i in range(0x0, len(s)-0x100):
            if s[i:i+8]=="\x68\x01\x01\x00\x80\x6a\x00\x68" and s[i+8] in "0123456789abcdefABCDEF" and s[i+9:i+12]=="\x00\x00\x00":
                key+=s[i+8]
        return key
    
    #################################################
    
    def get_strings_from_pe(s):
        ldecs = []
        lenc = findencstrings(s)
        lk1 = findkey1(s)
        k2 = findkey2(s)
        if lk1 and k2 and lenc:
            for k1 in lk1:
                for i in range(0,len(k2)-6):
                    for senc in lenc:
                        decs = decstr(senc, k1, k2[i:i+6])
                        if decs[0]: ldecs.append(decs[1])
        return ldecs
    
    #################################################
    
    def analexe(s):
        decrypted_string_list = []
        try: decrypted_string_list = get_strings_from_pe(s)
        except Exception as e:
            print "blackmoon exception in get_strings_from_pe"
            print traceback.format_exc()
        for e in decrypted_string_list: 
            print "blackmoon decrypted string:", e
    
    #################################################
    
    if __name__ == "__main__":
        if os.path.exists(sys.argv[1]):
            f = open(sys.argv[1], "rb")
            s = f.read()
            f.close()
            analexe(s)
        else:
            print "Incorrect path"
    
    


    6. Other Notes


    6.1. Another sample dated 2018 suspicious of being BlackMoon

    Once I started to investigate a bit more and to search information about BlackMoon family, I found a tweet talking about another sample that could be BlackMoon and whose first submission is 2018-08-08. 

    I toke a quick look at this sample, here you can find the unpacked module. Some interesting strings from this unpacked module:

    • http://aa.mrmr11[.]cn:8000/fdeee.dll
    • yPBfy0A4q1Y3gvgmREe0r1UR0fZVidMd4V8CB3oKTzNaOYCyPaSVz48Sw5mVifR3sVxYgeM7EyVu6DwnrfAG/AxGgDr+9GIP3cQ59d/eLtPqTBMb7bzrty65ymU5lH4omQOCFGqOfHggHlhjv97kF1eKnstRomin+KSVtT1TWWtI4BqcY6tP7xJBMzDUgouwpGUwzDY4wnnDEU+8B+MtEncFn1EOAXA3ZMW3/3mVwLFpKP9XH6xJSjjJqbXr4y1VqqwH/lZOYnPVcYlpfbmwdOYvbsIwCxLaU1HvWmBiDNxKRTLhhXAn3GuBy5OzbI01IVVnQtG2WrbM2T5Rk6m1+eMW2c90Uouf7pTesS6m8oCNEclwGQNZtpEIZojzjwPSrPUQPxz/sKtHrhMEdl90wI+GyO7mwvrONsO6h+OvYas6f2QgxxiaIYlK/IJIVFM=
    • C:\Program Files\AppPatch\lpDllName
    • 360zipUpdate.EXE

    The original sample was packed with Aspack, as other recent BlackMoon samples. However this first unpacked module doesn't look like BlackMoon: the code, the strings, etc... are totally different.

    Anyway, when I have analyzed this sample, the dll that it tries to download (http://aa.mrmr11[.]cn:8000/fdeee.dll) had been already removed. Maybe that dll was the BlackMoon module. I can't be sure if this sample is BlackMoon or not (this other any.run analysis contains this same IoC: "C:\Program Files\AppPatch\lpDllName", it downloads a dll too, and the second process name is similar format. Maybe same family. This other one was tagged as #trojan #dupzom).

    No comments:

    Post a Comment