{
	"id": "1d84a228-7a80-485a-831a-76fa41d26991",
	"created_at": "2026-04-06T00:17:56.478703Z",
	"updated_at": "2026-04-10T03:35:25.300707Z",
	"deleted_at": null,
	"sha1_hash": "f9d1b22008472850fd75eec87978b3c000edfea1",
	"title": "GhostEmperor: From ProxyLogon to kernel mode",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1270411,
	"plain_text": "GhostEmperor: From ProxyLogon to kernel mode\r\nBy Mark Lechtik\r\nPublished: 2021-09-30 · Archived: 2026-04-05 17:25:15 UTC\r\n Download GhostEmperor’s technical details (PDF)\r\nWhile investigating a recent rise of attacks against Exchange servers, we noticed a recurring cluster of activity that\r\nappeared in several distinct compromised networks. This cluster stood out for its usage of a formerly unknown\r\nWindows kernel mode rootkit that we dubbed Demodex, and a sophisticated multi-stage malware framework\r\naimed at providing remote control over the attacked servers.\r\nThe former is used to hide the user mode malware’s artefacts from investigators and security solutions, while\r\ndemonstrating an interesting undocumented loading scheme involving the kernel mode component of an open-source project named Cheat Engine to bypass the Windows Driver Signature Enforcement mechanism.\r\nIn an attempt to trace the duration of the observed attacks, we were able to see the toolset in question being used\r\nfrom as early as July 2020. Furthermore, we could see that the actor was mostly focused on South East Asian\r\ntargets, with outliers in Egypt, Afghanistan and Ethiopia which included several governmental entities and\r\ntelecommunication companies.\r\nWith a long-standing operation, high profile victims, advanced toolset and no affinity to a known threat actor, we\r\ndecided to dub the underlying cluster GhostEmperor. Our investigation into this activity leads us to believe that\r\nthe underlying actor is highly skilled and accomplished in their craft, both of which are evident through the use of\r\na broad set of unusual and sophisticated anti-forensic and anti-analysis techniques.\r\nHow were the victims initially infected?\r\nWe identified multiple attack vectors that triggered an infection chain leading to the execution of malware in\r\nmemory. We noticed that the majority of the GhostEmperor infections were deployed on public facing servers, as\r\nmany of the malicious artefacts were installed by the ‘httpd.exe’ Apache server process, the ‘w3wp.exe’ IIS\r\nWindows server process, or the ‘oc4j.jar’ Oracle server process. This means that the attackers likely abused\r\nvulnerabilities in the web applications running on those systems, allowing them to drop and execute their files.\r\nIt is worth mentioning that one of the GhostEmperor infections affected an Exchange server, and took place on\r\nMarch 4, 2021. This was only two days after the patch for the ProxyLogon vulnerability was released by\r\nMicrosoft, and it is possible that the attackers exploited this vulnerability in order to allow them to achieve remote\r\ncode execution on vulnerable Exchange servers.\r\nAlthough GhostEmperor’s infections often start with a BAT file, in some cases the known infection chain was\r\npreceded by an earlier stage: a malicious DLL that was side-loaded by wdichost.exe, a legitimate command line\r\nutility by Microsoft originally called MpCmdRun.exe. The side-loaded DLL then proceeds to decode and load an\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 1 of 19\n\nadditional executable called license.rtf. Unfortunately, we did not manage to retrieve this executable, but we saw\r\nthat the consecutive actions of loading it included the creation and execution of GhostEmperor scripts by\r\nwdichost.exe.\r\nExample of a GhostEmperor infection chain started by a side-loaded DLL\r\nLastly, some of the Demodex deployments were performed remotely from another system in the network using\r\nlegitimate tools such as WMI or PsExec, suggesting that the attackers have infected parts of the victims’ networks\r\nbeforehand.\r\nInfection chain overview\r\nThe infection can be divided into several stages that operate in succession to activate an in-memory implant and\r\nallow it to deploy additional payloads during run time. This section provides a brief overview of these stages,\r\nincluding a description of the final payloads. The internals of these payloads can be found in a technical document\r\nthat accompanies this publication.\r\nThe flow of infection starts with a PowerShell dropper. The purpose of this component is to stage the subsequent\r\nelement in the chain by installing it as a service. Before doing so, it creates a couple of registry keys that it assigns\r\nencrypted data to, one of which corresponds to a payload that will be deployed in the later stages. It’s worth noting\r\nthat the script itself is delivered in a packed form, whereby its complete execution is dependent on a command-line argument that is used as a key to decrypt the bulk of its logic and data. Without this key, it’s impossible to\r\nrecover the flow that comes after this stage.\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 2 of 19\n\nInitial stage comprised of encrypted PowerShell code that is decrypted based on an attacker-provided AES key\r\nduring run time\r\nThe next stage, which is executed as a service by the former, is intended to serve as yet another precursor for the\r\nnext phases. It is used to read the encrypted data from the previously written registry keys and decrypt it to initiate\r\nthe execution of an in-memory implant. We identified two variants of this component, one developed in C++ and\r\nanother in .NET. The latter, which appeared in the wild as early as March 2021, uses the GUID of the infected\r\nmachine to derive the decryption key, and is thus tailored to be executed on that specific system. The C++ variant,\r\non the other hand, relies on hardcoded AES 256 encryption keys.\r\nThe third stage is the core implant that operates in memory after being deployed by the aforementioned loader,\r\nand is injected into the address space of a newly created svchost.exe process. Its main goal is to facilitate a\r\ncommunication channel with a C2 server, whereby malicious traffic is masqueraded under the guise of\r\ncommunication with a benign service, based on a Malleable C2 profile embedded within its configuration. It is\r\nimportant to note that the implementation of the Malleable C2 feature, which is originally provided in the Cobalt\r\nStrike framework, is customized and most likely rewritten based on reverse engineering of Cobalt Strike’s code.\r\nAnother interesting technique used to conceal the malicious traffic is the malware’s usage of fake file format\r\nheaders to encapsulate the data passed to the C\u0026C server. To do so, the in-memory implant synthesizes a fake\r\nmedia file of one of the formats RIFF, JPEG or PNG and puts any data conveyed to the server in encrypted form\r\nas its body. Thus, the transmitted packet appears as either an image or audio file and blends with other legitimate\r\ntraffic in the network.\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 3 of 19\n\nMalleable C2 profile and fake header\r\nThe last stage is the payload injected to the winlogon.exe process by the aforementioned implant and used to\r\nprovide remote control capabilities to the attackers. Such capabilities include initiation of a remote console or\r\ndesktop session, with the latter supporting execution of sent mouse clicks and keystrokes on the target machine\r\nand retrieval of periodic screenshots that reflect the output of those actions. This stage can also allow the attackers\r\nto load arbitrary .NET assemblies or execute PowerShell commands, as well as fully control the victim’s\r\nfilesystem in order to search, retrieve or push files to it.\r\nIn addition to the last stage payload, the core component is also capable of deploying a Windows kernel mode\r\ndriver on the system. The purpose of this driver is to serve as a rootkit that conceals malware artefacts such as\r\nfiles, registry keys and network traffic, thus gaining stealth and ability to avoid detection by security products and\r\nforensic investigators. The upcoming sections elaborate on how this driver is deployed (namely how it bypasses\r\nWindows mitigations, given that it’s not digitally signed) and what particular features it provides to the user mode\r\nmalicious implant.\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 4 of 19\n\nOverview of the GhostEmperor infection chain\r\nRootkit loading analysis\r\nOn modern 64-bit Windows operating systems, it is generally not possible to load an unsigned driver in a\r\ndocumented way due to the Driver Signature Enforcement mechanism introduced by Microsoft. For this reason,\r\nattackers have abused vulnerabilities in signed drivers to allow execution of unsigned code to kernel space. A\r\ntypical approach1 taken by many actors to date, and mostly in older versions of Windows, is to disable the Code\r\nIntegrity mechanism by switching the nt!g_CiEnabled flag that resides within the CI.DLL kernel module after\r\ngetting write and execution primitives via vulnerable signed drivers. After shutting down the Code Integrity\r\nmechanism, an unsigned driver can be loaded.\r\nThis approach was limited by Microsoft with the introduction of Kernel Patch Protection (a.k.a PatchGuard). This\r\nmechanism protects modification of specific data structures in the Windows kernel memory space, including the\r\nnt!g_CiEnabled flag. For this reason, the modification of this flag can now cause an invocation of a BSOD. This\r\ncan be tackled by quickly setting the flag value, loading an unsigned driver and switching it back to the previous\r\nstate before PatchGuard identifies a change, though this still introduces a race condition that can crash the system.\r\nThe approach used by the developer of this rootkit allows loading an unsigned driver without modifying the Code\r\nIntegrity image and dealing with a potential crash. It abuses features of a legitimate and open-source2 signed\r\ndriver named dbk64.sys which is shipped along with Cheat Engine, an application created to bypass video game\r\nprotections and introduce cheats into them. This driver provides capability to write and execute code in kernel\r\nspace by design, thus allowing it to run arbitrary code in kernel mode.\r\nAfter dropping the dbk64.sys driver with a randomly generated filename to disk and loading it, the malware issues\r\ndocumented3 IOCTLs to the driver that allow shellcode to be run in kernel space through the following sequence\r\nof actions:\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 5 of 19\n\nFirst, a memory buffer is allocated in the kernel space non-paged pool by issuing\r\nIOCTL_CE_ALLOCATEMEM_NONPAGED.\r\nA successfully allocated memory buffer will be then shared between the user mode malware process and\r\nkernel address spaces using a direct I/O approach, whereby the kernel mode buffer’s address is mapped to a\r\ndifferent address in user space. This is achieved by locking the buffer’s pages in physical memory so that\r\nthey cannot be paged out (which is possible since they are allocated in the non-paged pool) following\r\nwhich an MDL for the buffer is created and a call to the MmMapLockedPagesSpecifyCache API function\r\nis made. All of this is implemented in the handler of IOCTL_CE_MAP_MEMORY.\r\nAt this point the malware can access the buffer in user mode through the provided pointer from the\r\nprevious IOCTL and write to it. The written data will in turn be reflected in the same buffer in kernel\r\nspace. This is used to write the shellcode into the buffer.\r\nAfter the writing is done, the buffer is unmapped from user space by issuing\r\nIOCTL_CE_UNMAP_MEMORY.\r\nThe written shellcode now resides only in kernel space and can be run by issuing\r\nIOCTL_CE_EXECUTE_CODE.\r\nThe purpose of the shellcode is to replace the dbk64.sys IOCTL dispatcher with an alternative one that in turn\r\nallows the loading of an unsigned driver. The alternative dispatcher is also implemented as position-independent\r\ncode and is bundled with the shellcode. To replace the original dispatcher, the shellcode maps the code of the new\r\ndispatcher in memory and patches the pointer to the IRP_MJ_DEVICE_CONTROL routine in the dbk64.sys\r\ndriver object. At this point, the IRP_MJ_DEVICE_CONTROL pointer is set to the new dispatcher’s address and\r\nany IOCTL issued to the driver will pass through it.\r\nIRP_MJ_DEVICE_CONROL hooking\r\nThe alternative dispatcher provides the same core capabilities as the original one, with the addition of a few that\r\nallow it to load a new driver to kernel space. The functionality that makes it possible to achieve this goal is\r\nexposed through a set of IOCTL handlers that are called in succession, finally leading to the load of the malware’s\r\nkernel mode rootkit. Below is a table of these IOCTLs with descriptions, arranged in the order they are invoked by\r\nthe malware’s user mode logic in charge of deploying the rootkit.\r\nIOCTL\r\nCode\r\nDescription\r\n0x220180\r\nProcesses a buffer provided by the user mode malware component by verifying its size is 272\r\nbytes and then decodes it by negating its bytes. This IOCTL is in fact not invoked by the user\r\nmode code.\r\n0x220184 Allocates a buffer in kernel space, locks its pages, creates an MDL and maps the buffer to a user\r\nmode address using the MmMapLockedPagesSpecifyCache API. This is essentially equivalent\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 6 of 19\n\nto the chaining of functionalities in IOCTL_CE_ALLOCATEMEM_NONPAGED and\r\nIOCTL_CE_MAP_MEMORY from the original dispatcher.\r\nAfter this call, the user mode code has access to a kernel mode buffer and can write to it using a\r\npointer in user mode, as was the case for writing the shellcode. This time, however, the malware\r\nmanually loads the rootkit’s PE image into the allocated buffer.\r\n0x2201B4\r\nSince the malware’s user mode code is in charge of loading the rootkit’s image manually in\r\nIOCTL 0x220184, it has to resolve some function addresses in kernel space that appear as\r\ndependencies in the image’s Import Address Table. This IOCTL allows the function names to be\r\nreceived from user space as strings, retrieving their address with the\r\nMmGetSystemRoutineAddress API and providing it back to the user mode code. The latter\r\nplaces the resolved address in the corresponding IAT entry of the loaded image.\r\n0x220188\r\nUnmaps the address of the kernel mode buffer from user space so it’s only accessible through\r\nits kernel mode pointer.\r\n0x2201B8\r\nCreates a new driver object using the IoCreateDriver function, assigning the driver initialization\r\nfunction pointer to a position-independent stub that is delivered with the shellcode and, once\r\ninvoked, calls the loaded rootkit’s DriverEntry function.\r\nIt is worth mentioning that the malware’s service makes use of a Cheat Engine utility called\r\nkernelmoduleuloader.exe (MD5: 96F5312281777E9CC912D5B2D09E6132) during the loading of the dbk64.sys\r\ndriver. The driver is dropped along with the utility and a .sig file, with the latter being used as a means of\r\nauthenticating the component calling dbk64.sys by conveying a digital signature that is associated with its binary.\r\nAs the malware is not a component of Cheat Engine, it runs kernelmoduleunloader.exe as a new process and\r\ninjects it with a small shellcode that merely opens a handle to the dbk64.sys device with the CreateFileW API. The\r\nvalue of the handle is written as the second QWORD in the injected buffer, read by the malware’s process and gets\r\nduplicated using the DuplicateHandle API. From this point on, the malware’s service can call the driver as if it\r\nwas a signed Cheat Engine component.\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 7 of 19\n\nAn outline of the rootkit’s loading phases\r\nDemodex rootkit functionality\r\nThe loaded rootkit, which we dubbed Demodex, serves the purpose of hiding several artefacts of the malware’s\r\nservice. This is achieved through a set of IOCTLs exposed by the rootkit’s driver that are in turn called by the\r\nservice’s user mode code, each disguising a particular malicious artefact. To access the rootkit’s functionality, the\r\nmalware ought to obtain a handle to the corresponding device object, after which the following IOCTLs are\r\navailable for further use:\r\n0x220204: Receives an argument with the PID of the svchost.exe process which runs the code of the\r\nmalicious service and stores it within a global variable. This variable is used by other IOCTLs later on.\r\n0x220224: Initializes global variables that are later used to hold data such as the aforementioned\r\nsvchost.exe PID, the name of the malware’s service, the path to the malware’s DLL and a network port.\r\n0x220300: Hides the malware’s service from a list within the services.exe process address space. The\r\nservice’s name is passed as an argument to the IOCTL, in turn being sought in a system-maintained linked\r\nlist. The corresponding entry is being unlinked, thus hiding the service from being easily detected. The\r\nlogic in this handler is reminiscent of the technique outlined here.\r\n0x220304: This IOCTL is used to register a file system filter driver’s notification routine by using the\r\nIoRegisterFSRegistrationChange API. The notification routine invoked upon registration of a new file\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 8 of 19\n\nsystem verifies if it is an NTFS-based one and if so, creates a device object for the rootkit which is attached\r\nto the subject file system’s device stack. Additionally, both the file system’s device object and the\r\nassociated rootkit device object are registered in a global list maintained by the rootkit’s driver. Subsequent\r\nattempts to retrieve information from, access or modify the file will fail and generate error codes such as\r\nSTATUS_NO_MORE_FILES or STATUS_NO_SUCH_FILE.\r\n0x220308: Hides TCP connections that make use of ports within a given range from utilities that list them,\r\nsuch as netstat. This is done through a known4 method whereby the IOCTL dispatch routine of the NSI\r\nproxy driver is hooked and the completion routine is set to one that inspects the port of a given connection.\r\nIf the underlying connection’s port falls within the given range, its entry is removed from the system’s TCP\r\ntable. The two ports that constitute the range are passed as arguments to the IOCTL.\r\n0x22030C: Hides malware-related registry keys by hooking several registry operations through the\r\nCmRegisterCallback API. The registered callback checks the type of operation and acts according to the\r\nfollowing logic:\r\nFor operations of the type RegNtPostEnumerateKey or RegNtPostEnumerateValueKey\r\n(enumeration of a key or subkey) it verifies if there is an attempt to enumerate the driver related key\r\nunder HKLM\\SYSTEM\\ControlSet0**\\Services\\\u003cmalware_service_name\u003e and if so, sets the return\r\nstatus of the operation to STATUS_NO_MORE_ENTRIES in order to indicate there is no data to\r\nprovide for the requested enumeration.\r\nFor operations of the type RegNtPreOpenKeyEx (attempt to open a key) on\r\nSOFTWARE\\Microsoft\\{EAAB20A7-9B68-4185-A447-7E4D21621943} it clears all the driver’s\r\ninternal global variables, which is equivalent to resetting its operation. That’s because this key is\r\nused by the malware’s uninstaller PowerShell script, mentioned in previous sections.\r\nFor any attempt to change a key under HKLM\\MACHINE\\SYSTEM via an operation with code\r\nRegNtPreSaveKey or lower, it sets that return status to the application error 0xC0000043.\r\nInterestingly, the pointer passed to CmRegisterCallback does not contain the direct address of the function\r\nhandling the logic above, but instead an address at the end of the executable section of the pci.sys driver’s image,\r\nwhich is originally filled with zeros as a means to align the section in memory. Before passing the callback pointer\r\nto CmRegisterCallback, such a section is sought within the pci.sys driver and the corresponding bytes within it are\r\npatched so as to invoke the call to the actual callback handling the above logic, as outlined below. This allows all\r\nintercepted registry operations to appear as if they are handled by code that originates in the legit pci.sys driver.\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 9 of 19\n\nCode used to patch a section in the pci.sys image in memory in order to write it with a short shellcode stub that\r\njumps into a registry inspection callback\r\nIt is worth mentioning that the Demodex rootkit supports Windows 10 by design, and indeed appears to work\r\naccording to our tests on Windows 10 builds. This is evident in the driver’s code in multiple places where different\r\nflows of the code are taken based on the underlying operating system’s version. In such checks it is possible to\r\nobserve that some flows correspond to the latest builds of Windows 10, as outlined in the code snippet below.\r\nObfuscation and anti-analysis methods\r\nThe authors of the malware components used in the GhostEmperor cluster of activity have made some\r\ndevelopment choices that have implications on the forensic analysis process. To demonstrate some of the hurdles\r\nthat investigators face, we will limit the discussion to two common analysis tools – WinDbg and Volatility. Other\r\ntools may encounter similar drawbacks when dealing with the implants in question.\r\nFirst, due to the way Demodex is loaded, its driver is not properly enlisted in WinDbg along with other system\r\nmodules that are loaded in a documented way. That said, it is still possible to find the rootkit’s driver object by\r\nreferring to its name (\\driver\\dump_audio_codec0), thus being able to list its associated device objects as well:\r\nDriver object name listed in WinDBG\r\nSimilarly, when trying to list system modules with the Volatility3 widows.driverscan module, the Demodex driver\r\nis absent from the output. However, the framework does indicate that an anomaly is detected in the process of\r\nscanning the kernel’s memory space in search for the driver:\r\nAnomaly while listing the Demodex driver with the windows.driverscan Volatility3 module\r\nIn addition, the malware authors have made a deliberate choice to remove all PE headers from memory-loaded\r\nimages in both the third stage of the malware and the rootkit’s driver. This is done by either introducing the image\r\nwith a zeroed-out header to begin with (as is the case in the third stage) and relying on a custom loader to prepare\r\nit for execution or by replacing the header of the image after its loaded with the 0x00 value, as is the case with the\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 10 of 19\n\nrootkit’s driver.  From a forensic perspective, this impedes the process of identifying PE images loaded to memory\r\nby searching for their headers.\r\nAs mentioned in previous sections, the developers implemented a trampoline within the pci.sys legitimate driver\r\nin order to mask the source of callbacks that are invoked for registry-related operations. Thus, analysts that try to\r\ntrack such callbacks may miss out on some because they will appear to be benign calls. As demonstrated in the\r\nWinDbg listing of the Cm* callbacks below, one of them is associated with the symbol\r\npci!ArbLibraryDeinitialize+0xa4; however, if we look at the code at the same address we can see that it is in fact a\r\nsmall piece of shellcode emitted by the rootkit in order to jump to the actual malicious callback that hides the\r\nmalware’s registry keys.\r\nListing of Cm* callbacks and shellcode found within a seemingly benign code invoked from the pci.sys driver\r\nApart from the above, the developers introduced more standard methods of obfuscation that typically slow the\r\nstatic analysis of the code and are evident across multiple malware components. An example of this is a pattern of\r\nstring obfuscation whereby each string is decoded with a set of predefined arithmetic and logic operations, such\r\nthat different operands (e.g., shift offsets) are chosen for each string. This suggests that each string is obfuscated\r\nduring compilation and that the authors have established a form of SDK that aids in uniquely obfuscating each\r\nsample during build time.\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 11 of 19\n\nString decoding logic used to obtain clear-text strings from hardcoded blobs through a set of arithmetic and logic\r\noperations\r\nSimilarly, it is possible to observe multiple instances of API call obfuscation in the code. This is done by replacing\r\ninline calls to API functions with other stub functions that build the requested API name as a stack string, resolve\r\nit using GetProcAddress and call it while passing the arguments provided in a special struct to the stub function.\r\nThe struct has a bigger size than required to pass the argument data, and most of it is filled with junk, such that\r\nonly particular fields have meaningful data that gets encoded before being passed to the stub. Those fields get\r\ndecoded within the stub function and in turn passed to the API function.\r\nExample of a stub used for API call obfuscation\r\nIt is worth noting that as in the case of string obfuscation, each stub is uniquely built and makes use of an\r\nargument struct of a different size where the fields that are occupied with actual argument data are chosen at\r\nrandom. The order in which the stack string is initialized is also random and each stub function is used only once\r\nas a replacement for a single inline API function call. In other words, the same API function used in different\r\nplaces in the code will have different stubs for each place with different argument structs. This reinforces the\r\nobservation that the authors were using a designated obfuscation SDK in which the API call obfuscation is yet\r\nanother feature.\r\nFinally, it is possible to see that some variants appeared in both obfuscated and non-obfuscated form. For example,\r\nwe managed to view the C++ version of the second stage loader in two forms – one form that has no obfuscation\r\nat all and another that is heavily obfuscated (MD5: 18BE25AB5592329858965BEDFCC105AF). In the figure\r\nbelow we can see the same function in the two variants: one has the original flow of the code as produced by a\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 12 of 19\n\ncompiler without obfuscation, while the other has its control flow flattened to the point where it is impossible to\r\ntrack the order of actions.\r\nExample of the same function used in two variants of the second stage loader; one is non-obfuscated and the\r\nother’s control flow was flattened\r\nPost-exploitation toolset\r\nOnce the attackers gain access to the compromised systems through the aforementioned infection chain, they use a\r\nmix of legitimate and open-source offensive toolsets to harvest user credentials and pivot to other systems in the\r\nnetwork. This includes common utilities from the Sysinternals suite used to control processes (e.g., PsExec, PsList\r\nand ProcDump), as well as other tools like WinRAR, CertUtil and BITSAdmin. As for open-source tools, the\r\nattackers used tools such as mimkat_ssp, Get-PassHashes.ps1, Token.exe and Ladon. Internal network\r\nreconnaissance and communication is often carried out by NBTscan and Powercat.\r\nA more comprehensive outline of these tools along with the actual command lines used by the threat actor to\r\noperate them can be found in the supplementary technical document.\r\nNetwork infrastructure\r\nFor C2 communication, the attackers registered domains whose names appear to have been randomly generated,\r\npotentially not to attract any attention to the malicious traffic. GhostEmperor mainly used hosting services based\r\nin Hong Kong and South Korea, such as Daou Technology or Anchent Asia Limited.\r\nnewlylab[.]com\r\nreclubpress[.]com\r\nwebdignusdata[.]com\r\nfreedecrease[.]com\r\naftercould[.]com\r\ndatacentreonline[.]com\r\nnewfreepre[.]com\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 13 of 19\n\nWe also observed additional IP addresses used for downloading some of the malicious samples, or for C2\r\ncommunication by the in-memory implant:\r\n154.223.135[.]214\r\n107.148.165[.]158\r\n27.102.114[.]55\r\n27.102.113[.]57\r\n27.102.113[.]240\r\nWho were the targets?\r\nThe majority of GhostEmperor’s victims were government entities and telecommunication companies in South\r\nEast Asia, with multiple high-profile entities targeted in Malaysia, Thailand, Vietnam and Indonesia. We also\r\nobserved additional victims of a similar nature from countries such as Egypt, Ethiopia and Afghanistan. Even\r\nthough the latter cluster of victims belongs to a different region from the one in which we saw GhostEmperor to\r\nbe highly active, we noticed that some of the organizations within it have strong ties with countries in South East\r\nAsia. This means that the attackers might have leveraged those infections to spy on the activities in countries that\r\nare of geopolitical interest to them.\r\nWho is behind the attacks?\r\nWe attribute this activity to a formerly unknown Chinese-speaking threat actor. This is due to the fact that the\r\nattackers made use of open-source tools such as Ladon or Mimikat_ssp that are popular among such actors, with\r\nadditional data points such as version info found within the resource section of second stage loader binaries that\r\nincluded a legal trademark field with a Chinese character: ‘Windows庐 is a registered trademark of Microsoft\r\nCorporation.’\r\nVersion info of loader binary with a Chinese character\r\nOn the same note, we observed that one of the decryption keys provided in a command line by the attackers and\r\nused to decode the first stage PowerShell scripts was ‘wudi520’. Looking it up in publicly available sources led us\r\nto a GitHub account under the same name. Although we cannot confirm this account is indeed connected to the\r\nGhostEmperor attackers, it has forked multiple code repositories with descriptions in Chinese or that are otherwise\r\nauthored by Chinese-speaking developers.\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 14 of 19\n\n“wudi520” GitHub account\r\nIn addition, we noticed some similarities between the features of Demodex and those of the Derusbi rootkit, which\r\nwas publicly described in the past and also attributed to a Chinese-speaking actor. The purpose of both is to hide\r\nmalicious artefacts, where notably both have an almost identical flow for hiding TCP connections by hooking the\r\nnsiproxy.sys IOCTL dispatcher. The implementation of this filtering in the Demodex sample we analyzed is nearly\r\nidentical to one seen in an older Derusbi sample (MD5: 24E9870973CEA42E6FAF705B14208E52) to the point\r\nthat both use the same device control code for this action and receive an IOCTL input of the same size. That said,\r\nit is worth noting that while Derusbi used a hardcoded range of 1025 to 1777 for the targeted ports to hide,\r\nDemodex allows for an arbitrary range that can be configured by the attackers through the user mode malware.\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 15 of 19\n\nComparison of a similar IOCTL in the Demodex and Derusbi rootkits\r\nIt is worth noting that in one of the victim systems we observed two instances of malicious samples being dropped\r\nvia a web shell. One led to the initiation of an infection chain consisting of the first stage PowerShell dropper and\r\nsecond stage .NET service DLL, and another was a drop of two binaries5 of the Netbot malware, formerly seen\r\nbeing used6 by the Lucky Mouse group. Though we cannot attest to the fact that the very same web shell was used\r\nto drop both files, the proximity of events which occurred in the course of two days, may suggest that underlying\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 16 of 19\n\nactor indeed deployed both samples and that it has a possible connection to the Lucky Mouse group, whether\r\nthrough shared development resources or reused tools.\r\nConclusions\r\nGhostEmperor is an example of an advanced threat actor that goes after prominent targets and aims to maintain a\r\nlong standing and persistent operation within their environments. We observed that the underlying actor managed\r\nto remain under the radar for months, all the while demonstrating a finesse when it came to developing the\r\nmalicious toolkit, a profound understanding of an investigator’s mindset and the ability to counter forensic\r\nanalysis in various ways.\r\nAdditionally, while rootkits are generally considered a deprecated method of attack, this case and other recent\r\nones show that with a creative approach they can still be leveraged to gain a considerable level of stealth. As we\r\nhave seen, the attackers conducted the required level of research to make the Demodex rootkit fully functional on\r\nWindows 10, allowing it to load through documented features of a third-party signed and benign driver. This\r\nsuggests that rootkits still need to be taken into account as a TTP during investigations and that advanced threat\r\nactors, such as the one behind GhostEmperor, are willing to continue making use of them in future campaigns.\r\nIndicators of compromise\r\nStage 1 – PowerShell Dropper\r\n012862165EC105A44FEA14FACE53492F – u_ex200822.ps1\r\nStage 2 – Service DLL\r\n6A44FDD66AB841C33949620666CA847A – RAudioUniConfig.dll\r\n2DD0885F84B890883A396030DB841D28\r\n1BC301AA9B861F762CE5F376228E992A – svchosts.exe\r\nStage 4\r\n0BBFBA106FBB9E310330DC87C32CB6D1 – Payload DLL\r\n6685323C61D8EDB4A6E35796AF34D626 – Remote Desktop Control DLL\r\nPost-exploitation\r\nBE38D173E4E9118BDC2E83FD5F90BE3B – kekeo.exe\r\nF078AC9B012C503D35254AF9629D3B67 – debugall.vbs\r\nDriver\r\n7394229455151a9cd036383027a1536b\r\nFile paths\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 17 of 19\n\nC:\\Windows\\debug\\wia\r\nPDB paths\r\nC:\\c\\getpwd\\x64\\Release\\getpwd.pdb\r\nD:\\Source\\workspace\\ExCtrl\\XControl\\Release\\XCLoader.pdb\r\nService name and DLL path\r\nMsMp4Hw – C:\\Windows\\System32\\msmp4dec.dll\r\nMsdecode – C:\\ProgramData\\Microsoft\\Network\\Connections\\msdecode.dll\r\nAuthSvc – C:\\Windows\\System32\\AuthSvc.dll\r\nRegistry keys for encrypted buffer\r\nHKLM\\Software\\Microsoft\\hiaudio\r\nHKLM\\Software\\Microsoft\\midihelp\r\nHKLM\\Software\\Microsoft\\data\r\nHKLM\\Software\\Microsoft\\update\r\nDomains and IPs\r\nimap.newlylab[.]com\r\nmail.reclubpress[.]com\r\nimap.webdignusdata[.]com\r\nfreedecrease[.]com\r\naftercould[.]com\r\ndatacentreonline[.]com\r\ngame.newfreepre[.]com\r\n27.102.113[.]57\r\n27.102.113[.]240\r\n27.102.114[.]55\r\n27.102.115[.]51\r\n27.102.129[.]120\r\n107.148.165[.]158\r\n154.223.135[.]214\r\n1\r\n This approach is well documented and demonstrated in the DSEFix public repository:\r\nhttps://github.com/hfiref0x/DSEFix\r\n2\r\n The source code of the driver can be found on GitHub.\r\n3\r\n They are outlined in the IOPLDispatcher.c source code within the Cheat Engines repository.\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 18 of 19\n\n4\r\n A technique similar to the one observed in the Demodex rootkit is outlined in this code:\r\nhttps://github.com/bowlofstew/rootkit.com/blob/master/cardmagic/PortHidDemo_Vista.c\r\n5\r\n Those binaries had the MD5s: 145FF08E736693D522F8A09C8D3405D6,\r\n7A162C26D56B0C55E6CD81CD953F510B\r\n6\r\n https://securelist.com/ksb-2019-review-of-the-year/95394/, detailed analysis of the Netbot malware as part of\r\nLucky Mouse campaigns is available to customers of our APT reporting service.\r\nSource: https://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nhttps://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/\r\nPage 19 of 19",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia",
		"MISPGALAXY",
		"ETDA"
	],
	"references": [
		"https://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/"
	],
	"report_names": [
		"104407"
	],
	"threat_actors": [
		{
			"id": "f0eca237-f191-448f-87d1-5d6b3651cbff",
			"created_at": "2024-02-06T02:00:04.140087Z",
			"updated_at": "2026-04-10T02:00:03.577326Z",
			"deleted_at": null,
			"main_name": "GhostEmperor",
			"aliases": [
				"OPERATOR PANDA",
				"FamousSparrow",
				"UNC2286",
				"Salt Typhoon",
				"RedMike"
			],
			"source_name": "MISPGALAXY:GhostEmperor",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "d390d62a-6e11-46e5-a16f-a88898a8e6ff",
			"created_at": "2024-12-28T02:01:54.899899Z",
			"updated_at": "2026-04-10T02:00:04.880446Z",
			"deleted_at": null,
			"main_name": "Salt Typhoon",
			"aliases": [
				"Earth Estries",
				"FamousSparrow",
				"GhostEmperor",
				"Operator Panda",
				"RedMike",
				"Salt Typhoon",
				"UNC2286"
			],
			"source_name": "ETDA:Salt Typhoon",
			"tools": [
				"Agentemis",
				"Backdr-NQ",
				"Cobalt Strike",
				"CobaltStrike",
				"Crowdoor",
				"Cryptmerlin",
				"Deed RAT",
				"Demodex",
				"FamousSparrow",
				"FuxosDoor",
				"GHOSTSPIDER",
				"HemiGate",
				"MASOL RAT",
				"Mimikatz",
				"NBTscan",
				"NinjaCopy",
				"ProcDump",
				"PsExec",
				"PsList",
				"SnappyBee",
				"SparrowDoor",
				"TrillClient",
				"WinRAR",
				"Zingdoor",
				"certutil",
				"certutil.exe",
				"cobeacon",
				"nbtscan"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "c63ab035-f9f2-4723-959b-97a7b98b5942",
			"created_at": "2023-01-06T13:46:38.298354Z",
			"updated_at": "2026-04-10T02:00:02.917311Z",
			"deleted_at": null,
			"main_name": "APT27",
			"aliases": [
				"BRONZE UNION",
				"Circle Typhoon",
				"Linen Typhoon",
				"TEMP.Hippo",
				"Budworm",
				"Lucky Mouse",
				"G0027",
				"GreedyTaotie",
				"Red Phoenix",
				"Iron Tiger",
				"Iron Taurus",
				"Earth Smilodon",
				"TG-3390",
				"EMISSARY PANDA",
				"Group 35",
				"ZipToken"
			],
			"source_name": "MISPGALAXY:APT27",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "b399b5f1-42d3-4b53-8c73-d448fce6ab43",
			"created_at": "2025-08-07T02:03:24.68371Z",
			"updated_at": "2026-04-10T02:00:03.64323Z",
			"deleted_at": null,
			"main_name": "BRONZE UNION",
			"aliases": [
				"APT27 ",
				"Bowser",
				"Budworm ",
				"Circle Typhoon ",
				"Emissary Panda ",
				"Group35",
				"Iron Tiger ",
				"Linen Typhoon ",
				"Lucky Mouse ",
				"TG-3390 ",
				"Temp.Hippo "
			],
			"source_name": "Secureworks:BRONZE UNION",
			"tools": [
				"AbcShell",
				"China Chopper",
				"EAGERBEE",
				"Gh0st RAT",
				"OwaAuth",
				"PhantomNet",
				"PoisonIvy",
				"Sysupdate",
				"Wonknu",
				"Wrapikatz",
				"ZxShell",
				"reGeorg"
			],
			"source_id": "Secureworks",
			"reports": null
		}
	],
	"ts_created_at": 1775434676,
	"ts_updated_at": 1775792125,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/f9d1b22008472850fd75eec87978b3c000edfea1.pdf",
		"text": "https://archive.orkl.eu/f9d1b22008472850fd75eec87978b3c000edfea1.txt",
		"img": "https://archive.orkl.eu/f9d1b22008472850fd75eec87978b3c000edfea1.jpg"
	}
}