How to access kernel-level files on Windows platforms --- fdcwq from the CN black guest Alliance)

Source: Internet
Author: User
1. Background
On windows, applications usually use API functions to access, create, open, and read/write files. From the CreateFile/ReadFile/WriteFile function of kernel32 to the local system service, to FileSystem and Its FilterDriver, it has gone through many layers. At each layer, there are opportunities for security protection software, viruses or backdoors to monitor or filter. As security product developers, we need to go further than others, therefore, we need an underlying "windows kernel-level file access" method to ensure that we can see the correct and clean file system.

2. Purpose
Direct kernel-level file access is widely used in the information security field. Attackers can bypass anti-virus software, IDS, and other security protection systems. For the detector, you can see a clean system to kill hidden backdoors or rootkit. For the monitor, you can learn about the latest bypass monitoring technology and design an updated monitoring solution based on it.

3. Direct Access to FSD kernel-level File Access
The FSD (FileSystemDriver) layer is the driver level that the file API function reaches after the local system service layer (native API. If we can imitate the operating system and send IRP directly to FSD in our own driver, we can bypass native APIs and win32 APIs, in this way, you can bypass monitoring measures such as API hooks configured on these levels.

3.1 file Create and Open
You can send IRP_MJ_CREATE to FSD or call the IoCreateFile function to Create and Open files. The difference between Create and Open lies in the value of Disposition, a parameter of IoCreateFile/IRP_MJ_CREATE. Sample Code for using the IoCreateFile function:

HANDLE openfile (WCHAR * name, ACCESS_MASK access, ULONG share)
{
// Return 0 for error.
HANDLE hfile;
IO_STATUS_BLOCK iosb;
Int stat;
OBJECT_ATTRIBUTES oba;
UNICODE_STRING nameus;
///
If (KeGetCurrentIrql ()> PASSIVE_LEVEL) {return 0 ;}
RtlInitUnicodeString (& nameus, name );
InitializeObjectAttributes (& oba, & nameus, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 0, 0 );
Stat = IoCreateFile (& hfile, access, & oba, & iosb, 0, FILE_ATTRIBUTE_NORMAL, share, FILE_OPEN, 0, 0, 0, 0, 0 );
If (! NT_SUCCESS (stat) {return 0 ;}
Return hfile;
}

HANDLE createnewfile (WCHAR * name, ACCESS_MASK access, ULONG share)
{
// Return 0 for error.
HANDLE hfile;
IO_STATUS_BLOCK iosb;
Int stat;
OBJECT_ATTRIBUTES oba;
UNICODE_STRING nameus;
///
If (KeGetCurrentIrql ()> PASSIVE_LEVEL) {return 0 ;}
RtlInitUnicodeString (& nameus, name );
InitializeObjectAttributes (& oba, & nameus, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 0, 0 );
Stat = IoCreateFile (& hfile, access, & oba, & iosb, 0, // AllocationSize this set to 0 that when file opened it was zeroed.
FILE_ATTRIBUTE_NORMAL, share, FILE_OVERWRITE_IF, 0, 0, 0, 0 );
If (! NT_SUCCESS (stat) {return 0 ;}
Return hfile;
}

The method for sending IRP_MJ_CREATE to FSD is similar. For details, refer to the IRP_MJ_CREATE description of IFSDDK document. Unlike the above method, you need to create a FILE_OBJECT by yourself. Better than the above method, this method does not require a HANDLE, HANDLE is thread dependent, and FileObject is thread independent.

3.2 file Read and Write
We send IRP_MJ_READ to FSD to read the file and send IRP_MJ_WRITE to FSD to rewrite the file.
If we use a HANDLE for execution (for example, to open a file using IoCreateFile), we must first use the ObReferenceObjectByHandle function to obtain the FileObject corresponding to the Handle. We can only send IRP to FileObject.

Stat = ObReferenceObjectByHandle (handle, GENERIC_READ, * IoFileObjectType, KernelMode, (PVOID *) & fileob, 0 );

Then we use IoAllocateIrp to allocate an IRP. Based on the value of FileObject-> DeviceObject-> Flags, we can determine the IO method used by the target file system.

If (fileob-> DeviceObject-> Flags & DO_BUFFERED_IO)
{
Irp-> AssociatedIrp. SystemBuffer = buffer; // buffered io
}
Else if (fileob-> DeviceObject-> Flags & DO_DIRECT_IO)
{
Mdl = IoAllocateMdl (buffer, count, 0, 0 );
MmBuildMdlForNonPagedPool (mdl );
Irp-> MdlAddress = mdl; // direct io
}
Else
{
Irp-> UserBuffer = buffer; // neither I/o, use kernel buffer
}

Different address transfer methods are used for different IO methods. Then we can fill in the parameter fields in the IRP to send the IRP. Take Read as an example:

Irpsp-> FileObject = fileob;
Irpsp-> majorfunction = irp_mj_read;
Irpsp-> minorfunction = irp_mn_normal; // 0
Irpsp-> parameters. Read. byteoffset = offsetused;
Irpsp-> parameters. Read. Key = 0;
Irpsp-> parameters. Read. Length = count;

Next, we need to consider the situation that asynchronous responses will be returned if IRP cannot be completed in a timely manner. We will install a completionroutine and set an event to activated in completionroutine, notify our main thread that the read or write operations have been completed.

Iosetcompletionroutine (IRP, iocompletion, & event, 1, 1 );

Ntstatus
Iocompletion (
In pdevice_object deviceobject,
In pirp,
In pvoid Context
)
{
Kesetevent (prkevent) Context, io_disk_increment, 0 );
Return status_more_processing_required;
}

Now you can send IRP. If no special action is taken, the IRP Sending target is the deviceobject corresponding to the fileobject. After sending the message, wait for the completion of IRP and release the resource, and return.

Stat = IoCallDriver (fileob-> DeviceObject, irp );
If (stat = STATUS_PENDING ){
KeWaitForSingleObject (& event, Executive, KernelMode, 0, 0 );
Stat = irp-> IoStatus. Status;
}
If (! NT_SUCCESS (stat ))
{
IoFreeIrp (irp );
If (mdl) {IoFreeMdl (mdl) ;}// if DO_DIRECT_IO
Return-1;
}
Stat = irp-> IoStatus. Information; // bytes read
IoFreeIrp (irp );
If (mdl) {IoFreeMdl (mdl) ;}// if DO_DIRECT_IO
Return stat;

3.3 Delete a file
Delete is actually executed by sending IRP_MJ_SET_INFORMATION IRP to FSD, setting IrpSp-> Parameters. SetFile. FileInformationClass to FileDispositionInformation, and filling the buffer with a FILE_DISPOSITION_INFORMATION structure.

Fdi. DeleteFile = TRUE;

Irpsp-> MajorFunction = IRP_MJ_SET_INFORMATION;
Irpsp-> Parameters. SetFile. Length = sizeof (FILE_DISPOSITION_INFORMATION );
Irpsp-> Parameters. SetFile. FileInformationClass = FileDispositionInformation;
Irpsp-> Parameters. SetFile. DeleteHandle = (HANDLE) handle;

Rename of file 3.4
Similar to Delete, Rename sends IRP_MJ_SET_INFORMATION IRP to FSD, sets IrpSp-> Parameters. SetFile. FileInformationClass to FileRenameInformation, and fills the buffer with the FILE_RENAME_INFORMATION structure.

Fri. ReplaceIfExists = TRUE;
Fri. RootDirectory = 0; // Set fri. FileName to full path name.
Fri. FileNameLength = wcslen (filename) * 2;
Wcscpy (fri. fileName, filename); // If the RootDirectory member is NULL, and the file is being moved to a different directory, this member specifies the full pathname to be assigned to the file.

Irpsp-> MajorFunction = IRP_MJ_SET_INFORMATION;
Irpsp-> Parameters. SetFile. Length = sizeof (FILE_FILE_RENAME_INFORMATION );
Irpsp-> Parameters. SetFile. FileInformationClass = FileRenameInformation;

In summary, we can directly access the file system by sending IRPs in the driver, bypassing the native API and win32 API layers.

4. bypass the file system filter driver and hook

With the third part, we can directly send the request operation file to FSD. However, this is not enough because many anti-virus software or monitoring tools use the FSD Filter Driver or FSD Hook method to monitor file operations. In this article, I will introduce some principles and provide ideas for bypassing the FSD Filter Driver/FSD Hook.

4.1 File System Filter Driver

The file system filter driver Attach monitors and filters file access on a normal file system. The file system driver stack is composed of a series of filters driven by Attach. We can use the IoGetRelatedDeviceObject function to obtain the underlying function-Driven Object (FDO) corresponding to a FileObject ). However, although these filter drivers are bypassed, normal FSD, such as Ntfs/Fastfat, is also bypassed, because normal FSD also exists as a filter driver. The underlying FDO of the disk file object is Ftdisk. sys, which is too low-level to handle the IRP request.
In fact, the normal FSD information is stored in a Vpb structure. We can use the undisclosed kernel function IoGetBaseFileSystemDeviceObject to obtain it. It is the target for sending IRP.

4.2 Replace the DispatchRoutine FSD Hook

This is a common FSD Hook method. We need to get the original DispatchRoutine and send our IRP to the original DispatchRoutine. Here we provide an idea: we can read the original FSD driver. INIT segment or. TEXT section. Find its DriverEntry function. In its DriverEntry function, you must have set the DispatchRoutine of your DriverObject. In this function, we can find the desired DispatchRoutine address. You only need to use the Pattern Search Method to search for this value.

4.3 deal with the FSD Hook of the Inline Hook DispatchRoutine function itself

This Hook method is very toxic, but not very common in security products. It is generally applied to Trojans and rootkits, such as my own rootkit. It does not change the DispatchRoutine function pointer in DriverObject, but writes the JMP of the assembly instruction to the beginning of the function to jump to the function. The basic idea is to read the FSD files on the disk and load them to the memory for a clean backup, check whether the bytes starting with DispatchRoutine we want to call are consistent with the clean backup. If they are inconsistent, especially when there are Assembly commands such as JMP, RET, and INT3, there may be Inline hooks. (However, the relocation should be fully considered .) If an Inline Hook exists, we copy the beginning of the clean function to overwrite the infected function header. Then, when an IRP is sent, it will not be monitored or tampered with by the Inline Hook.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.