#
TONESHELL and Protections Test 4
TONESHELL consists of a shellcode loader DLL (wsdapi.dll) and backdoor shellcode used by the Mustang Panda adversary.
The TONESHELL DLL will be executed via DLL sideloading/hijacking via EssosUpdate.exe, which is a renamed legitimate signed binary wsddebug_host.exe. All of the DLL's exports call the same malicious internal function, which executes the shellcode to perform backdoor functionality.1,4
The TONESHELL DLL, with embedded shellcode, is packaged in a .rar file called 250325_Pentos_Board_Minutes.rar, which also contains EssosUpdate.exe and a malicious LNK file Essos Competitiveness Brief.lnk. When run, the LNK file will execute EssosUpdate.exe via: %COMSPEC% /c .\EssosUpdate.exe. The .rar file is password protected with password: Pentos
The protections test 4 component is a dropper that drops a similar shellcode loader dll (gflagsui.dll) with similar embedded backdoor shellcode. The dropper will open a decoy PDF and execute the DLL via DLL sideloading, but this time by running the gflags.exe legitimate signed binary.3
The test 4 DLL exports the ShowGflagsUI function that gets called by the legitimate binary, resulting in the same malicious routine as the TONESHELL DLL, except the test 4 shellcode is what will ultimately get executed.
Note that to avoid loader lock, the malicious routines are not performed in DllMain, but rather in the exported DLL functions that the legitimate executables are known to call.
#
TONESHELL Main Features
This project builds a malicious DLL wsdapi.dll that will be executed via DLL sideloading/hijacking by the signed, legitimate wsddebug_host.exe binary, which is a Windows debugging tool and is renamed as EssosUpdate.exe.
wsdadpi.dll is built from scratch, exporting only the functions that EssosUpdate.exe imports from the real DLL:
WSDSetConfigurationOptionWSDXMLCreateContextWSDFreeLinkedMemoryWSDCreateDiscoveryPublisherWSDAttachLinkedMemoryWSDCreateDeviceHostWSDAllocateLinkedMemoryWSDCreateDeviceHostAdvancedWSDCreateHttpAddress
Calling any of these functions will trigger the malicious routine, which will execute the backdoor shellcode in memory.1 wsdadpi.dll is signed using a self-signed certificate using the following certificate subject: CN=Tully Enterprises, O=Tully Enterprises, L=Riverrun, S=Riverlands, C=Westeros.3
The DLL performs certain checks prior to executing its malicious routine.
- The first check consists of retrieving the current process name using the
GetModuleFileNameWAPI call and making sure it matches the expected process nameEssosUpdate.exe.4 This makes it harder to perform sandbox or dynamic analysis on the DLL, since the DLL will only continue if running from a process with a specific name. - The second check consists of checking for foreground window changes every second for up to a minute or until the window changes at least 2 times.4 If the entire minute passes without enough window changes, the DLL will terminate early without executing the malicious routine. This check deters sandbox analyses that do not emulate real user behavior by switching windows.
If all checks pass, the DLL triggers the malicious routine using a custom C++ exception and associated exception handler.1,4
The malicious routine will do the following:1,4
- Register the current malicious DLL using
regsvr32.exe, which will execute the DLL's exportedDllRegisterServerfunction.C:\Windows\System32\regsvr32.exe /s "PATH_TO_DLL"
- The
DllRegisterServerexport will create a victimwaitfor.exeprocess and inject the current DLL into it usingmavinject.exe.C:\Windows\System32\waitfor.exe Event183785251387C:\Windows\System32\mavinject.exe WAITFOR_PID /INJECTRUNNING "PATH_TO_DLL"
- Once
waitfor.exeloads the malicious DLL,DllMainwill create a thread to execute the shellcode in the victim process memory.DllMainchecks if it is running withinC:\Windows\System32\waitfor.exe
The shellcode is XOR-encrypted and stored in the .data section of the DLL at build time. The encryption is performed using a randomly-generated 32-byte key, which is then XOR-encrypted using a single-byte key 0x3F and compiled into the DLL with the encrypted shellcode.1,4
- The XOR encryption of the shellcode payload consists of three rounds with modifications made to the XOR key. The first round is standard XOR encryption using the original key, the second round rotates the key by one byte, and the third round rotates the key by 7 bytes.1
When executed, the shellcode will do the following:
- Generate a random 16-byte victim ID using the
CoCreateGuidAPI call.1 - Obtain the victim hostname using the
GetComputerNameAAPI call to send to the C2 server.1 - Establish a TCP-based C2 channel and send data via the
sendAPI fromWs2_32.dll1 - Routinely beacons out to the C2 server to request tasking. The following tasks are supported:
The main DLL also dynamically resolves certain Windows API calls to hide them from its import table. The shellcode dynamically resolves all of its API calls to maintain its position-independent nature. In both cases, API calls are resolved by traversing DLL exports and comparing them to the desired API name using the FNV1-A hash function. Any required libraries besides ntdll and kernel32 are imported at run-time using LoadLibraryW. 4
Key string literals are XOR-encrypted at compile-time and are decrypted at run-time to obfuscate them within the compiled binary.4
#
TONESHELL C2 Communications
All communications between TONESHELL and the C2 server will begin with the magic bytes 0x18 0x04 0x04 (the original malware used 0x17 0x03 0x03).1,4
Messages sent to the C2 server have the following structure:1,8
Messages received from the C2 server have the following structure:8
Each message sent to the C2 server has its non-header data (everything past the XOR key field) encrypted using a 256-byte XOR key that is randomly generated for each message1,4. The server response will encrypt its non-header data (everything past the size field) using the same XOR key, which the backdoor shellcode will use to decrypt the response.
The backdoor shellcode will first establish C2 communications by establishing a handshake with the C2 server. The handshake protocol is as follows:8
- The client sends a handshake message to the C2 server (message type
0x1), where the message-specific data consists of the following:- hostname length (4 bytes)
- current hostname
- The C2 server sends a handshake response (message type
0x08) with a 1-byte data payload.
After establishing the handshake, the shellcode will then send beacon messages (message type 0x02) to request tasking.
The server will respond with one of the following task codes:
0x3- file download. The shellcode will then send file chunk requests (type0x13) until the entire file is downloaded or until an error occurs.0x4- no tasking. The shellcode will simply sleep until the next beacon.0x5- execute process. The server will provide a timeout value in seconds and a command line to execute that contains an executable name and optional arguments.0x7- file upload. The shellcode will then send file upload chunks as task output until the entire file is uploaded or until an error occurs.0x9- task output acknowledgment. Server sends this to the implant whenever it receives task output from command execution or file uploads.0xA- reconnect handshake request. The server needs the implant to re-identify itself by re-sending a handshake to the server.0xFF- terminate self. The shellcode will exit after receiving this task.
While the shellcode performs its tasking, it may send the following task codes to the C2 server:
0x15- sends task output, such as output from process execution or a file upload chunk. The message contains output data no larger than 4096 bytes. Large output will result in multiple output messages. Expects a server response acknowledging the output chunk (type0x9)0x14- successful task completion. Will include an exit code if the task required process execution. If the task resulted in any output, this message is sent after all output has been successfully sent to the C2 server. Does not expect a server response.0x13- sends a file chunk request, specifying the associated task number, file offset in bytes, and the maximum chunk size that it can handle.0x3- task error. This message will contain an error code and is sent to the C2 server if the shellcode fails to perform its task. Does not expect a server response.
#
Protections Test 4 Main Features
The Test 4 dropper executable will do the following:3
- Attempt to create the
C:\ProgramData\GFlagEditordirectory. If it doesn't already exist, the dropper will decrypt and drop the embedded DLL and legitimate signed binary in the directory asgflagsui.dllandgflags.exe, respectively- Components are embedded and encrypted the same way as with the TONESHELL detections scenario components
- Open the decoy PDF located at
..\Appendix II\Assessing Westeros-Essos Global Influence (1).pdfrelative to the dropper executable - Create a scheduled task
GFlagEditorthat will executeC:\ProgramData\GFlagEditor\gflags.exeevery 3 minutesschtasks /F /create /TN GFlagEditor /SC minute /MO 3 /TR C:\ProgramData\GFlagEditor\gflags.exe
The gflagsui.dll DLL is effectively the same as the TONESHELL DLL, except for the following:
- Exports the
ShowGflagsUIfunction instead of thewsdapi.dll-specific functions - Performs a mutex check using the global mutex
Global\1247893689173278to avoid running more than one instance of the shellcode via scheduled tasks
The shellcode is effectively the same as the TONESHELL shellcode, except for the following:
- Encrypts C2 communications with RC4 instead of XOR4
- 256-byte key is randomly generated for each message
- The victim GUID is generated using the hostname and volume serial number4
Both the dropper and the DLL are signed using separate self-signed certificates with the following certificate subject: CN=Casterly Enterprises, O=Casterly Enterprises, L=Casterly Rock, S=Lannisport, C=Westeros.3
#
Usage
Since the public release of this repository does not include the vulnerable legitimate 3rd-party binaries, you will need to download them.
- For
EssosUpdate.exe, you will need to grab and renamewsddebug_host.exefrom a Windows machine that has Windows SDK or the Windows Driver Kit (WDK) installed.- The executable path will typically follow the format:
%PROGRAMFILES%\Windows Kits\10\bin\%VERSION%\x64\wsddebug_host.exe. The binary used in the 2025 evaluations came fromC:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\wsddebug_host.exewith a SHA256 hash of3DC7F38CB68FA316205BEC35AFEF875DC0A748030D4005A491BB6FE350E6F8B2 - Save the executable as
Resources/toneshell/EssosUpdate.exeprior to building.
- The executable path will typically follow the format:
- For
gflags.exe, you will need to grab the executable from a Windows machine with Debugging Tools for Windows 10 (WinDbg) installed. These should already be available if the Windows SDK or WDK are already installed.- The executable path will typically follow the format:
%PROGRAMFILES%\Windows Kits\10\Debuggers\%VERSION%\gflags.exe. The binary used in the 2025 evaluations came fromC:\Program Files (x86)\Windows Kits\10\Debuggers\x64\gflags.exewith a SHA256 hash of8A5DD351E4A1FB5CCE2816D17FA7130240938735B5AB5F0C7C67996D687557DA. - Save the executable as
Resources/toneshell/gflags.exeprior to building.
- The executable path will typically follow the format:
To execute TONESHELL, run EssosUpdate.exe with wsdadpi.dll in the same directory.
To execute Protections test 4, run the dropper executable.
- For best results, ensure the decoy PDF is staged at
..\Appendix II\Assessing Westeros-Essos Global Influence (1).pdfrelative to the dropper executable
#
Troubleshooting
Both the DLL and shellcode components will log to hidden files on disk.
Log messages are encrypted by default using AES-256-CTR and then base64-encoded.
The encryption key used is: c47001f8de67d8fe23b76d7685fe75fbb0abec9b3bb23f4cf99d7f3ece345c18, and a randomly generated 16-byte IV is prepended to each ciphertext prior to base64 encoding.
To decrypt the logs, use the log decryptor Python utility:
python3 aes_base64_log_decryptor.py -i /path/to/log -o /path/to/output --aes-256-ctr -k c47001f8de67d8fe23b76d7685fe75fbb0abec9b3bb23f4cf99d7f3ece345c18
#
TONESHELL
The shellcode component logs to C:\Windows\System32\wsdapi_dat.log, while the DLL component logs to different log files depending on which part of the DLL component is running:
C:\Windows\System32\wsdapih.log: log file for the main handler routine up until the DLL is registered viaregsvr32C:\Windows\System32\wsdapireg.log: log file for when the DLL is run byregsvr32to inject intowaitfor.exeusingmavinject.C:\Windows\System32\wsdapisr.log: log file for when the DLL is injected into the victimwaitfor.exeprocess and runs the shellcode payload.
#
Protections Test 4
The dropper logs to C:\Windows\System32\t4.log.
The shellcode component logs to C:\Windows\System32\gflagsui_dat.log, while the DLL component logs to different log files depending on which part of the DLL component is running:
C:\Windows\System32\gflagsh.log: log file for the main handler routine up until the DLL is registered viaregsvr32C:\Windows\System32\gflagsreg.log: log file for when the DLL is run byregsvr32to inject intowaitfor.exeusingmavinject.C:\Windows\System32\gflagssr.log: log file for when the DLL is injected into the victimwaitfor.exeprocess and runs the shellcode payload.
#
Build
All components can be built in Debug or Release mode using the included CMakePreset.json configurations.
The following PowerShell command was used to build the LNK file:
$WshShell = New-Object -COMObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut("C:\path_to_mustang_panda_repository\Resources\toneshell\src\wsdapi\Essos Competitiveness Brief.lnk")
$Shortcut.TargetPath = "%COMSPEC%"
$Shortcut.Arguments = "/c .\EssosUpdate.exe"
$Shortcut.IconLocation = "C:\Windows\System32\shell32.dll,70"
$Shortcut.Save()
#
Dependencies
CMakeversion3.26CMakePresets.jsonversion6support (Visual Studio 17.7)
#
Third-Party Libraries
The project leverages the following third party libraries/projects:
These projects are pulled down and built automatically as part of the build process.
#
Quickstart
#
Command Line
Build both Debug and Release configurations of the component.
cd Resources\toneshell
cmake.exe --workflow --preset cicd-debug
cmake.exe --workflow --preset cicd-release
For simplicity, all of the generated artifacts can be bundled into the
top-level install/ directory using the CMake installation facility.
cmake.exe --install ./build --config release
cmake.exe --install ./build --config debug
#
Developer Notes
The following table describes the project files and their purposes:
#
CTI
- https://www.trendmicro.com/en_us/research/25/b/earth-preta-mixes-legitimate-and-malicious-components-to-sidestep-detection.html
- https://unit42.paloaltonetworks.com/stately-taurus-abuses-vscode-southeast-asian-espionage/
- https://hunt.io/blog/toneshell-backdoor-used-to-target-attendees-of-the-iiss-defence-summit
- https://www.trendmicro.com/en_us/research/22/k/earth-preta-spear-phishing-governments-worldwide.html
- https://unit42.paloaltonetworks.com/stately-taurus-attacks-se-asian-government/
- https://www.trendmicro.com/en_us/research/23/c/earth-preta-updated-stealthy-strategies.html
- 2022-overwatch-q3-report.pdf
- https://www.trendmicro.com/en_us/research/23/f/behind-the-scenes-unveiling-the-hidden-workings-of-earth-preta.html