Prevent malware attacks using Windows kernel driver

A DEFINITION OF MALWARE

Malware is software that is intended to damage or disable computers and computer systems without the owner’s knowledge. Malware is the shortened term for “malicious software,” and it typically is characterized by the intent of the creator rather than by its features. Various types of malware exist, including spyware, viruses, worms, Trojans, and other types of malicious code that can infiltrate computers.

As malware attacks continue to grow in both frequency and sophistication, it is becoming increasingly difficult for enterprises to defend against them. The most serious malware attacks combine stealth, precision, and social engineering techniques to penetrate and compromise systems. When these cyber threats make it into a system, they steal proprietary data transmitted over corporate and classified networks, often causing serious damage before they are detected.

HOW TO PREVENT MALWARE ATTACKS

The best approach to preventing malware attacks is one that is proactive. A good starting place to prevent malware attacks in your organization is to educate your employees on how to recognize and protect their computers and devices from such attacks.

Understand where the malware comes from

  • suspicious links and emails – When you receive an unsolicited or suspicious-looking link or email, avoid it. Many times these are phishing emails intended to appear legitimate in order to trick users into downloading malware.
  • suspicious websites – Malware attackers often spoof popular websites, if you download the software from the website, the malware will go to your computer.
  • install software from untrusted source – installing anything new on a computer or device, including free or trial versions of software.

Prevent untrusted software from running using process filter driver.

Now we know the untrusted software was downloaded to the download folder, so if we can block these software to run at the first place, then we can prevent our computer from being attacked by the malware.

The process filter driver can block the process running, or limit the application privileges, control what a program can do: where the program can write to, where the program can’t write, which file the program can’t change or delete.

Easefilter process filter driver is a kernel-mode driver that filters process/thread creation and termination, it provides you an easy way to develop Windows application for the Windows process monitoring and protection. With the EaseFilter Process Filter Driver, it enables your application to prevent the untrusted executable binaries ( malwares) from being launched, protect your data being damaged by the untrusted processes. It also enables your application to get the callback notification for the process/thread creation or termination, from the new process information you can get the parent process Id and thread Id of the new created process, you also can get the exact file name that is used to open the executable file and the command line that is used to execute the process if it is available.

A demo project using the process filter driver monitor and control the process activities.

Process Filter Screenshot

Download the process filter driver library and example project source code here.

Here is the best practice how to use the process filter driver to protect your system against the malware attack.

HOW DOES THE PROCESS FILTER DRIVER WORK

The process filter driver  can register a list of callback routines for thread, process, and desktop handle operations.

NTSTATUS ObRegisterCallbacks(
  POB_CALLBACK_REGISTRATION CallbackRegistration,
  PVOID                     *RegistrationHandle
);
  • CallbackRegistration: OB_CALLBACK_REGISTRATIONA pointer to a list of callback routines and other properties
  • RegistrationHandle: A pointer to a value that identifies ObUnRegisterCallbacksthe registered callback routine, passed to to unregister the callback routine

OB_CALLBACK_REGISTRATION

typedef struct _OB_CALLBACK_REGISTRATION {
    _In_ USHORT                     Version;
    _In_ USHORT                     OperationRegistrationCount;
    _In_ UNICODE_STRING             Altitude;
    _In_ PVOID                      RegistrationContext;
    _In_ OB_OPERATION_REGISTRATION  *OperationRegistration;
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
  • Version: The version of the requested Object Callback Registration, the driver OB_FLT_REGISTRATION_VERSIONspecifies the value
  • OperationRegistrationCount: OperationRegistrationnumber of items in the array
  • Altitude: Altitude of driver (Unicode), registered and used in MS, also related to load order
  • RegistrationContext: When the callback routine is executed, the corresponding value is passed to the callback routine
  • OperationRegistration: OB_OPERATION_REGISTRATIONPointer to, ObjectPre, PostCallbackspecifies the type of routine being called

OB_OPERATION_REGISTRATION

typedef struct _OB_OPERATION_REGISTRATION {
    POBJECT_TYPE                *ObjectType;
    OB_OPERATION                Operations;
    POB_PRE_OPERATION_CALLBACK  PreOperation;
    POB_POST_OPERATION_CALLBACK PostOperation;
} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
  • ObjectType: Pointer to the object type that triggers the callback routine
    • PsProcessType: Type for process handle operation
    • PsThreadType: Type for thread handle operation
    • ExDesktopObjectType: Type for desktop handle operation
  • Operations: Specify the following flags
    • OB_OPERATION_HANDLE_CREATE: Operates when a new handle ( ObjectTypeaccording to) is created or opened
    • OB_OPERATION_HANDLE_DUPLICATE: Action when cloning or cloning a new handle
  • PreOperation: OB_PRE_OPERATION_CALLBACKpointer to, calls the routine before the requested operation occurs
  • PostOperation: OB_POST_OPERATION_CALLBACKpointer to, calls the routine after the requested operation occurs

OB_PRE(POST)_OPERATION_CALLBACK

POB_PRE_OPERATION_CALLBACK PobPreOperationCallback;
POB_POST_OPERATION_CALLBACK PobPostOperationCallback;

OB_PREOP_CALLBACK_STATUS PobPreOperationCallback(
  PVOID RegistrationContext,
  POB_PRE_OPERATION_INFORMATION OperationInformation
)
{...}

void PobPostOperationCallback(
  PVOID RegistrationContext,
  POB_POST_OPERATION_INFORMATION OperationInformation
)
{...}
  • RegistrationContext: Same as OB_CALLBACK_REGISTRATIONmineRegistrationContext
  • OperationInformation: OB_PRE(POST)_OPERATION_INFORMATIONSpecifies the pointer and handle operation parameters

OB_PRE(POST)_OPERATION_INFORMATION

typedef struct _OB_PRE_OPERATION_INFORMATION {
    _In_ OB_OPERATION           Operation;
    union {
        _In_ ULONG Flags;
        struct {
            _In_ ULONG KernelHandle:1;
            _In_ ULONG Reserved:31;
        };
    };
    _In_ PVOID                         Object;
    _In_ POBJECT_TYPE                  ObjectType;
    _Out_ PVOID                        CallContext;
    _In_ POB_PRE_OPERATION_PARAMETERS  Parameters;
} OB_PRE_OPERATION_INFORMATION, *POB_PRE_OPERATION_INFORMATION;

typedef struct _OB_POST_OPERATION_INFORMATION {
    _In_ OB_OPERATION  Operation;
    union {
        _In_ ULONG Flags;
        struct {
            _In_ ULONG KernelHandle:1;
            _In_ ULONG Reserved:31;
        };
    };
    _In_ PVOID                          Object;
    _In_ POBJECT_TYPE                   ObjectType;
    _In_ PVOID                          CallContext;
    _In_ NTSTATUS                       ReturnStatus;
    _In_ POB_POST_OPERATION_PARAMETERS  Parameters;
} OB_POST_OPERATION_INFORMATION,*POB_POST_OPERATION_INFORMATION;
  • Operation: Type of Handle Operation
    • OB_OPERATION_HANDLE_CREATE: Create process or thread handle
    • OB_OPERATIOIN_HANDLE_DUPLICATE: The handle of the process or thread is duplicated
  • Flags: reserved areas, KernelHandleuse
  • KernelHandle: A value that specifies whether the handle is a kernel handle. Kernel handle if TRUE
  • Reserved: Reserved area for use in the system
  • Object: Process or thread object (EPROCESS, ETHREAD, etc.)
  • ObjectType: PsProcessTypeorPsThreadType
  • CallContext: Pointer to driver specific context information
  • ReturnStatus(POST): for handle operation NTSTATUS
  • Parameters: OB_PRE(POST)_OPERATION_PARAMETERSpointer to

OB_PRE(POST)_OPERATION_PARAMETERS

typedef union _OB_PRE_OPERATION_PARAMETERS {
  OB_PRE_CREATE_HANDLE_INFORMATION    CreateHandleInformation;
  OB_PRE_DUPLICATE_HANDLE_INFORMATION DuplicateHandleInformation;
} OB_PRE_OPERATION_PARAMETERS, *POB_PRE_OPERATION_PARAMETERS;

typedef union _OB_POST_OPERATION_PARAMETERS {
  OB_POST_CREATE_HANDLE_INFORMATION    CreateHandleInformation;
  OB_POST_DUPLICATE_HANDLE_INFORMATION DuplicateHandleInformation;
} OB_POST_OPERATION_PARAMETERS, *POB_POST_OPERATION_PARAMETERS;
  • CreateHandleInformation: OB_PRE(POST)_CREATE_HANDLE_INFORMATION structure containing the open handle and related information
  • DuplicateHandleInformation: OB_PRE(POST)_DUPLICATE_HANDLE_INFORMATIONStructure containing the duplicated handle and related information

OB_PRE(POST)_CREATE_HANDLE_INFORMATION

typedef struct _OB_PRE_CREATE_HANDLE_INFORMATION {
  ACCESS_MASK DesiredAccess;
  ACCESS_MASK OriginalDesiredAccess;
} OB_PRE_CREATE_HANDLE_INFORMATION, *POB_PRE_CREATE_HANDLE_INFORMATION;

typedef struct _OB_POST_CREATE_HANDLE_INFORMATION {
  ACCESS_MASK GrantedAccess;
} OB_POST_CREATE_HANDLE_INFORMATION, *POB_POST_CREATE_HANDLE_INFORMATION;
  • DesiredAccess (PRE): OriginalDesiredAccessBasically the same as the value, but PreCallbackaccess can be restricted using a routine
  • OriginalDesiredAccess(PRE): A value specifying the original access requested for the handle
  • GrantedAccess(POST): Value specifying access granted to handle