Birthday Reminder looks benign but the devil’s in the details: Hooks DNS, serves dodgy ads

The strange behavior of a simple Windows application caught our attention and sparked ESET’s analysis of previously undocumented malware. A contact at the Norwegian HealthCERT —  following a question about this from the regional healthcare provider Sykehuspartner — reached out to us asking about DNS queries to domains with the format [0-9a-f]{60}.smoke. There is no .smoketop level domain, at least as of the time of writing.

The application responsible for that behavior is a very simple Birthday Reminder program. It actually works, but also has interesting features that are not explicitly disclosed to the user. We have seen the Birthday Reminder program download and execute additional components that hook DNS requests in order to inject ads into webpages. We have named this new threat DNSBirthday.

It is also pretty clear that the authors of this malware wrote all of the components and do not simply resell compromised machines. For example, the C&C server is for all samples and many of the artefacts in the malware point to a project called RQZTech.


We have only seen the Birthday Reminder installer downloaded from the following URL:


The aff_id parameter suggests distribution via an affiliate program, but we have been unable to confirm this. It could also be a decoy.

ESET’s telemetry shows this threat is distributed fairly evenly around the globe with a few spikes in some countries such as the US, Spain, Japan and Italy.

Technical analysis

DNSBirthday is modular malware with multiple components. It took us some time to understand the whole scheme behind this malware’s operation and put all the pieces of the puzzle together. However, all the components have a few things in common:

  • They communicate with just one C&C server ( using JSON formatted messages over HTTPS.
  • Most of the binaries are statically linked with OpenSSL and libcurl, as well as a JSON library.
  • Most of the component names are prefixed with rqz.
  • PDB paths in components have the form C:\Users\default.default-PC\Documents\Visual Studio 2013\Projects\rqz-[module-name]\Release\rqz-[module-name].pdb

The authors chose to pin two certificates to prevent Man-In-The-Middle attacks. However, the server also responded to unencrypted HTTP requests, so it was possible to capture network traffic while debugging by changing the URL scheme of these requests to http.

The certificates embedded in the executables are self-signed. The Not-before field shows that they were probably generated on the 16th of April 2016.

We will go into more details of each component but first here’s an overview of how they are linked together.

Although all of the components are PE executables, only a few are written to disk. The others are loaded and executed in memory using a custom PE loader implementation.


BirthdayReminderSetup.exe is an 18MB NSIS package. This installer first determines whether the system is a 32- or 64-bit version and extracts several files to the specified install folder accordingly.

After this, it achieves persistence by creating the value BirthdayReminder in the registry key HKLM\Software\Microsoft\Windows\CurrentVersion\Run with the path to the BRController.exe application. After all, how could it remind you of birthdays if it’s not continuously running? It even has an icon in the system tray notification area.

BRController.exe — rqz-loader

The sole purpose of the component BRController.exe is to decrypt the br.dll.enc file into memory, load it and call rqz_stg1_init, one of its exported functions.

The decryption algorithm used is AES-256-CBC, implemented via a statically linked OpenSSL library.

The decryption key is generated in two steps. First, the SHA-256 hash of the logo.png file is computed. Then a simple XOR routine is applied to the hash. The first byte is XORed with the last and all other bytes are XORed with the first.

The initialization vector (IV) is the first 16 bytes of the key which is then reshuffled by the same XOR routine used for the key.

br.dll — rqz-stg1

We call br.dll the unencrypted form of br.dll.enc. This library acts as the core component of this malware.

First, br.dll creates a mutex Global\Global\RqzSingleInst and then creates a list of callable objects with explicit names such as dlExec, loader or even exfil. These callable objects, when invoked, can perform tasks like downloading executable files, optionally saving them to disk and executing them, or exfiltrating data to the C&C server.

The component retrieves a unique bot identifier hardcoded in the BRController executable by searching for the sequence of bytes, 0xB00B1355 and then reading the 16 following bytes. Then it tries to launch the Birthday Reminder application graphical user interface and enters a loop to communicate with its C&C server.

The first HTTP POST request made to the server (hxxps:// contains some basic information in JSON format inside the data parameter.

Here is a tidied version of the first POST made to C&C server:

    "compStatus": [],
    "ver": "1.1.0-x32",
    "osver": "Windows 7 HomeBasic -unknown- x32",
    "uuid": "7cbf93f588f70f6cf514666dfb8d36d34943dd924c7bb7a5372a5ae765de2009",
    "checkinCount": 0

This JSON contains the version of the malware (ver, 1.1.0-x32), the version of Windows (osver), the bot identifier (uuid), the number of times the malware tried to contact the server (checkinCount) and an array containing the status of the latest loaded component (compStatus).

The server replies with a JSON array containing a list of parameters to pass to the different components. Although the request looks like a software update mechanism, what we have observed is that it is used to push malicious components to the victims.

The first time the malware contacts the server, the latter replies with the following JSON (payloadstring is truncated for readability).

Reply from C&C server:

        "args": {
            "exit": "0",
            "env": "RQZ_SESSIONID=58a72526b10d8e000aef05d7;",
            "sleepTime": "28800000"
        "component": "callback"
    }, {
        "args": {
            "pname": "rqz_info_gatherer",
            "payload": "+j5kXRAtalG4PNEwXrhX [...] nhG0JfKbF7OzmcE7ULfiwm1Sg=="
        "component": "loader",
        "exec": "1"
    }, {
        "args": {},
        "component": "rqz_info_gatherer",
        "exec": "1"

The response from the server shows three actions to be executed in succession. The first sets some environment variables using the callback component.

The loader component is then called in order to decrypt and load the component rqz_info_gatherer in memory. The payload string is a base64-encoded and encrypted DLL (rqz_info_gatherer). The decryption routine is the same as that used to decrypt the br.dll.encfile.

Once loaded, the now-decrypted component is called.

After that, the malware sleeps for 8 hours.


This module’s purpose is to collect some information about the machine and to send a report using the exfil component from br.dll.

The exfil component makes an HTTPS POST request to hxxps:// with the bot uuid and payload. The payloadparameter is a JSON object composed of two elements: data and sha256.

The sha256 string is the hash of the data before it was base64 encoded.

The data string is a base64-encoded JSON containing information about the computer. The following snippet is an example of a decoded report sent to the server (procStat is truncated for readability).

Example report from the rqz-info-gatherer module:

"infoGatherer": {
    "defaultBrowser": "FIREFOX.EXE",
    "firewallEnabled": 1,
    "winBuild": "Windows 7Home Basic - unknown - x32",
    "dirStat": {
      "appData": 275865504,
      "webTemp": 109159833,
      "docu": 1679,
      "desktop": 66397544
    "infoGathererVersion": "1.0.4",
    "procStat": "[System Process],System,smss.exe, [...]firefox.exe,audiodg.exe,",
    "installDate": 0,
    "dotNetVer": "3.5.30729.5420;3.0.30729.5420;2.0.50727.5420",
    "ieVer": "8.0.7601.17514",
    "oemLogo": "0",
    "uptime": 13771487,
    "permCheckSuccess": "1"

Most of these fields are pretty self-explanatory. The dirStat object contains the size in bytes of certain folders.

Once sent, the server replies with just danke (German for “thank you”) which, interestingly, matches with the country name field in the public certificate.


It has been observed that after a certain period of time (one or two weeks), the br.dll component downloads the rqz-dnsduvel-ldr component. duvel is (Old) Dutch and Frisian for “devil” so this probably means “devil DNS”.

This component looks for browser processes such as iexplore.exe, chrome.exe and firefox.exe to inject malicious code inside them.

Once a process is found, the module drops and executes an embedded executable in the %TEMP%folder (GetTempPathA). The name of the file is the process identifier (PID) of the process to inject code into, with the .tmp extension. This means that for every browser process to be injected, a copy of the executable file is dropped in a .TMP file in the temporary folder.

The dropped binary uses the internal name rqz-dnsduvel-ldr-exe and both the PID of the process to be injected and a session identifier are passed to it as parameters.


This component is an injector that uses Reflective DLL injection in order to load a DLL into the address space of another process.

This executable also contains another executable, but unlike the rqz-dnsduvel-ldr module, the embedded binary is encrypted. Once again, the decryption routine is AES-256-CBC but this time the IV and key are hardcoded.

The injector queries the server for a configuration file. The query is done via an HTTPS POST request to:


The POST parameters are, again, uuid and payload. payload is, again, a JSON object with a data and a sha256 key. The data string is the following base64-encoded JSON where procName is the browser to inject and sessionID is the cookie set by the second command line argument.

Example report from rqz-dnsduvel-ldr-exe:

  "duvel": {
    "procName": "chrome.exe",
    "loaderVer": "rqz-dnsduvel-ldr-exe-1.0.4-x64",
    "duvelVer": "rqz-dnsduvel-1.0.3-68c0c5",
    "sessionId": "[...]"

The server replies with the following JSON configuration file (blockList array is truncated for readability).

Example configuration for rqz-dnsduvel-ldr-exe:

  "duvelDetails": {
    "token": "be1728523f82428fc2016155f6dd65867b01997dc0b1c93097a8b7cc60cb.smoke",
    "dnsServer": "",
    "blockList": [

The full configuration with a complete “block list” is available on ESET’s Github.

The blockList array contains approximately 500 domain names that usually host advertisements. The content of this configuration is stored in a file mapping backed by memory and named rqzduvel-checkin-payload created with CreateFileMapping(INVALID_HANDLE_VALUE, …​).

The token field contains a domain name that is used by the malware to check whether the DNS server used is the one in the dnsServer field. DNSBirthday queries this domain and checks if the returned address is

The module retrieves the export ReflectiveLoader in the decrypted binary (rqz-dnsduvel), maps the library in the browser’s address space using WriteProcessMemory and calls CreateRemoteThread with the lpStartAddress parameter set at the retrieved export address.

Once injected, the component will inform the C&C server if the injection was successful with a POST request to: hxxps://

Injection result sent to the C&C server is as follows:

    "password" : "74f20fc0a7274",
    "duvel" : {
        "function": "smokeFail",
        "arg" : {
            "smokeUrl" : "be1728523f82428fc2016155f6dd65867b01997dc0b1c93097a8b7cc60cb.smoke",
            "reason" : "1"

The reason string can have the following values:

  1. The binary failed to open the victim process
  2. The injection was successful (process still running after 1 minute)
  3. The process has likely crashed and the injection did not succeed


rqz-dnsduvel is the final stage and its purpose is to hook DNS resolver functions.

The authors have likely borrowed some code in order to achieve the reflective DLL injection. They have also statically linked the NTHooklib project, which includes the udis86 library. NTHooklib is a library that provides a hooking engine.

The component hooks the following DNS functions:

  • getaddrinfo
  • GetAddrInfoW
  • gethostbyname
  • GetAddrInfoEx

The goal of the hook is to query an alternate DNS server when the query is for a domain name present in the “block list” of the configuration file.

Every time the injected browser needs to resolve one of these domain names, the server set in dnsServer is used ( here). Regardless of the queried domain name, while monitoring this, the IP address returned from that rogue DNS server was always either or

The following code snippet is a loop replacing all the responses from the real getaddrinfo function with the IP address resolved by the rogue server.

Ad injection

As mentioned previously, the domain names in the “block list” are related to advertisements, which leads us to think that the main purpose of this malware is to replace or inject advertisements in webpages.

When queried for any files ending in .js, the server at would always return the same file. The script adds a div element with id greenteainthesahara. Then it makes an HTTP POST request to the URL hxxp:// and simply evaluates (eval) the response.

The JavaScript we have observed from contains code for different browsers and platforms and, interestingly, even for mobile phones. The main purpose of this script is to add an event listener on the page that opens a new browser window with an ad when a click is made.

Here is an example redirection chain we have observed.

  1. hxxp://
  2. hxxp://
  3. hxxp://
  4. hxxp://

The rest of the chain changes and probably depends on the result of the ad bidding. It sometimes redirects to a drive-by download that could result in even more malware being installed.


Authors of this malware have gone to great lengths, just to push unsolicited advertisements.

As shown here, the authors have put a lot of effort into avoiding being detected, by including a PE loader, loading and decrypting components in memory, creating a modular architecture that allows updates and addition of more components, and using a pinned public key to secure their communications.

However, some choices are hard to understand:

  • Newer versions of some components contain the .pdb path, which was not present in older versions
  • Most of the components are not written to disk, but the final stage rqz-dnsduvel-ldr-exe is
  • The component rqz-dnsduvel-ldr-exe uses a hardcoded key and IV instead of deriving them from the hash of the logo.png file.

The modularity of this malware allows for more features that perhaps we haven’t witnessed as yet. It is possible that the operators of this malware send other types of malware such as spyware to chosen victims. Some components could also be in development as we speak.

We have reached out to OVH regarding the C&C server and the rogue DNS server and both have been taken down.

thanks to
Romain Dumont for his help on the analysis and write-up.


Samples analyzed

Filename Internal name Versions analyzed Debug Timestamp Main purpose
BRController.exe rqz-loader 1.1.0 x32 & x64 Sun 02 Oct 2016 16:11:40 Loader:

Decrypts and loads br.dll.enc in memory

BRController.exe (debug) unknown unknown x32 & x64 unknown Loader:

Decrypt and loads br.dll.enc in memory

br.dll(.enc) rqz-stg1 1.0.4 x32 & x64

1.1.0 x32 & x64


Sun 02 Oct 2016 16:12:07

Core component:

C&C communication

Data exfiltration

Update/Download other components

Download/Exec other modules in memory

rqz-info-gatherer 1.0.4 x32 & x64 Tue 13 Sep 2016 23:25:43 Module:

Gather information about the computer

rqz-dnsduvel-ldr 1.0.4 x32 & x64 Sat 17 Sep 2016 19:55:10 Module:

Drop and execute rqz-dnsduvel-ldr-exe for each browser process

%d.tmp rqz-dnsduvel-ldr-exe 1.0.3 x32 & x64

1.0.4 x32 & x64

Sat, 03 Sep 2016 19:02:11

Sat 17 Sep 2016 19:54:36


Inject a given process with its embedded dll (rqz-dnsduvel)

rqz-dnsduvel 1.0.2-30fa39 x32 & x64

1.0.3-68c0c5 x32 & x64

Sat 03 Sep 2016 19:01:51

Sat 17 Sep 2016 19:53:50

DNS hooker:

Hook DNS functions inside a process

Replace IP addresses for some domain names



  • “HKLM\Software\Microsoft\Windows\CurrentVersion\Run\BirthdayReminder”


  • Global\Global\RqzSingleInst
  • Global\downloadExec


Component SHA-1 ESET Detection name
BirthdayReminderSetup.exe 6a07de60da0962ee952e63ac89ce86d2581f3926 Win32/Adware.DNSBirthday.A
rqz-loader 1.1.0 x32 19041323a4ecd92eb888664e1d2c0b2893419f78 Win32/Adware.DNSBirthday.A
rqz-loader 1.1.0 x64 94c6f2bbad0ce47957d18b53ef1938d846d7576f Win64/Adware.DNSBirthday.B
rqz-stg1 1.1.0 x32 59eb5b5d3171069761a13389a1a7cce12a95e0bd Win32/Adware.DNSBirthday.A
rqz-stg1 1.1.0 x64 f02e0012aedf02f898f1558c827491d7099c1d62 Win64/Adware.DNSBirthday.A
rqz-info-gatherer 1.0.4 x32 8cfbd1f7e4d8c4357766f0f4b84bb08cf2e78c17 Win32/Adware.DNSBirthday.B
rqz-info-gatherer 1.0.4 x64 0f4aeee1a0878eb510229b871e02eb1e1939107e Win64/Adware.DNSBirthday.B
rqz-dnsduvel-ldr 1.0.4 x32 892785875fcdfe4cc672ba1c3fc59bfbf37c7efe Win32/Adware.DNSBirthday.A
rqz-dnsduvel-ldr 1.0.4 x64 5a5174739bbb7881c46112704cbf039f39d98fec Win64/Adware.DNSBirthday.B
rqz-dnsduvel-ldr-exe 1.0.4 x32 cc291be6cbc7b0dc3aa09973d0ed98e363f9083f Win32/Adware.DNSBirthday.A
rqz-dnsduvel-ldr-exe 1.0.4 x64 ce84d96a974e95499fadd3320f851c0b728cd438 Win64/Adware.DNSBirthday.B
rqz-dnsduvel 1.0.3-68c0c5 x32 e6b6fe919cf6c3af0d40594e86da4cf776dbcf9a Win32/Adware.DNSBirthday.B
rqz-dnsduvel 1.0.3-68c0c5 x64 d1085fb7f2c4d1add9244cb8af6d0e25b50d7b14 Win64/Adware.DNSBirthday.B

Because BirthdayReminderSetup.exe and BRController.exe contain a unique bot id, here are ssdeep fuzzy hashes:

Component ssdeep
BirthdayReminderSetup.exe 393216:ZD4b8Ev/xl3OB4fcUx6uj55/Q7COLc1cm+DkC1GWF2jazuIYRCxEfFCqgY9iHtKZ:ZD5EhFOmcUs85/OCOLecm+14OzzY9Fdl
BRController.exe (x86) 24576:0+KpP0PYnsKdFCH6BMKHiBMikwMbSyM52it6YTekcys4e6faNe0M4RzRPxM4TuZR:cfs4F6KHiy7kM4CjlpRPx1TuZ+tgP8K
BRController.exe (x64) 49152:l4+VwASOwGtlqKPb8KHh+3ulMrqkvTiV3ML3OsQXIU6inTe2mEPEB:jCTiVGV+q2mHB


  • Rogue DNS server:
  • C&C server: (
  • Ad server IP addresses: and
  • DNS query to domain matching [0-9a-f]{60}.smoke

SSL certificates


        Version: 3 (0x2)
        Serial Number:
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=DE, ST=Berlin,
            Not Before: Apr 16 11:38:38 2016 GMT
            Not After : Apr 14 11:38:38 2026 GMT
        Subject: C=DE, ST=Berlin,
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (4096 bit)
                Modulus (4096 bit):
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
            X509v3 Authority Key Identifier:

            X509v3 Basic Constraints:
    Signature Algorithm: sha256WithRSAEncryption


        Version: 3 (0x2)
        Serial Number:
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=DE, ST=Berlin,
            Not Before: Apr 16 11:38:38 2016 GMT
            Not After : Apr 11 11:38:38 2036 GMT
        Subject: C=DE, ST=Berlin,
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (4096 bit)
                Modulus (4096 bit):
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
            X509v3 Authority Key Identifier:

            X509v3 Basic Constraints:
    Signature Algorithm: sha256WithRSAEncryption

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 )

Google+ photo

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

Connecting to %s