Pull to refresh
-1
-0.1
Иван@ia_alpatov

Software Engineer

Send message

MiniFilter и Protector/Rejector (ObCallback) в одном драйвере с управлением через C#

В продолжение этого поста.

Предлагаю вашему внимаю мою поделку основанную на MiniFilter, ObCallback и Avalonia

Можно грабить корованы защищать от закрытия, регулировать доступ к файлам и запрещать запускать процессы.

C# код для управления драйвером:

using System;
using System.Diagnostics;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Threading;
using SharpMiniFilter.Driver.MiniFilter;
using SharpMiniFilter.Driver.Protector;

namespace SharpMiniFilter.Protected;

public partial class MainWindow : Window
{
    private bool allowClose = false;
    
    public MainWindow()
    {
        InitializeComponent();
        this.Closing += (sender, args) =>
        {
            args.Cancel = !allowClose;

            if (!args.Cancel)
            {
                ProtectorClient.ReplaceProtectList(Array.Empty<string>());
                ProtectorClient.ReplaceRejectList(Array.Empty<string>());
                MiniFilterClient.CloseConnection();
                MiniFilterClient.DriverFilter -= DriverClientOnDriverFilter;
            }
        };
        
        MiniFilterClient.DriverFilter += DriverClientOnDriverFilter;
        
        if (MiniFilterClient.Connect())
        {
            ProtectorClient.ReplaceProtectList(new[] { $"PID:{Process.GetCurrentProcess().Id}" });
            ProtectorClient.ReplaceRejectList(new[] {  "*cmd.exe" });
            
            Log_TextBox.Text += "Added current process to protection list." + Environment.NewLine;
            Log_TextBox.Text += "Added cmd.exe to reject list." + Environment.NewLine;
        }
        else
        {
            Log_TextBox.Text += "Connection to driver failed." + Environment.NewLine;
            MiniFilterClient.DriverFilter -= DriverClientOnDriverFilter;
        }
    }

    private void DriverClientOnDriverFilter(MinifilterEventArgs e)
    {
        Dispatcher.UIThread.Invoke(() =>
        {
            if (e.Path.Contains("test.txt"))
            {
                if (!Process.GetProcessById((int)e.ProcessId).ProcessName.ToLower().Contains("notepad"))
                {
                    e.SetHandled(true);
                    Log_TextBox.Text += "Minifilter: test.txt blocked" + Environment.NewLine;
                }
                else
                {
                    e.SetHandled(false);
                    Log_TextBox.Text += "Minifilter: test.txt not blocked for notepad.exe" + Environment.NewLine;
                }
            }
        });
    }

    private void Button_OnClick(object? sender, RoutedEventArgs e)
    {
        allowClose = true;
        this.Close();
    }
}

Бонусом - создание .cab файла для отправки в Microsoft на сертификацию при Release сборке.

Ссылка на репозиторий.

P.S. Если вам будет интересно, а у меня силы и карма - то расскажу, что там и как в отдельной статье. А теперь и ответ на всех мучающий вопрос: "Почему пингвин пошёл в горы?"

Tags:
Total votes 1: ↑0 and ↓1-1
Comments2

Отправка уведомления от имени другого приложения

Результат
Результат

В продолжение этого поста

Когда у вас AOT приложение, которое запускается от администратора - 99% библиотек для работы с COM не работают, плюс для Windows App SDK отдельно указано "Notifications for an elevated (admin) app is currently not supported.", а issue на github висит с 2023 года и поэтому для отправки системных уведомлений надо выкручиваться через другое приложение/PowerShell.

Пример как отправлять уведомления:

using System.Diagnostics;
using Windows.UI.Notifications;
using Microsoft.Toolkit.Uwp.Notifications;
using Vanara.PInvoke;
using Vanara.Windows.Shell;

namespace ConsoleNotifications;

class Program
{
    static async Task Main(string[] args)
    {
        string messageTitle = "Habr";
        string messageText = "Hello Habrahabr!";
        string targetExePath = Environment.SystemDirectory + "\\notepad.exe";
        string appUserModelId = GetAppAumid().First(var=>var.Name.Contains("Chrome")).Aumid;
        await SendNotification(appUserModelId, messageTitle, messageText, targetExePath);
    }

    private static Task SendNotification(string appUserModelId, string title, string content, string targetPath)
    {
        var tcs = new TaskCompletionSource();
        var notification = new ToastNotification(new ToastContentBuilder().AddText(title)
            .AddText(content).Content.GetXml());
        notification.Priority = ToastNotificationPriority.High;
        notification.Activated += (s, e) =>
        {
            Process.Start(new ProcessStartInfo(targetPath));
            tcs.SetResult();
        };
        notification.Failed += (s, e) => tcs.SetResult();
        notification.Dismissed += (s, e) => tcs.SetResult();
        ToastNotificationManager.CreateToastNotifier(appUserModelId).Show(notification);
        return tcs.Task;
    }
    
    public sealed record AppAumidInfo(string Name, string Aumid);
    
    public static List<AppAumidInfo> GetAppAumids()
    {
        var results = new List<AppAumidInfo>();
        var f = new ShellFolder(Shell32.KNOWNFOLDERID.FOLDERID_AppsFolder);
        foreach (ShellItem i in f.EnumerateChildren(FolderItemFilter.NonFolders | FolderItemFilter.Folders))
            results.Add(new AppAumidInfo(i.Name, i.ParsingName));
        return results;
    }
}

В вызываемом приложении надо выставить AppUserModelID и предварительно создать ссылку на него

[LibraryImport("shell32.dll", SetLastError=true)]
internal static partial void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);

Создание .lnk ссылки с параметрами:

var link = new ShellLink()
{
        ToastActivatorId = guid, 
        AppUserModelID = appUserModelId,
        TargetPath = exePath
};
link.Save(shortcutPath);

P.S. Буду рад услышать про другие существующие решения этой проблемы

Tags:
Total votes 3: ↑3 and ↓0+3
Comments0

Определение типа fullscreen

Понадобилось мне как‑то определять тип fullscreen для вывода подходящего типа уведомления (звуковое/системное/окном) во время запущенных игр и родился такой код:

    public enum WindowFullscreenState
    {
        None,
        Emulated,
        Shared,
        Exclusive,
        ExclusiveGdi,
        NotOwned
    }

    public static WindowFullscreenState GetForegroundWindowFullscreenType()
    {
        var result = WindowFullscreenState.None;   
        uint dwProcessId;
        D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP query = new D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP
        {
            hWindow = GetForegroundWindow()
        };

        GetWindowThreadProcessId(query.hWindow, out dwProcessId);

        query.hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, dwProcessId);
        if (query.hProcess != IntPtr.Zero)
        {
            D3DKMTQueryVidPnExclusiveOwnership(ref query);
            CloseHandle(query.hProcess);

            result = query.OwnerType switch
            {
                D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_UNOWNED => WindowFullscreenState.NotOwned,
                D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_SHARED => WindowFullscreenState.Shared,
                D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE => WindowFullscreenState.Exclusive,
                D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVEGDI => WindowFullscreenState.ExclusiveGdi,
                D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_EMULATED => WindowFullscreenState.Emulated,
                _ =>WindowFullscreenState.None
            };
        }

        return result;
    }

    public enum D3DKMT_VIDPNSOURCEOWNER_TYPE
    {
        D3DKMT_VIDPNSOURCEOWNER_UNOWNED = 0,
        D3DKMT_VIDPNSOURCEOWNER_SHARED = 1,
        D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE = 2,
        D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVEGDI = 3,
        D3DKMT_VIDPNSOURCEOWNER_EMULATED = 4
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
        public uint LowPart;
        public int HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP
    {
        public IntPtr hProcess;
        public IntPtr hWindow;
        public uint VidPnSourceId;
        public LUID AdapterLuid;
        public D3DKMT_VIDPNSOURCEOWNER_TYPE OwnerType;
    }

    [DllImport("user32.dll", SetLastError = true)]
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    private static extern int MessageBoxW(IntPtr hWnd, string lpText, string lpCaption, uint uType);

    private const uint PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;

    [DllImport("gdi32.dll", EntryPoint = "D3DKMTQueryVidPnExclusiveOwnership")]
    private static extern int D3DKMTQueryVidPnExclusiveOwnership(ref D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP data);
    
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();

Схема использования с типами уведомлений:

WindowFullscreenState.Exclusive -> SendVoiceNotification
WindowFullscreenState.ExclusiveGdi -> SendVoiceNotification
WindowFullscreenState.Emulated -> ShowSystemNotification
WindowFullscreenState.Shared -> ShowSystemNotification
WindowFullscreenState.NotOwned || WindowFullscreenState.None -> IsForegroundWindowSmallerThanScreen ? ShowCustomWindow : ShowSystemNotification

Подробнее можно прочитать про виды захвата экрана тут и тут.

P.S. Некоторые игры (ExclusiveGdi) можно заставить (Emulated) получать системные уведомления через режим совместимости.

Tags:
Total votes 5: ↑4 and ↓1+3
Comments0

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Registered
Activity

Specialization

Software Developer, Application Developer
Senior
C#
AvaloniaUI
WPF
.NET
OOP
Git
Docker
English
Linux