{
	"id": "6eff95ed-3758-42b0-884a-82c0adedfac3",
	"created_at": "2026-04-06T00:12:46.472837Z",
	"updated_at": "2026-04-10T03:22:50.418363Z",
	"deleted_at": null,
	"sha1_hash": "aca5bc98ea3e936d75b09162dc4ff52bb4e3308a",
	"title": "Dissecting Emotet’s network communication protocol • Raashid Bhat",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 590695,
	"plain_text": "Dissecting Emotet’s network communication protocol • Raashid\r\nBhat\r\nPublished: 2019-04-22 · Archived: 2026-04-05 18:47:17 UTC\r\nApril 22, 2019\r\nDissecting Emotet’s network communication protocol\r\nRequest Packet format\r\nCommunication protocol for any malware lies at the core of its functionality . It is the essential way for any\r\nmalware to communicate and receive further commands . Emotet has a complex communication format .\r\nIts peculiarities are the way the protocol is built and sent across the network . Knowing internal details of its\r\ncommunication format is essential to keep tabs on it . In this post we are going to analyze Emotet communication\r\nformat .\r\nwe will be skipping the unpacking and reconstruction part , as it is irrelevant to this topic of discussion .\r\nIn this post , we will be specifically looking for areas of interest in the binary , there will be some parts that are\r\nanalyzed preemptively .\r\nAn unpacked emotet sample has around ~100 functions , as populated by IDA . Going through each of them to\r\nlook for communication subroutines would be “A short in the dark” . The easiest way would be to look for\r\nnetwork API calls and xrefs would sort out most of the dirty work for us\r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 1 of 11\n\nLuckily in emotet., there is only one xref to this API call , which perhaps would be the subroutine where the\r\ncommunication to c2 server happens . This subroutine receives an encrypted and compressed packet with\r\nparameters like c2 server, port and sends it out . Xrefing back few subroutines would land us to the place where\r\nthe packet is formulated . For comprehension , let’s name this subroutine as ConnectAndSend\r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 2 of 11\n\nTracking back xfrefs , we finally reach to the subroutine where the packet is generated . And , based on API calls\r\nand variables used , we can easily name few local variables and subroutines used , for example Botid, crc32, etc\r\nBased on how stack variable are set , we get an idea that a struct is formulated . The definition of the structure\r\nwould be as following\r\nstruct Emotet_BotInfo\r\n{\r\n DWORD Uptime;\r\n BYTE *BotID;\r\n DWORD BotIDLen;\r\n DWORD MajMinOSversion;\r\n DWORD TermSessID;\r\n DWORD Crc32HashBinary;\r\n BYTE *ProcList;\r\n DWORD ProlistLen;\r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 3 of 11\n\nDWORD PluginsInstalled[];\r\n DWORD PluginsLen;\r\n};\r\nUptime - Measure of uptime of the infection\r\nBotID - Botnet Identifier (unique per infection)\r\nBotIDLen - Length of BotID\r\nMajMinOSversion *- Operating system identifier\r\n*TerminalSessID - Terminal Session ID\r\nCrc32HashBinary - CRC32 hash of binary\r\nProcList - List of running processes ( comma segregated )\r\nPluginsInstalled - Array of DWORD consisting of MODID’s of plugins installed\r\nThis structure is passed on to a function that calculates total round size based on some bit shifts . This shifting\r\ngives us a clue about the format of the packet . Lets look at these patterns\r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 4 of 11\n\nTranslating it to a code snippet would roughly be equivalent to\r\ntowrite = number \u0026 x7f\r\nnumber \u003e\u003e= 7\r\nThis code encodes an integer to LEB128 or Little Endian Base 128 format (VARINT). And one of the serialized\r\nbuffer formats that support it is the google protobuf format , this clue again makes the reversing equation easy for\r\nus . Some old emotet analysis blogs support our assumption . \r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 5 of 11\n\nEmotet has two packets one being encapsulated in the other . The inner layer lets call it base packet. \r\nBase packet\r\nfundamentally is a group of entries with metadata information . Metadata includes type of data and an index\r\nnumber particular to the entry . Entries have a simple structure , but varies according to the type of entry\r\nStruct EmotetEntry\r\n{\r\n VARINT ULEB128_EntryLength ;\r\n BYTE Data[ULEB128_EntryLength];\r\n}\r\nEmotet’s base packet has three type of data entries, and are marked by numbers in the metadata\r\nType of element and type of data entry is specified in the metadata field\r\nso, the complete definition of base packet would be something like this\r\nstruct BaseEmotetPacket\r\n{\r\n BYTE MetaData\r\n Struct EmotetEntry\r\n {\r\n VARINT ULEB128_EntryLength ;\r\n BYTE Data[ULEB128_EntryLength];\r\n }\r\n}[n];\r\nMetaData is a bitfield data type , which consists of\r\n**0-3 bits - Type of data field **\r\n**3-7 bits - Index Number of Data field **\r\nWhere index is a incremental number and type is an enum\r\nEnum Type\r\n{\r\n Type 5 : Machine dependent endian WORD size integer\r\n Type 2 : Buffer Struct { VARINT ULEN128_Size, BYTE data[ULEN128_Size];\r\n Type 0 : ULEN128 encoded variant\r\n }\r\nThe code to add an entry in base packet can be defined in python as\r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 6 of 11\n\ndef AppendElement(protoBuf, type, value, itemNum):\r\n protoBuf = protoBuf + struct.pack(\"B\", ( (itemNum \u003c\u003c 3) | type ) \u0026 0xff)\r\n if type == 5: #DWORD Copy 32bit integer as it is\r\n return protoBuf + struct.pack(\"I\", value)\r\n if type == 2: # Memory Buffer struct {VARINT ULEB128_Size, void * buf}\r\n return protoBuf + encode(len(value)) + value\r\n if type == 0: # encode DWORD in ULEB128\r\n return protoBuf + encode(value)\r\nLater on , base packet is compressed and further more encapsulated in another packet\r\nThe definition of the final packet is almost the same as the base packet , but the only subtle difference is that it\r\nonly has one field , which is the encapsulated base packet\r\nstruct FinalPacket\r\n{\r\n BYTE MetaData;\r\n Struct BaseEmotetPacket BasePacket;\r\n};\r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 7 of 11\n\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 8 of 11\n\nThis data is sent to c2 server immediately after encrypting the final packet .\r\nResponse Packet format\r\nResponse data from c2 from received is decompressed , and the plain text data is supplied to a subroutine for\r\ndeserialization .\r\nThe response data field uses the same variable length integer encoding and is almost structured in the same way .\r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 9 of 11\n\nResponse format is complex and tentative for each type of request and bot configuration .\r\nSimilarly like base request packet, this structure consists of a type and number bitfield , which determines which\r\ntype of data field is it . In case of response , it has three of them\r\n1 : Main module packet *\r\n*2 : Binary update data\r\n3 : Deliverables data\r\nstruct EmotetResponse\r\n{\r\n unsigned char Number : 4;\r\n unsigned char Type : 4;\r\n unsigned char ModID; // Each module has modid ( 0 for main module)\r\n unsigned char Number : 4;\r\n unsigned char Type : 4;\r\n VARINT UpdateBinLen; // Varint Type ULEB128 Encoded\r\n BYTE BinaryBlob[UpdateBinLen]; // Update Binary PE FILE\r\n unsigned char Number : 4;\r\n unsigned char Type : 4;\r\n VARINT deliverablesLen;\r\n struct deliverables_\r\n {\r\n unsigned char Number : 4;\r\n unsigned char Type : 4;\r\n unsigned char ModID; // PluginModid\r\n unsigned char ExeFlag; // \"\" 3 - Plugin , 2 - WriteElevatedExecute, 1 - writeExecute\"\"\"\r\n VARINT PluginLen; // Varint Type ULEB128 Encoded\r\n BYTE PluginBinaryBlob[PluginLen]; // Update Binary PE FILE\r\n }\r\n}\r\n32\r\nKudos\r\n32\r\nKudos\r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 10 of 11\n\nSource: https://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nhttps://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol\r\nPage 11 of 11",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"ETDA",
		"Malpedia"
	],
	"references": [
		"https://int0xcc.svbtle.com/dissecting-emotet-s-network-communication-protocol"
	],
	"report_names": [
		"dissecting-emotet-s-network-communication-protocol"
	],
	"threat_actors": [
		{
			"id": "b740943a-da51-4133-855b-df29822531ea",
			"created_at": "2022-10-25T15:50:23.604126Z",
			"updated_at": "2026-04-10T02:00:05.259593Z",
			"deleted_at": null,
			"main_name": "Equation",
			"aliases": [
				"Equation"
			],
			"source_name": "MITRE:Equation",
			"tools": null,
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434366,
	"ts_updated_at": 1775791370,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/aca5bc98ea3e936d75b09162dc4ff52bb4e3308a.pdf",
		"text": "https://archive.orkl.eu/aca5bc98ea3e936d75b09162dc4ff52bb4e3308a.txt",
		"img": "https://archive.orkl.eu/aca5bc98ea3e936d75b09162dc4ff52bb4e3308a.jpg"
	}
}