Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple API Hook for prevent file deletion?

I would like to intercept when the user deletes a file on ANY directory by hooking the needed API function(s) with the availability of asking a simple boolean question in a mesagebox "Really Would you like to Delete this file?", the question is an example to express that I would like to have control on the file, to delete it or to prevent deletion.

My OS Is Windows 8 x64, but I would like to write a method for generic usage in other Windows OS and their arquitechtures (if this don't suppose harder headaches to do it).

In this SO question I've read that the best choice is to hook the NtSetFileInformation function Intercept FIleSytemCall for Deletion by the way I've seen that exists a WinAPI function named DeleteFile and also the interface ICopyHook and I don't know the differente between these, but anyways I really don't know how to start doing this...

I would like to clarify that I'm looking for a VBNET solution, I've headaches because the absence of any VBNET Code example from these API-Hooking libraries over Google, and C# code translations to VBNET goes really wrong when a complex code is involved.

EDIT: I've found a EasyHook library Example about NtSetFileInformation which seems to be perfect for my needs, but it is C# code and I've tried to translate it without success: Hooking NtCreateFile API from ntdll.dll with EasyHook (c#)

So, I've tried this with Deviare library 2.6, but does nothing:

Public Class Form1

    Private _mgr As Deviare2.NktSpyMgr = Nothing
    Private WithEvents _hook As Deviare2.NktHook = Nothing
    Private _proc As Deviare2.INktProcess = Nothing

    Private Shadows Sub Shown() Handles MyBase.Shown

        _mgr = New Deviare2.NktSpyMgr()
        _hook = _mgr.CreateHook("ntdll.dll!NtSetFileInformation", Nothing)
        _hook.Hook()

    End Sub

    Private Sub OnFunctionCalled(ByVal proc As Deviare2.INktProcess,
                                 ByVal callInfo As Deviare2.INktHookCallInfo,
                                 ByVal rCall As Deviare.IRemoteCall) Handles _hook.OnFunctionCalled

        MsgBox("Caught function call in " & proc.Name)

    End Sub

End Class

Basically the code above is the same as @mazoula answered here hooking another program's calls to winapi functions in vb.net ,he says that the code worked for him, but I've tried it as is (without doiing my modifications above) and throwed me an exception at the _hook.Attach(_mgr.Processes) instruction.

Also I've tried this with the library EasyHook but again does nothing when I delete a file from Explorer.exe or from CMD, the code is a translation of this C# code http://www.codeproject.com/Questions/528094/DeleteFileplushookingpluswithplusEasyHookplussucce :

Imports System.Runtime.InteropServices
Imports EasyHook

Public Class Form1

    <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.StdCall)>
    Private Shared Function DeleteFile(filename As String) As Integer
    End Function

    <UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet:=CharSet.Unicode)>
    Private Delegate Function DeleteFileHandler(filename As String) As Integer

    Private Shared deleted As Boolean = False

    public Function DeleteFileHookInstance(filename As String) As Integer
        MsgBox("works?")
        If deleted Then
            deleted = False
            Return 1
        End If
        If MessageBox.Show((Convert.ToString("Do you really want to delete file ") & filename) + "?", "Confirm delete file", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
            deleted = True
            Return DeleteFile(filename)
        Else
            Return 1
        End If
        'Assume the call is successfull
    End Function

    Public Sub Run()

        Dim hook As EasyHook.LocalHook

        Try
            MsgBox("Creating...")
            hook = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "DeleteFileW"), New DeleteFileHandler(AddressOf DeleteFileHookInstance), Me)
            'It stops here, the main interface receives the reported status 'Creating...' seemly forever, I understand that is for the unexpected restarting of explorer.exe
            MsgBox("Completing...")
            hook.ThreadACL.SetExclusiveACL(New Integer() {0})
            RemoteHooking.WakeUpProcess()
            MsgBox("OK")
        Catch ex As Exception
            MsgBox("CreateHook failed: " + ex.Message)
            System.Diagnostics.Process.GetCurrentProcess().Kill()
        End Try
        While True
            Application.DoEvents()
        End While
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Run()
    End Sub

End Class
like image 774
ElektroStudios Avatar asked Dec 28 '13 13:12

ElektroStudios


2 Answers

If it were me, I would revisit my architecture to see whether I really needed to prevent any and all file deletions. Likely you only need to prevent deletions in a few sensitive directories (and possibly just a few sensitive files in those directories). This should make for a less-annoying UI.

like image 70
Mark Leighton Fisher Avatar answered Oct 07 '22 09:10

Mark Leighton Fisher


few days ago I've write this approach to temporally resolve the problem, but I'm not 100% secure that the method will work properly in all the scenarios (for example the user can press ctrl+z to restore a file deletion and my method logic uses the datetime property of the files to try to pick the last deleted which I'm not 100% secure), this works by now, but I would like to learn how to API hook instead of doing this.

Also obviously this will not work with a permanent file deletion.

Imports System.IO
Imports Shell32

Public Class Test

    Private SH As New Shell
    Private RecycleBin As Folder = SH.NameSpace(ShellSpecialFolderConstants.ssfBITBUCKET)
    Private WithEvents FSW As New FileSystemWatcher

    Private Shadows Sub Load() _
    Handles MyBase.Load

        With FSW
            .Path = "C:\Test"
            .IncludeSubdirectories = True
            .Filter = "*"
            .NotifyFilter = NotifyFilters.FileName Or NotifyFilters.DirectoryName
            .EnableRaisingEvents = True
        End With

    End Sub

    Private Sub OnItemDeleted(sender As FileSystemWatcher, e As FileSystemEventArgs) _
    Handles FSW.Deleted

        Dim DeletedItems As IEnumerable(Of FolderItem) =
            RecycleBin.Items.Cast(Of FolderItem).
                             Where(Function(Item) Item.Name = e.Name).
                             OrderBy(Function(Item) Item.ModifyDate)

        Dim LastDeletedItem As Shell32.FolderItem = DeletedItems.LastOrDefault

        If LastDeletedItem IsNot Nothing Then

            If (LastDeletedItem.IsFolder AndAlso Directory.Exists(e.FullPath)) _
               OrElse (Not LastDeletedItem.IsFolder AndAlso File.Exists(e.FullPath)) Then

                Throw New Exception(String.Format("¿ Item has been restored ?: {0}", e.FullPath))
                Exit Sub

            End If

            LastDeletedItem.InvokeVerb("undelete")

        End If

    End Sub

End Class
like image 26
ElektroStudios Avatar answered Oct 07 '22 08:10

ElektroStudios