Poweliks – Command Line Confusion

Recently, hFireF0X provided a detailed walkthrough on the reverse engineering forum kernelmode.info about Win32/Poweliks malware. The particularity of this malware is that it resides in the Windows registry and uses rundll32.exe to execute JavaScript code.

I found it funny that we can execute some JavaScript through Rundll32 and obviously I was not the only one.

Capture d’écran 2014-08-20 à 15.57.26

When we first saw the command line executing JavaScript, we were wondering how it worked.

In this blog post, we analyze how and why JavaScript is executed when calling this simple command line:

rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";alert(‘foo’);

Reminder about Rundll32

Rundll32 usage is documented on MSDN; it is used to call an exported function of a DLL file which can be achieved with the following command line:

RUNDLL32.EXE <dllname>,<entrypoint> <optional arguments>

entrypoint is the exported function; its prototype must be:

void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);

The lpszCmdLine parameter is given the <optional arguments> value specified on the rundll32 command line.

We will try to figure out how Rundll32 is able to call the function RunHTMLApplication exported by the library mshtml.dll and how the “javascript:” prefix is used to execute actual JavaScript code.

Analysis of Rundll32


One of the first things done by Rundll32 is to parse the command line in the internal function ParseCommand. This function searches for a comma (‘,’, 0x2C) to locate the DLL name and for a space (‘ ‘, 0x20) to locate the entrypoint name.

Capture d’écran 2014-08-20 à 16.00.23

When using our sample command line, ParseCommand returns javascript:"\..\mshtml as the DLL name and RunHTMLApplication as the entrypoint. In this context, the space after RunHTMLApplication delimits the ‘optional arguments’ part of the rundll32 command line:

Capture d’écran 2014-08-20 à 16.01.37

Dll loader

Rundll32 will perform several tries to load the actual DLL from the initial specification javascript:"\..\mshtml.

The first test uses the function GetFileAttributes(“javascript:”\..\mshtml”). This function eventually accesses C:\Windows\system32\mshtml. As this file is not found, the function returns -1.

Capture d’écran 2014-08-20 à 16.04.07

SearchPath is then invoked to resolve the DLL name. This function reads the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode. The Microsoft definition of this key is:

When the value of this REG_DWORD registry value is set to 1, SearchPath first searches the folders that are specified in the system path, and then searches the current working folder. When the value of this registry value is set to 0, the computer first searches the current working folder, and then searches the folders that are specified in the system path. The system default value for this registry key is 0.

By default this registry key doesn’t exist (on Windows XP / 7 / 8) so SearchPath tries to load the file mshtml in the current directory of rundll32 (c:\windows\system32) prior to trying locating it in the system path.

Capture d’écran 2014-08-20 à 16.05.45

All these attempts fail and rundll32 moves to the next step. GetFileAttributes is called again searching for the manifest for the module: javascript:”\..\mshtml.manifest

Capture d’écran 2014-08-20 à 16.07.09 Since all the previous steps failed, Rundll32 eventually calls LoadLibrary("javascript:"\..\mshtml").

LoadLibrary is just a thin wrapper around LdrLoadDll located in ntdll.dll. Internally, LdrLoadDll adds the default extension .dll and parses the resulting string javascript:”\..\mshtml.dll as a path. The token .. instructs to go one folder up: it resolves to mshtml.dll (think of foo\..\mshtml.dll resolved as mshtml.dll).

With mshtml.dll specification, LdrLoadDll is able to load the library in the system directory.

Capture d’écran 2014-08-20 à 16.09.02 Rundll32 then calls GetProcAddress with the previously extracted entry point name RunHTMLApplication.

For the moment, the javascript: prefix seems pretty useless: LoadLibrary("foobar:\"\..\mshtml") works fine. So, why prefixing with javascript:?

Protocols Handler

Once the entry point address has been resolved, Rundll32 calls the function mshtml.dll!RunHTMLApplication.

Even if not documented, the actual RunHTMLApplication can be inferred from the call made by c:\windows\system32\mshta.exe (the application dedicated to launch an .hta file):

HRESULT RunHTMLApplication(
LPSTR szCmdLine,
int nCmdShow

This is not far from the function prototype expected for a rundll32 entry point:

void CALLBACK EntryPoint(
HWND hwnd,
LPSTR lpszCmdLine,
int nCmdShow

RunHTMLApplication receives a handle to a window instead of a handle to a module as the first parameter. This parameter is used when mshml registers for a window class and creates a window of this new class. Passing a value not corresponding to an actual instance doesn’t seem to disturb user32 very much…

The second parameter is not used at all, so the mismatch is not important.

The last parameter, nCmdShow, is used by the RunHTMLApplication function to display the window hosting the HTML application. Rundll32 always calls the entry point function with the value SW_SHOWDEFAULT to instruct any potential opened window to use window default placement.

The main parameter of interest would be lpszCmdLine (";alert('foo')) in our case.

Capture d’écran 2014-08-20 à 16.16.36

This obviously leads to an issue since this is not a valid JavaScript statement (please note the missing double-quote at the end of the statement). But it works anyway, because RunHTMLApplication ignores the given parameter and prefers to request again the original command line from the GetCommandLine Windows API (wrapped in a call to the GetCmdLine function).

Capture d’écran 2014-08-20 à 16.20.09

The full command line contains the name of the executable and the parameters: GetCmdLine extracts the parameters by cleaning up the executable specification:

Capture d’écran 2014-08-20 à 16.23.29

After that, RunHTMLApplication calls CreateUrlMoniker:

Capture d’écran 2014-08-20 à 16.25.04

This is where the string « javascript: » is essential.

CreateUrlMoniker parses the command line to extract the string before the char “:” (0x3A): “javascript”.
Capture d’écran 2014-08-20 à 16.28.27

CreateUrlMoniker crawls the registry key HKCR\SOFTWARE\Classes\PROTOCOLS\Handler\. These keys refer to a set of protocols and their CLSID.

CreateUrlMoniker finds an appropriate protocol handler for the JavaScript protocol (HKCR\SOFTWARE\Classes\PROTOCOLS\Handler\javascript):

Capture d’écran 2014-08-20 à 16.29.55

The CLSID {3050F3B2-98B5-11CF-BB82-00AA00BDCE0B} matches « Microsoft HTML Javascript Pluggable Protocol ».

Capture d’écran 2014-08-20 à 16.31.51

It is for this reason that the string “javascript” is essential in the beginning of the parameters.

The same mechanism comes into play when one types javascript:alert(‘foo’); in the Internet Explorer navigation bar:

Capture d’écran 2014-08-20 à 16.34.18

The remaining of the string located after the ‘:’ separator is interpreted by the JavaScript URL moniker as JavaScript instructions:

"\..\mshtml,RunHTMLApplication ";alert(‘foo’);

This is a valid JavaScript with a string "\..\mshtml,RunHTMLApplication " (hence the double-quotes skipped in all the previous steps!) and a function (alert).

Finally RunHTMLApplication calls CHTMLApp::Run and the JavaScript is executed:

Capture d’écran 2014-08-20 à 16.35.36

Security point

From a security point of view, executing JavaScript through Rundll32 is like executing an HTML Application.

In other words, we can have all the power of Internet Explorer—its object model, performance, rendering power and protocol support—without enforcing the strict security model and user interface of the browser. Zone security is off, and cross-domain script access is allowed, we have read/write access to the files and system registry on the client machine.

With this trick, JavaScript is executed outside the Internet Explorer process and script is not subject to security concept like Protected Mode / Sandbox on Vista and superior.


RunHTMLApplication has the perfect prototype to work with Rundll32. Attackers have made great efforts to build a command line using the perfect syntax for passing through all the mechanisms (library loading, command line parsing, URL syntax correctness, valid JavaScript, etc.) leading to JavaScript execution in an uncontrolled environment.

From our understanding, this technique allows bypassing some security products that may trust actions performed by the built-in rundll32 while specifying the script to run without writing any file on the file system.

That’s all folks!


Atrax is a malware discovered during the summer of 2013. It includes some basic features like distributed denial-of-service, keylogging, the ability to steal banking credentials, to send spam or to install a Bitcoin miner for crafting bitcoin money. The particularity of Atrax is that it communicates with command and control server over TOR, which is a protocol that enables online anonymity. An ESET blog post has been made to give more information about this tor based botnet: http://www.welivesecurity.com/2013/07/24/the-rise-of-tor-based-botnets/.

Atrax’s specification highlight us about anti-analyzer technics:

- Anti-Analyzer (Protection against e.g. anubis.iseclab.org, malwr.com)
- If you need: Anti-VM (Please request it explicitly)
- Anti-Debug/Anti-Hook Engine

The sample we studied was seen in the wild in April 2014 and submitted to the VirusTotal web site (https://www.virustotal.com/en/file/adf246a57baecef5c8c85c60152e9b2f5060bf2e720ad1623cc95177e7259401/analysis/).

We choose to analyze the Atrax botnet in the process of our permanent security monitoring, in order to be sure that our best of breed HIPS engine is able to block new technics used by hackers. This article is not a full analysis of the malware, it chooses to focus on the capabilities to do not be detected or analyzed.

Sandbox detection

We started by looking at the anti-sandbox capability. To obtain a fast dynamic analysis of a potential malware, many online services provide sandbox capabilities to give you a deeper look of what the application is doing on the operating system: the principle is to start the malware execution in a virtual machine to trace its behavior. At the end of the timeout the service provides a report and sets the virtual machine to its initial state for the next analysis. In this way, we can quickly know if a binary file is malicious or not. Malwares now try to detect this kind of sandbox to be sure that people couldn’t analyze the behavior of the malware or that security solution couldn’t block it proactively.

To test the protection mechanism of Atrax, the sample was submitted to multiple online sandboxes:

  • Anubis http://anubis.iseclab.org/: when executing, the binary file crashes (STATUS_ACCESS_VIOLATION) preventing behavioral analysis. It is a normal behavior of Atrax when it detects online sandbox. The virtual machine was not infected.
  • Malwr http://malwr.com: the binary file runs normally, the virtual machine was infected.
  • JoeBox (CWSandbox / File-analyzer) http://file-analyzer.net/: The binary file runs normally, the virtual machine was infected.
  • Comodo http://camas.comodo.com: the binary file runs normally, the virtual machine was infected.

Except Anubis, it becomes clear that the detection of sandbox is not fully functional. This dysfunction is due to the method used for environment fingerprinting. Atrax simply looks for the ProductId of the operating system.

ProductId is a unique value of 20 digits which is derived from the product key and the hardware configuration. This key is just displayed to user for information. It can be used when you contact the Microsoft Support. This key is stored in the registry key located here: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductId. You can display it by right-clicking My Computer and selecting Properties:

Capture d’écran 2014-08-20 à 14.37.28


Because it is unique, this key enables identifying the computer. However it is possible to alter this key without having any instability.

Atrax has an hardcoded list of ProductId keys:

-   1: 76487-640-1457236-23837
-   2: 76487-644-3177037-23510
-   3: 55274-640-2673064-23950
-   4: 76497-640-6308873-23835
-   5: 76487-640-1464517-23259

If it finds one these values, its means that the actual environment is an online sandbox and Atrax process exits with an access violation.

Capture d’écran 2014-08-20 à 14.39.33


In order to check the correspondence of these values, we developed a test program that display the ProductId value of the sandboxes available on Internet.

Some sandboxes report screenshots of the virtual machine, so it is easy to check the ProductId with a MessageBox. For sandboxes which do not report screenshot, the binary file creates a text file with the ProductId as filename.

long lResult =
RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"Software\\Microsoft\\Windows NT\\CurrentVersion",0,KEY_QUERY_VALUE,&hkey );
if(ERROR_SUCCESS == lResult)
DWORD keytype;
TCHAR data[200];
DWORD bread=200;
lResult =

if(ERROR_SUCCESS == lResult)
// Key found
found = _tfopen(data, TEXT("w"));

With this trick, we have determined that the first key (76487-640-1457236-23837) is the ProductId of Anubis sandbox. This is why the execution inside this sandbox turns into STATUS_ACCESS_VIOLATION.

The second and third keys do not work due to updated sandboxes. These keys are some kind of signature that matches CWSandbox and JoeBox.

76487-644-3177037-23510: matches CWSandbox.

55274-640-2673064-23950: matches JoeBox.

CWSandbox and JoeBox now appear to be a single product: JoeSecurity is accessed through the URL http://file-analyzer.net/. JoeSecurity now automatically generates a new key for each run, making the two previously known keys obsolete. But strangely they are a recognizable pattern easy to detect. For example:

Windows XP:

Windows 7:

Funny fact, during our tests we have to submit several times our fingerprint executable to be sure that the ProductId is unique at each run. This apparently did not please JoeSecurity and our IP address was simply banned from the server.

The last two keys 76497-640-6308873-23835 and 76487-640-1464517-23259 are less common and seem to be related to old instances of Malwr sandbox. Today Malwr generates a unique key for each run with no identifiable pattern:


In addition, although it is not implemented into Atrax, it is possible to detect if an executable file has been uploaded to VirusTotal; the sandbox associated to the “Behavioral information” section has always the same ProductId: 76487-341-0620571-22546.

As we can see, this technique is not really efficient for multiple reasons. First, because it is easy to implement a mechanism to auto generate a ProductId for each run. We tried to edit the ProductId of Windows 7 and Windows Update was fully functional. Moreover, looking at this registry key can be detected as a malicious behavior. It is not common for an executable file to look for the ProductId of the operating system.

Security products detection

Atrax also checksif security productshaveinjectedcode in therunning process of the malware.

To do this check, it uses a well-documented technics:

  • It finds PEB (Process Environment Block address) (instruction mov eax, fs :0x30)
  • It looks for Ldr (LoaderData) in PEB (instruction mov ecx, [eax+0x0C])
  • It finds the InLoadOrderLinks list which contain all the module loaded by the running process (instruction mov edi, [ecx+0x0C])
  • It browses InLoadOrderLinks and compares it to some values.

Capture d’écran 2014-08-20 à 14.54.36


For more information about this method: http://phrack.org/issues/65/10.html,

Atrax looks for the following loaded binary files to detect if a security product monitors the current application:

This technique is limited to a few security products but does not prevent detection by antivirus.

Anti Debug

Atrax uses 3 different technics to check the presence of a debugger.


The first way to do it involves using the ZwSetInformationThread function.

IN HANDLE ThreadHandle,
IN THREADINFOCLASS ThreadInformationClass,
IN PVOID ThreadInformation,
IN ULONG ThreadInformationLength

When ThreadInformationClass is set to 0x11 (ThreadHideFromDebugger), any debugger becomes blind to actions performed by this thread.

Capture d’écran 2014-08-20 à 15.00.56



The second way to bypass debug involves using ZwQueryInformationProcess in order to find a debugger.

TSTATUS WINAPI ZwQueryInformationProcess(
_In_       HANDLE ProcessHandle,
_In_       PROCESSINFOCLASS ProcessInformationClass,
_Out_     PVOID ProcessInformation,
_In_       ULONG ProcessInformationLength,
_Out_opt_ PULONG ReturnLength


When ProcessInformationClass is set to 0x7 (ProcessDebugPort), ProcessInformation is set to -1 when the process is being debugged.

Capture d’écran 2014-08-20 à 15.03.33



Finally, Atrax uses the classical IsDebuggerPresent function call which looks for the BeingDebugged flag inside the PEB. If BeingDebugged equals 1, the process is debugged.


Malware’s specifications refer to VM detection. This functionality seems not to be included into the sample that has been studied but we can find some significant strings inside the binary file:

  • VMWare
  • VBOX
  • DiskVirtual_HD

It looks like some codes about VM detection is present but after static analysis we saw that this part of code is never called.


In this post we have seen that an effort was made to detect security products but the detection of analysis environment are not really well implemented. One year after malware launch, it’s fully detected by the sandboxes and the tricks used here are not efficient.Yet there are a huge number of tricks documented on the Internet for anti-debug, anti-VM and anti-analysis. Atrax uses only the most basics tests.

For further information, please see: