Post

Domain-KillSwitch

Domain-KillSwitch

What is it?

Queries a DNS A record for a specific domain using DnsQuery_A. Returns TRUE if the domain resolves, FALSE if it doesn’t. Used as a killswitch or sandbox evasion check — the behavior before executing the payload depends on whether the domain is registered or not.

How it works

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DomainCheck("microsoft.com"):

  DnsQuery_A(
    DomainName,          ← the domain to check
    DNS_TYPE_A,          ← looking for an A (IPv4 address) record
    DNS_QUERY_STANDARD,  ← normal recursive query, no caching tricks
    NULL,                ← no extra server list
    NULL,                ← don't return the actual records
    NULL                 ← no reserved
  )

  if Status == ERROR_SUCCESS:
    domain resolves → return TRUE
  else:
    domain not found or query failed → return FALSE

The current implementation checks microsoft.com as a demo, which always resolves. In a real deployment, the domain would be:

1
2
3
4
5
6
7
8
9
10
11
Killswitch design 1 — exit if domain resolves:
  DomainCheck("killswitch.attacker.com")
  │ TRUE  → domain registered → exit (operator kills campaign)
  │ FALSE → domain doesn't exist → run payload
  
  Operator flip: register the domain to kill all active samples

Killswitch design 2 — run only if C2 is alive:
  DomainCheck("c2.attacker.com")  
  │ TRUE  → C2 online → run payload
  │ FALSE → C2 offline → exit (avoids running without comms)

WannaCry famously used Design 2 in reverse — it exited if a specific unregistered domain resolved. A security researcher registered it, the domain started resolving, and all WannaCry instances treated it as a “sandbox detected” signal and stopped propagating. That was an unintended killswitch activated by accident.

DnsQuery_A uses the system’s configured DNS resolver, which means the query goes through normal network channels and can be logged by network monitoring tools. For stealth, DNS_QUERY_NO_LOCAL_NAME or querying specific resolvers directly would reduce the logging footprint.

domain-killswitch.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <Windows.h>
#include <stdio.h>
#include <windns.h>
#pragma comment(lib, "dnsapi.lib")

/*
    Checks whether a domain resolves via DNS A record lookup.
*/
BOOL DomainCheck(_In_ PCSTR DomainName) {
    if (!DomainName)
        return FALSE;

    DNS_STATUS Status = DnsQuery_A(DomainName, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, NULL, NULL);
    if (Status == ERROR_SUCCESS) {
        printf("[+] Domain exists: %s \n", DomainName);
        return TRUE;
    }

    printf("[!] Domain not found or query failed: %s (Status: %d) \n", DomainName, Status);
    return FALSE;
}

int main() {
    DomainCheck("microsoft.com");
    return 0;
}
This post is licensed under CC BY 4.0 by the author.
Source code: Domain-KillSwitch