Betabot in the Rearview Mirror

Posted on

AKA Alpha reverse engineer vs Betabot

Betabot is a malware that by now should be familiar to most, if only in name. Initially developed in 2013, the last version, 1.8.0.11, was released around 2015-2016 and a crack was made around September 2016 which eventually became public. Rumors of a 1.9 version were heard of, however no binaries were ever seen that corroborated this, so it is safe to say that development has ceased completely since then. Despite this lack of updates, Betabot is still widely used – a recent Kaspersky report suggests that it accounts for 3.5% of their banking malware detections in 2020, up from 2019’s 2.4%. Comprehensive deep dives into the malware is lacking – the closest thing to this is the excellent 2013 analysis by Zhongchun Huo – and as such this series will aim to provide such a comprehensive overview covering everything notable that is in the binary.

In this post, we’ll be analyzing a cracked 1.8.0.11 binary, which is also known as “Neurevt” due to the string being present in the binary. What is great about this crack is that unlike a lot of cracks where integrity checks and anti-RE code are either entirely removed or circumvented by patching deeper inside the binary, the reverse engineer has kept them entirely intact and generated the correct checksums instead, meaning that the binary we get from the crack is effectively identical to what the original malware author would’ve given us. There are at least 10 different integrity checks for the config spread throughout the binary – if any of these fails, the bot will not function properly. In addition, this is the main crack that is floating around, so virtually all Betabot binaries that are observed in the wild will be identical to this (with the exception of configuration values changing of course). Another implication of analyzing this binary is that the specific protocol version (Betabot has had several incremental protocol updates throughout its history) is version 1.8.0.6 for the response, and 1.8.0.5 for the bot request. This should not matter much at the end of the day however – as there are no other relevant copies of Betabot available.

We will start out with the general methodology of reverse engineering Betabot and the basic building blocks of the malware, and then start looking at the most important parts of Betabot.

The first layer

We first start with the initial Betabot binary, which is a loader of sorts. The first layer is a fairly typical packer. It sets an exception handler to relaunch itself upon a crash, and also detects debuggers through the PEB.

The packer then xors an encrypted buffer and decompresses it using aplib, before finally mapping and executing it. The mapping is a bit special as the PE header at the beginning of the buffer is fake, while the real PE header is semi-custom and encrypted.

The inner payload

In order to analyze this payload, I simply dumped it directly from memory at the OEP to avoid dealing with the PE header issues and then used fasm to generate a PE file that would allow me to analyze the dump in IDA. The simple FASM template is included in the appendix. From this point on, all analysis is done statically using IDA Pro.

Entrypoint(s) and import handling

The payload has 3 entrypoints, a primary one and two others that are executed by the injector for other functionalities (I believe it is for the botscript loader and the ring3 kit, which is discussed in the later section). All entrypoints call the same common-entrypoint function, however they differ in that they store their own address to a variable that is used to determine which entrypoint was called, in addition to setting two other flags to indicate to other functions which entrypoint was used.

One of the things the common entrypoint does is initializing the imports, which are stored in a global structure. This structure is initialized from a table of hashes (which I named ImportHashTable) which takes the following form.

Hash, apiNameLen and indexDll should be fairly self-evident, however ptrStore is a very strange entry – it points to members in another structure (which I named ImportTableRegular) that receives the final pointer. This structure is simply a bunch of pointers to imported APIs.

DLLs are loaded from a similar struct which is stored in an array – and then APIs are loaded from a custom hash which combines the DLL name and API name together.

The most interesting part is in how Betabot does not just load the pointers for some APIs – it also creates a table of thunks for them. The first thunk for LdrGetProcedureAddress is a simple push-ret stub and is not stored in the global thunk region. For all other thunked functions, the thunk is placed in the global thunk region and has a small structure appended marked with the magic value (0xF820AB06) containing the original pointer. The thunk itself depends on the kind of function – if the function is a service function (for example a syscall stub, or a thunk itself), it is copied in its entirety to the new thunk region. If the function appears hooked, a special thunk stub is used instead.

Service functions are directly copied
Thunking of hooked functions
Code for retrieving the original pointer of a thunked function pointer

Code for automatic handling of the imports will be attached in the appendix after it is cleaned up.

After initializing the import table, Betabot creates the registry key “HKCU\\Software\\AppDataLow\\Software\\MyMailClient”, which is used to track the crash count (more on this later).

Thread manager

Betabot has a slot-based system for managing its threads. This thread tracker supports tracking either 256 or 45 threads depending on whether the current process is Betabot’s main process or not.

As we can see, there are either 45 or 256 slots available in the thread tracker. The first 31 (starting from slot 0) are reserved for special usage, slot 31 and 32 are markers indicating that the thread is a “free” thread without a hardcoded index, and will be dynamically allocated a space starting from slot 34.

When Betabot creates a new thread, it fakes the thread starting address as either being in Kernel32 or being in Ntdll. It chooses the address as follows.

To fake the thread start address, it creates the thread suspended at the address, and then change the Eax register to a custom stub which will receive the threadInfo structure and do the final processing to call the desired function. This works because the thread is still in BaseThreadInitThunk and hasn’t called the target function yet – it will do so by reading Eax which contains the new thread’s function.

The new stub it is set to a function I called EaxProc, which first hides itself from debuggers by using NtSetInformationThread, and then finally register itself in the thread tracker structure.

Back to the creator thread, it waits for it for 2 seconds and then sets the appropriate ACL if requested and then returns.

Registry manager

Betabot has a two-level registry structure that uses a pseudorandom algorithm to generate registry names from seed values. A value is referred to by two strings, its group and subidentifier. Known groups are CS1 and CG1. The registry path is identified as follow (where str1 is the group ID):

The registry value name is generated from the subidentifier as follow:

The appendix contains information on known subidentifiers and their meanings.

Anti-analysis

Betabot employs several methods for the detection of virtual machines, sandboxes and debuggers. Detection of sandboxes and debuggers result in the bot artificially crashing/exiting, whereas VM detections are stored in some variables and do not result in a crash – however it will result in behaviors being modified in some specific code paths.

Several antidebug tricks are also littered throughout regular functions – for example the following detection and crash appears in the middle of the initialization of the Dynamic Context structure.

VM detection is done as follows.

There also appears to be a bug in the isVirtualMachine routine – the result of isInVM is discarded. Regardless, if a VM is detected, it sets 2 variables and the bot attribute flag for VMs.

In addition to this, Betabot also detects the presence of Ollydbg, Regmon, ImmunityDbg, Rohitab’s API Monitor, Procmon, IDA Pro. It also checks whether the disk contains the string VMWare or VBox.

It also tries to see whether its parent process is suspicious, and logs the information found inside the dynamicCTX and registry.

AV handling

Betabot detects AVs and modifies its behaviors based on what AV is installed. In addition to this, it also is capable of attempting to kill AV solutions. To detect AVs, Betabot has several signature packs with the format below, which are used to search in various places such as services, Run key entries, and SOFTWARE registry keys.

Betabot is also capable of terminating AVs. The orchestrators’ logic is quite simple and repetitive.

To see how it attacks an AV solution, let’s look at ESET.

Here, we see that it tries to block the AV executables from launching using the IFEO key. It does not do so from its own context, instead it spawns a new process and injects into it to perform the registry operation from there. Some AVs do have a custom process that gets spawned and injected to (this is specifiable in the regWriteInjectedCall) but by default it is regedit.

If the attempt to set the IFEO key fails, Betabot attempts to prevent the executable from launching by creating a manifest/config file for it that contains invalid content. How it does this is most interesting: it creates a pagefile there, which would get filled with random (and thus invalid) data.

This method originated probably from KernelMode.info in 2012. Interestingly enough – I don’t think this idea has gained much prominence since then, as this is the first that I’ve seen it in practice or mentioned anywhere at all.

LPE and UAC bypass

Betabot employs 2 CVEs as well as several other tricks to gain administrator privilege. The first thing we will be discussing are the LPEs. Currently, there are only 2 LPEs available, however the exploit orchestrator is designed in a module-based fashion so that more LPEs can be added with little code change.

As we can see, Betabot checks for the presence of the KB that patches the exploit and the OS version checked prior to exploitation. The two exploited vulnerabilities are CVE-2015-1701 (KB3045171) and CVE-2015-0003 (KB3013455), and both are only exploited on 32-bit machines. The first is exploited on Windows 7 and Vista whereas the second is exploited only on Windows 7. The KB check is done as follows.

For both exploits, Betabot retrieves the base address of Ntoskrnl by using NtQuerySystemInformation with SystemModuleInformation.

The goal for both are to eventually be able to replace the current process’s token with a token from either explorer.exe or printui.exe (which would be launched as admin using ShellExecute with runas), however in practice the code path for using printui is never reached so the token is always stolen from explorer.

Both exploits are public, ancient and well documented so I will not go into details about how they each function here. However, an interesting little detail that I discovered while reversing this exploit is that back in Windows 7, one is able to allocate memory at the address 0, which is then used to exploit the null pointer dereference vulnerability in CVE-2015-0003. This is done by passing a value between 1 and 0x1000 (page size) as the base address to NtAllocateVirtualMemory.

For gaining administrator privileges, Betabot also has some other tricks, some interesting and some less so. The first simply tries to force the user to accept the administrator prompt by spamming it while faking the executed file as cmd.exe with some custom texts.

I wish I could fix my issues so easily

The second abuses the ISecurityEditor interface to overwrite eudcedit.exe’s Image File Execution Options with the path to the current module. The ISecurityEditor interface did not have proper security checks, allowing an unprivileged user to modify the ACL of an object that they should not have access to. This was fixed on Windows 10 build 10147.

If this operation is successful, Betabot will attempt to launch eudcedit.exe, the debugger for which is now hijacked to be the Betabot payload.

USB Spreader

The USB spreader runs as a Betabot managed thread if the feature is enabled in the C2. It uses RegisterDeviceNotificationA to register a notification whenever a new drive is inserted.

Upon receiving a window callback, Betabot ensures that the message is one for a new volume being inserted, and ensures that it can get the drive letter for the drive.

Then, it checks whether the drive was already infected or not. This is done by checking for the presence of a file called usb20.sys which Betabot will create as Hidden + Read-Only after the infection process has completed.

After this, the betabot binary is copied to Drive:\\pp.exe, and files on the drive are replaced with malicious .lnk files that launch betabot along with the original files.

If a file has been successfully replaced, the usb20.sys marker file is created.

Later on, if this shortcut is executed, Betabot is able to tell that it was spreaded like this by checking whether its drive is removable.

Persistence

Betabot has persistence for both its file and process. Process protection is achieved via a Ring3 userkit that filters process access, as well as a watchdog that monitors both the file and process.

Crash handling

Early in the execution flow, Betabot registers an exception handler. Interestingly enough, this is used not for anti-debugging purposes but quite the opposite – it is used to help the developer debug issues and to increase stability.

If the exception handler is ever called, it first logs this in the registry in the CD1\ECC values.

Then, it writes the crash count to the MyMailClient registry key, or increments it if it already exists.

Finally, if there is less than 24 crashes logged, it’ll relaunch itself with the /exc parameter corresponding to the number of retries, and then terminates itself.

Hooking engine

Betabot features an impressive ring-3 system wide hooking mechanism for persistence. As described by Zhongchun Huo, it utilizes TLS slots to detect its own threads where hooking behavior should not be applied. There are several “classes” of hooks, which I will detail below.

The first class of hooks is defensive hooks, meant to prevent access to files/registry keys that are deemed protected by Betabot. Generally speaking, they take the following form:

The second class of hooks are hooks designed to sniff information for the stealer. The first example of this are the hooks placed inside Putty’s process.

Hooks being applied
Data being saved temporally
Data finally being queued for sending via IPC to main process in savePuttyLog for sending to the C2 server

There are also hooks for NtDeviceIoControl, PR_Write, EncryptMessage and SSL_Write.

The hook for NtDeviceIoControl is extremely fascinating, it is designed to intercept operations to the AFD device to filter unencrypted traffic directly. Major filtered operations are AFD_CONNECT where the hostname is checked against Betabots’ internal blacklist, and AFD_SEND where the buffer is scanned and sniffed for passwords. This is also where the mysterious strings “neurevt” comes into play 😉

As we can see, it searches each packet inside the AFD_SEND request for usernames and passwords to log, but then curiously also performs another operation where it checks whether the string “windowsupdate” or “neurevt” is inside the buffer. If so, it forces the connection to be disconnected. Unfortunately however, we do not know where the string came from. Searches of intelligence feeds yielded no results, and there is no indicator as to whether this is a competing malware variant or something else entirely. No mentions of neurevt can be found that is not from an analysis where the malware is referred to by the alias. If anyone from back then knew what this string is, please DM me on twitter, I would love to hear the behind-the-scenes of this.

The hook for SSL_Write and EncryptMessage is fairly simple, both call the searchForPasswordAndUsername routine to find usernames and passwords in ports for protocols like FTP, SMTP, SMTPS, etc.

Likewise, PR_Write just tries to parse the HTTP data for credentials.

Lastly in this group, there are hooks for Chrome. Here there are two variants of hooks – one intercepting SSL_Write (which is located via scanning for the VMT), and the other intercepting IPC via hooking NtReadFile. The SSL_Write hook is similar in practice to the hook for Firefox.

The other hook for NtReadFile tries to find interesting strings inside the IPC buffer (namely POST/post and HTTP/http), and tries to extract usernames and passwords out of the buffer if this is found.

The final notable detail of Betabot’s hooking subsystem is its blocking of MBR bootkit installation via hooking NtOpenFile – file operations on the physical drive without going through the filesystem are prohibited.

Termination of older versions of the bot

Betabot finds and kills threads belonging to older versions of itself by checking the TLS slots belonging to threads inside its own process.

Communication cycle and protocol

Betabot’s protocol is binary-over-HTTP. RC4 is used for encryption. First, the URL is generated from the config, and then a random parameter is appended.

Then, depending on the stage of its lifecycle, Betabot chooses a type of request to perform, and depending on the specific requests, some streams might be added.

After the information streams are built, the generic request is constructed.

It encrypts and formats this data and then finally sends the request to the server. If a response is available, it tries to receive it and then parse it.

First, the response’s disposition value is checked and if it is set to BB_DISPOSITION_UNINSTALL, the bot uninstalls itself. This might be of particular interest to those who want to write tools to terminate Betabot, since simply executing the function will be enough to disable the bot permanently 😉.

Then, it processes and propagates the new general flags, minor flags, and custom flags via its windows-based IPC mechanism. It also tries to kill old betabot versions if told to do so by the C2 server.

It then saves these values to the registry.

Then, if proactive defense is enabled, it tries once to elevate privileges.

The knock interval is also saved to the dynamic context.

Then, commands are processed. The structure of the commands are already described in two previous writeups on VB, so I will focus on the higher level details here:

For each command, first, the command ID is retrieved from a table by hashing the command string.

The table is as follows:

After that, the command ID is used to find out how to parse the parameters, and then finally the handler inside the table is called.

Finally, after all the commands are processed, the configuration streams are saved to the registry and updated in-memory. Interestingly, the stream CF07 has no identified uses and seems to be reserved for future functionalities (that likely will never arrive).

Interesting commands

Most of the commands are self-explanatory and as such I will not discuss them in detail. The first interesting command that people would likely notice is “Botscript”. What exactly is a botscript? Does Betabot have an embedded scripting engine? As it turns out, this is not the case. Botscript is simply the developers name for injecting wscript into another process using RunPE and then using that to execute a script.

Translated sales thread describing Botscript

Botscript operations run inside a new thread with index 3.

In the new thread, the botscript is downloaded and then injected.

The other interesting feature is support for running a SOCKS proxy server. The server config is parsed and then started in a new thread.

Outside of attempting to port forward using COM’s functionalities, it is a fairly bog standard proxy server.

An interesting detail is that the VB analysis considers the two following commands to be handlers for Skype spamming operations.

Interestingly, the handler for the hash 30A2060Dh currently seems to point to the same handler as the hash for the command “sys”, which is essentially just the shellexecute operation. The reason for this is unknown and I do not know what the original value before hashing might be. The handler for the hash 6EE4094Dh is no longer present.

Another thing you might notice is that a lot of commands are pointing to null handlers and are entirely missing. Unfortunately, these are now lost to time.

Inaccuracy in past public research

While looking at some past materials on Betabot, I noticed some inaccuracies by other reverse engineers. For example, this post by CyberReason claims that the following code is used for anti-debugging reasons.

https://www.cybereason.com/blog/betabot-banking-trojan-neurevt

The code snippet above, when fully annotated, is as follows.

This is then used as part of the hooking/filtering mechanism for NtCreateFile/NtOpenFile APIs and is not used for anti-debugging reasons as suggested by CyberReason, but rather as a defensive feature as stated in the section on hooking.

An even bigger inaccuracy is in this post by Talos where they analyze a binary they consider Neurevt. They claim that “the dropped payload ends up in a benign location of the filesystem and runs, thereby elevating its privilege by stealing service token information”. Problem is, the binary they disassembled is not Neurevt at all, and none of the screenshot shown belongs to Neurevt. The claim that this is a “new version of the Neurevt” appears entirely false to me – Neurevt has been abandoned by the author since 2016 and this is unlikely to change any time soon. As for how this misconception came to be – it looks like multiple binaries are dropped and the reverse engineer mixed them up, as the last request shown that contains logout.php is indeed a Betabot knock request and the drop path (C:\ProgramData\Google Updater 2.09\q99ig1gy1.exe) is indeed betabot-like, however other than that none of the details described in the post matches Betabot.

When publishing public information, reverse engineers should strive to verify their findings to avoid unintentionally disseminating inaccurate information.

Appendix

The IDC and sample for analysis will be uploaded within the next few days. Be warned that the IDA database is NOT CLEAN, while it has enough information to give a solid overview of the malware, I have not had the time to tidy it up in its entirety, as such it is not up to my usual standards. There is around 15% of the binary left that is unlabelled, and there are some portions of the binary that is more clearly seen by simply looking at the code than at my description – as such, it is highly encouraged that readers toy around with Betabot and see for themselves.

FASM for making a fake PE file out of the dumped payload:

real_addr = 2560000h
real_ep = 259848Bh


format PE GUI at (real_addr - 1000h)
entry section_begin + real_ep - real_addr

section '.text' code readable writable executable
section_begin:
        file 'bbdump0x2560000.bin'

List of registry key seeds and their identified meanings (some are previously identified in the original VB analysis):

utw = uac trick worked
UTWS = shim elevation
UTWIEF = ifeo reg trick
AVKR = av kill ran
BK32 = botkill run count
BIS = bot came from spreading
LCT = last communication time
BID = bot installation date
LSF = general flag
LMSF = general flag minor
LCSF = custom flags
LISF = infoblob flags
CF01 = cfg_versions_config
CF02 = cfg_versions_dns_blocklist
CF03 = cfg_versions_url_tracklist
CF04 = cfg_versions_filesearch
CF05 = cfg_versions_plugins
CF06 = cfg_versions_web
CF07 = unknown config, not used anywhere
PNR1 = persistence restore count
ECRC = crash count
ECC1 - access violation
ECC2 - privileged instruction
ECC3 - illegal instruction
ECC4 - stack overflow
ECC5 - in page error

Partial listing of significant enums and structures used by the bot

enum BB_AV_INSTALLED
{
  BB_AV_INSTALLED_NORTON = 1,
  BB_AV_INSTALLED_KAV = 2,
  BB_AV_INSTALLED_AVG = 4,
  BB_AV_INSTALLED_AVIRA = 8,
  BB_AV_INSTALLED_ESET = 16,
  BB_AV_INSTALLED_MCAFEE = 32,
  BB_AV_INSTALLED_TRENDMICRO = 64,
  BB_AV_INSTALLED_AVAST = 128,
  BB_AV_INSTALLED_MS_ESSENTIALS = 256,
  BB_AV_INSTALLED_BITDEFENDER = 512,
  BB_AV_INSTALLED_BULLGUARD = 1024,
  BB_AV_INSTALLED_RISING = 2048,
  BB_AV_INSTALLED_ARCAVIR = 4096,
  BB_AV_INSTALLED_WEBROOT = 8192,
  BB_AV_INSTALLED_EMSISOFT = 16384,
  BB_AV_INSTALLED_FSECURE = 32768,
  BB_AV_INSTALLED_PANDA = 65536,
  BB_AV_INSTALLED_PCTOOLS = 131072,
  BB_AV_INSTALLED_GDATA = 262144,
  BB_AV_INSTALLED_ZONEALARM = 524288,
  BB_AV_INSTALLED_BKAV = 1048576,
  BB_AV_INSTALLED_GBUSTER = 2097152,
  BB_AV_INSTALLED_DRWEB = 4194304,
  BB_AV_INSTALLED_SOPHOS_ENDPOINT = 8388608,
  BB_AV_INSTALLED_COMODO = 16777216,
  BB_AV_INSTALLED_AHNLAB_FREE = 33554432,
  BB_AV_INSTALLED_BAIDU_FREE = 67108864,
  BB_AV_INSTALLED_MALWAREBYTES_PRO = 134217728,
};

/* 620 */
enum BB_CURRENT_PROCESS_FLAGS
{
  BB_CURRENT_PROCESS_FLAGS_EXPLORER = 0x1,
  BB_CURRENT_PROCESS_FLAGS_BROWSER = 0x2,
  BB_CURRENT_PROCESS_FLAGS_USERPROFILE = 0x4,
  BB_CURRENT_PROCESS_FLAGS_DOTNET = 0x8,
  BB_CURRENT_PROCESS_FLAGS_HAS_SUSPICIOUS_MEM = 0x10,
};

/* 530 */
enum BB_SOFTWARE
{
  BB_SOFTWARE_STEAM = 1,
  BB_SOFTWARE_ORIGIN = 2,
  BB_SOFTWARE_RUNESCAPE = 4,
  BB_SOFTWARE_MINECRAFT = 8,
  BB_SOFTWARE_BLIZZARD = 16,
  BB_SOFTWARE_LOL = 64,
  BB_SOFTWARE_BITCOIN_RELATED = 128,
  BB_SOFTWARE_WEBCAM = 256,
  BB_SOFTWARE_JAVA = 512,
  BB_SOFTWARE_SKYPE = 1024,
  BB_SOFTWARE_VISUAL_STUDIO = 2048,
  BB_SOFTWARE_VM_SOFTWARE = 4096,
};

/* 631 */
enum BB_GENERAL_FLAGS
{
  BB_GENERAL_FLAGS_PROACTIVE_DEFENSE = 0x1,
  BB_GENERAL_FLAGS_FORMGRAB_DISABLED = 0x2,
  BB_GENERAL_FLAGS_DNS_MODIFY_DISABLED = 0x4,
  BB_GENERAL_FLAGS_USB_SPREAD_ENABLED = 0x8,
  BB_GENERAL_FLAGS_AGGRESSIVE_PROACTIVE_DEFENSE_ENABLED = 0x10,
  BB_GENERAL_FLAGS_DYNAMIC_CONFIG_DISABLED = 0x20,
  BB_GENERAL_FLAGS_LOGIN_GRAB_DISABLED = 0x40,
  BB_GENERAL_FLAGS_USERKIT_DISABLED = 0x80,
  BB_GENERAL_FLAGS_SYS_INJECTIONS_DISABLED = 0x100,
  BB_GENERAL_FLAGS_SYS_INJECTIONS_XBROWSER_DISABLED = 0x200,
  BB_GENERAL_FLAGS_ANTI_EXPLOIT_KIT_ENABLED = 0x400,
  BB_GENERAL_FLAGS_ANTI_BOOTKIT_ENABLED = 0x800,
  BB_GENERAL_FLAGS_FORCE_IE_ENABLED = 0x1000,
  BB_GENERAL_FLAGS_PRIVILEGE_ESCALATION_EXPLOITS_ENABLED = 0x2000,
  BB_GENERAL_FLAGS_PROACTIVE_MINER_DEFENSE_ENABLED = 0x4000,
  BB_GENERAL_FLAGS_PROACTIVE_LOCKER_DEFENSE_ENABLED = 0x8000,
  BB_GENERAL_FLAGS_PROACTIVE_ANTI_OLDER_BETABOT_ENABLED = 0x10000,
};

/* 632 */
enum BB_MINOR_FLAGS
{
  BB_MINOR_FLAGS_DISABLE_IMAGE_EXECUTION_OPTIONS_FUNC = 0x1,
  BB_MINOR_FLAGS_DISABLE_UAC_FAKE_WINDOW = 0x2,
  BB_MINOR_FLAGS_DO_NOT_DISABLE_WINDOWS_SEC_SERVICES = 0x4,
  BB_MINOR_FLAGS_DISABLE_LUA = 0x8,
  BB_MINOR_FLAGS_DISABLE_AUTOUPDATES_ADDONS = 0x10,
  BB_MINOR_FLAGS_DISABLE_USERKIT_64BIT = 0x20,
  BB_MINOR_FLAGS_INSTALL_USE_HKLM_RUNONCE = 0x80,
  BB_MINOR_FLAGS_MINOR_FLAGS_INSTALL_ENABLE_SHELL_FOLDER = 0x100,
  BB_MINOR_FLAGS_ENABLE_DEBUG_MSG_SYSTEM = 0x200,
  BB_MINOR_FLAGS_ENABLE_DEBUG_ATTRIBUTES = 0x400,
  BB_MINOR_FLAGS_DEBUG_RESERVED_FOR_FUTURE_USE = 0x800,
  BB_MINOR_FLAGS_FORMGRAB_FILTER_USELESS_GRABS = 0x1000,
  BB_MINOR_FLAGS_FORMGRAB_RESERVED_R1 = 0x2000,
  BB_MINOR_FLAGS_FORMGRAB_RESERVED_R2 = 0x4000,
  BB_MINOR_FLAGS_DISABLE_INJECT_INTO_LOADERS = 0x8000,
  BB_MINOR_FLAGS_INJECT_RESERVED_R1 = 0x10000,
  BB_MINOR_FLAGS_INJECT_RESERVED_R2 = 0x20000,
  BB_MINOR_FLAGS_DISABLE_SSL_CERTIFICATE_WARNINGS = 0x40000,
};

/* 633 */
enum BB_CUSTOM_FLAGS
{
  BB_CUSTOM_FLAGS_DISABLE_WEB = 0x1,
  BB_CUSTOM_FLAGS_DISABLE_META_TAG_MODIFIER = 0x2,
  BB_CUSTOM_FLAGS_DISABLE_DOCTYPE_MODIFIER = 0x4,
  BB_CUSTOM_FLAGS_DISABLE_WEB_FOR_VM = 0x8,
  BB_CUSTOM_FLAGS_DISABLE_X_FRAME_OPTIONS_REMOVER = 0x10,
};
enum BB_OSVERFLAG
{
  BB_OSVERFLAG_SERVER2003 = 0x1,
  BB_OSVERFLAG_SERVER2008 = 0x2,
  BB_OSVERFLAG_SERVER2008R2 = 0x4,
  BB_OSVERFLAG_UNSUPPORTED = 0x8,
  BB_OSVERFLAG_WIN8 = 0x10,
  BB_OSVERFLAG_WIN7 = 0x20,
  BB_OSVERFLAG_VISTA = 0x40,
  BB_OSVERFLAG_XP = 0x80,
  BB_OSVERFLAG_BIT_32 = 0x100,
  BB_OSVERFLAG_BIT_64 = 0x200,
  BB_OSVERFLAG_SP1 = 0x400,
  BB_OSVERFLAG_SP2 = 0x800,
  BB_OSVERFLAG_SP3 = 0x1000,
  BB_OSVERFLAG_SERVER2012 = 0x2000,
  BB_OSVERFLAG_WIN10 = 0x4000,
  BB_OSVERFLAG_4001 = 0x8000,
  BB_OSVERFLAG_STARTER = 0x10000,
  BB_OSVERFLAG_HOMEBASIC = 0x20000,
  BB_OSVERFLAG_HOMEPREMIUM = 0x40000,
  BB_OSVERFLAG_PROFESSIONAL = 0x80000,
  BB_OSVERFLAG_ULTIMATE = 0x100000,
  BB_OSVERFLAG_BUSINESS = 0x200000,
  BB_OSVERFLAG_ENTERPRISE = 0x400000,
  BB_OSVERFLAG_DATACENTER = 0x800000,
};
enum BB_THREAD_TRACKER_INDEX : __int16
{
  BB_THREAD_TRACKER_INDEX_0 = 0,
  BB_THREAD_TRACKER_INDEX_1 = 1,
  BB_THREAD_TRACKER_INDEX_ANTIBOT = 2,
  BB_THREAD_TRACKER_INDEX_BOTSCRIPT = 3,
  BB_THREAD_TRACKER_INDEX_PERSISTENCE = 4,
  BB_THREAD_TRACKER_INDEX_5 = 5,
  BB_THREAD_TRACKER_INDEX_6 = 6,
  BB_THREAD_TRACKER_INDEX_7 = 7,
  BB_THREAD_TRACKER_INDEX_8 = 8,
  BB_THREAD_TRACKER_INDEX_9 = 9,
  BB_THREAD_TRACKER_INDEX_10 = 10,
  BB_THREAD_TRACKER_INDEX_11 = 11,
  BB_THREAD_TRACKER_INDEX_IS_BEHIND_ROUTER_CHECK = 12,
  BB_THREAD_TRACKER_INDEX_PATCH_DETECTION = 13,
  BB_THREAD_TRACKER_INDEX_LAZY_DECRYPT_MAYBE = 14,
  BB_THREAD_TRACKER_INDEX_15 = 15,
  BB_THREAD_TRACKER_INDEX_16 = 16,
  BB_THREAD_TRACKER_INDEX_17 = 17,
  BB_THREAD_TRACKER_INDEX_INTEGRITY_CHECK = 18,
  BB_THREAD_TRACKER_INDEX_19 = 19,
  BB_THREAD_TRACKER_INDEX_20 = 20,
  BB_THREAD_TRACKER_INDEX_21 = 21,
  BB_THREAD_TRACKER_INDEX_WINDOW_HANDLER_IPC = 22,
  BB_THREAD_TRACKER_INDEX_USB_SPREADER = 23,
  BB_THREAD_TRACKER_INDEX_PERSISTENCE_PROCESS = 24,
  BB_THREAD_TRACKER_INDEX_UAC = 25,
  BB_THREAD_TRACKER_INDEX_26 = 26,
  BB_THREAD_TRACKER_INDEX_BROWSER_HOOK = 27,
  BB_THREAD_TRACKER_INDEX_BROWSER_DUMMY = 28,
  BB_THREAD_TRACKER_INDEX_29 = 29,
  BB_THREAD_TRACKER_INDEX_30 = 30,
  BB_THREAD_TRACKER_INDEX_FREE2 = 31,
  BB_THREAD_TRACKER_INDEX_FREE1 = 32,
  BB_THREAD_TRACKER_INDEX_33 = 33,
  BB_THREAD_TRACKER_INDEX_FREE_START = 34,
};
enum BB_COMMAND_HASH
{
  BB_COMMAND_HASH_DIE = 0x2A66058D,
  BB_COMMAND_HASH_UAC = 0x2A870594,
  BB_COMMAND_HASH_REM = 0x2A90059F,
  BB_COMMAND_HASH_SYS = 0x2AC105BA,
  BB_COMMAND_HASH_DDOS = 0x306B0605,
  BB_COMMAND_HASH_SPAM = 0x30A9060C,
  BB_COMMAND_HASH_SOCKS = 0x3726067E,
  BB_COMMAND_HASH_DWFILE = 0x3DCF06D6,
  BB_COMMAND_HASH_UPDATE = 0x3E0206DE,
  BB_COMMAND_HASH_PLUGIN = 0x3E1906EA,
  BB_COMMAND_HASH_BOTKILL = 0x4526074C,
  BB_COMMAND_HASH_BROWSER_CLEAR_CACHE = 0x4565075F,
  BB_COMMAND_HASH_DDOS_UDP = 0x4BCE077C,
  BB_COMMAND_HASH_DDOS_RUDY = 0x53D207F7,
  BB_COMMAND_HASH_BOTSCRIPT = 0x55330835,
  BB_COMMAND_HASH_DDOS_CONDIS = 0x647608B3,
  BB_COMMAND_HASH_DDOS_HTTPGET = 0x6E0A0933,
  BB_COMMAND_HASH_BROWSERVISIT = 0x794409BC,
  BB_COMMAND_HASH_DDOS_SLOWLORIS = 0x821A0A21,
  BB_COMMAND_HASH_BROWSERSETHOME = 0x8DC00A82,
};
enum BB_BOT_ATTRIBUTE
{
  BB_BOT_ATTRIBUTE_HAS_SOURCE_USB = 0x1,
  BB_BOT_ATTRIBUTE_HAS_NET_FRAMEWORK = 0x2,
  BB_BOT_ATTRIBUTE_HAS_JAVA = 0x4,
  BB_BOT_ATTRIBUTE_HAS_STEAM = 0x8,
  BB_BOT_ATTRIBUTE_HAS_ROUTER = 0x10,
  BB_BOT_ATTRIBUTE_IS_ELEVATED = 0x20,
  BB_BOT_ATTRIBUTE_IS_GOOD_FOR_BITCOIN = 0x40,
  BB_BOT_ATTRIBUTE_IS_COMPUTER_SAVVY = 0x80,
  BB_BOT_ATTRIBUTE_IS_LAPTOP = 0x100,
  BB_BOT_ATTRIBUTE_UAC_ENABLED = 0x200,
  BB_BOT_ATTRIBUTE_HAS_USED_RDP = 0x400,
  BB_BOT_ATTRIBUTE_IS_VIRTUAL_MACHINE = 0x800,
  BB_BOT_ATTRIBUTE_HAS_SAMSUNG_DEVICE = 0x1000,
  BB_BOT_ATTRIBUTE_HAS_APPLE_DEVICE = 0x2000,
  BB_BOT_ATTRIBUTE_4000_UNKNOWN = 0x4000,
  BB_BOT_ATTRIBUTE_SAFE_BOOT = 0x8000,
  BB_BOT_ATTRIBUTE_AVKILL_HAS_EXECUTED = 0x1000000,
  BB_BOT_ATTRIBUTE_TRICK_WORKED_USED_IFEO_TRICK = 0x8000000,
  BB_BOT_ATTRIBUTE_TRICK_WORKED_USED_SHIM_TRICK = 0x10000000,
  BB_BOT_ATTRIBUTE_UAC_REQUIRES_TRICK = 0x20000000,
  BB_BOT_ATTRIBUTE_UAC_TRICK_WORKED = 0x40000000,
};

/* 532 */
enum BB_SECURITY_TOOL_INSTALLED
{
  BB_SECURITY_TOOL_INSTALLED_ADWCLEANER = 0x1,
  BB_SECURITY_TOOL_INSTALLED_COMBOFIX = 0x2,
  BB_SECURITY_TOOL_INSTALLED_ADAWARE = 0x4,
  BB_SECURITY_TOOL_INSTALLED_SPYBOTSND = 0x8,
  BB_SECURITY_TOOL_INSTALLED_BANKERFIX = 0x10,
  BB_SECURITY_TOOL_INSTALLED_HOUSECALL = 0x20,
  BB_SECURITY_TOOL_INSTALLED_HIJACKTHIS = 0x40,
  BB_SECURITY_TOOL_INSTALLED_TRUSTEER = 0x80,
};
enum BB_BOT_REQUEST_TYPE
{
  BB_BOT_REQUEST_TYPE_CHECKIN = 0x1,
  BB_BOT_REQUEST_TYPE_CHECKIN_BOOT = 0x2,
  BB_BOT_REQUEST_TYPE_UPDATE_STATS = 0x4,
  BB_BOT_REQUEST_TYPE_UPDATE_FORMGRAB = 0x8,
  BB_BOT_REQUEST_TYPE_UPDATE_STEALER = 0x10,
  BB_BOT_REQUEST_TYPE_UPDATE_INFOBLOB = 0x100,
};

struct BB_REPORT_UNK
{
  char JpegFakeHeader[8];
  __int16 size;
  __int16 magic;
  int header_crc32;
  int stringsCount;
  int exdataKey;
  int botVer;
  int reqType;
  int osVerFlag;
  int botAttribute;
  int botOS;
  int botAttribs;
  int botCustomAttrib;
  int debugAttribs;
  int currentTimeUnix;
  int currentTickCount;
  int timezoneBias;
  int botLocale;
  WORD botkillStats;
  __int16 socksPortA16MachineId;
  char hwid[16];
  int CFRegKeys[8];
  DWORD tasksStatus[8];
  int field_9C;
  int field_A0;
  int installedAV;
  int installedSoft;
  int securityToolsInstalled;
  int killedAVs;
  DWORD webAttributes;
  int screenSize;
  int exploitStatus;
  int field_C0;
  int field_C4;
  int field_C8;
  int field_CC;
  int field_D0;
  WORD RegECC[5];
  __int16 exceptionUnused1;
  __int16 exceptionUnused2;
  __int16 exceptionUnused3;
  __int16 exceptionUnused4;
  __int16 exceptionUnused5;
  __int16 exceptionUnused6;
  __int16 exceptionUnused7;
  __int16 persistenceRestoreCount;
  WORD crashCount;
  _BYTE gapF0[20];
  char stringBotGroupName[12];
  char botProcName[20];
};

/* 637 */
enum BB_ENUMS
{
  BB_REQUEST_MAGIC = 0xC1E5,
  BB_DISPOSITION_UNINSTALL = 0x10A15,
};

struct BB_RESPONSE_STRUCT
{
  int field_0;
  int field_4;
  int size;
  int statusCode;
  int knockInterval;
  int contentType;
  int disposition;
  int generalOpts;
  int minorOpts;
  int customOpts;
  int infoBlobStatus;
  int dynConfigVer;
  int dnslistVer;
  int urltrackVer;
  int filesearchVer;
  int pluginVer;
  int webVer;
  int reserved1;
  int reserved2;
  int cmdSize;
  int dnsSize;
  int trackedUrlSize;
  int dynConfSize;
  int filesearchConfSize;
  int pluginConfSize;
  int webConfSize;
  int field_68;
};

On a more personal side of things, as you might’ve noticed, the blog has been fairly inactive and this is unlikely to change any time soon. In all likelihood, this is probably the last post on this blog. The past years have been fun, much appreciation to all of those who stuck around, especially those who are still doing cool research. If you have unfinished projects/dealings/etc with me, it is best to contact me soon to get things resolved.