{
	"id": "84581577-b35e-4931-a18d-151afeec2837",
	"created_at": "2026-04-06T00:18:24.472493Z",
	"updated_at": "2026-04-10T03:24:24.473376Z",
	"deleted_at": null,
	"sha1_hash": "b74c55df6cd7c35b48bcb65a3f2882511b5a30df",
	"title": "Unpacking ICEDID",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 731084,
	"plain_text": "Unpacking ICEDID\r\nBy Cyril François\r\nPublished: 2023-05-04 · Archived: 2026-04-05 21:47:31 UTC\r\nPreamble\r\nICEDID is a malware family discoveredin 2017 by IBM X-force researchers and is associated with the theft of login\r\ncredentials, banking information, and other personal information. ICEDID has always been a prevalent family but achieved\r\neven more growth since EMOTET’s temporary disruption in early 2021. ICEDID has been linked to the distribution of\r\nseveral distinct malware families including DarkVNC and COBALT STRIKE. Regular industry reporting, including\r\nresearch publications like this one, help mitigate this threat.\r\nICEDID is known to pack its payloads using custom file formats and a custom encryption scheme. Following our latest\r\nICEDID research that covers the GZip variant execution chain.\r\nIn this tutorial, we will introduce these tools by unpacking a recent ICEDID sample starting with downloading a copy of the\r\nfake GZip binary:\r\nAnalyzing malware can be dangerous to systems and should only be attempted by experienced professionals in a\r\ncontrolled environment, like an isolated virtual machine or analysis sandbox. Malware can be designed to evade\r\ndetection and infect other systems, so it's important to take all necessary precautions and use specialized tools to\r\nprotect yourself and your systems.\r\n54d064799115f302a66220b3d0920c1158608a5ba76277666c4ac532b53e855f\r\nEnvironment setup\r\nFor this tutorial, we’re using Windows 10 and Python 3.10.\r\nElastic Security Labs is releasing a set of tools to automate the unpacking process and help analysts and the community\r\nrespond to ICEDID.\r\nScript Description Compatibility\r\ndecrypt_file.py Decrypt ICEDID encrypted file\r\nWindows and others (not\r\ntested)\r\ngzip_variant/extract_gzip.py\r\nExtract payloads from ICEDID fake GZip\r\nfile\r\nWindows and others (not\r\ntested)\r\ngzip_variant/extract_payload_from_core.py\r\nExtract and decrypt payloads from the\r\nrebuilt ICEDID core binary\r\nWindows and others (not\r\ntested)\r\ngzip_variant/load_core.py Load and execute core custom PE binary Windows only\r\ngzip_variant/read_configuration.py\r\nRead ICEDID configuration file contained\r\nin the fake GZip\r\nWindows and others (not\r\ntested)\r\nrebuild_pe.py Rebuild a PE from ICEDID custom PE file\r\nWindows and others (not\r\ntested)\r\nIn order to use the tools, clone the Elastic Security Lab release repository and install the nightMARE module.\r\ngit clone https://github.com/elastic/labs-releases\r\ncd labs-release\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 1 of 10\n\npip install .\\nightMARE\\\r\nAll tools in this tutorial use the nightMARE module, this library implements different algorithms we need for\r\nunpacking the various payloads embedded within ICEDID. We’re releasing nightMARE because it is required for\r\nthis ICEDID analysis, but stay tuned - more to come as we continue to develop and mature this framework.\r\nUnpacking the fake GZip\r\nThe ICEDID fake GZip is a file that masquerades as a valid GZip file formatted by encapsulating the real data with a GZip\r\nheader and footer.\r\nGZip header and footer\r\nGZip magic bytes appear in red.\r\nThe GZip header is rendered in green.\r\nThe dummy filename value is blue.\r\nAfter the GZip header is the true data structure, which we describe below.\r\nFakeGzip data structure\r\nWe will use the labs-releases\\tools\\icedid\\gzip-variant\\extract_gzip.py script to unpack this fraudulent GZip.\r\nusage: extract_gzip.py [--help] input output\r\npositional arguments:\r\n input Input file\r\n output Output directory\r\noptions:\r\n -h, --help show this help message and exit\r\nWe'll use extract_gzip.py on the ICEDID sample linked above and store the contents into a folder we created called “\r\nextract ” (you can use any existing output folder).\r\npython extract_gzip.py 54d064799115f302a66220b3d0920c1158608a5ba76277666c4ac532b53e855f extract\r\n============================================================\r\nFake Gzip\r\n============================================================\r\nis_dll: True\r\ncore: UponBetter/license.dat (354282 bytes)\r\nstage_2: lake_x32.tmp (292352 bytes)\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 2 of 10\n\nextract\\configuration.bin\r\nextract\\license.dat\r\nextract\\lake_x32.tmp\r\nThis script returns three individual files consisting of:\r\nThe encrypted configuration file: configuration.bin\r\nThe encrypted core binary: license.dat\r\nThe persistence loader: lake_x32.tmp\r\nFiles extracted from the fake GZip\r\nDecrypting the core binary and configuration files\r\nThe configuration and the core binary we extracted are encrypted using ICEDID’s custom encryption scheme. We can\r\ndecrypt them with the labs-releases\\tools\\icedid\\decrypt_file.py script.\r\nusage: decompress_file.py [--help] input output\r\npositional arguments:\r\n input Input file\r\n output Output file\r\noptions:\r\n -h, --help show this help message and exit\r\nAs depicted here (note that decrypted files can be written to any valid destination):\r\npython .\\decrypt_file.py .\\extract\\license.dat .\\extract\\license.dat.decrypted\r\npython .\\decrypt_file.py .\\extract\\configuration.bin .\\extract\\configuration.bin.decrypted\r\nThe core binary and the configuration are now ready to be processed by additional tools. See the data from the decrypted\r\nconfiguration presented in the following screenshot:\r\nHex view of the decrypted configuration file\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 3 of 10\n\nReading the configuration\r\nThe configuration file format is presented below.\r\nConfiguration file\r\nThe configuration can be read using the labs-releases\\tools\\icedid\\gzip-variant\\read_configuration.py script.\r\nusage: read_configuration.py [--help] input\r\npositional arguments:\r\n input Input file\r\noptions:\r\n -h, --help show this help message and exit\r\nWe’ll use the read_configuration.py script to read the configuration.bin.decrypted file we collected in the previous step.\r\npython .\\gzip-variant\\read_configuration.py .\\extract\\configuration.bin.decrypted\r\n============================================================\r\nConfiguration\r\n============================================================\r\nbotnet_id: 0x3B7D6BA4\r\nauth_var: 0x00000038\r\nuri: /news/\r\ndomains:\r\n alishaskainz.com\r\n villageskaier.com\r\nThis configuration contains two C2 domains:\r\nalishaskainz[.]com\r\nvillageskaier[.]com\r\nFor this sample, the beaconing URI that ICEDID uses is “ /news/ ”.\r\nRebuilding the core binary for static analysis\r\nICEDID uses a custom PE format to obfuscate its payloads thus defeating static or dynamic analysis tools that expect to deal\r\nwith a normal Windows executable. The custom PE file format is described below.\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 4 of 10\n\nCustom PE file format\r\nIf we want to analyze the core binary, for example with IDA Pro, we need to rebuild it into a valid PE. We use the labs-releases\\tools\\icedid\\rebuild_pe.py script.\r\nusage: rebuild_pe.py [--help] [-o OFFSET] input output\r\npositional arguments:\r\n input Input file\r\n output Output reconstructed PE\r\noptions:\r\n -h, --help show this help message and exit\r\n -o OFFSET, --offset OFFSET\r\n Offset to real data, skip possible garbage\r\nHowever, when attempting to use rebuild_pe.py on the decrypted core binary, license.dat.decrypted , we receive the\r\nfollowing error message:\r\npython .\\rebuild_pe.py .\\extract\\license.dat.decrypted .\\extract\\core.bin\r\nTraceback (most recent call last):\r\n File \"rebuild_pe.py\", line 32, in \u003cmodule\u003e\r\n main()\r\n File \"rebuild_pe.py\", line 28, in main\r\n custom_pe.CustomPE(data).to_pe().write(args.output)\r\n File \"nightmare\\malware\\icedid\\custom_pe.py\", line 86, in __init__\r\n raise RuntimeError(\"Failed to parse custom pe\")\r\nRuntimeError: Failed to parse custom pe\r\nThe subtlety here is that the custom PE data doesn’t always start at the beginning of the file. In this case, for example, if we\r\nopen the file in a hexadecimal editor like HxD we can observe a certain amount of garbage bytes before the actual data.\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 5 of 10\n\nPrepended garbage bytes\r\nWe know from our research that the size of the garbage is 129 bytes.\r\nIdentifying garbage size\r\nWith that in mind, we can skip over the garbage bytes and rebuild the core binary using the rebuild_pe.py script using the\r\n“-o 129” parameter. This time we, fortunately, receive no error message. core.bin will be saved to the output directory,\r\nextract in our example.\r\npython .\\rebuild_pe.py .\\extract\\license.dat.decrypted .\\extract\\core.bin -o 129\r\nThe rebuilt PE object is not directly executable but you can statically analyze it using your disassembler of choice.\r\nIDA view of core.bin\r\nWe assigned custom names to the rebuilt binary sections ( .mare{0,1,2,...} ).\r\nRebuilt binary section names\r\nWe want to credit and thank Hasherezade’s work from which we took inspiration to build this tool.\r\nExecuting the core binary (Windows only)\r\nThe core binary can’t be executed without a custom loader that understands ICEDID’s custom PE format as well as the entry\r\npoint function prototype.\r\nFrom our research, we know that the entry point expects a structure we refer to as the context structure, which contains\r\nICEDID core and persistence loader paths with its encrypted configuration. The context structure is described below.\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 6 of 10\n\nContext structure\r\nTo natively execute the core binary we use the labs-releases\\tools\\icedid\\gzip-variant\\load_core.py script, but before using\r\nit we need to create the context.json file that’ll contain all the information needed by this script to build this structure.\r\nFor this sample, we copy the information contained in the fake gzip and we use the path to the encrypted configuration file.\r\nWe’ve included an example at gzip_variant/context.json.example.\r\nExample configuration file\r\nPlease note that “field_0” and “stage_2_export” values have to be found while reversing the sample.\r\nPopulating values from previous research\r\nHere we use values from our previous research as placeholders but we have no guarantee that the sample will work 100%.\r\nFor example, in this sample, we don’t know if the #1 ordinal export is the actual entry point of the persistence loader.\r\nWe also reproduce the first stage behavior by creating the UponBetter directory and moving the license.dat file into it.\r\nlicense.dat in the UponBetter directory\r\nWe execute the labs-releases\\tools\\icedid\\gzip_variant\\load_core.py script using the decrypted core binary:\r\nlicense.dat.decrypted , the context.json file.\r\nWARNING: The binary is going to be loaded/executed natively by this script, Elastic Security Labs does not take\r\nresponsibility for any damage to your system. Please execute only within a safe environment.\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 7 of 10\n\nusage: load_core.py [--help] [-o OFFSET] core_path ctx_path\r\npositional arguments:\r\n core_path Core custom PE\r\n ctx_path Path to json file defining core's context\r\noptions:\r\n -h, --help show this help message and exit\r\n -o OFFSET, --offset OFFSET\r\n Offset to real data, skip possible garbage\r\nBecause we have the same garbage bytes problem as stated in the previous section, we use the “-o 129” parameter to skip\r\nover the garbage bytes.\r\npython .\\gzip-variant\\load_core.py .\\extract\\license.dat.decrypted .\\gzip-variant\\context.example.json -o 129\r\n============================================================\r\nCore Loader\r\n============================================================\r\nBase address: 0x180000000\r\nEntrypoint: 0x180001390\r\nPress a key to call entrypoint...\r\nWhen launched, the script will wait for user input before calling the entry point. We can easily attach a debugger to the\r\nPython process and set a breakpoint on the ICEDID core entry point (in this example 0x180001390 ).\r\nBreakpoint set on the ICEDID core entry point\r\nOnce the key is pressed, we reach the entry point.\r\nICEDID entry point\r\nIf we let the binary execute, we see ICEDID threads being created (indicated in the following screenshot).\r\nICEDID threads being created\r\nUnpacking and rebuilding payloads from the rebuilt core binary\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 8 of 10\n\nFor extracting any of the payloads that are embedded inside the core binary, we will use the labs-releases\\tools\\icedid\\gzip-variant\\extract_payloads_from_core.py script\r\nusage: extract_payloads_from_core.py [--help] input output\r\npositional arguments:\r\n input Input file\r\n output Output directory\r\noptions:\r\n -h, --help show this help message and exit\r\nWe’ll use this script on the rebuilt core binary.\r\npython .\\gzip-variant\\extract_payloads_from_core.py .\\extract\\core.bin core_extract\r\ncore_extract\\browser_hook_payload_0.cpe\r\ncore_extract\\browser_hook_payload_1.cpe\r\nFrom here, we output two binaries corresponding to ICEDID’s payloads for web browser hooking capabilities, however,\r\nthey are still in their custom PE format.\r\nICEDID payloads\r\nBased on our research, we know that browser_hook_payload_0.cpe is the x64 version of the browser hook payload and\r\nbrowser_hook_payload_1.cpe is the x86 version.\r\nBrowser hook payload architectures\r\nIn order to rebuild them, we use the rebuild_pe.py script again, this time there are no garbage bytes to skip over.\r\npython .\\rebuild_pe.py .\\core_extract\\browser_hook_payload_0.cpe .\\core_extract\\browser_hook_payload_0.bin\r\npython .\\rebuild_pe.py .\\core_extract\\browser_hook_payload_1.cpe .\\core_extract\\browser_hook_payload_1.bin\r\nNow we have two PE binaries ( browser_hook_payload_0.bin and browser_hook_payload_1.bin ) we can further\r\nanalyze.\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 9 of 10\n\nPayloads for further analysis\r\nAttentive readers may observe that we have skipped the VNC server unpacking from the core binary, a decision we made\r\nintentionally. We will release it along with other tools in upcoming research, so stay tuned!\r\nConclusion\r\nIn this tutorial we covered ICEDID GZip variant unpacking, starting with the extraction of the fake GZip binary, followed\r\nby the reconstruction of the core binary and unpacking its payloads.\r\nICEDID is constantly evolving, and we are going to continue to monitor major changes and update our tooling along with\r\nour research. Feel free to open an issue or send us a message if something is broken or doesn’t work as expected.\r\nElastic Security Labs is a team of dedicated researchers and security engineers focused on disrupting adversaries through the\r\npublication of detailed detection logic, protections, and applied threat research.\r\nFollow us on @elasticseclabsand visit our research portal for more resources and research.\r\nReferences\r\nThe following were referenced throughout the above research:\r\nhttps://www.elastic.co/pdf/elastic-security-labs-thawing-the-permafrost-of-icedid.pdf\r\nhttps://securityintelligence.com/new-banking-trojan-icedid-discovered-by-ibm-x-force-research/\r\nhttps://www.justice.gov/opa/pr/emotet-botnet-disrupted-international-cyber-operation\r\nhttps://malpedia.caad.fkie.fraunhofer.de/details/win.darkvnc\r\nhttps://www.cybereason.com/blog/threat-analysis-report-all-paths-lead-to-cobalt-strike-icedid-emotet-and-qbot\r\nhttps://github.com/elastic/labs-releases\r\nhttps://github.com/hasherezade/funky_malware_formats/blob/f1cacba4ee347601dceacda04e4de8c699971d29/iced_id_parser/iceid_\r\nhttps://mh-nexus.de/en/hxd/\r\nhttps://hex-rays.com/IDA-pro/\r\nSource: https://www.elastic.co/security-labs/unpacking-icedid\r\nhttps://www.elastic.co/security-labs/unpacking-icedid\r\nPage 10 of 10",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.elastic.co/security-labs/unpacking-icedid"
	],
	"report_names": [
		"unpacking-icedid"
	],
	"threat_actors": [
		{
			"id": "610a7295-3139-4f34-8cec-b3da40add480",
			"created_at": "2023-01-06T13:46:38.608142Z",
			"updated_at": "2026-04-10T02:00:03.03764Z",
			"deleted_at": null,
			"main_name": "Cobalt",
			"aliases": [
				"Cobalt Group",
				"Cobalt Gang",
				"GOLD KINGSWOOD",
				"COBALT SPIDER",
				"G0080",
				"Mule Libra"
			],
			"source_name": "MISPGALAXY:Cobalt",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434704,
	"ts_updated_at": 1775791464,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/b74c55df6cd7c35b48bcb65a3f2882511b5a30df.pdf",
		"text": "https://archive.orkl.eu/b74c55df6cd7c35b48bcb65a3f2882511b5a30df.txt",
		"img": "https://archive.orkl.eu/b74c55df6cd7c35b48bcb65a3f2882511b5a30df.jpg"
	}
}