{
	"id": "9da5f065-0e21-4bfa-9a39-46e406a87dc2",
	"created_at": "2026-04-10T03:21:21.492949Z",
	"updated_at": "2026-04-10T13:12:16.389732Z",
	"deleted_at": null,
	"sha1_hash": "63901227d95963695c5cb3e18858f3b431fcfae9",
	"title": "The DGA in Alureon/DNSChanger",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 71797,
	"plain_text": "The DGA in Alureon/DNSChanger\r\nArchived: 2026-04-10 03:03:58 UTC\r\nAt least some of the famous DNSChanger malware samples use a domain generation algorithm (DGA) to generate\r\nfive pseudo random domains. In contrast to most other uses of DGAs, the domains are never intended to be\r\nactually registered. Instead, by contacting the domains, the rogue name servers are informed immediately of newly\r\ninfected clients. Failed DNS queries also reveal that the DNS changes did not succeed, or that the queries are\r\nblocked.\r\nBecause I couldn’t find an implementation of the DGA, I post it here. Skip to Reimplementation and Domains to\r\nsee the algorithm. I reversed the following sample:\r\nmd5\r\n2563874010c5adf9009cb9b231c3d0fc\r\nsha256\r\n852c45049ec6e384dea40e3cc70479ad06015277646cf30da7ef9a038de9267e\r\nsource\r\nmalwr\r\nupload date\r\n2014-10-21\r\nReverse Engineering\r\nContext\r\nThe queries to the algorithmically generated domains are made after the DNS settings are changed. Five different\r\ndomains are generated and tested, see offsets 0x1F1E08 to 0x1F1E13 in the following graph view clipping:\r\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 1 of 10\n\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 2 of 10\n\nIf the last DNS query fails, i.e., the malicious DNS servers can’t be reached, then DNSChanger determines the\r\nWindows version and calls some Windows 2000 specific remedies if applicable.\r\nGeneration and Resolving of Domains\r\nThe routine to generate and call the DGA-domains is very simple:\r\nThe DGA routine is called. The routine takes the length as the only argument. The parameter is set to 10.\r\nThe DGA returns a second level domain.\r\nThe top level domain .com is appended to the second level domain by a wsprintf call.\r\nA DNS query is made for the domain by calling gethostbyname . The routine returns True if the DGA\r\nquery succeeds, and False otherwise.\r\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 3 of 10\n\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 4 of 10\n\nThe DGA Routine\r\nThe DGA is kept simple. It generates a random string by repeatedly calling the randint routine to generate\r\nrandom lower case letters. The length parameter of the subroutine determines the length of the string.\r\nPseudo Random Number Generators and Seeding\r\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 5 of 10\n\nThe randint function is:\r\nif upper \u003e lower\r\nreturn lower + rand() % (upper - lower + 1)\r\nelse\r\nreturn lower\r\nThe rand function is a linear congruential generator as implemented in C:\r\nr = 214013*r + 2531011\r\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 6 of 10\n\nreturn (r \u003e\u003e 16) \u0026 0x7FFF\r\nSeeding is done with the srand routine:\r\nThe seed itself is set to the sum of the current thread id and the approximate number of milliseconds since\r\nWindows last booted:\r\nThis number can’t be predicted precisely by the backers of DNSChanger. It shows that they don’t intend to\r\nactually register the DGA domains. The domains are used to test the changes to DNS settings and potentially to\r\nnotify the operators of DNSChanger of newly infected systems.\r\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 7 of 10\n\nReimplementation and Domains\r\nPython\r\nHere is a reimplementation in Python. The script takes the seed as the one and only argument.\r\nimport argparse\r\nfrom ctypes import c_int\r\nclass Rand:\r\n def __init__(self):\r\nself.r = c_int()\r\n def srand(self, seed):\r\nself.r.value = seed\r\n def rand(self):\r\nself.r.value = 214013*self.r.value + 2531011\r\nreturn (self.r.value \u003e\u003e 16) \u0026 0x7FFF\r\n def randint(self, lower, upper):\r\nreturn lower + self.rand() % (upper - lower + 1)\r\ndef dga(r):\r\n sld = ''.join([chr(r.randint(ord('a'), ord('z'))) for _ in range(10)])\r\n return sld + '.com'\r\nif __name__==\"__main__\":\r\n parser = argparse.ArgumentParser()\r\n parser.add_argument(\"seed\", type=int)\r\n args = parser.parse_args()\r\n r = Rand()\r\n r.srand(args.seed)\r\n for _ in range(5):\r\nprint(dga(r))\r\nFor example:\r\n$ python dga.py 60000\r\nxyinotlgjm.com\r\npzebjxgftf.com\r\njsgjmbtbdr.com\r\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 8 of 10\n\nnhuknekrdg.com\r\njaebiztqia.com\r\nBrute-Forcing\r\nI also wrote a small C program that checks if a provided domain could stem from DNSChanger:\r\n#include\u003cstdio.h\u003e\r\n#include\u003cstdlib.h\u003e\r\n#include\u003cstring.h\u003e\r\nunsigned int r;\r\nlong myrand() {\r\n r = 214013*r + 2531011;\r\n return (r \u003e\u003e 16) \u0026 0x7FFF;\r\n}\r\nlong randint (int lower, int upper) {\r\n return lower + (myrand() % (upper - lower + 1));\r\n}\r\nvoid dga(unsigned long seed, char* url) {\r\n long int i;\r\n long int domain_len = 10;\r\n r = seed;\r\n for(i = 0; i \u003c 10; i++) {\r\n url[i] = randint('a', 'z');\r\n }\r\n url[domain_len] = 0;\r\n}\r\nlong int find(char* wanted) {\r\n char url[11];\r\n printf(\"searching %s\\n\", wanted);\r\n long int seed;\r\n long int maximum = 0xFFFFFFFF;\r\n for(seed = 0; seed \u003c maximum; seed++) {\r\n dga(seed, url);\r\n if(strcmp(url, wanted) == 0) {\r\n printf(\"\\r-\u003e found seed %u\\n\", (unsigned int)seed);\r\n return 1;\r\n }\r\n if(seed % (2 \u003c\u003c 22) == 0)\r\n printf(\"\\r%.3f %%\", (seed)/(double)maximum);\r\n }\r\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 9 of 10\n\nprintf(\"\\n\");\r\n return 0;\r\n}\r\nint main (long int argc, char *argv[])\r\n{\r\n if ( argc != 2 )\r\n printf( \"usage: %s hostname (without tld)\\n\", argv[0] );\r\n else\r\n find(argv[1]);\r\n}\r\nProvide the second level domain to the program to find the corresponding seed. For example, to find the seed for\r\nthe domain xyinotlgjm.com :\r\n$ ./reverse_dga xyinotlgjm\r\nsearching xyinotlgjm\r\n-\u003e found seed 60000\r\nDomains\r\nThis file (about 9MB) lists the first DGA domain for seeds up to 600`000, i.e., roughly ten minutes after system\r\nreboot. The domains from sandboxes should fall within this time range.\r\nSource: https://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nhttps://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/\r\nPage 10 of 10",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://www.johannesbader.ch/2016/01/the-dga-in-alureon-dnschanger/"
	],
	"report_names": [
		"the-dga-in-alureon-dnschanger"
	],
	"threat_actors": [],
	"ts_created_at": 1775791281,
	"ts_updated_at": 1775826736,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/63901227d95963695c5cb3e18858f3b431fcfae9.pdf",
		"text": "https://archive.orkl.eu/63901227d95963695c5cb3e18858f3b431fcfae9.txt",
		"img": "https://archive.orkl.eu/63901227d95963695c5cb3e18858f3b431fcfae9.jpg"
	}
}