{
	"id": "21f19f2d-d888-49de-b85b-1bdca8564ab3",
	"created_at": "2026-04-06T00:22:34.273493Z",
	"updated_at": "2026-04-10T03:22:10.331101Z",
	"deleted_at": null,
	"sha1_hash": "4dc055d640cd990abfb0a6837cd46c529f3d5718",
	"title": "Shellcode Detection Using Real-time Kernel Monitoring",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 767086,
	"plain_text": "Shellcode Detection Using Real-time Kernel Monitoring\r\nBy CounterCraft\r\nPublished: 2021-09-07 · Archived: 2026-04-05 18:20:40 UTC\r\nThe tools used to load code into memory have changed a lot recently. I have seen this evolution in shellcode,\r\nmanually mapped images and other types of code execution methods. Sometimes, some of these techniques need\r\nto circumvent mitigations imposed by the operating system, such as bypassing AMSI, disabling writing to the\r\nEvent-Log or evading hooks placed by EDRs in user space to avoid being detected.\r\nA typical use case used by attackers is to patch EDR’s user-space memory hooks or use Direct System Calls to\r\nevade detection by EDRs and then load their code into the memory. This is a scenario where having an extra layer\r\nof kernel detection can be useful to detect shellcode loading in real time.\r\nIt is important to note that nothing in this post is a new technique. We are going to discuss very specific examples,\r\nbut there are many more methods in addition to those listed below.\r\nLet’s discuss what challenges we are going to face in order to detect the shellcode at runtime. To accomplish this\r\nwe will use two different approaches:\r\nHooking some syscalls via hypervisor EPT feature\r\nDetecting shellcodes from kernel callback\r\nRead on for more insights.\r\nSetup\r\nhttps://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nPage 1 of 9\n\nWe are going to use Metasploit as a C2 (Command \u0026 Control ) and the shellcode will be loaded into local process\r\npowershell.exe. We’ve chosen powershell as the process that launches meterpreter because it is a common way to\r\nload shellcodes in the local process.\r\nWe are going to generate a one-liner script to execute in powershell using:\r\nmsfconsole -x \"use exploit/multi/script/web_delivery; set target 2; set lhost 192.168.1.44; set lport 1234; set\r\nThe script generated is:\r\nDetection by Hooking\r\nOnce the powershell script is executed and after unzipping and decoding it, we can capture the loader of the stage\r\n1 of our implant from the memory:\r\nhttps://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nPage 2 of 9\n\nIn the stage 1 shellcode loader code we identify the following steps:\r\n1. Allocate memory in the local process\r\n2. Write the shellcode to the allocated memory\r\n3. Create a thread pointing to the shellcode\r\nThe first step is the easiest to detect. The second step is just a memory copy, so there are no external calls we can\r\nmonitor or filter. The last step calls a system function to spawn the thread, a very common action in any code that\r\ncan be used for detection. However, using ROP, detection is very easily avoided, so in this post I won’t go into\r\nfurther detail.\r\nLet’s take a look at the following piece of code :\r\nWe can see how VirtualAlloc is called with the flags:\r\n0x3000 = MEM_RESERVE | MEM_COMMIT\r\n0x40 = PAGE_EXECUTE_READWRITE (RWX)\r\nhttps://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nPage 3 of 9\n\nIn order to detect suspicious allocations (in our case private memory with RWX permissions), we are going to\r\nneed to place some hooks. Windows does not allow users to place kernel hooks, and uses Patchguard to prevent it.\r\nThat is why we are going to use EPT to hook some syscalls and bypass PatchGuard mitigation. More info\r\nabout EPT here.\r\nOnce we have our driver working we can monitor the Allocations by hooking NtAllocateVirtualMemory. In our\r\nexample, it will be easy to detect since the shellcode loader is allocating RWX memory. As an example we might\r\nuse the following code to detect suspicious allocations:\r\nSo once the loader is executed we see how we detect the shellcode:\r\nBy monitoring NtAllocateVirtualMemory I have seen that there are RWX allocations coming from clr.dll,\r\ngenerating false positives:\r\nAs you see in the screenshot above, VirtualAlloc is being called from clr.dll using MEM_COMMIT with a\r\nspecific memory address so our function called IsSuspiciousAllocation() will work fine and will not report it as\r\nsuspicious allocation. However it is quite easy to circumvent our detection code.\r\nFrom the attacker’s perspective allocating memory regions with RWX permissions is not desirable because, as we\r\nhave seen, it is easily detectable. So we are going to do some more tests improving this aspect to cover some more\r\nhttps://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nPage 4 of 9\n\ncases.\r\nFor the following example, let’s Allocate RW memory, write shellcode to it, and then modify permissions to RX to\r\nexecute it. Modifying the code of the shellcode loader, we would have the following code:\r\nTo detect this new scenario we will need to monitor NtProtectVirtualMemory and check when the permissions\r\nare being changed to executable. So we can use the following code in NtProtectVirtualMemory hook to detect it:\r\nBased on these last two scenarios, we can draw some conclusions:\r\nThe memory allocation phase is the easiest to detect\r\nThe biggest problem with the hooking approach are the false positives coming from crl.dll\r\nhttps://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nPage 5 of 9\n\nKeeping these ideas in mind, we might create another possible enhancement using RWX allocations made by\r\nclr.dll and writing our shellcode there. Therefore, we will not need to allocate memory and avoid being flagged at\r\nthis step. So the new loader code could look something like this:\r\nNote: This above code may not be very reliable because the legitimate process might want to overwrite this buffer\r\nwe are using to store the shellcode without taking into account the new memory permissions, causing an access\r\nviolation exception.\r\nHooking Takeaways\r\n1. We could continue iterating with potential improvements using other APIs such as\r\nCreateFileMapping or NtMapViewOfSection to allocate memory, which would turn into a cat-and-mouse game\r\ntrying to monitor more APIs and attackers trying to find new ways to allocate the memory.\r\n2. The downside of trying to detect shellcode loading processes using hooks is having to deal with possible false\r\npositives. This is not exclusive to the kernel hooking we are using here, the EDRs working in user space need to\r\nface the same problem.\r\n3. It should be noted that this type of detection based on monitoring syscalls with hooks using EPT can only be\r\naccomplished on systems with EPT capabilities.\r\nDetecting Shellcodes from Kernel Using Callbacks\r\nhttps://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nPage 6 of 9\n\nOnce the shellcode loader loads stage1 into memory, we notice that the code is a reverse_tcp that will try to\r\nconnect to the C2 server and load the meterpreter payload. We can access the code directly from github to read it\r\nbetter:\r\nBy looking at the stage1 code we notice how it needs to load the ws2_32.dll library to resolve the memory\r\naddress of the network APIs it will use to communicate with the C2 server:\r\nThe idea of detection is to monitor from the kernel the libraries loaded from userspace and inspect the call stack of\r\nthe thread that has made the syscall to detect if the base address of the call stack elements has been manually\r\nmapped code.\r\nIn order to monitor the libraries loaded in the system, we are going to use PsSetLoadImageNotifyRoutine, which\r\nallows us to install our callback and monitor the images that are loaded in the system using the API including the\r\nlibraries(dll).\r\nhttps://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nPage 7 of 9\n\nTo carry out detection, we can follow these steps:\r\nWalk the call stack to obtain the memory base address of its elements.\r\nObtain MEMORY_BASIC_INFORMATION structure returned by ZwQueryVirtualMemory for each\r\nelement.\r\nDetect private(MEM_PRIVATE) or mapped(MEM_MAPPED) as executable.\r\nIn the image above we can see the detection of a suspicious region at 0x0000017d61ae013b within the call stack\r\nwhich is mapped as private with executable permissions(RWX) trying to load the mswsock.dll library.\r\nIf we examine the instructions within the detected shellcode, we see that it coincides with\r\nmeterpreter reverse_tcp code just after call to WSASocketA:\r\nWe see that the first library loaded by the shellcode is mswsock.dll which is loaded when calling WSASocketA.\r\nWhy didn’t we catch the call to LoadLibraryA(ws2_32.dll) ? Well, in our case this library is already loaded by\r\npowershell.exe by default so the first library that is actually loaded from the shellcode is mswsock.dll which is a\r\ndependency when calling WSASocketA.\r\nThis allows us to see other libraries that are loaded from the shellcode when connecting to the C2 server and\r\ndownloading the payload.\r\nhttps://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nPage 8 of 9\n\nConclusions\r\nThis article was just a quick overview of how to detect shellcodes from the kernel in real time using specific and\r\nnot very advanced examples. As I mentioned earlier in the introduction, none of the techniques we are using here\r\nare anything new, and they can be bypassed with some additional work. These are only some concrete examples of\r\nwhat can be detected from the kernel. However, I think it may be useful for researchers, who develop of offensive\r\nsecurity tools, to consider these methods in addition to EDR userland hooks. There may be specific environments\r\nor situations in which kernel detection could be more effective.\r\nAbout the Author\r\nAlonso Candado is a security software engineer at CounterCraft where he focuses on low level programming and\r\nresearch of new threats. You can find him on LinkedIn.\r\nSource: https://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nhttps://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/\r\nPage 9 of 9",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.countercraftsec.com/blog/post/shellcode-detection-using-realtime-kernel-monitoring/"
	],
	"report_names": [
		"shellcode-detection-using-realtime-kernel-monitoring"
	],
	"threat_actors": [],
	"ts_created_at": 1775434954,
	"ts_updated_at": 1775791330,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/4dc055d640cd990abfb0a6837cd46c529f3d5718.pdf",
		"text": "https://archive.orkl.eu/4dc055d640cd990abfb0a6837cd46c529f3d5718.txt",
		"img": "https://archive.orkl.eu/4dc055d640cd990abfb0a6837cd46c529f3d5718.jpg"
	}
}