{
	"id": "0eca447a-1a13-4464-aaed-6091d48a3d75",
	"created_at": "2026-04-06T00:19:58.885212Z",
	"updated_at": "2026-04-10T03:21:13.433018Z",
	"deleted_at": null,
	"sha1_hash": "c028e4266d59d61d9e0a85bd74c86de9dea12c5a",
	"title": "A Look into PlugX Kernel driver",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 541946,
	"plain_text": "A Look into PlugX Kernel driver\r\nBy Mahmoud Zohdy\r\nPublished: 2024-01-21 · Archived: 2026-04-05 20:02:18 UTC\r\nIn this blog I will talk about the Signed kernel driver that is used in a recent PlugX attack, the signed kernel\r\ndrivers that were found on Virus Total are signed through Windows Hardware compatibility program (WHCP)\r\nand Sharp Brilliance Communication Technology Co., Ltd..\r\nIn summary the kernel driver act as user-mode loader which decrypt a 32-bit user-mode PE file and inject it inside\r\nSvchost.exe as child process for services.exe.\r\nin this blog i focused my analysis on the sample “ab7ebc82930e69621d9bccb6698928f4a3719d29”\r\nDriver Analysis:\r\nthe driver first registers a mini-filter callback functions and create a communication port with the name\r\n“\\DtSfProtect{A71A0369-D7CA-4d4f-9EEE-01F8FE53C0D3}” to be able to communicate with the user-mode\r\nagent, the driver allows only for one user-agent to connect and accept connection from any process, and the port\r\ncommunication was not used by the user-client.\r\nFigure 1: Register Mini-Filter Driver and create Port Communication.\r\nFigure 2: Port Connection CallBack function.\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 1 of 13\n\nAlso, the registered filesystem callback pre-operation and post-operation does not do any monitor/protection and\r\njust return.\r\nFigure 3: FileSystem Pre-Operation.\r\nThen it creates Process Object Notifications for protection it monitors any attempt to open the user-mode\r\nprocess and forbids any attempt to access it from kernel drivers and user mode process, so the user-mode\r\ncomponent can not be terminated either from user-mode and from kernel mode.\r\nFigure 4: Register Process object Callback.\r\nFigure 5: Pre-Process Callback Function.\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 2 of 13\n\nAfter those initializations it creates a thread that will be responsible for resolving all the needed functions address\r\nand starting the main user-mode component.\r\nIt first tries to check if services.exe process started or not, it do that by using the NtQuerySystemInformation\r\nAPI to get information about the running process, and if services.exe still not running it will go in infinite loop\r\nuntil it starts before continue its operation.\r\nFigure 6: Check if Services.exe process running.\r\nFigure 7: Loop untill Services.exe start.\r\nThen it reads configuration from the registry key “\\Registry\\Machine\\SOFTWARE\\DtSft\\d1” and subkeys\r\n“M1” and the data is compared to the current system time, and based on the data in that registry “76 da 34 01” if\r\nthe current time is after “Wednesday, March 9, 2033 8:07:29 PM” the driver will not continue operation and\r\nreturn and will not start the user-mode component\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 3 of 13\n\nFigure 8: Read Attack time from registry.\r\nFigure 9: check if current time before configured time.\r\nThen the driver will read the decryption key from the registry subkeys “M3” under the key\r\n“\\Registry\\Machine\\SOFTWARE\\DtSft\\d1*, the decryption key will be used to decrypt the PE module from the\r\nregistry\r\nDecryption_Key= “ec,a4,00,c4”\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 4 of 13\n\nFigure 10: Read Decryption Key from Registry.\r\nAfter that the driver will resolve the needed API functions from the windows kernel and from ntdll.dll and\r\nkernel32.dll the driver keeps the API information in the structure API_Info and it will do the following steps to\r\nfill in the structure fields:\r\nFor ntdll.dll and kernel APIs\r\n1. Locate the KeServiceDescriptorTable (SSDT Table)\r\n2. Read ntdll.dll from hard disk.\r\n3. Manually Map ntdll.dll DLL to kernel memory.\r\n4. Search the export address table for the API it needs using the field “API_Info.API_Name” from the\r\nAPI struct.\r\n5. Extract the value that will be moved inside the EAX register before the sysenter instruction. It will\r\nbe used as index in the SSDT table to resolve the Kernel API.\r\n6. Fill in the rest of the fields in the struct (kernel address, user-mode address, EAX value)\r\nFor kernel32.dll APIs\r\n1. Read kernel32.dll from hard disk.\r\n2. Manually Map kernel32.dll DLL to kernel memory.\r\n3. Search the export address table for the API it needs using the field “API_Info.API_Name” from the\r\nAPI struct.\r\n4. Fill in the user-mode address field in the struct (the rest of the fields will be null values)\r\ntypedef Struct API_Info{\r\nDWORD64 Kernel_API_Address; // will be null when used in resolving address in kernel32.dll\r\nDWORD64 User_API_Address;\r\nDWORD64 EAX_Value; //index of the function in the SSDT table, will be null in case kern\r\nchar API_Name[80h];\r\n}\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 5 of 13\n\nFigure 11: Resolving API Address.\r\nLocate the SSDT table:\r\nTo resolve the kernel API address the driver first locate the SSDT table, it does so by scanning the nt!ZwClose\r\nFunction for the byte “0xE9” which is a JUMP instruction to “nt!KiServiceInternal”.\r\nFigure 12: Locating the nt!KiServiceInternal function.\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 6 of 13\n\nFigure 13: Locating the nt!KiServiceInternal function.\r\nAfter locating “nt!KiServiceInternal” code the driver will search in it for the pattern “0x8D4C” which is “lea\r\nr11,[nt!KiSystemServiceStart]” to locate the address of the function “nt!KiSystemServiceStart”\r\nFigure 14: Locating the nt!KiSystemServiceStart function.\r\nThen search for the pattern “0x4c8d15” to locate the address of “lea r10,[nt!KeServiceDescriptorTable]” and\r\nfrom there it will have the address of KeServiceDescriptorTable to continue the operation to resolve Kernel API\r\naddress.\r\nFigure 15: Locating the KeServiceDescriptorTable Address.\r\nAfter locating the SSDT table it will read the DLLs from disk and map it to memory to fill in the API_Info\r\nstructure.\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 7 of 13\n\nFigure 16: Reading and mapping ntdll.dll to kernel memory.\r\nFigure 17: Filling the API_Info structure.\r\nalso the driver will resolve the functions address twice once to get the kernel API, and the second time to get the\r\nuser-mode API from ntdll.dll and kernel32.dll, and the reason for that is because the services.exe process might\r\nnot be fully initialized and the ntdll.dll and kernel32.dll DLLs might not be fully loaded yet.\r\nFigure 18: Get Kernel API Address.\r\nFigure 19: Get User API Address.\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 8 of 13\n\nThen the driver will read the User-Mode component from registry subkeys “M2” under registry key\r\n“\\Registry\\Machine\\SOFTWARE\\DtSft\\d1” and then XOR decrypt it.\r\nFigure 20: Read User-mode component and decrypt it.\r\nThen it confirms that the user-mode component is a 32-bit file and if not it will not start it, after that it will allocate\r\nmemory and copy a ShellCode function which will be injected in services.exe to start the main user-component\r\nafter that it will do a sequence of NtWriteVirtualMemory calls to write the ShellCode, path to Svchost.exe file\r\nand the User-mode component to the services.exe process.\r\nFigure 21: Allocate Memory for the shellcode.\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 9 of 13\n\nFigure 22: write the shellcode and svchost path to services.exe process.\r\nFigure 23: change permission of memory to be able to write to it.\r\nAnd to make the ShellCode gets executed it will hook the Ntdll!NtClose to make it jump to the ShellCode after\r\nthe ShellCode gets execute it will restore the Ntdll!NtClose Function to its original state and make the process\r\ncontinue operation and normal\r\nFigure 24: Hook Ntdll!NtClose to make the shellcode execute.\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 10 of 13\n\nFigure 25: Hook Ntdll!NtClose to make the shellcode execute.\r\nUser-Mode Component\r\nUser-mode component is a simple code that injects another 32-bit PE module in svchost.exe process and monitors\r\nit if it gets terminated it will start it again.\r\nFigure 26: User-Mode Component.\r\nYare Rule:\r\nrule PlugX{\r\n meta:\r\nauthor = \"Mahmoud Zohdy\"\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 11 of 13\n\ndate_created = \"2024-01-20\"\r\ndescription = \"Kernel driver used in recent PlugX attack\"\r\nstrings:\r\n$string0 = \"\\\\SystemRoot\\\\system32\\\\drivers\\\\DtSfProtect\" wide ascii\r\n$string1 = \"\\\\DtSfProtect{A71A0369-D7CA-4d4f-9EEE-01F8FE53C0D3}\" wide ascii\r\ncondition:\r\nuint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and any of ( $string* )\r\n}\r\nIOC:\r\nSHA-1 Hash Signer\r\nSigning\r\nDate\r\nProgram Name\r\n4307c1e76e66fb09e52c44b83f12374c320cea0d\r\nMicrosoft\r\nWindows\r\nHardware\r\nCompatibility\r\nPublisher\r\n2023-\r\n03-23\r\n淮南锋川网络科\r\n技有限责任公司\r\n(Huainan\r\nFengchuan\r\nNetwork\r\nTechnology Co.,\r\nLtd.)\r\nb421c7fb5a041b9225e96f9c82b418b5637dd763\r\nSharp Brilliance\r\nCommunication\r\nTechnology Co.,\r\nLtd.\r\n2023-\r\n08-27\r\n43e00adbbc09e4b65f09e81e5bd2b716579a6a61\r\nMicrosoft\r\nWindows\r\nHardware\r\nCompatibility\r\nPublisher\r\n2022-\r\n09-14\r\n大连纵梦网络科\r\n技有限公司\r\n(Dalian\r\nZongmeng\r\nNetwork\r\nTechnology Co.,\r\nLtd.)\r\nab7ebc82930e69621d9bccb6698928f4a3719d29\r\nMicrosoft\r\nWindows\r\nHardware\r\nCompatibility\r\nPublisher\r\n2022-\r\n09-14\r\n大连纵梦网络科\r\n技有限公司\r\n(Dalian\r\nZongmeng\r\nNetwork\r\nTechnology Co.,\r\nLtd.)\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 12 of 13\n\nSHA-1 Hash Signer\r\nSigning\r\nDate\r\nProgram Name\r\n7e836dadc2e149a0b758c7e22c989cbfcce18684\r\nMicrosoft\r\nWindows\r\nHardware\r\nCompatibility\r\nPublisher\r\n2022-\r\n08-17\r\n大连纵梦网络科\r\n技有限公司\r\n(Dalian\r\nZongmeng\r\nNetwork\r\nTechnology Co.,\r\nLtd.)\r\n0dd72b3b0b4e9f419d62a4cc7fa0a7d161468a5e\r\nMicrosoft\r\nWindows\r\nHardware\r\nCompatibility\r\nPublisher\r\n2023-\r\n03-22\r\n淮南锋川网络科\r\n技有限责任公司\r\n(Huainan\r\nFengchuan\r\nNetwork\r\nTechnology Co.,\r\nLtd.)\r\n097e32d2d6f27a643281bf98875d15974b1f6d85 N/A N/A\r\n2084dd19a5403a4245f8bad30b55681d373ef638 N/A N/A\r\nc4d4489ee16ee537661760879bd36e0d4ab35d61 N/A N/A\r\nc98b3ce984b81086cea7b406eb3857fd6e724bc8 N/A N/A\r\n7079c000d9d25c02d89f0bae5abfe54136daf912 N/A N/A\r\nc4aa3e66331b96b81bd8758e5abcba121a398886\r\nSharp Brilliance\r\nCommunication\r\nTechnology Co.,\r\nLtd.\r\n2023-\r\n08-23\r\n9883593910917239fc8ff8399e133c8c73b214bc N/A N/A\r\n501114B39A3A6FB40FB5067E3711DC9389F5A802 N/A N/A\r\nSource: https://mahmoudzohdy.github.io/posts/re/plugx/\r\nhttps://mahmoudzohdy.github.io/posts/re/plugx/\r\nPage 13 of 13",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://mahmoudzohdy.github.io/posts/re/plugx/"
	],
	"report_names": [
		"plugx"
	],
	"threat_actors": [],
	"ts_created_at": 1775434798,
	"ts_updated_at": 1775791273,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/c028e4266d59d61d9e0a85bd74c86de9dea12c5a.pdf",
		"text": "https://archive.orkl.eu/c028e4266d59d61d9e0a85bd74c86de9dea12c5a.txt",
		"img": "https://archive.orkl.eu/c028e4266d59d61d9e0a85bd74c86de9dea12c5a.jpg"
	}
}