Solarmarker: The Old is New

The purpose of this blogpost is to document the PowerShell used by Solarmarker. The PowerShell was first observed between Feb 2022 until May 2022 and then resurfaced in September 2022.

The goal of this post is to publish information regarding the PowerShell to enable others to identify and understand what the PowerShell is doing.

Detecting these tactics is important to detect Solarmarker and detecting other malware.


From May 2022 – August 2022, the Solarmarker Developer moved away from using PowerShell scripts and from executing PowerShell using System.Automation.Management.dll to creating persistent with native .NET commands. The use of PowerShell was observed between Feb 2022 and May 2022. The PowerShell was also observed in a recent sample and as a result, it became worthwhile to publish about the PowerShell. The PowerShell during both periods is virtually the same helping us identify the malware easily and consistently identify the malware as Solarmarker.

Script Overview

PowerShell script content can be logged with PowerShell Scriptblock Logging, or it can be logged through EDR. In this instance, the detection logged 13 massive blocks of PowerShell. Most of the PowerShell script blocks consisted of a Base64 encoded payload. I’ve included the PowerShell below without the encoded payload.

The PowerShell script is normally one block, but we’ve broken it up for readability in the image below.

Image: PowerShell from the payload. .

First, let’s talk about the (many) red flags that suggest it’s malicious:

  • The functions and variables don’t have human readable names.

Sometimes, there’s a good reason to have short and simple PowerShell function or variable names, but in many cases, PowerShell should be easy to follow. This helps analysts understand what is happening and helps developers revise the PowerShell when needed. In this case, the long random names are suspicious.

  • The PowerShell uses “chunking.”

Chunking is breaking up words to avoid detection. For example, ‘\M’+’icr’+’oso’+’ft’+’\W’+’ind’+’ow’+’s\’+’St’+’art’+’ Me’+’nu’+’\Pr’+’ogr’+’ams\’+’St’+’art’+’up’. This chunking can prevent some detections from catching the full words. Chunking is abnormal for benign scripts and is an indicator the author is trying to avoid being detected.

  • The script uses “Reflection.Assembly” to load something into memory.

“Reflection.Assembly” has legitimate uses, but combined with the other red flags, this tells us the author is loading a DotNet binary into memory instead of writing it to disk. This prevents antivirus from finding the binary on disk, as the payload is only decrypted in memory.

  • The massive Base64 string is suspicious. 

Base64 encoding can have legitimate purposes. But, if it’s uncommon in an environment or if an administrator or developer is unfamiliar with the Base64 used, the PowerShell should be considered suspicious.

  • The use of AES encryption in a script (“AesCryptoService Provider”).

Using AES encryption is a reliable way for malware to avoid detection, and it’s uncommon and highly unusual to find it in legitimate PowerShell scripts.

  • The script uses “iex,” also known as “Invoke Expression.”

Invoke Expression is a common way for attackers to execute code. When reviewing PowerShell, it’s important to investigate what’s being executed. When “iex” is used, it should be considered suspicious.

Script Content

To make the PowerShell script more readable, we use “find and replace” to rename variables based on what we think each part is doing, given the surrounding context. Find and replace allows us to clarify where the same variables are reused. 

If you do this, be prepared to make guesses that you’ll likely revise later. In renaming the variables, we may also need to do some Googling to better understand functions and to help us give the variables better names. If you can’t read the image, don’t worry, parts will be copied below.

Image: PowerShell after variables have been renamed.

Now that we’ve cleaned up the PowerShell, we finally have an idea of what’s going on.

The PowerShell first sets up two functions: “create_random,” which is used for generating random numbers later, and “create_registry_key.” “Create_registry_key” takes two parameters: the path of the registry key to be created and the content the key will have.

function create_random {
    return -join (0..(10..30|Get-Random)|%{char+(97..122)|Get-Random)})        
function create_registry_key { param($registryKeyPath, $registryKeyContent);
    if (-Not (Test-Path "Registry::$registryKeyPath ".Trim())){
        New-Item -Path "Registry::$registryKeyPath ".Trim() -ItemType RegistryKey -Force;            
        Set-Item -Path "Registry::$registryKeyPath ".Trim() -Value $registryKeyContent;      

The PowerShell imports a Windows DLL (user32.dll) to access the Windows API “‘Win32ShowWindowAsync’.” Using this Windows API, the malware can make sure the PowerShell or current window stays hidden at execution.

$hiddenWindow="$showWindowAsync=Add-Type -MemberDefinition ('[DllImport("user32.dll")]public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);') -Name ('Win32ShowWindowAsync') -Namespace Win32Functions -PassThru; $showWindowAsync::ShowWindowAsync((Get-Process -Id $pid).MainWindowHandle, 0);";   
iex $hiddenWindow;      

The script then creates a few random names, and also creates a directory in the user’s temporary directory. This randomly named folder, with a randomly named file, with a random file extension, will be used later: for now, it’s saved as “$pathToWriteTo.”

New-Item -ItemType Directory -Force -Path $randomFolderInTemp;
$pathToWriteTo = $randomFolderInTemp+'\'+$randomFileName+'.'+$newFileExtension;

After this path is created, a shortcut, or “.lnk” file, is created in the user’s Startup folder. The shortcut is created using WScript, which will have a random name and point to our $pathToWriteToFile variable. This is a favorite directory for malware authors, as files in it are executed on startup.

$wscriptCommand=New-Object -comObject WScript.Shell;
$startupShortcut=$wscriptCommand.CreateShortcut($env:appdata+'\Microsoft\Windows\Start Menu\Programs\Startup\'+(create_random)+'.lnk');

The PowerShell then uses the “create_registry_key” function defined earlier. It creates “HKEY_CURRENT_USER\Software\Classes\”+$extensionClass+”\shell\open\command,” which holds “powershell -command $binaryDecodeAndExecute.”

The variable “$binaryDecodeAndExecute” uses AES to decrypt the “LARGE-BLOCK-OF-BASE64” after it’s decoded from base64. 

This variable also contains two cryptic lines:


These lines load this DotNet module into memory using “Reflection Assembly” and then execute it using a function exported by the module. The random strings are to avoid detection: previously, defenders would flag the binary’s name, but the author has now randomized it.

$binaryDecodeAndExecute = $hiddenWindow+ "$AC=New-Object System.Security.Cryptography.AesCryptoServiceProvider;
$AC.IV = $EB[0..15];$Decryptor=$AC.CreateDecryptor();
$UB=$Decryptor.TransformFinalBlock($EB, 16, $EB.Length-16);
create_registry_key -registryKeyPath ("HKEY_CURRENT_USER\Software\Classes\"+$extensionClass+"\shell\open\command") -registryKeyContent ('powershell -command "'+$binaryDecodeAndExecute+'"');
create_registry_key -registryKeyPath ("HKEY_CURRENT_USER\Software\Classes."+$newFileExtension) -registryKeyContent $extensionClass;
[IO.File]::WriteAllText($pathToWriteTo, ‘LARGE-BLOCK-OF-BASE64’);
iex $binaryDecodeAndExecute;

The first part of this block calls the necessary functions to decrypt the binary and all of the decrypting commands are saved in the registry.

The second “create_registry_key” function sets up a registry key that will call the other registry key that was just established. This establishes an execution chain every time the computer is rebooted. This is explained in the following screenshots from a sandboxed environment.

As described previously, a file (“ydCbwPDZwnuefc”) was created in the Startup folder. This shortcut executes a file with a really long name. The file names are created by the “create_random” function and they differ between infections.

Image: The file in the Startup directory for running the malware at each boot

This file is stored in the user’s local temp directory. The file with a really long name has a random extension: “PSDQD…” When this extension is used, it takes info stored in the randomly named “xqmsyf…” registry key.

Image: The file with a new file extension and the file extension in the Windows registry

The “xqmsyf…” registry key contains the PowerShell command the script set up earlier. This PowerShell is the decryption and execution process noted above.

Image: The registry key that contains the PowerShell to decode and execute the backdoor.

At the end of the script, the author also used “iex $binaryDecodeAndExecute” to execute the binary file and start the backdoor for its first run.


We’ve looked thoroughly at the PowerShell script used by Solarmarker in Feb 2022 – May 2022; and which was recently seen in September 2022. I hope this analysis helps you in identifying the malware in the past, present, and future.

2 thoughts on “Solarmarker: The Old is New

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: