{"id":21557295,"url":"https://github.com/sweeticelolly/prevent_file_deletion","last_synced_at":"2025-04-10T10:33:54.226Z","repository":{"id":159225870,"uuid":"280785402","full_name":"SweetIceLolly/Prevent_File_Deletion","owner":"SweetIceLolly","description":"Record \u0026 prevent file deletion in kernel mode","archived":false,"fork":false,"pushed_at":"2020-07-22T15:57:58.000Z","size":17,"stargazers_count":42,"open_issues_count":0,"forks_count":10,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-24T09:21:31.014Z","etag":null,"topics":["driver","file-protector","filesystem","kernel","kernel-driver","kmdf","minifilter","minifilter-driver","tutorial"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SweetIceLolly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-19T03:39:49.000Z","updated_at":"2025-02-18T14:58:14.000Z","dependencies_parsed_at":"2023-07-29T16:15:13.759Z","dependency_job_id":null,"html_url":"https://github.com/SweetIceLolly/Prevent_File_Deletion","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SweetIceLolly%2FPrevent_File_Deletion","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SweetIceLolly%2FPrevent_File_Deletion/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SweetIceLolly%2FPrevent_File_Deletion/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SweetIceLolly%2FPrevent_File_Deletion/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SweetIceLolly","download_url":"https://codeload.github.com/SweetIceLolly/Prevent_File_Deletion/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248199245,"owners_count":21063641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["driver","file-protector","filesystem","kernel","kernel-driver","kmdf","minifilter","minifilter-driver","tutorial"],"created_at":"2024-11-24T08:11:54.042Z","updated_at":"2025-04-10T10:33:54.214Z","avatar_url":"https://github.com/SweetIceLolly.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Prevent_File_Deletion\nRecord \u0026 prevent file deletion in kernel mode\n\nHuge thanks to https://0x00sec.org/t/kernel-mode-rootkits-file-deletion-protection/7616\n\nThis guy has some awesome things! Thanks to the tutorials! https://github.com/NtRaiseHardError\n\n# Study Notes\n\n## What to do in `DriverEntry`\n1. Use `FltRegisterFilter` to register a minifilter.\n2. We can use `0x%08x` format specifier in `DbgPrint` to print error codes.\n3. After `FltRegisterFilter`, use `FltStartFiltering` to start the minifilter.\n4. If `FltStartFiltering` fails, we should unregister the minifilter by calling `FltUnregisterFilter`.\n\nNow here comes the tough things...\n\n## `FltRegisterFilter` function\nFor `FltRegisterFilter` function, we need three parameters:\n\n(Reference: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/fltkernel/nf-fltkernel-fltregisterfilter)\n\nThe code should be like this:\n\n```c\nPFLT_FILTER Filter;\nstatus = FltRegisterFilter(DriverObject, \u0026FilterRegistration, \u0026Filter);\n```\n\nThe `Registration` parameter can be a little complicated. Other parameters are straightforward. The type of `Registration` is [FLT_REGISTRATION](https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/fltkernel/ns-fltkernel-_flt_registration), which will be something like this:\n\n(Reference: https://github.com/NtRaiseHardError/Anti-Delete/blob/9fbe5ac0e46ba7a70b9e9983977d1bd38a3999a0/Anti%20Delete/Anti%20Delete/Driver.c#L24)\n\n```c\nconst FLT_REGISTRATION FilterRegistration = {\n\tsizeof(FLT_REGISTRATION),\t// Size\n\tFLT_REGISTRATION_VERSION,\t// Version\n\t0,\t\t\t\t\t\t\t// Flags\n\tNULL,\t\t\t\t\t\t// ContextRegistration\n\tCallbacks,\t\t\t\t\t// OperationRegistration\n\tbadgirlFilterUnload,\t\t// FilterUnloadCallback\n\tNULL,\t\t\t\t\t\t// InstanceSetupCallback\n\tNULL,\t\t\t\t\t\t// InstanceQueryTeardownCallback\n\tNULL,\t\t\t\t\t\t// InstanceTeardownStartCallback\n\tNULL,\t\t\t\t\t\t// InstanceTeardownCompleteCallback\n\tNULL,\t\t\t\t\t\t// GenerateFileNameCallback\n\tNULL,\t\t\t\t\t\t// NormalizeNameComponentCallback\n\tNULL,\t\t\t\t\t\t// NormalizeContextCleanupCallback\n\tNULL,\t\t\t\t\t\t// TransactionNotificationCallback\n\tNULL,\t\t\t\t\t\t// NormalizeNameComponentExCallback\n\tNULL\t\t\t\t\t\t// SectionNotificationCallback\n};\n```\nNote that we need to specify `OperationRegistration` and `FilterUnloadCallback` in this demo. I don't know what do other callbacks do so far.\n\nPay attention to `OperationRegistration`. Note that `Callbacks` should be `FLT_OPERATION_REGISTRATION`, which is an array. It binds major function and callbacks. It should be like this:\n\n(Reference: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/fltkernel/ns-fltkernel-_flt_operation_registration)\n\n```c\nconst FLT_OPERATION_REGISTRATION Callbacks[] = {\n\t{ IRP_MJ_CREATE, 0, badgirlFilterAntiDelete, NULL, NULL },\n\t{ IRP_MJ_SET_INFORMATION, 0, badgirlFilterAntiDelete, NULL, NULL },\n    \n    ...\n\n\t{ IRP_MJ_OPERATION_END }\n};\n```\n\n- The 1st element specifies MajorFunction of the operation.\n- The 2nd element is Flags, I don't know what's that, even after reading the documentation. Leave that with 0.\n- The 3rd element is PreOperation, which is the callback function that will be called before an operation.\n- The 4th element is PostOperation, which is the callback function that will be called after an operation. In this demo, we don't need PostOperation callbacks, so we set them to NULLs.\n- The 5th element is reserved. Set that to NULL.\n- The last element in the array must be `{ IRP_MJ_OPERATION_END }`.\n\nSo... That's what you need to do to call `FltRegisterFilter`.\n\n## Registry\nWhen `FltRegisterFilter` returns STATUS_OBJECT_NAME_NOT_FOUND (0xc0000034), it usually indicates there's something wrong with the registry. (Reference: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/fltkernel/nf-fltkernel-fltregisterfilter#return-value) After searching for this problem, I found the reason. It is because I am too lazy and I didn't create an INF file for this driver. So the minifilter is not recognized by the system. To solve this, we need to write an appropriate INF file. (Reference: https://stackoverflow.com/questions/42389211/fltregisterfilter-not-working) The INF file for a minifilter is different from INF file for other drivers. (https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/creating-an-inf-file-for-a-minifilter-driver) There are several things to notice.\n\n### Service name\nThe service name that the driver loader passes to `CreateService` should be the same as the `ServiceName` specified in the INF file. Otherwise, the system won't recognize the minifilter.\n\n### INF file\n1. You need to specify `CatalogFile` to `your_driver_name.cat`, even though the documentation (https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/creating-an-inf-file-for-a-minifilter-driver?redirectedfrom=MSDN#version-section-required) says minifilter drivers except antivirus minifilter drivers should leave this entry blank (This demo is not an antivirus minifilter (320000 \u003c Altitude \u003c 329999), but an activity monitor minifilter (Altitude = 365000)). I don't know why, but my solution refuses to compile unless I specify the value of `CatalogFile`.\n2. Change `Class` and `ClassGuid` according to your purpose. (https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/file-system-filter-driver-classes-and-class-guids)\n3. Change `Instance1.Altitude` to an appropriate value according to your purpose. (https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/load-order-groups-and-altitudes-for-minifilter-drivers)\n4. An example INF file: https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/miniFilter/NameChanger/NameChanger.inf\n5. If the solution fails to build and says `Section xxx should have an architecture decoration`, go to project properties - Driver Settings - General - Set \"Target Platform\" to \"Desktop\". (https://github.com/microsoft/Windows-driver-samples/issues/366) This may be a better solution, but I havn't tried that: https://community.osr.com/discussion/291286/wdk10-stampinf-returns-error-1420-defaultinstall-based-inf-cannot-be-processed-as-primitive\n\n## Linking\nIf the compiler says \"unresolved external symbol _Flt*\", you need to link fltMgr.lib. Go to project properties - Linker - Input, edit \"Additional Dependencies\" and add `$(DDK_LIB_PATH)fltMgr.lib`.\n\n## IRQL\nI don't have much concept about IRQL. But I noticed that every minifilter callback function (like PreOperation, FilterUnloadCallback) has `PAGED_CODE();` in its body. This is related to IRQL, but I still need to understand the concept.\n\n## Misc\n1. `FalgOn(a, b)` macro can be used to determine if a includes b. (i.e. a \u0026 b != 0 indicates a includes b)\n2. We can use `FltGetFileNameInformation` and `FltParseFileNameInformation` to get file name information from `FltObjects`.\n3. `Data-\u003eThread` can be used to identify the process that's requesting the operation.\n4. To prevent an operation:\n```c\nData-\u003eIoStatus.Status = STATUS_ACCESS_DENIED;\nData-\u003eIoStatus.Information = 0;\nret = FLT_PREOP_COMPLETE;\n```\n\n# UPDATE: Prevent file modification\nTo prevent file modification, we can check flags in `Data-\u003eIopb-\u003eParameters.Create.SecurityContext-\u003eDesiredAccess`. The following code will prevent rename, delete, modify and property change (Not strictly tested though). If we want to prevent the file from being read, we can deny the access when related `DesiredAccess` flag is detected.\n\n```c\nif (FlagOn(Data-\u003eIopb-\u003eParameters.Create.SecurityContext-\u003eDesiredAccess, FILE_WRITE_DATA) ||\n    FlagOn(Data-\u003eIopb-\u003eParameters.Create.SecurityContext-\u003eDesiredAccess, FILE_WRITE_ATTRIBUTES) ||\n    FlagOn(Data-\u003eIopb-\u003eParameters.Create.SecurityContext-\u003eDesiredAccess, FILE_WRITE_EA) ||\n    FlagOn(Data-\u003eIopb-\u003eParameters.Create.SecurityContext-\u003eDesiredAccess, FILE_APPEND_DATA) ||\n    FlagOn(Data-\u003eIopb-\u003eParameters.Create.SecurityContext-\u003eDesiredAccess, DELETE) ||\n    FlagOn(Data-\u003eIopb-\u003eParameters.Create.SecurityContext-\u003eDesiredAccess, WRITE_DAC) ||\n    FlagOn(Data-\u003eIopb-\u003eParameters.Create.SecurityContext-\u003eDesiredAccess, WRITE_OWNER) ||\n    FlagOn(Data-\u003eIopb-\u003eParameters.Create.SecurityContext-\u003eDesiredAccess, GENERIC_WRITE)) {\n\n    Data-\u003eIoStatus.Status = STATUS_ACCESS_DENIED;\n    Data-\u003eIoStatus.Information = 0;\n    ret = FLT_PREOP_COMPLETE;\n}\n```\n\n# UPDATE: Find out which process requested the operation\nTo find out which process requested the operation, we can use `Data-\u003eThread`.\n```c\nPEPROCESS TargetProcess = IoThreadToProcess(Data-\u003eThread);\nHANDLE Pid = PsGetProcessId(TargetProcess);\nPUNICODE_STRING ProcessName = NULL;\nSeLocateProcessImageName(TargetProcess, \u0026ProcessName);\n```\n\n# What to do next\n1. Currently, loading the driver will return an error code that indicates `An instance of the service is already running`. I don't know why, because there is no an intance of the service is already running.\n2. Loading the driver for a second time will fail to register the minifilter, I don't know why. (Update: I found that reinstall the service will solve the problem, but still don't know why).\n3. I will need to figure out how to prevent file creation and modification. (Solved)\n4. I found that the minifilter will be loaded even if I whatever path I specified in the driver loader. This is weird! Maybe it's because the system puts the newly installed minifilter driver into a \"pending to load\" list, and it will be loaded as soon as some program loads other drivers? I don't know.\n5. HRSword can delete/rename protected files without the specific `DesiredAccess`. Maybe it is because it simply passes the file handle to the kernel-mode driver and let the driver to finish the job? I am not sure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsweeticelolly%2Fprevent_file_deletion","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsweeticelolly%2Fprevent_file_deletion","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsweeticelolly%2Fprevent_file_deletion/lists"}