CATEGORIES

Tunnel Warfare: Exposing DNS Tunneling Campaigns using Generative Models – CoinLoader Case Study

August 24, 2023

Introduction

Generative AI has been around for nearly a decade, strictly speaking, but the recent boom in this technology has inspired renewed interest in its possible applications to challenges facing the information security community. Finding these challenges entails searching through a very large haystack consisting of brand-new binaries, documents, domains and other artifacts that flood the web every day.

In this blog post, we provide a deep dive into Check Point’s ongoing use of such a model to sweep across this haystack, and routinely thwart malicious campaigns abusing the DNS protocol to communicate with C&C servers. We focus on one such campaign, of CoinLoader, and lay out its infrastructure as well as an in-depth technical analysis of its DNS tunnelling functionality.

A Crash Course in DNS Tunneling

What is DNS?

Domain Name Server (DNS) protocol can be considered “the phonebook of the internet.” When you enter a website address (let’s say wikipedia.org) into your web browser’s address bar and press enter, your web browser sends a DNS request to its favorite DNS server, asking what IP addresses correspond to that domain. The IP address of this default DNS server is either supplied by the user’s network provider or specified manually by the user.

Under the hood, a typical DNS query rides on top of the UDP protocol (to jog your memory, whereas TCP deals with the issue of “did my peer really get that message?” using SYNs and ACKs, UDP deals with it using thoughts and prayers). A DNS packet, whether a query or a response, consists of a header and 4 main sections:

  • Question or Query – For example, “What domain name? What kind of answer do you expect?”
  • Response – An answer to the question.
  • Authority – Information about the servers responsible for keeping track of the domain addresses.
  • Additional – Miscellaneous data such as the IP addresses of the authoritative servers.

How does one “Tunnel” using DNS?

“DNS Tunneling” is the practice of abusing DNS, using it as a covert channel of communication such as between a malware and its C&C server. In this scenario, the malicious actor controls both the client and the server, giving them a lot of wiggle room with respect to what kind of query to make, and where to hide the “spicy” part of the response.

However, the scheme the actors choose is inherently subject to the limitations of the DNS protocol itself. For example:

  • Request and response lengths are bounded. The entire domain that is being looked up must not exceed 255 bytes, and the maximum length of a DNS packet is 576 bytes.
  • The DNS protocol naturally lends itself to caching. Servers make note of a response they sent an hour ago and when asked, simply repeat that response, instead of going all the way to the authoritative server and nagging “Hey, is that answer from an hour ago still valid?” This is great for legitimate users of DNS, but not so great for DNS tunneling clients, which typically resort to querying many fictitious subdomains (af34deb93557.maliciousdomain.xyz, then later 48bd9a577d114.maliciousdomain.xyz, and so on) to keep the queries fresh.

If this all sounds too theoretical, one well-known malware that utilizes DNS tunneling is the high-profile SUNBURST backdoor, which was delivered to unsuspecting victims as part of the infamous 2020 SolarWinds hack. SUNBURST used DNS queries as a light recon channel, covertly transferring victim information encrypted as an identifier, and then used it as a subdomain in a DNS query. This subdomain was prepended to one of the four main domains:

appsync-api.us-east-1[.]avsvmcloud[.]com
appsync-api.us-east-2[.]avsvmcloud[.]com
appsync-api.eu-west-1[.]avsvmcloud[.]com
appsync-api.us-west-2[.]avsvmcloud[.]com

For example, the resulting fictitious FQDN looks like this:
7cbtailjomqle1pjvr2d32i2voe60ce2[.]appsync-api[.]us-east-1[.]avsvmcloud[.]com.
Based on the information transferred over the DNS requests, the DNS server would return a CNAME record to targets of interest. The CNAME would point to a C&C server that communicates with the malware over HTTPS.

Analyzing DNS Tunnels

Can a determined defender, standing atop a network gateway, detect DNS tunneling? This is a surprisingly loaded question, because the definition of DNS tunneling is very broad, and some implementations are more difficult to detect than others. We list some points of interest below that are worth keeping in mind while analyzing activities suspected to be DNS tunneling.

We asked ourselves the following questions:

  • How many? and How Long? Take a look at the number and length of sub-domains associated with a suspicious domain. As mentioned previously, DNS packets are limited in size, offering actors a small number of fields to manipulate. The most effective way to transfer data in DNS queries is using subdomains, which results in a high volume of DNS requests to multiple, often long, subdomains of the same domain. This also helps to avoid potential caching problems.
Figure 1 – DNS Tunneling
  • Who’s answering? DNS is authoritative, meaning specific name-servers (NS) are responsible for the final resolution of specific domains. DNS queries for those domains do eventually end up reaching those servers (unless they are cached somewhere along the way). To facilitate DNS Tunneling, an actor must control the nameserver associated with a particular domain. A look at a suspicious domain’s NS record or WHOIS record, that indicates the authoritative nameserver for that domain, might actually point to the threat actors’ infrastructure.

Answering those questions may not be easy, but luckily for us as researchers, a lot of them can be answered using public resources. Passive DNS is a very helpful tool in triaging a wide variety of threats but is extremely efficient when dealing with DNS tunneling. As DNS tunneling relies on the DNS protocol itself, passive DNS replications often document artifacts transferred with it. In some cases, it might even be possible to extract information related to the victims themselves.

Introducing DeepDNS

As part of our ongoing interest in general DNS tunneling and malicious web traffic, this year we saw the introduction of DeepDNS, an artificial neural network that hunts and blocks campaigns that abuse DNS. DeepDNS is a Gated Recurrent Unit Autoencoder (GRU-AE) that is trained on the vast amount of DNS traffic routinely available to Check Point as part of the telemetry. The DeepDNS conclusions drawn are automatically pushed to Check Point ThreatCloud.

This document is certainly not a treatise on the inner workings of AI, but we still felt you would be well served by a very simplified explanation of what a “Gated Recurrent Unit Autoencoder” is, at least in broad strokes.

To begin with, an autoencoder is an artificial neural network, meaning, it is a virtual brain that begins its life as a blank slate. During its training phase, it is given an input — the output is then observed, and changes to the brain’s parameters that would make the output more desirable are determined using calculus, then applied (this is a fancy way of saying that you close your eyes, imagine that the wrongness of the output as a function of the brain parameters is a mountain, then go as quickly down the mountain as you can until you cannot go further down). This process repeats until the virtual brain’s actual output sufficiently resembles the desired output. If this whole description sounds alien to you, consider that it is not so conceptually different from what you do when you repeatedly shout “NO!! NO!! LEAVE THAT ALONE!!!” at your three-year-old.

Figure 2 - Schematic of an Artificial Neural Network (ANN).
Figure 2 – Schematic of an Artificial Neural Network (ANN).

Artificial neural networks have a surprising capacity to learn all sorts of functions (this is even theoretically proven). One such function is simply “map this text to some short representation (code), then change the code back to a text so that the final text resembles the initial text as much as possible.” A neural network that’s been trained to learn this kind of function is called an autoencoder. An autoencoder can function as a generative model: obtain a novel point in code space in some way (by picking at random or just mixing some known points together), and if the model has learned a good representation of the data, decoding this point will result in novel text. As this isn’t technically part of an autoencoder’s specification, the literature appears divided on how correct it is to refer to it as a generative model, as opposed to a model with generative capacity (have fun with this Google search); but “model with generative capacity” did not fit so neatly into the main title, so here we are.

Figure 3 - Schematic structure of an autoencoder.
Figure 3 – Schematic structure of an autoencoder.

One other use case for autoencoders, which is relevant here, is that of anomaly detection. Applying some mathematical intuition will lead you to the conclusion that “typical” input will be compressed and reconstructed by the autoencoder with relative success, whereas compression and reconstruction of “atypical” input is more likely to introduce errors. This is basically for the same reason that if I say “the quick brown fox jumps over the lazy dog” then five minutes later ask you to repeat that sentence, you will probably succeed, but the same is not true for “the abstruse purple platypus confounds the prolific cheetah”.

DeepDNS works on this same principle. Using deep inspection of subdomain names which are further broken down into smaller constituent parts, it uses the encode-decode process that it learned to render its judgment on the simple question, “how normal does this set of queries look?” If the reconstruction sufficiently fails, DeepDNS concludes that the answer is “not normal enough”, and delivers a malicious verdict. This approach is elegant in its simplicity, if you ignore the part where training the model involves colorful floating surfaces and a bunch of partial derivatives.

At the End of the Tunnel – Fishing Out and Drilling Down into CoinLoader DNS Tunneling

Now that we’ve covered the theory, it’s time to put it into practice. Knowing how DeepDNS works at the black box level (and even some of its inner workings thanks to the section above), it is natural to ask what it can find if we make it search for anomalies across our available telemetry. We did just that and ran DeepDNS on our sample. Among the many results that it flagged as anomalous, one previously unknown cluster of domains caught our eye in particular:

  • rqmetrixsdn[.]info
  • candatamsnsdn[.]info
  • mapdatamsnsdn[.]info

A closer look at the infrastructure connected with these domains suggests they are part of a DNS backup channel used for CoinLoader infections.

Coinloader was first described in this extensive report by Avira, but we could not find prior documentation describing this specific feature. Samples were found in an archive, typically a rar or a zip, containing several files. While the names varied, what you see below is more or less representative of the file structure in each sample.

Figure 4 – CoinLoader file structure.
Figure 4 – CoinLoader file structure.

The executable (ZD_1.4.24.17 in the image) is always some legitimate tool which is used for DLL sideloading. The main malicious logic is in the sideloaded DLL (here AppleVersions.dll). Upon being loaded, it goes through several layers of unpacking, including a well-obfuscated check that its parent process was launched from inside the Z-1-36-81 directory (again, the directory name varies from sample to sample) that is buried inside some complex control flow structures.

Figure 5 – CoinLoader execution flow.
Figure 5 – CoinLoader execution flow.

Once unpacking is complete, the malicious logic is visible. This final stage still contains several anti-analysis features, such as junk code; encrypted stack strings that are decrypted on-the-fly using a simple substitution cipher; and indirect calls that are resolved using a homebrew function table, in which the register points at what is passed to each function in ecx. This is then copied to a random register each time, which is used to implement the calls.

Figure 6 – Junk instructions used as anti-analysis.
Figure 7 – Obfuscated stack strings.
Figure 8 – Indirect calls using homebrew function table.

While the junk code is best ignored and the obfuscated strings are best dealt with by dynamically executing the code and observing the decoder output, the resolution of the function calls in the IDA database requires a dedicated script. To see such a script, go to Appendix A.

The traffic capture generated by one such sample seemed promising:

Figure 9 – Packets captured in CoinLoader execution.
Figure 9 – Packets captured in CoinLoader execution.

So we set out to perform a technical analysis of this feature.
The function get_c2_domain receives an enum argument (here passed in the register edx). The values 0, 1, 2 and 3 cause the function to decrypt and return, respectively, each of the malware’s hardcoded C&C domain names — in this case rqmetrixa.info, rqmetrixb.info, rqmetrixc.info, rqmetrixd.info (we were honestly disappointed not to find some piece of logic appending a letter to rqmetrix but these were all hardcoded as-is).

Figure 10 – Different switch branches of the “get c2” function.

Finally, if this enum value equals 4 (above annotated as GET_DOMAIN_DNS_TUNNEL_BACKUP), the malware resorts to a backup plan, and attempts to obtain a domain name by conferring with a different server, rqmetrixsdn.info, via the TXT DNS tunneling query as seen in the traffic capture.

Figure 11 – DNS TXT query.

The FQDN is created by taking one of the hardcoded domains and prepending to it hexlify(md5(timestamp)). In the image below we show it as a code block to filter out junk instructions.

mov     ebx, eax
mov     [ebp+md5_of_timestamp], ebx
call    [edi+FuncTable.GetSystemTime]

xor     eax, eax        
mov     [esi+0Eh], ax
push    ebx             ; allocated buffer
call    mre_get_filetime_md5 ; now has md5 of current timestamp

The timestamp md5 is obtained using SystemFileToFileTime (then converted into a timestamp using additional WinAPI functions). Once the server responds, its response is fed to an inline BASE64 decoder. The result is interpreted as a C&C domain to check in with, similar to the SUNBURST setup that we mentioned earlier. The check-in format, which is the output of the string_decoder deobfuscation handler, is visible below.

Figure 12 – Construction of C&C check-in.

Conclusion

DNS tunneling is what you might call an “old-school” technique. It originated in a security landscape created by the advent of the first firewalls, and the drawing of simplistic boundaries: who initiated a connection? With whom? On what port? Using what protocol? Therefore allow, or deny. The industry has since greatly evolved and the benefits of DNS tunneling have become less clear-cut. DNS is no longer some “covert channel” where no security solution would think to look; and conversely, attackers have refined their understanding of how to effectively communicate using HTTP and hide in plain sight, using a variety of techniques such as steganography and encryption.

Still, DNS tunneling is clearly not dead. Whether because it less obviously jumps out at the human eye, or because malware authors simply figure the technique is worth a try if straightforward HTTP communication has failed — or for other reasons — modern malware is not shy to engage in this practice. As defenders, we are naturally interested in ways of catching it in the act. In this post, we explained how it is possible to model DNS tunnels as anomalies and hunt them from an unusual perspective, as demonstrated with DeepDNS. This hunt has led us to evidence of a number of actors currently using the technique, including state-sponsored cybercriminals and even hacktivists. As an example, we performed a technical analysis of a Coinlander sample and its tunneling protocol that DeepDNS sniffed out as anomalous. Other than its natural interest to us as threat hunters, this also served as a nice proof-of-concept for DeepDNS’s capabilities.

While academia carries the torch of pushing scientific boundaries and proving what is possible, it often falls to industry to implement academic ideas at scale, and usher them along the path from promising whitepaper to surviving impact with the messy real world. While we continuously work to apply ANNs to security at that level of maturity, the frontier is far from exhausted. With the recent surge of interest in ANNs and their applications, we can only expect more and more artificial brains to be making real-world security decisions, and it is our responsibility as an industry that they do so with skill and accountability.

So, in that spirit, let this article be a testament to that time when we said “Oh, model, you say that’s DNS tunneling? Let our analysts and reverse-engineers double-check you on that”.

Indicators of Compromise

CoinLoader Samples

a05144d7254b419d3a09787e280b4be3
84548cf16e26979ff9a3fa2b3f854f34

CoinLoader Infrastructure

candatamsnsdn[.]info
candatamsna[.]info
candatamsnb[.]info
candatamsnc[.]info
candatamsnd[.]info
mapdatamsnsdn[.]info
mapdatamsna[.]info
mapdatamsnb[.]info
mapdatamsnc[.]info
mapdatamsnd[.]info
rqmetrixsdn[.]info
rqmetrixa[.]info
rqmetrixb[.]info
rqmetrixc[.]info
rqmetrixd[.]info

Check Point Software Customers remain protected against the threat described in this research.

Check Point Threat Emulation and Harmony Endpoint provide comprehensive coverage of attack tactics and is protecting against the type of attacks and threats described in this report.

Check Point Harmony Endpoint:

APT.Win.Coinloader.B
APT.Win.Coinloader.C

Check Point Threat Emulation:

APT.Wins.Coinloader.A
APT.Wins.Coinloader.D

Appendix A — Python script for resolving indirectly called functions in the final stage of Coinloader

(Requires function table ripped from memory — sample function table included below.)

from abc import ABC, abstractmethod, abstractclassmethod
from typing import List, Tuple, NewType, Dict, Set, Callable, TypeVar, Any, cast, Optional
from functools import wraps
from enum import Enum
import sys

FuncT = TypeVar("FuncT", bound=Callable[...,Any])

try:
    import idc #type: ignore
    import idautils #type: ignore
    import ida_struct #type: ignore
    import ida_bytes #type: ignore
    import ida_idaapi #type: ignore

except ModuleNotFoundError:
    pass #ok, not running within IDA

#IDA
def ida(func: FuncT) -> FuncT:
    ida_modules = set(["idc","idaapi"])
    @wraps(func)
    def wrapper_ida_check(*args: Any, **kwargs: Any) -> Any:
        if not set(sys.modules).issuperset(ida_modules):
            print("ERROR: IDA function called outside IDA context!")
            raise NotImplementedError
        return func(*args, **kwargs)
    return cast(FuncT, wrapper_ida_check)

class OPERAND_TYPE(Enum):
    o_void = 0
    o_reg = 1
    o_mem = 2
    o_phrase = 3
    o_displ = 4
    o_imm = 5
    o_far = 6
    o_near = 7
    o_idpspec0 = 8
    o_idpspec1 = 9
    o_idpspec2 = 10
    o_idpspec3 = 11
    o_idpspec4 = 12
    o_idpspec5 = 13

Addr = NewType("Addr",int)

#Functable

class Functable(ABC):
    @abstractmethod
    def funcname_from_offset(self, addr: Addr) -> str:
        raise NotImplementedError

    @abstractmethod
    def as_dict(self) -> Dict[Addr, str]:
        raise NotImplementedError

    @ida
    @abstractmethod
    def ida_struct_id(self) -> int:
        raise NotImplementedError
    
    @abstractclassmethod
    def from_file(cls, fname: str) -> "Functable":
        raise NotImplementedError

class _Functable(Functable):
    def __init__(self, base: Addr, addr_contents: List[Tuple[Addr,str]]) -> None:
        self.base = base
        self.content_by_addr = {k: v for (k,v) in addr_contents}
        self.struct_id = None

    def funcname_from_offset(self, offset: int) -> str:
        return self.content_by_addr[Addr(self.base+offset)]

    def as_dict(self) -> Dict[Addr, str]:
        return self.content_by_addr

    @ida
    def ida_struct_id(self) -> int:
        if self.struct_id is None:
            self.struct_id = ida_struct.add_struc(ida_idaapi.BADADDR, "FuncTable", False)
            struct_ptr = ida_struct.get_struc(self.struct_id)
            for (addr, funcname) in sorted(self.as_dict().items(), key = lambda item: item[0]):
                ida_struct.add_struc_member(struct_ptr, funcname, addr-self.base, ida_bytes.dword_flag(), None, 4)
        return self.struct_id #type: ignore
    
    @classmethod
    def from_file(cls, fname: str) -> "_Functable":
        with open(fname, "r") as fh:
            tokenized_entrylist = [line.strip().split(" ") for line in fh.readlines()]
            base = Addr(int(tokenized_entrylist[0][0],16))
            addr_contents : List[Tuple[Addr,str]] = []
            for tokenized_entry in tokenized_entrylist:
                if len(tokenized_entry) > 2:
                    addr_contents.append((
                        Addr(int(tokenized_entry[0],16)), 
                        tokenized_entry[2].replace("!","_")
                    ))
            return _Functable(base, addr_contents)

#CoinLoaderFunction

class CoinLoaderFunction(ABC):
    
    @ida
    @abstractmethod
    def functable_register(self) -> Optional[str]:
        raise NotImplementedError

    @ida
    @abstractmethod
    def heads(self) -> List[Addr]:
        raise NotImplementedError

    @ida
    @abstractmethod
    def is_indirect_call(self, addr: Addr) -> bool:
        raise NotImplementedError

    @ida
    @abstractmethod
    def all_indirect_calls(self) -> Dict[Addr,int]:
        raise NotImplementedError
    
    @ida
    @abstractmethod
    def patch_single_indirect_call(self, ea: Addr, ft: Functable) -> None:
        raise NotImplementedError

    @ida
    @abstractmethod
    def patch_indirect_calls(self, ft: Functable) -> None:
        raise NotImplementedError

    @ida
    @abstractclassmethod
    def from_addr(cls, addr: Addr) -> "CoinLoaderFunction":
        raise NotImplementedError

class _CoinLoaderFunction(CoinLoaderFunction):
    @ida
    def __init__(self, addr: Addr) -> None:
        self.addr = addr
        self._functable_register = self.functable_register()

    @ida
    def heads(self) -> List[Addr]:
        return [insn for bound in idautils.Chunks(self.addr) for insn in idautils.Heads(*bound)]
    
    @ida
    def is_regload_insn(self, ea: Addr) -> bool:
        if idc.print_insn_mnem(ea) != "mov": return False
        for i in (0,1):
            if OPERAND_TYPE(idc.get_operand_type(ea,i)) != OPERAND_TYPE.o_reg:
                return False
        if idc.print_operand(ea,1) != "ecx": return False
        return True

    @ida
    def functable_register(self) -> Optional[str]:
        try:
            regload_insn = next(filter(self.is_regload_insn, self.heads()))
            return idc.print_operand(regload_insn,0) #type: ignore
        except StopIteration:
            return None

    @ida
    def is_indirect_call(self, ea: Addr) -> bool:
        if self._functable_register is None: return False
        if idc.print_insn_mnem(ea) != "call": return False
        if OPERAND_TYPE(idc.get_operand_type(ea,0)) != OPERAND_TYPE.o_displ: return False
        if not idc.print_operand(ea,0).startswith("dword ptr ["+self._functable_register+"+"): return False
        return True

    @ida
    def all_indirect_calls(self) -> Dict[Addr,int]:
        eas = [h for h in self.heads() if self.is_indirect_call(h)]
        return {ea:idc.get_operand_value(ea,0) for ea in eas}

    @ida
    def patch_single_indirect_call(self, ea: Addr, ft: Functable) -> None:
        sid =  ft.ida_struct_id() 
        if sid is None:
            print("Cannot patch, functable doesn't have IDA struct")
            print("Use: functable.create_struct()")
        idc.op_stroff(ea, 0, sid,0)

    @ida
    def patch_indirect_calls(self, ft: Functable) -> None:
        for call in self.all_indirect_calls():
            self.patch_single_indirect_call(call,ft)

    @ida
    @classmethod
    def from_addr(cls, addr: Addr) -> "CoinLoaderFunction":
        return _CoinLoaderFunction(addr)

def patch_indirect_calls_all_functions(ft: Functable):
    for ea in idautils.Functions():
        clf : CoinLoaderFunction = _CoinLoaderFunction(ea)
        clf.patch_indirect_calls(ft)

def test_get_name() -> None:
    f = _Functable.from_file("functable.txt")
    assert(f.funcname_from_offset(0x0) == "kernel32_OpenProcess")
    assert(f.funcname_from_offset(0x4) == "kernel32_VirtualProtect")

Sample function table:

0x26cfb94 0x7dd71986 OpenProcess
0x26cfb98 0x7dd7435f VirtualProtect
0x26cfb9c 0x7dd711c0 GetLastError_0
0x26cfba0 0x7dd74913 LoadLibraryExA
0x26cfba4 0x7dd8e4be GlobalReAlloc
0x26cfba8 0x7dd7588e GlobalAlloc
0x26cfbac 0x7dd734d5 CreateThread
0x26cfbb0 0x7dd8d16f GlobalSize
0x26cfbb4 0x7dd7492b LoadLibraryW_0
0x26cfbb8 0x7dd71856 VirtualAlloc
0x26cfbbc 0x7dd71072 CreateProcessA
0x26cfbc0 0x7dd7495d LoadLibraryExW
0x26cfbc4 0x7dd77a10 ExitProcess
0x26cfbc8 0x7dd732bb SetThreadPriority
0x26cfbcc 0x7dd7186e VirtualFree
0x26cfbd0 0x7dd7168c LocalAlloc_0
0x26cfbd4 0x7dd734c8 FreeLibrary_0
0x26cfbd8 0x7dd75558 GlobalFree
0x26cfbdc 0x7dd72d3c LocalFree
0x26cfbe0 0x7ddeaeee SetFileCompletionNotificationModes
0x26cfbe4 0x7dd8cf28 SetPriorityClass
0x26cfbe8 0x7dd93102 lstrcpyW
0x26cfbec 0x7dd75971 FindResourceW
0x26cfbf0 0x7dd8ecbb SetFileTime
0x26cfbf4 0x7dd71809 GetCurrentProcess_0
0x26cfbf8 0x7dd7e2ce FindFirstFileA
0x26cfbfc 0x7dd8e9bb FindResourceA
0x26cfc00 0x7dd734b0 GetModuleHandleW
0x26cfc04 0x7dd741f0 QueryPerformanceFrequency
0x26cfc08 0x7dd9d53e FindNextFileA
0x26cfc0c 0x7dd75444 DeleteFileA
0x26cfc10 0x7dd9cb05 RegisterWaitForSingleObject
0x26cfc14 0x7ddf453f SetNamedPipeHandleState
0x26cfc18 0x7dd9691f K32EnumProcesses
0x26cfc1c 0x7dd8d3ab ReleaseSemaphore
0x26cfc20 0x7dd75a4b lstrlen
0x26cfc24 0x7df720c0 
0x26cfc28 0x7dd8192a lstrcpyn
0x26cfc2c 0x7dd997aa GetSystemWindowsDirectoryA
0x26cfc30 0x7ddf1807 CreateNamedPipeA
0x26cfc34 0x7dd743ef ResumeThread
0x26cfc38 0x7dd75ac9 SizeofResource
0x26cfc3c 0x7dd749ca GetSystemInfo
0x26cfc40 0x7dd71282 WriteFile
0x26cfc44 0x7dd73f5c CreateFileW
0x26cfc48 0x7dd75959 LockResource
0x26cfc4c 0x7dd7170d WideCharToMultiByte_0
0x26cfc50 0x7dd716c5 SetEvent
0x26cfc54 0x7ddf498e QueryFullProcessImageNameA
0x26cfc58 0x7dd71725 QueryPerformanceCounter_0
0x26cfc5c 0x7dd905a0 SetThreadAffinityMask
0x26cfc60 0x7ddf44bf RemoveDirectoryA
0x26cfc64 0x7dd8ca5a CreateSemaphoreW
0x26cfc68 0x7dd717ec GetCurrentThread
0x26cfc6c 0x7dd74f2b FlsAlloc
0x26cfc70 0x7dd7183e CreateEventW
0x26cfc74 0x7dd751a1 GetCommandLineA
0x26cfc78 0x7dd8b6e0 GetComputerNameA
0x26cfc7c 0x7dd75611 GetCurrentDirectoryW
0x26cfc80 0x7dd8eceb lstrcmp
0x26cfc84 0x7dd92a9d lstrcpy
0x26cfc88 0x7dd74208 FlsSetValue
0x26cfc8c 0x7ddfe6ab UnregisterWait
0x26cfc90 0x7dd71245 GetModuleHandleA
0x26cfc94 0x7dd9276c GetTempPathA
0x26cfc98 0x7dd8ecd3 SetFileAttributesA
0x26cfc9c 0x7dd7195e IsWow64Process
0x26cfca0 0x7dd7469b FlushFileBuffers
0x26cfca4 0x7dd75a7e SystemTimeToFileTime
0x26cfca8 0x7dde3161 EnumResourceNamesW
0x26cfcac 0x7dd8d650 Wow64DisableWow64FsRedirection
0x26cfcb0 0x7ddf40fb ConnectNamedPipe
0x26cfcb4 0x7dd71b00 SetErrorMode
0x26cfcb8 0x7dd8eef2 CreateIoCompletionPort
0x26cfcbc 0x7dd75aa6 GetLocalTime
0x26cfcc0 0x7dd74c6b CreateMutexA
0x26cfcc4 0x7dd7192e MultiByteToWideChar_0
0x26cfcc8 0x7dd7594c LoadResource
0x26cfccc 0x7dd74950 GetModuleFileNameW_0
0x26cfcd0 0x7dd8d3c3 GetQueuedCompletionStatus
0x26cfcd4 0x7dd71410 CloseHandle_0
0x26cfcd8 0x7dd7359f FlsFree
0x26cfcdc 0x7dd8195c SetHandleInformation
0x26cfce0 0x7dd710ff Sleep_0
0x26cfce4 0x7dd714b1 GetModuleFileNameA
0x26cfce8 0x7dd8d668 Wow64RevertWow64FsRedirection
0x26cfcec 0x7dd96dcb GetVolumeInformationA
0x26cfcf0 0x7dd75a96 GetSystemTime
0x26cfcf4 0x7dd73ed3 ReadFile
0x26cfcf8 0x7dd9d526 CreateDirectoryA
0x26cfcfc 0x7dd7110c GetTickCount_0
0x26cfd00 0x7dd73e8e lstrcmpiA
0x26cfd04 0x7dd9ab72 EnumResourceNamesA
0x26cfd08 0x7dd754ee FindNextFileW
0x26cfd0c 0x7ddf41df DisconnectNamedPipe
0x26cfd10 0x7dd74435 FindFirstFileW
0x26cfd14 0x7dd8eb39 ExpandEnvironmentStringsA
0x26cfd18 0x7dd75414 GetFileAttributesA
0x26cfd1c 0x7dd74220 WaitForMultipleObjects
0x26cfd20 0x7dd8d802 TerminateProcess_0
0x26cfd24 0x7dd74442 FindClose
0x26cfd28 0x7dded911 MoveFileA
0x26cfd2c 0x7dd753c6 CreateFileA
0x26cfd30 0x7ddf43af GetQueuedCompletionStatusEx
0x26cfd34 0x7dd789b3 DeleteFileW
0x26cfd38 0x7dd8ef29 PostQueuedCompletionStatus
0x26cfd3c 0x7dd74173 ExpandEnvironmentStringsW
0x26cfd40 0x7dd74407 GetFileTime
0x26cfd44 0x7dd71136 WaitForSingleObject
0x26cfd48 0x7dd716dd ResetEvent
0x26cfd4c 0x7dd71252 FlsGetValue
0x26cfd50 0x7dd717d1 SetFilePointer
0x26cfd54 0x7dd71700 lstrlenW_0
0x26cfd58 0x7dd8efec SwitchToThread
0x26cfd5c 0x77c69edf SetSecurityInfo
0x26cfd60 0x77c8077c LsaOpenPolicy
0x26cfd64 0x77c740e6 AllocateAndInitializeSid
0x26cfd68 0x77c740fe RegCreateKeyExW
0x26cfd6c 0x77c741b3 LookupPrivilegeValueW
0x26cfd70 0x77c7431c GetTokenInformation
0x26cfd74 0x77cb15a0 SetNamedSecurityInfoA
0x26cfd78 0x77c7469d RegCloseKey_0
0x26cfd7c 0x77c81af7 LsaClose
0x26cfd80 0x77c74620 InitializeSecurityDescriptor
0x26cfd84 0x77c7468d RegOpenKeyExW_0
0x26cfd88 0x77c714d6 RegSetValueExW
0x26cfd8c 0x77ca8819 LsaAddAccountRights
0x26cfd90 0x77cb15e9 SetEntriesInAclA
0x26cfd94 0x77c7412e FreeSid
0x26cfd98 0x77c7418e AdjustTokenPrivileges
0x26cfd9c 0x77cb187f GetExplicitEntriesFromAclA
0x26cfda0 0x77c715ad RegOpenCurrentUser
0x26cfda4 0x77c7157a GetUserNameW
0x26cfda8 0x77c7415e SetSecurityDescriptorDacl
0x26cfdac 0x77c60000 
0x26cfdb0 0x77c74304 OpenProcessToken
0x26cfdb4 0x77cb1554 GetNamedSecurityInfoA
0x26cfdb8 0x7deb01e3 
0x26cfdbc 0x7debd2f3 
0x26cfdc0 0x7dea9c70 
0x26cfdc4 0x7de922b0 
0x26cfdc8 0x7de70000 
0x26cfdcc 0x7deec240 
0x26cfdd0 0x7dea2265 
0x26cfdd4 0x7debc4ca 
0x26cfdd8 0x7dea45f5 
0x26cfddc 0x7de92340 
0x26cfde0 0x7de92270 
0x26cfde4 0x7debca3a 
0x26cfde8 0x7de9df20 
0x26cfdec 0x7dea2500 
0x26cfdf0 0x7dea2c42 
0x26cfdf4 0x7deebfa0 
0x26cfdf8 0x7dcbfd3f MessageBoxW
0x26cfdfc 0x7dcbfd1e MessageBoxA
0x26cfe00 0x7dc70a19 GetDesktopWindow
0x26cfe04 0x7dc8e061 wsprintfW
0x26cfe08 0x7dc50000 Ordinal2447
0x26cfe0c 0x7dc7ae5f wsprintfA
0x26cfe10 0x72589d0b CoCreateInstance
0x26cfe14 0x72540000 
0x26cfe18 0x72567259 CoInitializeSecurity
0x26cfe1c 0x725809ad CoInitializeEx
0x26cfe20 0x72555ea5 CoSetProxyBlanket
0x26cfe24 0x725886d3 CoUninitialize
0x26cfe28 0x6fc33e59 SysFreeString
0x26cfe2c 0x6fc34642 SysAllocString
0x26cfe30 0x6fc30000 Ordinal471
0x26cfe34 0x504b30 
0x26cfe38 0x504b58 
0x26cfe3c 0x535120 aAmdRyzen536006_0
0x26cfe40 0x1 
0x26cfe44 0x712175e8 InternetSetOptionA
0x26cfe48 0x7127a920 InternetGetLastResponseInfoA
0x26cfe4c 0xcc0004 
0x26cfe50 0x7121b406 InternetReadFile
0x26cfe54 0x712430f1 InternetOpenUrlA
0x26cfe58 0x7122f18e InternetOpenA
0x26cfe5c 0x71224c7d HttpOpenRequestA
0x26cfe60 0x712249e9 InternetConnectA
0x26cfe64 0x71200000 Ordinal367
0x26cfe68 0x7121ab49 InternetCloseHandle
0x26cfe6c 0x71211b56 InternetQueryOptionA
0x26cfe70 0x712918f8 HttpSendRequestA
0x26cfe74 0x6dc00000 
0x26cfe78 0x6dc2a9bc DnsQuery_A
0x26cfe7c 0x6dc0436b DnsFree
0x26cfe80 0x7d830000 
0x26cfe84 0x7d83647a BCryptVerifySignature
0x26cfe88 0x7d834d42 BCryptImportKey
0x26cfe8c 0x7d831fbc BCryptGenerateSymmetricKey
0x26cfe90 0x7d831b44 BCryptFinishHash
0x26cfe94 0x7d831a5f BCryptDestroyHash
0x26cfe98 0x7d831b93 BCryptCreateHash
0x26cfe9c 0x7d831b0b BCryptHashData
0x26cfea0 0x7d8318b8 BCryptDecrypt
0x26cfea4 0x7d83195c BCryptEncrypt
0x26cfea8 0x7d8320d4 BCryptSetProperty
0x26cfeac 0x7d83234e BCryptCloseAlgorithmProvider
0x26cfeb0 0x7d834f94 BCryptImportKeyPair
0x26cfeb4 0x7d83519b BCryptExportKey
0x26cfeb8 0x7d831ca7 BCryptGetProperty
0x26cfebc 0x7d831f40 BCryptDestroyKey
0x26cfec0 0x7d832d30 BCryptOpenAlgorithmProvider

POPULAR POSTS

BLOGS AND PUBLICATIONS

  • Check Point Research Publications
  • Global Cyber Attack Reports
  • Threat Research
February 17, 2020

“The Turkish Rat” Evolved Adwind in a Massive Ongoing Phishing Campaign

  • Check Point Research Publications
August 11, 2017

“The Next WannaCry” Vulnerability is Here

  • Check Point Research Publications
January 11, 2018

‘RubyMiner’ Cryptominer Affects 30% of WW Networks