#include "precomp.h" NTSTATUS Bs1FltFileInUserMode( __in PCFLT_RELATED_OBJECTS FltObjects, __in PUNICODE_STRING FilePath, __out PBOOLEAN SafeToOpen ) { NTSTATUS status = STATUS_SUCCESS; //PVOID buffer = NULL; //ULONG bytesRead; PFILE_OBJECT_DESC notification = NULL; //FLT_VOLUME_PROPERTIES volumeProps; //LARGE_INTEGER offset; ULONG replyLength; //ULONG length; //PFLT_VOLUME volume = NULL; UNREFERENCED_PARAMETER(FltObjects); *SafeToOpen = TRUE; if (g_bs1Flt.ClientPort == NULL) { return STATUS_SUCCESS; } try { notification = ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_OBJECT_DESC), 'pbsn'); if (notification == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; leave; } RtlZeroMemory(notification, sizeof(FILE_OBJECT_DESC)); notification->pid = HandleToULong(PsGetCurrentProcessId()); notification->size = min(FilePath->Length, PATH_SIZE - 2); RtlCopyMemory(¬ification->path, FilePath->Buffer, notification->size); /// À¯Àú Ŭ¶óÀÌ¾ðÆ®·Î Á¤º¸ Àü´Þ & Wait KLogEx(DEBUG_TRACE_INFO, "notify path (%d)(%S)\n", notification->pid, FilePath->Buffer); replyLength = sizeof(BS1FLT_REPLY); status = FltSendMessage(g_bs1Flt.Filter, &g_bs1Flt.ClientPort, notification, sizeof(FILE_OBJECT_DESC), notification, &replyLength, NULL); if (status == STATUS_SUCCESS) { *SafeToOpen = ((PBS1FLT_REPLY)notification)->SafeToOpen; KLogEx(DEBUG_TRACE_INFO, "FltSendMessage, Success %d size = %d\n", *SafeToOpen, sizeof(FILE_OBJECT_DESC)); } else { KLogEx(DEBUG_TRACE_INFO, "couldn't send message to user-mode to, status 0x%X\n", status); } } finally { if (NULL != notification) { ExFreePoolWithTag(notification, 'pbsn'); } } return status; } FLT_PREOP_CALLBACK_STATUS Bs1FltNofity(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PUNICODE_STRING pUniFilePath, ULONG ulPidType ) { BOOLEAN safeToOpen = FALSE; FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; ULONG create_option = 0; ULONG disposition = 0; DWORD desiredaccess = 0; USHORT fileattribute = 0; create_option = Data->Iopb->Parameters.Create.Options; disposition = (create_option >> 24) & 0xFF; desiredaccess = Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess; fileattribute = Data->Iopb->Parameters.Create.FileAttributes; if (disposition != FILE_OPEN) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } if (!(fileattribute & FILE_ATTRIBUTE_NORMAL)) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } /// µð·ºÅ丮¸é ¿¹¿Ü if (create_option & FILE_DIRECTORY_FILE) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } if (!(create_option & FILE_NON_DIRECTORY_FILE)) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } //cretaeoption = 1000140, disposition = 1, desiredaccess = a1 ¿¹¿Ü ó¸® Á¤º¸ if (create_option & FILE_COMPLETE_IF_OPLOCKED) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } if (ulPidType == PG_PID_WHITE) { Bs1FltFileInUserMode(FltObjects, pUniFilePath, &safeToOpen); if (!safeToOpen) { KLogEx(DEBUG_TRACE_INFO, "foul language detected in postcreate !!!\n"); Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; returnStatus = FLT_PREOP_COMPLETE;; } //SetFileObjectList(0, FltObjects->FileObject, pUniFilePath->Buffer, pUniFilePath->Length); } return returnStatus; } BOOLEAN Bs1FltIsFileName(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PUNICODE_STRING pUniFilePath, ULONG ulPidType, ULONG ulFileType ) { //WCHAR buf[260] = { 0, }; ULONG create_option = 0; WCHAR* ptr = NULL; UNICODE_STRING uniFileName = { 0, }; UCHAR major = Data->Iopb->MajorFunction; UNREFERENCED_PARAMETER(ulPidType); UNREFERENCED_PARAMETER(FltObjects); UNREFERENCED_PARAMETER(Data); if (major == IRP_MJ_CREATE) { create_option = Data->Iopb->Parameters.Create.Options; //KLogEx("PBShareLockIsFileName, CreateOption = %x\n", create_option); if (create_option & FILE_DIRECTORY_FILE) { return FALSE; } } // if(!(create_option & FILE_NON_DIRECTORY_FILE)) // { // return TRUE; // } ptr = wcsrchr(pUniFilePath->Buffer, '\\'); if (ptr) { ++ptr; RtlInitUnicodeString(&uniFileName, ptr); /// 2015.3.20 Á¤Ã¥ ÆÄÀÏ Á¢±Ù¿¡ ´ëÇÑ ¹®Á¦·Î ÀÎÇØ ¸ðµç ÇÁ·Î¼¼½º¿¡ Àбâ Àü¿ëÀ¸·Î º¯°æ if (IsFileName(ulFileType, uniFileName.Buffer, uniFileName.Length)/* && ulPidType == PG_PID_GREEN*/) { if (major == IRP_MJ_CREATE) { DWORD desiredaccess = Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess; KLogEx(DEBUG_TRACE_ERROR, "desiredaccess(%x) name(%S) len(%d)\n", desiredaccess, uniFileName.Buffer, uniFileName.Length); if (desiredaccess & ((WRITE_MODE | DELETE))) return FALSE; } else if (major == IRP_MJ_SET_INFORMATION) { FILE_INFORMATION_CLASS fileinfoclass = Data->Iopb->Parameters.SetFileInformation.FileInformationClass; /// À̸§ º¯°æ & »èÁ¦ÀÇ °æ¿ì Â÷´Ü if (fileinfoclass == FileRenameInformation || fileinfoclass == FileDispositionInformation || fileinfoclass == FileRenameInformationEx || fileinfoclass == FileDispositionInformationEx) return FALSE; } return TRUE; } } return FALSE; } /* BOOLEAN IsPolicyState(ULONG type, ULONG state, PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS fltobject) { ULONG disposition; ULONG desired_access = 0; ULONG create_option = 0; // ¾²±â ¹× º¯°æ°ú °ü·ÃµÈ ¸ðµç ±ÇÇÑ ¸¶½ºÅ© Á¤ÀÇ ULONG WriteAccessMask = FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_DELETE_CHILD | DELETE | WRITE_DAC | WRITE_OWNER | MAXIMUM_ALLOWED | GENERIC_WRITE | GENERIC_ALL; UNREFERENCED_PARAMETER(type); if (data->Iopb == NULL) return FALSE; // ¹æ¾î ÄÚµå desired_access = data->Iopb->Parameters.Create.SecurityContext->DesiredAccess; create_option = data->Iopb->Parameters.Create.Options; // Disposition ÃßÃâ (»óÀ§ 8ºñÆ®) disposition = (data->Iopb->Parameters.Create.Options >> 24) & 0xFF; if (state == DISABLE) return TRUE; if (state == ENABLE) return FALSE; // READONLY Á¤Ã¥ ó¸® if (state == READONLY) { KLogEx(DEBUG_TRACE_ERROR, "READONLY, disposition[%x],create_option(%x), desired_access(%x)\n", disposition, create_option, desired_access); // 1. [ÇÙ½É] Disposition º° ó¸® switch (disposition) { // [CASE A] ¹«Á¶°Ç ÆÄÀÏ ³»¿ëÀ» º¯°æÇϰųª »õ·Î ¸¸µå´Â °æ¿ì -> Áï½Ã Â÷´Ü case FILE_CREATE: // ¾øÀ¸¸é »ý¼º, ÀÖÀ¸¸é ½ÇÆÐ -> »ý¼º ½ÃµµÀ̹ǷΠÂ÷´Ü case FILE_SUPERSEDE: // ÀÖÀ¸¸é µ¤¾î¾²±â(»èÁ¦ ÈÄ »ý¼º) -> Â÷´Ü case FILE_OVERWRITE: // ÀÖÀ¸¸é µ¤¾î¾²±â -> Â÷´Ü case FILE_OVERWRITE_IF: // ¾øÀ¸¸é »ý¼º, ÀÖÀ¸¸é µ¤¾î¾²±â -> µÑ ´Ù º¯°æÀ̹ǷΠÂ÷´Ü KLogEx(DEBUG_TRACE_ERROR, "Block(Destructive Action) disposition[%x]\n", disposition); return TRUE; // [CASE B] ÆÄÀÏÀÌ ÀÖÀ¸¸é ¿­°í, ¾øÀ¸¸é ¸¸µå´Â °æ¿ì case FILE_OPEN_IF: { HANDLE hFileHandle = 0; OBJECT_ATTRIBUTES objectAttributes; // ÃʱâÈ­ ÁÖÀÇ IO_STATUS_BLOCK IoStatusBlock; NTSTATUS ntStatus = 0; InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); // ÆÄÀÏ Á¸Àç ¿©ºÎ È®ÀÎ (Àб⠱ÇÇÑÀ¸·Î ½Ãµµ) ntStatus = FltCreateFile( fltobject->Filter, fltobject->Instance, &hFileHandle, FILE_READ_ATTRIBUTES, // ÃÖ¼Ò ±ÇÇÑÀ¸·Î È®ÀÎ &objectAttributes, &IoStatusBlock, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE, // ¿É¼Ç ÁÖÀÇ NULL, 0, 0 ); if (NT_SUCCESS(ntStatus)) { // ÆÄÀÏÀÌ Á¸ÀçÇÔ -> "ÆÄÀÏ ¿­±â" ½Ãµµ FltClose(hFileHandle); // [Áß¿ä ¼öÁ¤] ÆÄÀÏÀÌ À־ '¾²±â ±ÇÇÑ'À» ¿äûÇß´Ù¸é Â÷´ÜÇØ¾ß ÇÔ if (desired_access & WriteAccessMask) { KLogEx(DEBUG_TRACE_ERROR, "Block(OPEN_IF/Exist but Write) access(%x)\n", desired_access); return TRUE; } // ¾²±â ±ÇÇÑ ¾øÀ¸¸é Çã¿ë (Àбâ Àü¿ë ¿ÀÇÂ) } else { // ÆÄÀÏÀÌ ¾øÀ½ -> "ÆÄÀÏ »ý¼º" ½Ãµµ -> Â÷´Ü KLogEx(DEBUG_TRACE_ERROR, "Block(OPEN_IF/Not Exist) -> Try Create\n"); return TRUE; } break; } // [CASE C] ÆÄÀÏÀÌ ÀÖÀ» ¶§¸¸ ¿©´Â °æ¿ì (±âÁ¸ Äڵ忡¼­ °¡Àå Ãë¾àÇß´ø ºÎºÐ) case FILE_OPEN: { // [Áß¿ä ¼öÁ¤] DELETE »Ó¸¸ ¾Æ´Ï¶ó Write Data, Append Data µîµµ Ã¼Å©ÇØ¾ß ÇÔ if (desired_access & WriteAccessMask) { KLogEx(DEBUG_TRACE_ERROR, "Block(FILE_OPEN with Write) access(%x)\n", desired_access); return TRUE; } break; } default: break; } } return FALSE; } */ BOOLEAN IsPolicyState(ULONG type, ULONG state, PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS fltobject) { ULONG disposition; ULONG desired_access = 0; ULONG create_option = 0; USHORT create_fileattribute = 0; //USHORT share_access = 0; //ULONG devicetype = 0; UNREFERENCED_PARAMETER(type); desired_access = data->Iopb->Parameters.Create.SecurityContext->DesiredAccess; create_option = data->Iopb->Parameters.Create.Options; disposition = (create_option >> 24) & 0xFF; create_fileattribute = data->Iopb->Parameters.Create.FileAttributes; if (state == DISABLE) return TRUE; if (state == ENABLE) { return FALSE; } else if (state == READONLY) { KLogEx(DEBUG_TRACE_ERROR, "READONLY, disposition[%x],create_option(%x), desired_access(%x)\n", disposition, create_option, desired_access); switch (disposition) { case FILE_CREATE: case FILE_SUPERSEDE: { /// Æú´õ »ý¼º Â÷´Ü if (create_option & FILE_DIRECTORY_FILE) { if (desired_access & (FILE_WRITE_EA)) { KLogEx(DEBUG_TRACE_ERROR, "block(1) create_option(%x), desired_access(%x)\n", create_option, desired_access); return TRUE; } // sskim - 170207 Added. if (desired_access & (FILE_LIST_DIRECTORY)) { KLogEx(DEBUG_TRACE_ERROR, "block(2) create_option(%x), desired_access(%x)\n", create_option, desired_access); return TRUE; } } if (desired_access & (FILE_WRITE_DATA)) { KLogEx(DEBUG_TRACE_ERROR, "block(3) disposition(%x), desired_access(%x)\n", disposition, desired_access); return TRUE; } // »èÁ¦ Â÷´Ü if (desired_access & (DELETE)) { KLogEx(DEBUG_TRACE_ERROR, "block(4) disposition(%x), desired_access(%x)\n", disposition, desired_access); return TRUE; } break; } case FILE_OVERWRITE_IF: case FILE_OPEN_IF: { KLogEx(DEBUG_TRACE_ERROR, "FILE_OVERWRITE_IF , FILE_OPEN_IF disposition[%x]create_option(%x), desired_access(%x)\n", disposition, create_option, desired_access); } { HANDLE hFileHandle = 0; OBJECT_ATTRIBUTES objectAttributes = { 0, }; IO_STATUS_BLOCK IoStatusBlock; NTSTATUS ntStatus = 0; ntStatus = FltCreateFile( fltobject->Filter, fltobject->Instance, &hFileHandle, GENERIC_READ, &objectAttributes, &IoStatusBlock, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, 0 ); if (NT_SUCCESS(ntStatus)) { // ÀÌ¹Ì ÆÄÀÏÀÌ ÀÖ´Â °æ¿ì FltClose(hFileHandle); // Çã¿ë KLogEx(DEBUG_TRACE_ERROR, "PERMIT(1) disposition(%x), desired_access(%x),create_option(%x)\n", disposition, desired_access, create_option); } else { //Â÷´Ü KLogEx(DEBUG_TRACE_ERROR, "block(5) disposition(%x), desired_access(%x)\n", disposition, desired_access); return TRUE; } } if (desired_access & (DELETE)) { KLogEx(DEBUG_TRACE_ERROR, "block(6) disposition(%x), desired_access(%x)\n", disposition, desired_access); return TRUE; } { if(desired_access & (FILE_WRITE_DATA)) { KLogEx(DEBUG_TRACE_ERROR, "block(3) disposition(%x), desired_access(%x)\n", disposition, desired_access); return TRUE; } // »èÁ¦ Â÷´Ü if(desired_access & (DELETE)) { KLogEx(DEBUG_TRACE_ERROR, "block(4) disposition(%x), desired_access(%x)\n", disposition, desired_access); return TRUE; } } break; case FILE_OPEN: { if (desired_access & (DELETE)) { KLogEx(DEBUG_TRACE_ERROR, "block(7) disposition(%x), desired_access(%x)\n", disposition, desired_access); return TRUE; } } break; case FILE_OVERWRITE: { KLogEx(DEBUG_TRACE_ERROR, "PERMIT(2) disposition(%x), desired_access(%x),create_option(%x)\n", disposition, desired_access, create_option); //return TRUE; } break; default: return FALSE; } } return FALSE; } BOOLEAN IsNetworkDrive(LPWSTR path) { static LPCWSTR s_networkSignatures[] = { /// ³×Æ®¿öÅ© µå¶óÀÌºê »ç¿ë /// etc /// win 7. \Device\Mup\;LanmanRedirector\;Z:00000000001cdd14\KMG-PC\share\allowpl - º¹»çº» (2).ini /// xp sp3 \Device\LanmanRedirector\;Z:00000000000133ab\kmg-pc\share\ L"\\;LanmanRedirector\\;", L"\\;lanmanredirector\\;", L"\\LanmanRedirector\\;", NULL }; LPCWSTR* ep = s_networkSignatures; while (*ep) { if (wcsstr(path, *ep) != NULL) return TRUE; ++ep; } //µå¶óÀÌºê ·¹ÅÍ ÆÐÅÏ È®ÀÎ(; Z: ¶Ç´Â; z: ÇüÅÂ) LPCWSTR p = path; while ((p = wcschr(p, L';')) != NULL) { // p[0]Àº ';' ÀÔ´Ï´Ù. // p[1]ÀÌ NULLÀÌ ¾Æ´Ï°í(¹®ÀÚ¿­ ³¡ ¾Æ´Ô), p[2]°¡ ':' ÀÎÁö È®ÀÎ if (p[1] != L'\0' && p[2] == L':') { WCHAR driveLetter = p[1]; // ¿µ¹®ÀÚ(A-Z, a-z)ÀÎÁö È®ÀÎ if ((driveLetter >= L'A' && driveLetter <= L'Z') || (driveLetter >= L'a' && driveLetter <= L'z')) { return TRUE; } } p++; } return FALSE; } static BOOLEAN once = FALSE; BOOLEAN IsUsbException(PCFLT_RELATED_OBJECTS FltObjects, ULONG device_type) { PVOLUME_CONTEXT vctx = NULL; NTSTATUS status = STATUS_SUCCESS; BOOLEAN state = FALSE; ULONG list_state = 0; UNREFERENCED_PARAMETER(device_type); status = FltGetVolumeContext(FltObjects->Filter, FltObjects->Volume, &vctx); if (!NT_SUCCESS(status)) { KLogEx(DEBUG_TRACE_ERROR, "FltGetVolumeContext Failed (%x)\n", status); return FALSE; } //KLogEx(DEBUG_TRACE_INFO, "Vendor ID(%s),productid(%s)(%s)\n", vctx->vendorid, vctx->productid, vctx->vendorspecific); list_state = IsUsbDiskExceptionList((PCHAR)vctx->vendorid, (PCHAR)vctx->productid, (PCHAR)vctx->productrevisionlevel, (PCHAR)vctx->vendorspecific); if (list_state == 1) { //KLogEx(DEBUG_TRACE_INFO, "Vendor ID(%s),productid(%s)(%s)\n", vctx->vendorid, vctx->productid, vctx->vendorspecific); state = TRUE; } else if (list_state == 2) { //2026.03.03 //°¡»ó º¼·ý º¸¾È USB ¿¹¿Ü ó¸® PATH: \\Device\\CNTDriveMMGTVolumeG //deviceType(3), Vendor ID(SecretBerry), productid(VirtualDisk)() if (_strnicmp((char*)vctx->vendorid, "SecretBerry", strlen("SecretBerry")) == 0 && (_strnicmp((char*)vctx->productid, "VirtualDisk", strlen("VirtualDisk")) == 0)) { state = TRUE; } } FltReleaseContext(vctx); return state; } // ±âº» ÇÊÅ͸µ Á¶°ÇÀ» È®ÀÎÇÏ¿© ÆÐ½º ¿©ºÎ¸¦ °áÁ¤ BOOLEAN IsSkipCondition(PFLT_CALLBACK_DATA Data) { if (!g_bs1Flt.IsAttached) return TRUE; if (IoThreadToProcess(Data->Thread) == g_bs1Flt.UserProcess) return TRUE; if (!NT_SUCCESS(Data->IoStatus.Status) || (STATUS_REPARSE == Data->IoStatus.Status)) return TRUE; if (Data->Iopb->MajorFunction == IRP_MJ_CLEANUP) return TRUE; // °ü½ÉÀÖ´Â Major Function¸¸ ó¸® if (Data->Iopb->MajorFunction != IRP_MJ_SET_INFORMATION && Data->Iopb->MajorFunction != IRP_MJ_CREATE && Data->Iopb->MajorFunction != IRP_MJ_READ && Data->Iopb->MajorFunction != IRP_MJ_WRITE) // READ/WRITE Ãß°¡ (ÄÚµå ·ÎÁ÷»ó ÇÊ¿ä) return TRUE; if (KeGetCurrentIrql() > PASSIVE_LEVEL) return TRUE; return FALSE; } // ·ÎÄà µð½ºÅ© Á¤Ã¥ ó¸® FLT_PREOP_CALLBACK_STATUS HandleLocalDiskPolicy( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PUNICODE_STRING pUniFileName, PUNICODE_STRING pProcessPath, ULONG pid, ULONG pidType ) { ULONG pathType = 0; ULONG majorFunction = Data->Iopb->MajorFunction; ULONG createOption = 0; ULONG disposition = 0; ULONG desiredAccess = 0; UNREFERENCED_PARAMETER(pProcessPath); if (!g_bs1Flt.IsFolderProtect) return FLT_PREOP_SUCCESS_NO_CALLBACK; // Çã¿ëµÈ ÇÁ·Î¼¼½ºÀÎ °æ¿ì, Rename/Delete Â÷´Ü ¿É¼Ç È®ÀÎ if (pidType & PG_PID_ALLOW) { if ((pidType & PG_PID_BLOCK_RENAME) && (majorFunction == IRP_MJ_SET_INFORMATION)) { FILE_INFORMATION_CLASS infoClass = Data->Iopb->Parameters.SetFileInformation.FileInformationClass; if (infoClass != FileRenameInformation && infoClass != FileRenameInformationEx) return FLT_PREOP_SUCCESS_NO_CALLBACK; // RenameÀÌ¸é ¾Æ·¡ ·ÎÁ÷ °è¼Ó ÁøÇà (Â÷´Ü °Ë»ç) } else { return FLT_PREOP_SUCCESS_NO_CALLBACK; } } pathType = IsProtectPath(PG_PATH_ALL, pUniFileName->Buffer, pUniFileName->Length); if (pathType == PG_PATH_UNDEFINED) return FLT_PREOP_SUCCESS_NO_CALLBACK; if (pathType == PG_PATH_GRAY) // GRAY: Àбâ Çã¿ë, ¾²±â/»èÁ¦/À̸§º¯°æ Â÷´Ü { if (majorFunction == IRP_MJ_CREATE) { createOption = Data->Iopb->Parameters.Create.Options; disposition = (createOption >> 24) & 0xFF; desiredAccess = Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess; if (disposition == FILE_CREATE || (desiredAccess & (WRITE_MODE | DELETE))) { KLogEx(DEBUG_TRACE_INFO, "PG_PATH_GRAY BLOCK: CREATE/WRITE/DELETE Attempt. Path(%S)\n", pUniFileName->Buffer); } else { // Àбâ Àü¿ë Á¢±Ù Çã¿ë return FLT_PREOP_SUCCESS_NO_CALLBACK; } } else if (majorFunction == IRP_MJ_SET_INFORMATION) { FILE_INFORMATION_CLASS infoClass = Data->Iopb->Parameters.SetFileInformation.FileInformationClass; if (infoClass != FileRenameInformation && infoClass != FileDispositionInformation && infoClass != FileRenameInformationEx && infoClass != FileDispositionInformationEx) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } else { KLogEx(DEBUG_TRACE_INFO, "PG_PATH_GRAY BLOCK: RENAME Attempt. Path(%S)\n", pUniFileName->Buffer); } } } if (pathType == PG_PATH_BLACK) // BLACK: ¸ðµç Á¢±Ù Â÷´Ü(´Ü, ¿¹¿Ü ÆÄÀÏÀº Çã¿ë) { if (Bs1FltIsFileName(Data, FltObjects, pUniFileName, pidType, PG_FILE_ALLOW)) { KLogEx(DEBUG_TRACE_INFO, "PG_PATH_BLACK PERMIT FILENAME: Path(%S)\n", pUniFileName->Buffer); return FLT_PREOP_SUCCESS_NO_CALLBACK; } KLogEx(DEBUG_TRACE_INFO, "ACCESS DENIED (Local Disk): Path(%S), Pid(%d)\n", pUniFileName->Buffer, pid); Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; return FLT_PREOP_COMPLETE; } return FLT_PREOP_SUCCESS_NO_CALLBACK; } FLT_PREOP_CALLBACK_STATUS HandleNetWorkInDevicePolicy( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, ULONG deviceType, ULONG policyState, ULONG policyLog ) { char szProcessName[20] = { 0, }; WCHAR processName[50] = { 0, }; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; NTSTATUS status; ULONG pid = HandleToULong(PsGetCurrentProcessId()); try { status = FltGetFileNameInformation(Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); if (!NT_SUCCESS(status)) { KLogEx(DEBUG_TRACE_ERROR, "FltGetFileNameInformation Failed [%x]\n", status); leave; } else { status = FltParseFileNameInformation(nameInfo); if (!NT_SUCCESS(status)) { KLogEx(DEBUG_TRACE_ERROR, "FltParseFileNameInformation Failed [%x]\n", status); leave; } } KLogEx(DEBUG_TRACE_INFO, "Network Drive In processName(%S), Path(%S)\n", processName, nameInfo->Name.Buffer); if (policyLog) { UGetProcessName(szProcessName); RtlStringCbPrintfW(processName, sizeof(processName), L"%S", szProcessName); SetLog(Data, FltObjects, LOG_POLICY, deviceType, policyState, 0, processName, nameInfo->Name.Buffer); } if (policyState != ENABLE) { KLogEx(DEBUG_TRACE_INFO, "ACCESS DENIED Pid(%d)\n", pid); Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; return FLT_PREOP_COMPLETE; } } finally { if (nameInfo != NULL) FltReleaseFileNameInformation(nameInfo); } return FLT_PREOP_SUCCESS_NO_CALLBACK; } // USB, ³×Æ®¿öÅ© ¹× ±âŸ ÀåÄ¡(CD-ROM µî) Á¤Ã¥ ó¸® FLT_PREOP_CALLBACK_STATUS HandleExternalDevicePolicy( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PUNICODE_STRING pUniFileName, PUNICODE_STRING pProcessPath, ULONG pid, ULONG deviceType, ULONG policyState, ULONG policyLog ) { BOOLEAN isBlock = FALSE; ULONG majorFunction = Data->Iopb->MajorFunction; ULONG createOption = 0; ULONG disposition = 0; ULONG desiredAccess = 0; UNREFERENCED_PARAMETER(policyLog); if (!g_bs1Flt.IsDeviceProtect) return FLT_PREOP_SUCCESS_NO_CALLBACK; try { if (deviceType == BDC_USB_DISK || deviceType == BDC_EXTERNALHDD) { if (IsUsbException(FltObjects, deviceType)) leave; } // ³×Æ®¿öÅ© µå¶óÀ̺ê/°øÀ¯ °æ·Î ÀçÈ®ÀÎ ¹× Á¤Ã¥ °»½Å if (deviceType == BDC_NETWORKDRIVEOUT) { if (!IsNetworkDrive(pUniFileName->Buffer)) { deviceType = BDC_NETWORKSHAREOUT; policyState = GetPolicyState(deviceType); } } // Operation º° Â÷´Ü ¿©ºÎ °áÁ¤ switch (majorFunction) { case IRP_MJ_CREATE: createOption = Data->Iopb->Parameters.Create.Options; disposition = (createOption >> 24) & 0xFF; desiredAccess = Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess; KLogEx(DEBUG_TRACE_INFO, "Check External Policy: Create !!!! Pid(%d), Dev(%d), (%x)(%x)(%x) Path(%S)\n", pid, deviceType, createOption, disposition, desiredAccess, pUniFileName->Buffer); if (IsPolicyState(deviceType, policyState, Data, FltObjects)) isBlock = TRUE; break; case IRP_MJ_SET_INFORMATION: { FILE_INFORMATION_CLASS infoClass = Data->Iopb->Parameters.SetFileInformation.FileInformationClass; KLogEx(DEBUG_TRACE_INFO, "Check External Policy: SetInformation !!!! Pid(%d), Dev(%d)(%d), Path(%S)\n", pid, deviceType, infoClass, pUniFileName->Buffer); if (policyState == ENABLE) { // ENABLE »óÅÂÀÏ ¶§ ·Î±× ó¸® ·ÎÁ÷ (ÁÖ¼®µÇ¾î ÀÖ¾úÀ½) } else { if (infoClass == FileRenameInformation || infoClass == FileDispositionInformation) isBlock = TRUE; } } break; case IRP_MJ_READ: KLogEx(DEBUG_TRACE_INFO, "Check External Policy: Read !!!! Pid(%d), Dev(%d), Path(%S)\n", pid, deviceType, pUniFileName->Buffer); if (deviceType == BDC_CDROM) { // Windows Burning °ü·Ã Àӽà ÆÄÀÏ Â÷´Ü if (wcsstr(pUniFileName->Buffer, L"\\AppData\\Local\\Microsoft\\Windows\\Burn\\Burn\\") != NULL) isBlock = TRUE; } break; case IRP_MJ_WRITE: KLogEx(DEBUG_TRACE_INFO, "Check External Policy: Write !!!! Pid(%d), Dev(%d), Path(%S)\n", pid, deviceType, pUniFileName->Buffer); if (policyState != ENABLE) { isBlock = TRUE; } break; } // ³×Æ®¿öÅ© È£½ºÆ® IP Çã¿ë ¿¹¿Ü ó¸® if ((deviceType == BDC_NETWORKDRIVEOUT || deviceType == BDC_NETWORKSHAREOUT) && isBlock) { if (IsAllowHostIp(pUniFileName->Buffer, pUniFileName->Length)) { isBlock = FALSE; // IP Çã¿ë ¸ñ·Ï¿¡ ÀÖÀ¸¸é Â÷´Ü ÇØÁ¦ } } // CD-ROM ¿¹¿Ü ó¸® //if (deviceType == BDC_CDROM && isBlock) //{ // PWCHAR pwszTemp = wcsstr(pUniFileName->Buffer, L"\\CdRom"); // if (pwszTemp) // { // size_t len = wcslen(pwszTemp); // if (len == 7 || len == 8) // isBlock = FALSE; // } //} } finally { // ·Î±× ±â·Ï if (policyLog) { if (policyState == READONLY && !isBlock) { } else { SetLog(Data, FltObjects, LOG_POLICY, deviceType, policyState, 0, pProcessPath->Buffer, pUniFileName->Buffer); } } // ÃÖÁ¾ Â÷´Ü ó¸® if (policyState != ENABLE && isBlock == TRUE) { KLogEx(DEBUG_TRACE_INFO, "ACCESS DENIED D(%d), Pid(%d), Path(%S)\n", deviceType, pid, pUniFileName->Buffer); Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; return FLT_PREOP_COMPLETE; } else { //if (deviceType == BDC_CDROM) //{ // //KLogEx(DEBUG_TRACE_INFO, "ALLOW CDROM (%d), policyState (%x), policyLog (%x)(%s)\n", pid, policyState, policyLog, pUniFileName->Buffer); // /* Data->IoStatus.Status = STATUS_ACCESS_DENIED; // Data->IoStatus.Information = 0; // return FLT_PREOP_COMPLETE;*/ //} } } return FLT_PREOP_SUCCESS_NO_CALLBACK; } /************************************************************************* MiniFilter callback routines. *************************************************************************/ FLT_PREOP_CALLBACK_STATUS Bs1FltPreOperation( _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID* CompletionContext ) /*++ Routine Description: This routine is a pre-operation dispatch routine for this miniFilter. This is non-pageable because it could be called on the paging path Arguments: Data - Pointer to the filter callbackData that is passed to us. FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. CompletionContext - The context for the completion routine for this operation. Return Value: The return value is the status of the operation. --*/ { FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; UNICODE_STRING filePath = { 0, }; UNICODE_STRING processPath = { 0, }; NTSTATUS status; ULONG pid = 0; ULONG pidType = 0; ULONG processType = 0; ULONG deviceType = 0; ULONG policyState = 0; ULONG policyLog = 0; char szProcessName[20] = { 0, }; UNREFERENCED_PARAMETER(CompletionContext); PAGED_CODE(); if (IsSkipCondition(Data)) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } deviceType = GetDeviceType(Data, FltObjects); if (deviceType == BDC_UNKNOWN_DEV) return FLT_PREOP_SUCCESS_NO_CALLBACK; if (Data->RequestorMode == KernelMode) { if (deviceType != BDC_NETWORKDRIVEIN) return FLT_PREOP_SUCCESS_NO_CALLBACK; } // Á¤Ã¥ »óÅ ȮÀÎ policyState = GetPolicyState(deviceType); policyLog = IsPolicyLog(deviceType); if (deviceType != BDC_LOCAL_DISK) { if (policyState == ENABLE && policyLog == FALSE) return FLT_PREOP_SUCCESS_NO_CALLBACK; } if (deviceType == BDC_NETWORKDRIVEIN) { return HandleNetWorkInDevicePolicy( Data, FltObjects, deviceType, policyState, policyLog ); } pid = HandleToULong(PsGetCurrentProcessId()); // ÇÁ·Î¼¼½º ID ¹× À̸§ È®ÀÎ pidType = PgGetPidState(pid); if ((pidType & PG_PID_ALLOW)) return FLT_PREOP_SUCCESS_NO_CALLBACK; UGetProcessName(szProcessName); if (deviceType == BDC_LOCAL_DISK) { if (IsDefalutLocalDiskExceptProcess(szProcessName)) return FLT_PREOP_SUCCESS_NO_CALLBACK; } else { //if (IsDefalutExternalDiskExceptProcess(szProcessName)) // return FLT_PREOP_SUCCESS_NO_CALLBACK; } // ÆÄÀÏ À̸§ Á¤º¸ ȹµæ status = FltGetFileNameInformation(Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); if (!NT_SUCCESS(status)) { KLogEx(DEBUG_TRACE_ERROR, "FltGetFileNameInformation Failed (%x)\n", status); return FLT_PREOP_SUCCESS_NO_CALLBACK; } try { FltParseFileNameInformation(nameInfo); if (!NT_SUCCESS(UStrNew(&filePath, nameInfo->Name.MaximumLength + 10))) { KLogEx(DEBUG_TRACE_ERROR, "FltParseFileNameInformation Failed (%S)\n", nameInfo->Name.Buffer); leave; } UStrCopy(&filePath, &nameInfo->Name); status = UGetCurrentStackProcessImageName(pid, &processPath); if (!NT_SUCCESS(status)) { KLogEx(DEBUG_TRACE_ERROR, "Get Process Name Info Failed. szProcessName(%s), pid(%d), status(%x)\n", szProcessName, pid, status); leave; } // Á¤ÀǵÇÁö ¾ÊÀº ÇÁ·Î¼¼½º Á¤Ã¥ ¾÷µ¥ÀÌÆ® if (pidType == PG_PID_UNDEFINED) { if (!IsAllowProcessName(processPath.Buffer, processPath.Length, &processType)) { pidType = PG_PID_BLACK; } else { KLogEx(DEBUG_TRACE_INFO, "Update Allow Process, Path(%S)(%d), Type(%d)\n", processPath.Buffer, pid, processType); pidType = processType; PgAddPid(pid, pidType); } } // µð¹ÙÀ̽º ŸÀÔº° ·ÎÁ÷ ºÐ±â if (deviceType == BDC_LOCAL_DISK) { returnStatus = HandleLocalDiskPolicy(Data, FltObjects, &filePath, &processPath, pid, pidType); } else { if (pidType & PG_PID_ALLOW) leave; returnStatus = HandleExternalDevicePolicy(Data, FltObjects, &filePath, &processPath, pid, deviceType, policyState, policyLog); } } finally { UStrFree(&processPath); UStrFree(&filePath); if (nameInfo != NULL) FltReleaseFileNameInformation(nameInfo); } return returnStatus; } FLT_PREOP_CALLBACK_STATUS Bs1FltPreRead( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID* CompletionContext ) { UNREFERENCED_PARAMETER(CompletionContext); NTSTATUS status = FLT_PREOP_SUCCESS_NO_CALLBACK; if (!g_bs1Flt.IsAttached) return FLT_PREOP_SUCCESS_NO_CALLBACK; if (g_bs1Flt.UserProcess == PsGetCurrentProcess()) return FLT_PREOP_SUCCESS_NO_CALLBACK; if(!g_bs1Flt.IsDeviceProtect) return FLT_PREOP_SUCCESS_NO_CALLBACK; if (Data == NULL) return FLT_PREOP_SUCCESS_NO_CALLBACK; if (Data->RequestorMode == KernelMode) return FLT_PREOP_SUCCESS_NO_CALLBACK; // CDROM Á¤Ã¥ È®ÀÎ if (GetPolicyState(BDC_CDROM) != ENABLE) { PFLT_FILE_NAME_INFORMATION nameInfo = NULL; HANDLE processid = PsGetCurrentProcessId(); BOOLEAN isblock = FALSE; UNICODE_STRING filepath = { 0, }; PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb; ULONG readLen = iopb->Parameters.Read.Length; ULONG uByteOffset = iopb->Parameters.Read.ByteOffset.LowPart; try { if (readLen == 0 || (!FLT_IS_IRP_OPERATION(Data)) || uByteOffset != 0) { leave; } /// ÆÄÀÏ °æ·Î ¾òÀ½ status = FltGetFileNameInformation(Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); if (!NT_SUCCESS(status)) { //KLogEx(DEBUG_TRACE_ERROR, "kdcmPreRead FltGetFileNameInformation fail(%x)\n", status); leave; } status = FltParseFileNameInformation(nameInfo); if (!NT_SUCCESS(status)) { //KLogEx(DEBUG_TRACE_ERROR, "kdcmPreRead FltParseFileNameInformation fail(%x)\n", status); leave; } status = UStrNew(&filepath, nameInfo->Name.MaximumLength + 10); if (!NT_SUCCESS(status)) leave; status = UStrCopy(&filepath, &nameInfo->Name); if (!NT_SUCCESS(status)) leave; if (wcsrchr(filepath.Buffer, '\\') == NULL) leave; _wcslwr(filepath.Buffer); if (wcsstr(filepath.Buffer, L"\\appdata\\local\\microsoft\\windows\\burn\\burn") != NULL && wcsstr(filepath.Buffer, L"\\desktop.ini") == NULL) { UNICODE_STRING processpath = { 0, }; ULONG state = 0; status = UGetCurrentStackProcessImageName(HandleToULong(processid), &processpath); state = GetPolicyState(BDC_CDROM); isblock = TRUE; SetLog(Data, FltObjects, LOG_POLICY, BDC_CDROM, state, 0, processpath.Buffer, filepath.Buffer); KLogEx(DEBUG_TRACE_INFO, "READ BLOCK!!!!!!!!!!!!! pid(%d),processpath(%S)", processid, processpath.Buffer); } } finally { UStrFree(&filepath); if (nameInfo != NULL) FltReleaseFileNameInformation(nameInfo); } if (isblock == TRUE) { Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; return FLT_PREOP_COMPLETE; } } return FLT_PREOP_SUCCESS_NO_CALLBACK; } VOID Bs1FltOperationStatusCallback( _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PFLT_IO_PARAMETER_BLOCK ParameterSnapshot, _In_ NTSTATUS OperationStatus, _In_ PVOID RequesterContext ) /*++ Routine Description: This routine is called when the given operation returns from the call to IoCallDriver. This is useful for operations where STATUS_PENDING means the operation was successfully queued. This is useful for OpLocks and directory change notification operations. This callback is called in the context of the originating thread and will never be called at DPC level. The file object has been correctly referenced so that you can access it. It will be automatically dereferenced upon return. This is non-pageable because it could be called on the paging path Arguments: FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. RequesterContext - The context for the completion routine for this operation. OperationStatus - Return Value: The return value is the status of the operation. --*/ { UNREFERENCED_PARAMETER(FltObjects); UNREFERENCED_PARAMETER(RequesterContext); UNREFERENCED_PARAMETER(OperationStatus); UNREFERENCED_PARAMETER(ParameterSnapshot); //KLogEx(DEBUG_TRACE_INFO, // ("cdsflt!cdsfltOperationStatusCallback: Entered\n")); //KLogEx(DEBUG_TRACE_INFO, // ("cdsflt!cdsfltOperationStatusCallback: Status=%08x ctx=%p IrpMj=%02x.%02x \"%s\"\n", // OperationStatus, // RequesterContext, // ParameterSnapshot->MajorFunction, // ParameterSnapshot->MinorFunction, // FltGetIrpName(ParameterSnapshot->MajorFunction))); } FLT_POSTOP_CALLBACK_STATUS Bs1FltPostOperation( _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags ) /*++ Routine Description: This routine is the post-operation completion routine for this miniFilter. This is non-pageable because it may be called at DPC level. Arguments: Data - Pointer to the filter callbackData that is passed to us. FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. CompletionContext - The completion context set in the pre-operation routine. Flags - Denotes whether the completion is successful or is being drained. Return Value: The return value is the status of the operation. --*/ { UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(FltObjects); UNREFERENCED_PARAMETER(CompletionContext); UNREFERENCED_PARAMETER(Flags); //PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, // ("cdsflt!cdsfltPostOperation: Entered\n")); return FLT_POSTOP_FINISHED_PROCESSING; } FLT_PREOP_CALLBACK_STATUS cdsfltPreOperationNoPostOperation( _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID* CompletionContext ) /*++ Routine Description: This routine is a pre-operation dispatch routine for this miniFilter. This is non-pageable because it could be called on the paging path Arguments: Data - Pointer to the filter callbackData that is passed to us. FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. CompletionContext - The context for the completion routine for this operation. Return Value: The return value is the status of the operation. --*/ { UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(FltObjects); UNREFERENCED_PARAMETER(CompletionContext); //PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, // ("cdsflt!cdsfltPreOperationNoPostOperation: Entered\n")); // This template code does not do anything with the callbackData, but // rather returns FLT_PREOP_SUCCESS_NO_CALLBACK. // This passes the request down to the next miniFilter in the chain. return FLT_PREOP_SUCCESS_NO_CALLBACK; } BOOLEAN Bs1FltDoRequestOperationStatus( _In_ PFLT_CALLBACK_DATA Data ) /*++ Routine Description: This identifies those operations we want the operation status for. These are typically operations that return STATUS_PENDING as a normal completion status. Arguments: Return Value: TRUE - If we want the operation status FALSE - If we don't --*/ { PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb; // // return boolean state based on which operations we are interested in // return (BOOLEAN) // // Check for oplock operations // (((iopb->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) && ((iopb->Parameters.FileSystemControl.Common.FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) || (iopb->Parameters.FileSystemControl.Common.FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK) || (iopb->Parameters.FileSystemControl.Common.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_1) || (iopb->Parameters.FileSystemControl.Common.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2))) || // // Check for directy change notification // ((iopb->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) && (iopb->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)) ); }