{
	"id": "b7485100-fea3-4693-a271-db89462a506d",
	"created_at": "2026-04-06T00:10:06.882348Z",
	"updated_at": "2026-04-10T03:22:08.874988Z",
	"deleted_at": null,
	"sha1_hash": "1fac46edcc5a4fb403cd23cb462b57a79db925f0",
	"title": "Emotet Command and Control Case Study",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1521879,
	"plain_text": "Emotet Command and Control Case Study\r\nBy Chris Navarrete, Yanhui Jia\r\nPublished: 2021-04-09 · Archived: 2026-04-05 13:13:20 UTC\r\nExecutive Summary\r\nOn March 8, 2021, Unit 42 published “Attack Chain Overview: Emotet in December 2020 and January 2021.”\r\nBased on that analysis, the updated version of Emotet talks to different command and control (C2) servers for data\r\nexfiltration or to implement further attacks. We observed attackers taking advantage of a sophisticated evasion\r\ntechnique and encryption algorithm to communicate with C2 servers in order to probe the victim's network\r\nenvironment and processes, allowing attackers to steal a user’s sensitive information or drop a new payload.\r\nIn this blog, we provide a step-by-step technical analysis, beginning from where the main logic starts, covering the\r\nencryption mechanisms and ending when the C2 data is exfiltrated through HTTP protocol to the C2 server.\r\nPalo Alto Networks Next-Generation Firewall customers are protected from Emotet with Threat Prevention and\r\nWildFire security subscriptions. Customers are also protected with Cortex XDR.\r\nTechnical Analysis\r\nThis analysis will use custom function names (i.e., collect_process_data) that replace the regular IDA Pro's\r\nfunction format (i.e., sub_*) and will assume a 32-bit (x86) DLL executable with an image base address\r\nof 0x2E1000. The user can refer to the following image that contains function offsets, names and custom names\r\nfor easy reference.\r\nNOTE: Sub-functions used are not listed, since these can be easily located from the presented function offsets.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 1 of 13\n\nFigure 1. IDA’s functions reference information.\r\nThe present analysis begins from the entry point function c2_logic_ep (sub_2E2C63).\r\nEncryption API Functions\r\nThis malware uses two main functions: encryption_functions_one and  encryption_functions_two. Both functions\r\nmakes use of Microsoft's Base Cryptography (CryptoAPI). The following section includes the properties used and\r\nactions performed by these crypto functions during the malware execution.\r\nCryptAcquireContextW - Uses a PROV_DH_SCHANNEL as provider type (0x18).\r\nThe CRYPT_VERIFYCONTEXT and CRYPT_SILENT flags are combined with a bitwise-OR\r\noperation (0xf0000040) to make sure that no user interface (UI) is displayed to the user.\r\nCryptDecodeObjectEx - Uses a message encoding\r\ntype X509_ASN_ENCODING and PKCS_7_ASN_ENCODING that are combined with a bitwise-OR\r\noperation (0x10001), a structure type X509_BASIC_CONSTRAINTS (0x13) and a total of 0x6a bytes\r\nthat are going to be decoded.\r\nCryptImportKey - Imports a key-blob of 0x74 in size (bytes) and type PUBLICKEYBLOB (0x6) with\r\na CUR_BLOB_VERSION (0x2) version.\r\nCryptGenKey - Uses an ALG_ID value that is set to CALG_AES_128 (0x0000660e) and generates a 128-\r\nbit AES session key.\r\nCryptCreateHash - Uses an ALG_ID value that is set to CALG_SHA (0x00008004), which, as the the\r\nname suggests, sets the SHA hashing algorithm.\r\nCryptDuplicateHash - Receives a handle to the hash to be duplicated.\r\nCryptEncrypt - This function receives two main parameters: a handle to the encryption key generated by\r\nthe CryptGenKey function and a handle to a hash object generated by CryptCreateHash. This value will be\r\nused after encryption by calling the CryptEncrypt function and passing as a parameter the pointer to the C2\r\ndata.\r\nCryptExportKey - Uses a SIMPLEBLOB (0x1) type and CRYPT_OAEP (0x00000040) as a flag. The\r\npointer to the buffer where the key-blob is exported is part of the malware's C2 data.\r\nCryptGetHashParam - As in the case of the CryptExportKey function, the destination pointer is part of the\r\nmalware's C2 data.\r\nCryptDestroyHash - As its name implies, destroys the given hash.\r\nMachine ID Generation and Length Checking\r\nThe generate_machine_id function, as its name states, is in charge of generating a machine identifier for the\r\ninfected computer. The method used to generate the machine identifier is by making a call to\r\nthe _snprintf function, which uses the format string %s_%08X to concatenate the value generated\r\nby GetComputerNameA and GetVolumeInformationW. In the particular case of the test machine used in this\r\nanalysis, the resulting value is ANANDAXPC_58F2C41B.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 2 of 13\n\nFigure 2. Function call to generate a machine identifier (machine-ID value).\r\nOnce the machine-id is generated, a length-check verification is also generated. This is achieved by calling\r\nthe \"lstrlen\" function wrapper gen_machine_id_length and passing as a parameter the returning value from the\r\nprevious function call. For the case of the testing machine, the resulting length was \"12\", and such value will\r\nreside in a particular stack variable since it will be used as part of the C2 data. Subsequently, a new function call is\r\nmade to the write_GoR function. Its original purpose is unknown, however, based on the analysis and how the\r\nreturning value (0x16F87C) is used. It’s presumably a delimiter, since it is located at the end of the C2 data.\r\nFigure 3 . Function call to generate C2 data delimiter.\r\nOperating System Data Collection\r\nPart of the exfiltrated data also includes OS information, and this is achieved by calling the collect_os_data\r\nfunction.\r\nFigure 4. Function call to collect OS information.\r\nThis function makes calls to RtlGetVersion, which stores data inside of an OSVERSIONINFOW structure,\r\nand GetNativeSystemInfo performs the same by saving its data inside a SYSTEM_INFO structure.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 3 of 13\n\nFigure 5. OSVERSIONINFOW and SYSTEM_INFO structures filled up by API calls.\r\nOnce the data structures are populated, specific data is fetched by the instructions located at these\r\noffsets: 0x2EC3DB (Ret value), 0x2EC440 (MajorVersion), 0x2EC3DB, 0x2EC3D0 (MinorVersion)\r\nand 0x2EC45A (Architecture|PROCESSOR_ARCHITECTURE_INTEL).\r\nThe returning value is computed by adding and multiplying against fixed\r\nvalues: MajorVersion, MinorVersion, Architecture and the returning value (0x1) of the RtlGetNtProductType call,\r\nwhich is a symbolic constant (NtProductWinNT) of the NT_PRODUCT_TYPE enumeration data type. The\r\nfollowing Python code simulates the logic that generates such value.\r\nFigure 6. Python proof of concept (PoC) emulating the OS data generation algorithm.\r\nRemote Desktop Services Session Information Collection\r\nMore calls are performed, including the one to GetCurrentProcessId, which retrieves the process identifier for the\r\ncurrent process, and the returning value is passed to the ProcessIdToSessionId function as parameter. According to\r\nthe MSDN description, the ProcessIdToSessionId function \"retrieves the Remote Desktop Services session\r\nassociated with a specified process.\" The returning value of this function indicates the Terminal Services session\r\nthe current process is running on.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 4 of 13\n\nFigure 7. Function call to retrieve the Terminal Service session identifier.\r\nProcess Scanning and C2 Data Collection\r\nThis function collects active running processes on the system by the execution of the traditional method of calling\r\nthe CreateToolhelp32Snapshot, Process32FirstW, GetCurrentProcessId and Process32NextW functions. Before\r\nentering to this function, the instruction at offset 0x2E4715 loads the address of a local variable in the\r\nEAX register and pushed onto the stack. This variable will contain a pointer generated by a call to the\r\nRtAllocateHeap function that will eventually receive the process data information.\r\nFigure 8. Function call to generate and initialize values with process data.\r\nThis function also makes calls to the sub-function named copy_collected_data_parent. During its execution, it\r\ngenerates a new memory section made by a call to the RtlAllocateHeap function, and some subsequent calls to\r\nthe memcpy wrapper function to copy collected C2 data to the new allocated section.\r\nFigure 9. Function call that collects and initializes values with C2 data.\r\nThe next function to call is HTTP_LAUNCHER, which contains sub-functions that provide web capability,\r\namong other tasks. At this point in time, the variables are initialized with the corresponding return values from the\r\npreviously executed functions. The following ASCII dump shows the variable addresses, the related data and\r\ninformation about which function, or instruction offset, provided the given data.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 5 of 13\n\nFigure 10. Stack-snapshot including collected data and the data generation functions references.\r\nThe next step is a call to the c2_data_write function, which calls the write_collected_data sub-function and passes\r\nas parameters two values:\r\n1. A pointer to the C2 data (0x2EAC3E).\r\n2. The returning value (address) of a new memory allocation generated by a call to\r\nthe RtlAllocateHeap function located at offset 0x2F989B.\r\nThis newly generated data passes through an algorithm, which in addition to writing (at offset 0x2FA830) also\r\nmodifies certain bytes (at offset 0x2FA6DE) of the C2 data, especially some filename extensions.\r\nFigure 11. Function calls that write collected data in memory.\r\nOnce the data is collected, a call to write_c2_data_zero is made, which will allocate additional memory by calling\r\nthe AllocateHeap (0x2E99DC) function. This function will eventually be called twice, and it will call more sub-functions in where the instructions at offset 0x2F362A of the write_c2_data_one function will generate two\r\nDWORD values: 0x1, which is a fixed value, and 0x132, which is the length of the C2 data. The next step is a call\r\nto copy_c2_data (a wrapper to memcpy at offset 0x2F794C) function, which copies the C2 data to a new location\r\nnext to the two values mentioned earlier.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 6 of 13\n\nFigure 12. Function calls that perform intermediary C2 data copying.\r\nThe next sequential function execution is a call to CryptDuplicateHash. After that, a call to copy_binary_data is\r\nmade, which makes a final C2 data copy to a new memory allocation. This location will contain the last C2\r\ndata before being encrypted by the CryptEncrypt function, as will be performed in subsequent steps.\r\nFigure 13. Function calls that make a final copy of unencrypted C2 data.\r\nThe following picture shows the buffer with its related values and description highlighted with different colors for\r\neasy reference.\r\nFigure 14. In-memory byte offsets and sizes, including individual descriptions.\r\nThe next call is to the CryptEncrypt function wrapper, which will reach the real API function via an indirect call\r\nto the EAX register located at offset 0x2F0AD4.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 7 of 13\n\nFigure 15. Function call to CryptEncrypt to encrypt C2 data.\r\nThe following picture shows the before and after encryption status of the C2 data.\r\nFigure 16. Before and after encryption status of C2 data.\r\nOnce the C2 data is encrypted, the following step is to export the current encryption key by calling\r\nthe CryptExportKey function at offset 0x2EFF2C.\r\nFigure 17. Function call to CryptExportKey wrapper.\r\nAfter exporting the key, a loop located at offset 0x2EFF41 has an instruction at offset 0x2EFF43 that writes into\r\nC2 data 0x60 bytes of the exported key.\r\nFigure 18. Write loop to populate exported crypto key data.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 8 of 13\n\nNow, a call to the API function CryptGetHashParam is made with a parameter that contains a pointer\r\nto CryptDestroyHash that will write 20 bytes of the generated hash into the C2 data.\r\nFigure 19. Function call to CryptGetHashParam.\r\nThe following image shows how the final C2 data is stored in memory.\r\nFigure 20. In-memory byte inclusion of Exported Key, Hash Value and Encrypted C2 data.\r\nC2 Exfiltration: HTTP Post Request Generation\r\nAt this stage, the C2 data containing Exported Key, Hash Value, and Encrypted C2 data are done. Thus, the last\r\nstage is the completion of the data exfiltration. The following steps prepare the required data (e.g., IP address,\r\nHTTP form structure and values, etc.).\r\nFigure 21. Function calls to fulfill the first half of HTTP requirements before data exfiltration.\r\nAt this point, subsequent function calls are performed to generate the binary data that will be included within the\r\nHTTP form. The following section will describe the detailed steps that lead to such encrypted data and its\r\nexfiltration to the C2 server.\r\nThis step consists of copying the C2 data (bytes) to the web form. This is achieved by the execution of the\r\ncopy_c2_data sub-function. This function will generate a binary MIME attachment of the \"application/octet-stream\" content type with the input data to be suitable for binary transfer.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 9 of 13\n\nFigure 22. Function calls to copy binary data to the web form.\r\nAt this stage, the final payload is preparing the environment to submit information to the C2 server. To do so, it\r\nexecutes function calls to retrieve the required data to finally perform the HTTP request.\r\nFigure 23. Function calls to fulfill the second half of HTTP requirements before data exfiltration.\r\nAs can be seen in the function call list, the HttpSendRequestW() API function is used to send the data to the\r\nserver. This function allows the sender to exceed the amount of data that is normally sent by HTTP clients.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 10 of 13\n\nFigure 24. Wireshark capture showing POST request including Exported Key, Hash Value and\r\nEncrypted C2 data.\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 11 of 13\n\nConclusion\r\nEmotet was active in the wild for several years before a coordinated law enforcement campaign shut down its\r\ninfrastructure in late January 2021. Its attack tactics and techniques had evolved over time, and the attack chain is\r\nvery mature and sophisticated, which makes it a good case study for security researchers. This research provides\r\nan example of Emotet C2 communication, including C2 server IP selection and data encryption, so we can better\r\nunderstand how Emotet malware utilizes this sophisticated technique to evade security production detection.\r\nPalo Alto Networks customers are protected from this kind of attack by the following:\r\n1. Threat Prevention signatures 21201, 21185 and 21167 identify HTTP C2 requests attempting to download\r\nthe new payload and post sensitive info.\r\n2. WildFire and Cortex XDR identify and block Emotet and its droppers.\r\nIndicators of Compromise\r\nSamples\r\n2cb81a1a59df4a4fd222fbcb946db3d653185c2e79cf4d3365b430b1988d485f\r\nDroppers\r\nbbb9c1b98ec307a5e84095cf491f7475964a698c90b48a9d43490a05b6ba0a79\r\nbd1e56637bd0fe213c2c58d6bd4e6e3693416ec2f90ea29f0c68a0b91815d91a\r\nURLs\r\nhttp://allcannabismeds[.]com/unraid-map/ZZm6/\r\nhttp://giannaspsychicstudio[.]com/cgi-bin/PP/\r\nhttp://ienglishabc[.]com/cow/JH/\r\nhttp://abrillofurniture[.]com/bph-nclex-wygq4/a7nBfhs/\r\nhttps://etkindedektiflik[.]com/pcie-speed/U/\r\nhttps://vstsample[.]com/wp-includes/7eXeI/\r\nhttp://ezi-pos[.]com/categoryl/x/\r\nIPs\r\n5.2.136[.]90\r\n161.49.84[.]2\r\n70.32.89[.]105\r\n190.247.139[.]101\r\n138.197.99[.]250\r\n152.170.79[.]100\r\n190.55.186[.]229\r\n132.248.38[.]158\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 12 of 13\n\n110.172.180[.]180\r\n37.46.129[.]215\r\n203.157.152[.]9\r\n157.245.145[.]87\r\nSource: https://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nhttps://unit42.paloaltonetworks.com/emotet-command-and-control/\r\nPage 13 of 13",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia",
		"ETDA"
	],
	"references": [
		"https://unit42.paloaltonetworks.com/emotet-command-and-control/"
	],
	"report_names": [
		"emotet-command-and-control"
	],
	"threat_actors": [],
	"ts_created_at": 1775434206,
	"ts_updated_at": 1775791328,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/1fac46edcc5a4fb403cd23cb462b57a79db925f0.pdf",
		"text": "https://archive.orkl.eu/1fac46edcc5a4fb403cd23cb462b57a79db925f0.txt",
		"img": "https://archive.orkl.eu/1fac46edcc5a4fb403cd23cb462b57a79db925f0.jpg"
	}
}