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.
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 SYN
s and ACK
s, 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:
“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:
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.
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:
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.
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.
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.
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.
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.
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.
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.
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:
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).
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.
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.
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”.
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 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
(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