 Memory manipulation is a technique that has been around for a long time. It is used for both security and malicious purposes. Today I'm going to cover some of the malicious uses of memory manipulation at Windows and how we can detect them. My name is Connor Morley and I'm a senior researcher with Secure. Formerly, I was a threat hunter for four years and I published multiple white papers and detection POCs. I have also presented a number of conferences on security related issues. Today we're going to be looking at what exactly a memory manipulation technique is. Then we'll be looking at inline hooking for exported functions, then for private functions and the detection issues associated with that. We'll then look at kernel level hooking on legacy Windows systems, Heaven's Gate hooking for Wow64 or X86 processes, and finally we'll look at vector exception handlers and how they can be used for memory manipulation techniques. First off, what is a memory manipulation technique? Memory manipulation revolves around live process memory, so we're not focusing on files or file system manipulation, we're only focusing on alterations made to memory that is currently running within a process. Changes to this can affect the control flow, which allows for various activities to occur, which can change or siphon off information, it can prevent functions from occurring, it can prevent checks on integrity, it can equally execute malicious code. Changes over the past few years have seen that malicious actors have moved away from the idea of manipulating memory within Vixen processes, and instead within to changing memory within their own processes. One of the primary reasons for this is that monitoring of alterations in memory of remote processes using virtual remote aliqua or anything like that is a long-standing security concern, and there are security vendors who are quite hot in detecting this, and that's such issues sparingly because it is so readily detected. Instead, a tactic is to start manipulating the memory of their own malicious agents or payloads in order to prevent detection. The reason for this is that manipulation of a process its own memory is not malicious in and of itself, and a process has full access permissions to all of its own memory space, which means you're not running into some of the areas that you encounter with remote processes. This can be used for two primary purposes. One, to prevent monitoring, or two, in order to redirect the control flow. Now, redirection is normally done in order to try and muddy the waters about what is happening, so you can call one function which will then hook and call another and you can make it quite complicated which can make reverse engineering quite painful. But we're going to be focusing on the preventing of monitoring by security vendors, in this case. To that end, I will be covering four very specific areas. Now, as I go through these, you should notice that the techniques I am outlining can be used for other activities besides just evasion techniques, where the hooking has been implemented or the memory manipulation has been implemented. Other activities can occur with some development choices and some alterations. But today I'm just going to be focusing on evasing detection using these malicious techniques. To that end, I'll be looking at ETW event prevention using DLLs or libraries, library manipulation, prevention of ETW telemetry via kernel memory manipulation, interception of x86 or R64 syscalls in order to evade detection, and finally, vexed exception handler or VEH specific bypasses that can be used in order to circumvent some security vendor techniques. So, first of all, let's look at inline hooking for exported functions. Now, first of all, it's important to know what exactly I mean by hooking. So hooking is the alteration of a function's start opcode in order to perform a secondary action. So imagine you call a function which, let's say, creates a file. Now, if you know where that function is located in memory, if you change the first set of commands to instead jump to a different function, that is what we would call hooking. So what it means is that every time that function is called, your hook or your alteration to the memory will cause something else to happen which changes the control flow of that function in order to perform a secondary action that you have implemented. This is used by security vendors and malicious actors. For security vendors, this is not be done for telemetry collection. So, again, let's say a security vendor has a particular function they want to monitor for because it's high value or it's something they know is used by particular attacker groups. Now, by placing a hook on that particular function, any time a process executes it, the security vendor or security software will get an advantage generated or telemetry generated with the process that called that function, what they were trying to do and when, which is very valuable. Attackers equally can use the same hooking for the same purpose in order to monitor system activity, but equally they can use it in order to prevent the function from executing and redirect the control flow to malicious code or shell code. There's lots of ways that malicious actors can use this and it is very simple to do and it is extremely effective. One of the things to note is that the export address table or EAT within the PE header of libraries makes hooking very easy. So, the EAT basically outlines all the exported functions, all the functions that are available to external processes from that library and where they're located in that library. This means that if you wanted to develop a hook for a particular function, looking at the EAT would give you information on where it's located in that library's memory which allows you to target your manipulation specifically at that address making it very easy. One of the other things to note is that dynamic information on modules that have been loaded into processes can be acquired either by the process environment block or PEB and through native libraries such as PSAPI. By examining these by either using PSAPI's functions against a particular process or by examining the PEB of a process you can actually enumerate all the modules that are currently loaded and their base address within that process which allows for the EAT's information to be cross-referenced to find particular functions within that process's instance of that library or that module which makes development very easy for hooking. Let's have a look at how this works in practice. In this case we're trying to target ETW EventWrite which is located within the NTDLL module or library. ETW EventWrite is a core function or exported function which is required for ETW event generation. One of the things to note here is that NTDLL is loaded into every single Windows process, it is not optional but this is just an example to show you how this could work. So first of all a attacker would determine where the process or the function is located to do this they can do it in one of two ways. They can either use the load library and getPROC address functions in order to load the library of NTDLL and then find the function address using getPROC address against the handler generated by load library or they can enumerate the PED of the process to find the base address of NTDLL and then cross-reference against the PED header of NTDLL in order to find the in order to calculate the RVA of where ETW EventWrite will be located for that process. Either way the result should be an address in this case of 7FF8916500. Once you have the address of where the function is located you can determine what you want to do how you want to install your handler. So in this case because we just don't want ETW EventWrite to work because we don't want ETW telemetry to be generated we're going to install an opcode of value 0xc3 which in x64 sends for RET or return. Now if you patch or hook the start of ETW EventWrite with a return command what happens is every time the function is called the first opcode returns control to the calling function. So if your function decides I'm going to generate an ETW Event calls ETW EventWrite as soon as it calls that function the calling function is returned to with the stack all corrected and resolved and it thinks that ETW EventWrite has been successful but because of the hook that's been implemented or the RET that's been patched in we know that the ETW EventWrite has not done anything and as such you prevent all ETW telemetry from being generated for that process. So now we know how this is implemented, how do we detect it? So detection methods are all to do with knowing, having a known good meaning able to compare what is within live memory. So the first thing to note is that all volatile memory begins as a file so all the loaded memory that's in volatile memory came from the file system to begin with and the file system has an unaltered version of what is in volatile memory. Now the loaded module file as we said before the information on that can be found dynamically primarily through the PEB. Now what's interesting about the PEB is that it provides a path to the source file within the file system for the library that's for the module that's been loaded, the library that's been loaded. Now let's say you wanted to monitor for NTDL ETW EventWrite you could use the PEB to find the source file which would be located in system 32 you could then use the PE header of NTDL to find the offset of where ETW is located within the file systems version and use that to calculate the RVA address within the running process and then you can compare what is in live memory at the address you just calculated for the RVA against what is within the file systems version and check whether there is disparity between the two. If there is a disparity you can say that a hook has been implemented at the start of the process and this can be done by by by comparison. So if an alteration occurs within the first 100 bytes or something to that effect that may be excessive, but you get the idea you can detect whether a deviation has occurred due to editing and this is very effective at detecting these types of hooks. But targeting is required for such operations. The reason for this is that inline hook or inline packaging can be done legitimately as we've said before this can be done for security purposes but equally there are some processes such as Firefox which do this legitimately to a number of internal functions. So unless you are targeting specific functions of value you may get a lot of noise or a lot of false positives on particular functions that aren't of security interest. So as such, targeting does need to be done in order to make this accurate and equally to make this resource manageable. Private functions within modules pose a different problem and they have detection issues. So whereas with exported functions where the exported function is defined within the EEAT which makes it very easy to locate private functions are not exposed to external processes in any way. They're not in the PED, the PE header or any index and as such it makes this much harder to find. But one of the key things to note is that exported functions from a module will almost inevitably rely on at least one private function in order to operate. This can be to do with argument integrity check, formatting checking or it can do with initial connections or anything to do with that sort of effect. And if you know that the exported function that you want to prevent utilises a private function it can be just as effective to instead hook on the private function instead of just the exported function although it takes a bit more work. Adam Chester, Research Adam Chester did a great example of this using DNS query underscore A which I'll demonstrate now. So in this example he identified that the private function he wanted had a specific code signature by scanning the by using load library or enumerating the PED he found the base address or the memory address of where the module was loaded for that particular process and then scanned the module's memory address space until he found the corresponding code signature which gave him the base address for the function in that module. From the above we can actually see that the internal function that we're looking at when put through a debugger is an internal symbolic function and as such it's not exported and from this we know that it's not going to be in the IAT or the IAT or anything to that sort of effect so without code signature or a PVB which I'll come to in a minute there is no way to know that this function is there unless you already have the code signature. Now the code signature was acquired by external reverse engineering and looking through the call stack of what happens before this performs a syscall and just I've actually found that this particular private function could be hooked quite effectively. Now in this case you can actually patch the private function with a ret command again. The reason for this is that the private function in this case subsequently calls the ETW publication so the private function in this case actually generates an event template which then hands off after two functions the NTDLL event write transfer but by performing by putting a hook here of ret you prevent the template from being generated and the ETW event from being generated within NTDLL and the calling function doesn't know the why is it as such we can see from the bottom window that the ret command has been implemented within the specific VA for where the post signature has been found which prevents the ETW from being generated. We didn't hook on the exported function we hooked on the subsequent private function which was called by the exported function which from a detection point of view creates some problems primarily one being the private functions are there's no information on them that's inbuilt into a process they're again they're not in any of the header files so that you cannot enumerate them from an external process i.e. they are private the only way to do this is to have a program database file or PDB now PDBs are generated at compilation time and they do provide symbolic address and symbol information for private functions the PDB files cannot always be guaranteed to be acquired. The reason for this can be there could be third party module files where the PDBs might not be available or you may be in an environment where a connection to the internet and the subsequent windows symbolic server where windows PDBs are available cannot be accessed so unless you have a large database of PDB files walking around with your detection system it can be hard to attribute or find where particular memory addresses are located to private functions secondly there's a double dependency issue so what this means is that each module can have an IAT or import address table as well. Effectively what this means is this module relies on a second module for functional capabilities. Now because of this if a module imports other modules you therefore and that module let's say that your first module calls a second module and your second module has the function that you're looking to monitor for any point in the stack from the first module to the second module the function within that stack can be hooked in order to prevent that second function the function within the second module being executed and as such all potential paths against all the double dependency modules need to be monitored in order to prevent hooking at an earlier stage in the stack but because of this the resources required are exponential so if you look at the table in the bottom left you'll see that the number of internal function symbols for the average module is around 3 to 5 thousand but the dependent modules can be as high as 806 with an average of 583. Now because of this when you start to count up all the internal functions that you're potentially going to have to map against all the module that they're now dependent on that number of rises very very very quickly which can create a big resource properly. Finally it's to do with the module versions so between module versions some internal functions can become obsolete and they're removed which means that all the addresses are subsequently changed so when you're monitoring for module private functions you have to have an accurate module type and if you want to attribute it you also have to have an accurate PDB version as well otherwise you run the risk of misattributing an alteration to the wrong address which can be very problematic so instead of just having one PDB per module you now have to have every version of PDB for every potential version of that module which again creates a resource issue so as such it becomes much more difficult to detect these private functions being hooking and there's no real reliable boating method for monitoring these they tend to be context dependent the manual mapping dependent on the primary function to target function also needs to be ascertained the reason for this is that different parts will have different values depending on their security vulnerability and this needs to be done unfortunately manually because all the potential parts can't be mapped automatically in order to assign resources to those of the highest value this will need to be research will need to be conducted however because as I said before this needs to be context focused you tend to find that this is either going to be inaccurate due to the lack of PDB or it's going to be so resource intensive because of the double linking issue that it becomes ineffective and very slow so there tends to be a balance between the two depending on what is available kernel hooking on legacy system so this is to do with systems pre-build 18950 post 18950 Microsoft actually targeted this particular vulnerability by adapting patch guard and removing a particular kernel variable which was susceptible to manipulation now in order to perform kernel level hooking you need to use a vulnerable kernel driver or an insecure variable type as we just mentioned the insecure variable type was something that Microsoft patched specifically some of the examples of this are Ghost in the Logs or GITL by Battec Infinity Hooked by Evedox and Kernel Driver Utility KDU by H Firefox so let's go into how these all fit together so kernel level patching first of all uses the kernel driver utility or KDU in order to effectively use a vulnerability within vulnerable kernel drivers to have ambiguous memory access to kernel space now the vulnerable drivers are still available in Windows 10 and KDU does still work the drivers have not been removed this is something that's important to know because what KDU does is it allows you to write a malicious kernel driver into kernel space by basically piggy backing on one of these vulnerable drivers so in this case a malicious executable will load a vulnerable driver and then by using the vulnerability with the associated CVS which are available it will write a malicious driver into kernel space and load it now the malicious driver will then start it to work now using Infinity Hooked the malicious kernel driver will check the ETW debugger data for the entry circular kernel context logger and now this is to do with an array of loggers which run within the kernel and they all have different ID values now the circular logger has an index ID too now this is important because the circular logger will run, as you might guess, circularly on every single sys command that's sent to the kernel and it creates a log for it now by finding this entry within the ETW debugger data the object has a WMI logger context and within this is an object called getCPUCLOCK which unfortunately is the type pointer now once you've found the circular logger you can overwrite the getCPUCLOCK pointer within the WMI logger context in order to point to hooked context now once the hook is in place what this effectively means is every time the logger is called at the current time it will instead run the hook content that the malicious driver has installed typically this means that the argument data and the syscall context will be siphoned off into an evil collector which will allow them to monitor system level activity but one of the really interesting things about an affinity hook is that it actually has the capability to run any syscall by using this hook capability and the reason for this is that the circular logger actually runs before the syscall is actually just before so once the hook has been called within the logger it can walk up the stack find the function pointer syscall that's been targeted and overwrite it with any syscall the malicious actor wants and from this they have kernel level syscall operational capabilities by using this hook which is extremely powerful both in the log works in the same way but where the hook has been implemented it only monitors one particular syscall function for antitrace event pointer now when it detects this it instead diverts it creates it will divert to the hooked function and the hooked function will determine against an IOCTL IOCTL flag from user space whether or not complication to the antitrace event will occur now this is important because notion logs allows for user land control of a kernel level monitoring element effectively using IOCTL a user land process can ambiguously decide yes generate an event or no I want to keep this secret and this is important because what it allows is a prevention of no data detection so where as with the previous examples where you can just prevent ETW events from being generated at all for a process you can therefore actually stand for lack of data so if you find that there is a process running but there are no ETW entries for that process you know that manipulation or malicious action is taking place but by using ghost in the logs you can actually prevent that and publish in events and keep secret malicious events from a user land control to a malicious hook that's been implemented which is really really cool detection for this again so it's post windows 7 but it's pre build 18950 and any system between that window is susceptible to this this kind of level hooking now as we said before ghost in the logs relies on the kernel driver a utility or KDU in order to utilize a vulnerable driver in order to load its malicious driver into memory in order to utilize infinity hook and then install its IOCTL based ETW prevention now but there are some other evasion techniques like by PG or by patch guard which rely on the kernel driver being installed via a different method so KDU can be used but it is not the in build mechanism so although kernel driver installation and service installation is something that can be monitored for it won't necessarily use KDU to do that but because ghost in the logs does use KDU it's quite easy to detect thankfully the reason for this is that KDU relies on a list of known vulnerable kernel drivers and services in order to allow for the ambiguous kernel memory access this is the full list but the ones in red are the ones that ghost in the log uses specifically so now driver RT core 64 GDRV, AT SCIO and MSIO 64 what's interesting to know is that the Intel Ethernet debug driver tends to be the go to from KDU and ghost in the logs and it is still present on the most up to date Windows 10 system so it is something to keep an eye on but by monitoring for any of these kernel services being installed or ran you can actually monitor for any of this activity because these are not run typically so any interaction with these services can be seen as malicious and it's very easy to detect alternatively at the kernel level by using a kernel driver with appropriate capabilities you can monitor for the WMI log or connect object instance with an entry lower ID too and check to get CPU clock pointer against a known good or simply just check that it it doesn't point somewhere it's not supposed to but by monitoring this you can you can equally check for infinity hook and back teaching so heaven skate hooking for x86 so this is heaven skate is the element that switches CPU modes between x32 and x64 when you're using well 64 or for x86 processes the reason that this occurs is because if you have an x32 process running on an x64 host the x64 host obviously only has an x64 kernel but if an x32 process decides it needs to perform a syscall it needs to be translated to an x64 CPU mode and x64 format before the kernel can handle it and so because of this all syscalls have to go through heaven's gate in order to be translated and switch between CPU mode x32 well 64 over to the native x64 CPU mode where the syscall can be handled and because of this hooking on this particular element means that you can monitor all syscall events from an x32 process running well 64 regardless of what it is so instead of being a targeted hook for particular functions instead you're hooking every syscall that process is making as you said hooks elsewhere can be stealthy as we saw earlier you can hook on particular functions or on particular exporting functions or private functions or anything like that but heaven's gate gives you a subsystem wide for that process monitoring of all the syscalls that are going to conduct which allows you to prevent particular syscalls from executing you can hijack the information you can manipulate the information effectively allows you to do whatever you want as long as the appropriate hooking is put in place let's have a quick look at it exactly how this works so on an x64 system an x32 program will say okay I need to call a function that's going to perform a syscall the wow64 version of ntdll what's interesting is x32 processes running wow64 actually have two versions of ntdll I won't go into that but first of all we will call the wow64 version the syscall will then need to be translated and then it will hand off to wow64cpu which is where heaven's gate presides heaven's gate will then perform what's called a long jump which is done by a code segment change from the x32 wow64 cpu mode over to the x64 cpu mode wow64 cpu module once in x64 cpu mode it will then hand off to the native ntdll instance the x64 instance which will then handle the command running to the kernel and the syscall will be handled the response will be then fed back down the same pipe a long jump will be made back into x32 back to the ntdll wow64 instance and then back to the x32 process and that's rudimentary how heaven's gate works and how wow64 syscalls are conducted but if you decide if a hook is implemented on heaven's gate within wow64 cpu all of this becomes compromised now at this point as soon as the syscall is handed off from ntdll to wow64 in order to perform cpu modes the malicious hook can do anything it wants it can change the syscall that's being implemented, siphon the data jump to malicious code ignore the syscall and just return and not do anything there are lots of things it can do but because of this it does mean it doesn't matter which function it's calling what module it's calling from if it performs a syscall it will have to go through wow64 cpu and go through heaven's gate and hooking at that gives full control and full access to all syscall operations so how would we go about detecting this before I move on to detection it is worth noting that heaven's gate in this instance is done through the inherent native heaven's gate but there are alternative functions to heaven's gate where the long jump that I've mentioned within wow64 cpu which constitutes heaven's gate can actually be implemented manually in order to conduct the cpu mode transfer without going through the native module now this is a malicious technique that can be used for evasion and it is something that can be developed into a system but it isn't manipulation of existing memory so it's not something we're going to cover here it's just something I wanted people to be aware of that heaven's gate can be used by a manual method being implemented within malicious x32 code on a wow64 system so talking about detection first thing to note is how do we know where heaven's gate is how do we know where we want to monitor while huangui actually found this in his research on wow64 processes and found that the tib of wow64 processes actually has a field filled at offset 0xc0 for fast syscall and this is actually the exact address of where heaven's gate is stored relative to that process now this is interesting because jeff chappell found that in the same offset if you look at his repository of information that the same offset is actually wow32 reserved now this is interesting because they obviously correlate to the two but have slightly different names either way in a wow64 process this offset when the tib corresponds to heaven's gate's address which allowed you to highlight from any running process where heaven's gate is located and where to monitor so x86 one of the things to note is that the gate location is at an offset of 0x7000 from wow64 cpu's base address and it is not changed legitimately the reason for this is that wow64 is actually loaded at the initialization stage of all wow64 processes so similar to NTDLL although for very different reasons wow64 cpu unless forced will always load in the same location for a running process and from that you know that the gate location is going to be the base address plus the 0x7000 offset and you can scan it very confidently this can be forced but it is very hard to do and it is not common the other thing to note is that x86 process and wow64 processes do legitimately change elements within wow64 cpu as well in the example below you can see that the offset is 77365000 so it tends to be a modification just prior to where heaven's gate is located but only modifications to the actual heaven's gate offset are found to be malicious through all experimentation so although modifications may happen elsewhere in wow64 cpu only the offset for heaven's gate are we concerned to keep track of in order to detect this is actually quite simple with the fast Cisco information from the TIB the reason is that heaven's gate is only 9 bytes big now if you have a known good process you can actually take collect the TIB find the fast syscall address extract the 9 bytes and use it as a template for every other process that is running you can't as with previous examples use the file system version the reason for this is that heaven's gate is dynamically allocated and so the value using the file system are never going to correspond to what is within virtual volatile memory so you can't compare one to the other you have to have a known good wow64 process in order to create a base against but compare by comparing only those 9 bytes which as you can imagine is quite quick allows you to detect any malicious hook on this particular element which can be so nefarious once if a malicious hook is detected you can therefore look at the memory address where the hook goes to and analyse its content by memory dumping or that is running on that and one example of that would be this example so the byte sequence is actually in reverse in this case the malicious hook was detected and the hook content was dumped out for analysis one of the other things to note is that in order for heaven's gate hooking to work a trampoline has to be implemented now a trampoline is effectively where the heaven's gate code is stored elsewhere that the malicious hook will know where it's been moved to and the reason for this is that when the heaven's gate legitimate location is called the malicious hook will then be called which will perform the malicious action and then after that it can then perform the heaven's gate CPU network jump by simply jumping to the trampoline or wherever the code has been moved to but by use of language in this nine bike check during experimentation it was 100% accurate and the information produced was gave great data for further analysis finally let's look at vectored exception handlers so first of all let's look at how exception handlers work so tri-catch code blocks are an example of exception handlers so effectively a tri-catch block is a frame so these code blocks where you have the tri-code that code is within the frame of the cache that you've implemented and what this means is that as programmers should know if an exception is happens within your tri-block and it corresponds to what you have specified in your catch statement the exception will be handled by your catch statement and this effectively creates a frame for that exception now the exception can either be specific now exceptions actually originate from the CPU not from the program itself the CPU will notice the exception has happened it will then prompt the kernel in order to with relative information which will create the environment context, exception records and all this sort of stuff which is then handed back to userland for handling within the program itself the kernel determines what kind of exception type it is and what handling mechanisms are required based on the data that's issued by the CPU the kernel does nothing it simply interprets what the CPU is telling it and then hands it off to userland to actually handle the issue this is typically done through NTDLL in userland let's have a quick look at what this looks like so after the kernel has handed back control I won't go into how the kernel handles the CPU information and translates it into a trapped frame and then the environment and exception records and all that sort of stuff we're going to look at the userland so once it's handed back control to userland from kernel using an irect command the trapped frame environment context and exception record are all available within the user stack but the trapped frame will have an EIP which will trigger the use of Ki user exception hammer within NTDLL this will subsequently call RTL dispatch exception which uses the information from the environment context and exception record provided from the kernel by translating the information from the CPU to know what frame the exception has occurred from within which process and from that it then scans the lowest frame again provided by the environment context and starts to check the frames outwards and what effectively what this means is if the first frame adequately adequately handles the exception that's been specified it doesn't need to go any further but if not it will move out and out and out and out through all the frames containing it until it will reach the end of the exception frames or the exception list and if it does that it then turns into a general exception which normally causes the program to crash so I've been saying frames and exceptions but frame-based exceptions are actually what we call structured exception handlers or SEH so a tri-catch block is an example of an SEH it is a frame-based exception which is very specific but whereas with a tri-catch block again if you have a tri-block and a catch but the catch doesn't check the exception it will then move to the surrounding frame to see whether that can handle the exception and move further and further out as I just explained the SEH adds to a chain so the SEH list is actually connected one after the other and it will do it as again from a lowest frame and it will start to move outwards if the chain is exhausted it will move to a general handler which is normally our kernel system level which normally causes the program to crash and if not the program to crash it can cause the operating system to crash so not something you want to have and hence why exception handling is it is quite important well program to crash will not likely be the kernel depends what you're doing but what exactly is a exception handler so the age are not frame specific so whereas SEH or structured exception handlers are very frame specific vectored exception handlers are the alternative so instead of being frame specific they override the priority of SEH and have a higher priority and effectively the exception that is generated from the kernel within the exception record will be checked against the vectored exception handler first before it moves to the structured exception handlers for that process this was introduced within Windows XP specifically to be able to override the SEH from a developer standpoint so instead of having to find a particular exception frame you could just install a veh and it would overwrite the exception as you had in place but because of that veh has an inherent higher priority and will run first and the way it did this Microsoft did this was to install RTL called vectored exception handlers within the exception handler process within the NDDLL so RTL dispatch exception which we just saw handles hands off and starts to scan through the frames instead will call RTL call vectored exception handlers and scan the vectored handler list first now this is very important because this means that no matter what you do vectored VEH vectored exception handlers will always have a higher priority and if an exception handler is found for that exception type within veh it will handle the exception regardless of whether an SEH exists now each handler instance can handle multiple exception types so whereas with SEH you only have to have a specific exception type or a general exception type veh can handle multiple specific exception types and it does this by within the handler actually do a comparison between what is inside the exception context against what is within the vectored exception handler for what it can handle and this is important because vectored exception handlers can handle vast arrays of exception types depending on how they're built which can make them quite clunky but equally can make them very sort of like a catchall which is quite nice adding to the list can be done at the front at the end at the discretion so you can either have the highest priority or the lowest priority depending on how you view the veh but as you can imagine from a malicious access standpoint you're going to want to be at the front of the list so that no matter why exception comes in your veh is being checked first but what's interesting is that you can add a veh on the command just before you know you're going to do something in the various which will cause the exception so you know your exception handler is going to be called first veh list is circular this is something just to know that effectively when it reaches the end of the list it will go back to the start so there has to be a check against what the exception handler entry ID is so you know when you reach the end of the list and finally that the handler function pointers are encoded using a process-specific cookie so only by using a process-specific cookie can you actually find the handler's point to adjust and find the handler code so let's look at some of the malicious uses so as we said veh will always be done first regardless of what seh is in place and veh can be added at any point because of this it can prevent coding integrity checks specifically with page guard which I will show you a great example of in a second it can perform force jumps this is to do with how vexed exception handlers are added to the veh list and it can also suddenly bypass functions this is where the security malicious memory manipulation is going to take place and I'm going to give you a great example of that in a minute so veh can hijack the acceptor change because it's a hybrid veh and it can need to be done against the victim process as long as there is adequate access or it can be done against malicious program simply just to remove any visibility by security vendors by checking for these there is exception generated behavior so let's look at coding integrity checks so this is actually from a researcher Shen and they violate the page guard exception and then effectively use veh to they install a veh seconds before they violate the page guard which creates a status page guard guard page violation exception but their veh effectively goes okay that's happened but don't worry about it and because their veh has a higher priority the program just goes yeah that's fine the exception has been handled what they actually do is inside their veh box they reassert the guard flag of that particular page so they violate it have the exception reassert the flag within the exception handler and then hand back to the process saying yeah everything was handled so from that they're able to basically violate page guard as they see fit as long as the veh is in place to handle it which is which can get around a lot of integrity checks which is quite cool false jump as I said this should do with how effective handlers are added so additive exception handler is the primary function of adding veh to a system or a running process but additive exception handler actually only requires a handler pointer or just a pointer to be added as an argument so from this you can allocate memory with a bunch of malicious shellcode and then hand it off to a veh and then add it as a veh and then as soon as an exception comes in as long as you put it at the front of the queue your shellcode is going to get executed so you've actually found an exception based shellcode execution mechanism by using veh which is pretty cool something bypassing is the one that we're really going to look at so veh has the capability so when a handler when you're generating a veh handler when it's handling an exception type it has two results it can either have exception continue execution or exception continue search and what this means is continue execution means the exception has been handled hand back to the process of continue execution continue search means my handler wasn't able to handle the exception generated move to the next in the list now because of this if you deliberately generate errors or you know that an error is going to be generated as with the page guard you can actually just say hey this has happened don't do anything about it and move on with the process the equally what you could do is you could say okay I know that a function is going to be called in a second that I don't want to happen so let's say I did a divide by 0 which will call an exception and from that I'm going to change the function pointer to go just after the command that I don't want to occur and then hand back to the running function and it will work from this you're able to basically jump around the code that you don't want to execute or by basically deliberately triggering exceptions as long as the VEH is in place because it will have a higher priority which is very very cool so detection of this relies on a number of things but primarily you need to know where the VEH list is. So prior work done by researcher Dimitri Forney did some really great work and he found that the VEH list was actually stored within NTDLL and it was under the pointer LDRP vector handler list and what he found was is that by scanning heuristically for a particular pattern within a known NTDLL function you could find this pointer and from that you could extract the list of the VEH and enumerate through it really recommend reading his work he did some great examples of this and a lot of information on how the heuristics work but effectively the list is not exported it is not externally available so you have to do this reach into the NTDLL systems in order to find the pointer and extract the list which is the nuisance the other thing to note is that the handle of point as we said earlier is actually encoded by the particular process cookie and in order to decode this you have to use a combination of query information process and roto write 64 Olly Whitehouse over at NCC group did a brilliant POC on the VEH enumeration where he actually solved all of these problems and allowed the handle of point for the 4x64 process handlers to be decoded and attributed to their modules and process spaces again really recommend reading that work he really jump-started everything it was very impressive to recommend reading that but one of the things that's important from a victim exception handler detection standpoint is what exceptions they are handling so although you can see when a VEH has been generated and what wanted their attribute to that's great but unless you know what they're doing within the handler or what exception types they're looking for it's not necessarily going to provide that much value but by checking the exception type you can actually check for again as the example with the bottom of the window shows institute divide by 0 so if you're looking at a divide by 0 which is in a randomly named process you can say that this is likely going to be a VEH malicious instance now this can be done using opcode heuristics by checking for comparison operators because all handlers will have to check the exception context exception type against a known exception type to see whether it matches and to know whether it needs to be handled which is a really easy way of finding what exception types are being used and from this it allows you to do a process to exception type comparison to see whether there's a mismatch and this is especially true about certain debugging exceptions which is actually key to a case I'm going to come to in a second so when it comes to detection criteria pointers outside process and module space i.e. virtual alloc just anywhere for shellcode pointer to a normalist module function so again if there's a randomly named module and this VEH is pointing to it pretty suspicious pointer location has COW in logistic module so this is to say a copy on write which is effectively a page modification in a shared library if the process if the VEH is actually pointing to a process-specific memory page within an adjustment module but only that page that's pretty sus and should probably be looked at to make sure that that particular function hasn't been hooked in order to prevent further malicious action by basically tricking it off from that hook pointer location contains shellcode again this can be done through memory dumps of the handler code or just through general heuristics and event type handler is unusual again as I said depending on the process and the handler type you can actually make what handler types are standards for that process or equally standard for a system so the example for EDR bypassing using VEH is Firewalker so Firewalker was developed by MDSec back in 2020 and it it's a brilliant POC effectively what it does is it scans for EDR hooks on known functions for bare telemetry gathering for security purposes and steps around them using VEH it does this by scanning for pointer duplication or func scanning and trap frame single step generation by registry manipulation I won't go into those the second part about trap frame single step effectively they manipulate one of the registries to trigger a single step exception which is what triggers their VEH or malicious VEH into working which is the bottom example of VEH exception single step handling and that's where we're going to look so operation is it creates a VEH entry for the exception type single step sets the TF flag in the registry in order to make the exception single step exception be caused on each individual execution that's done it then course the desired function knowing the single step exception is going to Fire then it uses the VEH to scan each subsequent instruction to see whether it's a jump command or a hook command and if it is it then scans the memory to see whether there is a subsequent duplication or basically a trampoline back to the same code which would indicate the hook if it is found it then replaces that jump with the trampoline and then it basically jumps itself back into the system of process without executing the EDR's hooked function so it scans so you create a VEH you trigger it to make these exceptions on each subsequent command you then run the process you want and you check to see whether it jumps to it does a hook or a hook jump and if it does you then scan to see whether it's duplicated and if it is you just jump around it and avoid the EDR telemetry acquisition altogether and then after that you can just remove the VEH reset the TF flag and continue your operation brilliant a really really really cool concept and although it had its limitations a really cool capability but one of the things about detecting this is the fact that it uses VEH now as I said earlier the exception types that are monitored for is one of the things that can be really easy to detect on so exception single step outside the use inside a debugger yeah that's something that should be flagged and really easy to basically say something's not right here and it needs to be looked at and as I said the VEH exception type the process nature easily equals detection again if you have calculator doing buffer overload exception handling but then this got like three instances of it or two instances of it not going to be right especially in the VEH because that should be something that should be SEH so it's something that can be easily monitored for now people would say that this could be handled by SEH but again because SEH could be used instead of VEH in fire walkers mechanism but because VEH has a high priority and it's easy to code and it has it's just more dynamic attackers will tend to use VEH over SEH simply because it has is much easier to use one of the final things to note about VEH is the x86 issue namely that the VEH for x86 process is stored within the x64 NTDLL and as such cannot be accessed by x86 processes which when you're enumerating them and trying to process the handle and see what's inside them makes it very difficult you end up with this memory access violation where you're trying to access 64 bit memory from x86 now this is a physical address extension issue which can be addressed through the kernel MMR but it goes beyond the scope of what I'm going to be covering today but it is something that is known to exist and the only way to do this is to take the physical address the virtual address of the x64 translate it to a physical address and then translate it to a PAE of x32 to then we ran through the x32 handler or you have to bridge between manually between x60 and x64 CPU modes in order to validate what is inside the handler for the x32 process which is quite complicated this is something that is still ongoing but the best method that I know of is to use the MMR so in summary memory manipulation is not a step away it's being here for a very long time and the capabilities that are being implemented with the new technologies that are being introduced by the operating system and equally the change from tactics to victim processes to their own processes is something that shows that they're always finding new ways to utilize tweaks inside live memory in order to make detection or just execute malicious commands but monitoring is always a fine balance between accuracy and resources. Ideally we'd love to monitor every single memory change and be able to 100% accuracy say this is attributed to this process and these bytes are going here and all this sort of stuff but the resources required for that are just too high so it's always a balancing act between the two and you have to decide where is the best place to monitor finally is the capability to avoid detection in unrestricted operations makes this a high value and what this means is memory manipulation provides a window to malicious actors to effectively size-depth detection multiple ways so it is never something that they're going to give up on it's always going to be something they're going to keep trying and keep finding new methods for and although the methods I have done today are interesting there are obviously a lot more out there and it's best to give you its ground because this is not going to stop thank you for listening if anyone has any questions do feel free to email me at my works email and thank you for listening