Tutorial Developing your own Anti-Exe (C - Device Driver Development)

D

Deleted member 65228

Guest
#22
If you worry like me why we need `integritycheck` flag, see doc: -INTEGRITYCHECK (Require Signature Check)
I am not the author of this thread but I hope you do not mind me stepping in and answering your question...

The reason you require the INTEGRITYCHECK flag is because it will force verification of the digital signature for the binary (your device driver which follows the Portable Executable (PE) Format). It is an additional security feature and without applying this flag through the linker options, you'll get back STATUS_ACCESS_DENIED error-code when attempting to register a callback for PsSetCreateProcessNotifyRoutineEx (or any other callbacks for that matter).

It may be worth mentioning that on Windows 10 there is a new version of PsSetCreateProcessNotifyRoutineEx, with the "2" prefix applied at the end of Ex: PsSetCreateProcessNotifyRoutineEx2. If you decide to use it in your software, remember to use the previous versions for earlier versions of Windows.
 
Joined
Nov 18, 2017
Messages
3
OS
Windows 10
#24
If you are interested in developing a security product such as an AV, performing cloud analysis on untrusted processes trying to run (and so on) then you need to auto-block execution and work with IOCTLs to send back to a user-mode process to perform the scan (and if clean then manually re-execute the program) since you cannot just hold up in kernel-mode and wait for scan responses since this would break the structure of kernel-mode (as it would result in hanging up the entire system!).

Really informing post by the way, I am developing exactly such application, I was wondering how can I auto-block and re-execute the program? Any hint on this one is really appreciated !

bromance
 
D

Deleted member 65228

Guest
#25
@bromance The author of the post was incorrect. You don't have to block execution and then re-start it and doing this would cause problems anyway because programs trying to start other programs would be under the impression that the operation failed, as well as on-screen error messages from Windows notifying that execution of a program failed (potentially).

You can change values for parameters in the callback routine to block the execution operation for the process spawn, and Kernel-Mode does not have support for spawning programs naturally. You can inject into a user-mode process via remote threads (if you can find the address for NtCreateThreadEx) or APC and have the injected code perform the process spawn.

There are multiples of methods you can use for communication to and from both kernel-mode and user-mode. Kernel-mode communication can be a lot tougher at the start if you are not used to it. You can look into using Ports though, you can even add support for named pipes manually if you know how to (cautious you may be frowned at by others though who will disagree with doing something unsupported and undocumented by default like this, even if you manage to do it right).

Another member recently asked about the function DeviceIoControl (KERNEL32) and I replied to them about communication a bit. You can find the thread here and my response is attached as a comment. Q&A - DeviceIoControl VS WriteFile and ReadFile

On Windows 10 there is now a new kernel-mode callback called PsSetCreateProcessNotifyRoutineEx2. You could check the OS version to decide whether to use the Ex prefix version, or the Ex2 prefix version accordingly.
 
Joined
Nov 18, 2017
Messages
3
OS
Windows 10
#26
@Opcode I read somewhere in docs Microsoft warns as follow:
  • Keep notify routines short and simple.
  • Do not make calls into a user mode service to validate the process, thread, or image.
  • Do not make registry calls.
  • Do not make blocking and/or Interprocess Communication (IPC) function calls.
  • Do not synchronize with other threads because it can lead to reentrancy deadlocks.
  • Use System Worker Threads to queue work especially work involving:
    • Slow API’s or API’s that call into other process.
    • Any blocking behavior which could interrupt threads in core services.
  • Be considerate of best practices for kernel mode stack usage. For examples, see How do I keep my driver from running out of kernel-mode stack? and Key Driver Concepts and Tips.
do you have any thoughts by considering these limitations?
 
D

Deleted member 65228

Guest
#27
@bromance If you implement the communication support properly then you won't have issues and it'll work fine, but you'll need to do extensive testing to ensure it really does work correctly. You could even use shared events and a log file -> user-mode program executes the callback routine for the event and replies back to the log based on the data read from it -> now another event is triggered from user-mode for kernel-mode and the driver stops waiting for the response and takes action accordingly depending on the new data within the log.

There are endless possibilities. You have to decide which route is best for your project and most comfortable for you, and at the same time ensure the implementation is reliable and secure.

You might want to look into ALPC (Native API) functions, might be interesting for you.
 
Joined
Nov 18, 2017
Messages
3
OS
Windows 10
#28
I digged into documentation of Trend Micro Endpoint Application Control here and here. For user-level blocking they say:

User-level blocking allows applications to start and then stops them at the task level. This may be unable to stop certain applications after they start and is less feature-rich than kernel-level blocking. User-level blocking is unable to block link libraries (DLLs) and is unable to support the Trusted Source feature.
For kernel-level blocking the say:

Kernel-level blocking prevents applications from starting by blocking file access. This provides greater security, but may unexpectedly block or momentarily delay access to certain files needed by allowed applications.
After Endpoint Application Control blocks or delays an application start using the kernel-level method, related notifications for the event may be displayed to the end-user.
I installed this software on my system, the have a driver named AcDriver.sys and AcDriverHelper.sys and also in .inf file for driver it has a this entry: DriverPackageType = FileSystemMinifilter, what does this mean?

I have a few questions:
1 - what do they mean at task level? How they have done it?
2 - what do they mean by being less feature-rich?
3 - in kernel-level blocking they say something about blocking file access file (what are we talking about here? :) )
4 - block or delaying application by kernel-level methods, what are those?

I have another question, how can I decipher a driver inner working? is it feasible or sane ?

Any help idea is much appreciated.
 
D

Deleted member 65228

Guest
#29
@bromance Please forgive me my friend, I have only just seen your response while browsing the forum list. I don't recall seeing the notification for the tag you used for me in your previous post, nor the reply at-all!

Regarding your question about Trend Micro Endpoint Application Control, they must be using a file-system mini-filter driver for process start-up interception. Please do not get confused between what I mean when I refer to "process start-up interception" under this context - I'm not referring to intercepting when a process is starting up, but more triggering a scan and delaying events when a suspicion is raised that a program is about to execute. A file-system mini-filter device driver will provide Trend Micro the ability to intercept file-system events via a kernel-mode callback called FltRegisterFilter, and when a program is about to be executed it will trigger these file-system events. The Portable Executable must be accessed so its data can be mapped into memory by the Windows loader for example. They must be using filter checks within their callback routines and then depending on these checks, performing a scan of the PE file which is responsible for those callback routine event triggers.

*.INF is data about the device driver, and also is configured for easier installation (e.g. right click -> Install -> now it copies to ..\\System32\\drivers and does other things which the Service Manager would have done, but it does a few extra things which the Service Manager does not do, which is why they are typically used for installation of file-system mini-filter drivers - you can still use the Service Manager to install those types of drivers but you'd have to do some manual things in addition for it to work).

Anti-Virus vendors tend to rely on Ports for communication from kernel-mode to user-mode and back when dealing with file-system mini-filter device drivers. The reason for this, is because Ports is officially supported but also documented by Microsoft when working a file-system mini-filter driver. The official Microsoft sample for this framework of kernel-mode development even demonstrates a basic example for communication implementation, but you'll be required to make changes to get it working for what you would need to do.

Heads up, if you decide to do checks from within a file-system mini-filter driver as opposed to relying on the standard kernel-mode driver framework for PsSetCreateProcessNotifyRoutine/Ex/Ex2, use wchar_t data-type when sending back the file-path down to user-mode. Stick to original data-types and you'll less likely run into problems. Also make sure that you don't blatantly pass pointers incorrectly (e.g. passing a pointer to a variable down to user-mode where the user-mode process accepting the request does not have access to the memory in-which the address of the pointer points-to will not work).

There are many ways to intercept process start-up requests. You could even use PsSetLoadImageNotifyRoutine and wait until you detect the loading of NTDLL.DLL. All new processes load NTDLL.DLL as the very first module, and every single user-mode process will have it loaded.

I have a few questions:
1 - what do they mean at task level? How they have done it?
2 - what do they mean by being less feature-rich?
3 - in kernel-level blocking they say something about blocking file access file (what are we talking about here? :) )
4 - block or delaying application by kernel-level methods, what are those?
1. I believe they are referring to user-mode, but I cannot be certain. If they do happen to be referring to user-mode, they are likely byte-patching various Native API routines within the address space of other running programs (an hooking technique) such as: CreateProcessInternalW; NtCreateUserProcess; NtResumeThread; or NtMapViewOfSection.

CreateProcessInternalW (KERNEL32) is an highly undocumented function, rarely anyone speaks of it nowadays although it has existed since Windows 2000 I believe (if not then Windows XP indefinitely). It is exported by kernel32.dll on Windows 7 and below, whereas for Windows 8 and above it is exported by both kernel32.dll and kernelbase.dll (always target kernelbase.dll for the function for Windows 8 and above otherwise you'll run into problems and I am saying this from experience). It is called internally by Windows for process start-up requests which pass through CreateProcessA/W. There's also an Ascii variant of the routine however the Ascii version will call the Unicode version anyway.

NtCreateUserProcess (NTDLL) is another undocumented function. For Windows 2000 and Windows XP the function does not exist therefore you would target RtlCreateUserProcess. Starting on Windows Vista, which is the time the routine was introduced, RtlCreateUserProcess will internally call NtCreateUserProcess. This routine performs a system-call since the routine actually exists in kernel-mode (ntoskrnl.exe). Interception of this routine will allow you to control whether the affected processes can execute a new process or not, unless the interception is being bypassed (unlikely but possible). I've actually posted a tutorial here on intercepting this routine should you be interested:

NtResumeThread (NTDLL) is a routine responsible for resuming a thread of a process. The reason this function can be intercepted to control process execution is because all new process start-ups in Windows will leave the new process in a suspended state until the Windows loader has finished initialisation. Once initialisation has completed, the Windows loader will resume the main thread of the new process which allows it to start executing its own code. The Windows loader executes under the process performing the start-up request - this means that when you call CreateProcessA/W to spawn a process, other routines related to memory mapping/memory access protection (NtMapViewOfSection, NtProtectVirtualMemory) as well as the actual process creation routine (NtCreateUserProcess) and the resuming of the main thread of the new process at the end (NtResumeThread) will be invoked from the process which made the call to CreateProcessA/W. Of course all these NTDLL routines exist in kernel-mode memory really, but NTDLL is a gate-way from user-mode to kernel-mode.

NtMapViewOfSection can be intercepted to replicate a user-mode variant of the PsSetLoadImageNotifyRoutine kernel-mode callback. This can be achieved by performing conditional statements in the callback routine to determine the flags for the memory (e.g. SEC_IMAGE and PAGE_EXECUTE_READWRITE flags or others which indicate it is an image and also executable). This can not only be used to intercept process creation attempts at an extremely early stage, but also for DLLs being loaded within a process.

2. By "less feature-rich" I would assume they are talking about one technique being more efficient/effective than another, and that based on the configuration, one technique will be used over the other for functionality.

3. Earlier when I mentioned FltRegisterFilter, the callback responsible for intercepting file-system requests, within the callback routines for these events you can block the action should you deem to as long as you are within the Pre operation callbacks. Similar to blocking with PsSetCreateProcessNotifyRoutine by setting the NTSTATUS error code to STATUS_ACCESS_DENIED, or returning non-STATUS_SUCCESS with the CmRegisterCallbackEx callback routine.

4. By "blocking" the action you would be denying the request at an early stage (Pre operation) so it cannot continue and be successfully carried out. By "delaying" I assume they are referring to holding up the request so the user can make a decision via an alert or similar.

I have another question, how can I decipher a driver inner working? is it feasible or sane ?
You can definitely do it however I highly recommend you don't reverse engineer technology belonging to other companies. Depending on your country laws it may be legal to reverse engineer other people's software for research purposes, but almost all the time, using this research to your own benefit by stealing their work is illegal. You also need to watch out for trademark infringement, which is when you use something another company has already done and trademarked which is in the scope of your location, without their consent.

Generally speaking, you can reverse with Interactive Disassembler (IDA) and debugging tools such as WinDbg. You'll need experience with Assembly for disassembly, C for pseudo-code generation, and kernel-mode debugging with WinDbg since you're talking about reverse engineering kernel-mode software.
 
Joined
Mar 23, 2018
Messages
22
#30
Excellent and informational article, however I can see people omit the biggest problem of all... protecting such routines/callbacks.

It’s enough to make a small driver and remove the callback/routine/tramp and then execute your “malicious” code.

Take PCHunter as an example, it can remove ANY callback or hook or anything with a simple click...

If someone can make a post regarding such protection, that would be something :)
 
Likes: Prorootect
D

Deleted member 65228

Guest
#31
The original poster isn't checking all the inputs before attempting to use them and registering the kernel-mode callback is only one stage, one of the easiest stages... You still need to handle all the algorithms for actually parsing the callback data and reacting to it responsibly in a secure fashion without reducing the system-wide process creation speed to a noticeable level... Which may or may not also include additional implementations such as a caching system, white-listing, etc.

Registering the callback is the easy part. You need fast and reliable, stable algorithms... Some use IPC mechanisms down to UM Windows Service to handle processing of hash check-sums and file paths. Alternatively, a really stable kernel-mode scan engine so you don't have the additional overhead of system calls from UM component to reply to the communication or hold up in KM thread waiting for responses. Since process creation can be excessive sometimes depending on what is going on (e.g. software installer or uninstaller, switching between apps for work a lot), so optimization needs to be good but not enough to make it more insecure.

however I can see people omit the biggest problem of all... protecting such routines/callbacks.
AV vendors aren't fussed about it because if the kernel is compromised then it is already game over. Attempting to protect something when the attacker is running at the same level as your protection code is a bit like trying to dive out the way of a car while it's a few cm away from hitting you at 50mph.

This is why Microsoft developed PatchGuard in a way so it's mostly obfuscation to put reverse engineer's off, it didn't last long... But it did make RE's step things up initially.

Take PCHunter as an example, it can remove ANY callback or hook or anything with a simple click...g
For informational and security purposes:

1. You can use the hyper-visor if the CPU supports virtualization (Intel have Intel VT-x, AMD have SVM). This will allow you to rely on Extended Page Table (EPT) for Intel or Rapid Virtualization Indexing (RVI) for AMD to hide kernel-patching from Kernel Patch Protection, meaning no BSOD is going to be forced via KeBugCheckEx because the Windows Kernel will not even detect your patches. You can then patch PspSetCreateProcessNotifyRoutine to prevent removal of the callback (one method).
2. You can use shim hooking in kernel-mode and target specific device drivers, or byte-patch them depending on the scenario -> callback routine (and thus only would affect specific device drivers targeted).

One idea would be memory protection to prevent writing to the memory the list of registered callbacks are stored internally in the Windows Kernel to non-trusted sources. If you intercept PspSetCreateProcessNotifyRoutine after working the hyper-visor and wait for removal attempts and block it, then you can setup memory protection enforcement when the operation is coming from routine XXXX on the call stack which is not trusted.

However you would also need to un-link your device driver or spoof the BaseAddress because an attacker could just byte-patch your actual callback routine in-memory.

Alternatively, an attacker could just unload your device driver... Forcefully setup a DriverUnload routine if you didn't already have one as well.

There's many attack vectors, it's pointless focusing on preventing your kernel-mode components from being attacked by other code executing in the kernel.

All it will likely to is do more harm than good by increasing system-wide instability and increasing noticeable system-wide performance issues. Even if you did as much as you can think successfully for both x86 and x64 support, you likely just introduced new vulnerabilities for exploitation (potentially) and an attacker will find a work-around regardless.

Focus on preventing malicious code from reaching execution from the kernel instead of preventing attacks coming from the kernel. It'll be less intrusive and likely more useful.
 
Last edited by a moderator:
Likes: harlan4096
D

Deleted member 65228

Guest
#32
Focus on preventing malicious code from reaching execution from the kernel instead of preventing attacks coming from the kernel. It'll be less intrusive and likely more useful.
For starters you can intercept device driver loads with an undocumented kernel-mode callback used by the Windows Defender driver since Windows 8 and it's called SeRegisterImageVerificationCallback. If an untrusted and suspicious driver is identified via scanning engine algorithms, then handle the image load to stop it in its tracks.

There's also kernel exploits for privilege escalation out there, you can hunt them down and analyse how they are deployed to put in accurate and reliable blocks for them and ones alike them... to stop them from being successfully deployed in the first place.

And of course if you ever run into a zero-day relying on a zero-day kernel exploit, then you could patch that up ASAP "virtually" until Microsoft officially do.
 
Likes: harlan4096
Joined
Mar 23, 2018
Messages
22
#33
For starters you can intercept device driver loads with an undocumented kernel-mode callback used by the Windows Defender driver since Windows 8 and it's called SeRegisterImageVerificationCallback. If an untrusted and suspicious driver is identified via scanning engine algorithms, then handle the image load to stop it in its tracks.

There's also kernel exploits for privilege escalation out there, you can hunt them down and analyse how they are deployed to put in accurate and reliable blocks for them and ones alike them... to stop them from being successfully deployed in the first place.

And of course if you ever run into a zero-day relying on a zero-day kernel exploit, then you could patch that up ASAP "virtually" until Microsoft officially do.
Interesting regarding "SeRegisterImageVerificationCallback", I shall have a look into this when I`m free. Thanks :)

However, regarding "PspSetCreateProcessNotifyRoutine" - I already have this, and it is pretty much useless...

I am trying/looking into solutions to prevent other kernel modules from affecting my one, but I always hit a "dead end" ...