Проверка веток реестра через RegistyMonitor

259
03 июля 2017, 15:58

Из проекта RegistryMonitor вытащил класс и немного изменил его так:

( смотрим код в ThreadLoop() )

P.S: Сама проблема в конце темы.

Оригинал: _eventNotify.Handle

Замена из оригинала на : _eventNotify.SafeWaitHandle.DangerousGetHandle()

public class RegistryMonitor : IDisposable
{
        #region P/Invoke
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int RegOpenKeyEx(IntPtr hKey, string subKey, uint options, int samDesired,
                                               out IntPtr phkResult);
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int RegNotifyChangeKeyValue(IntPtr hKey, bool bWatchSubtree,
                                                          RegChangeNotifyFilter dwNotifyFilter, IntPtr hEvent,
                                                          bool fAsynchronous);
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int RegCloseKey(IntPtr hKey);
        private const int KEY_QUERY_VALUE = 0x0001;
        private const int KEY_NOTIFY = 0x0010;
        private const int STANDARD_RIGHTS_READ = 0x00020000;
        private static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000));
        private static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001));
        private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));
        private static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003));
        private static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(unchecked((int)0x80000004));
        private static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005));
        private static readonly IntPtr HKEY_DYN_DATA = new IntPtr(unchecked((int)0x80000006));
        #endregion
        #region Event handling
        public event EventHandler RegChanged;
        protected virtual void OnRegChanged()
        {
            RegChanged?.Invoke(this, null);
        }
        public event ErrorEventHandler Error;
        protected virtual void OnError(Exception e)
        {
            Error?.Invoke(this, new ErrorEventArgs(e));
        }
        #endregion
        #region Private member variables
        private IntPtr _registryHive;
        private string _registrySubName;
        private object _threadLock = new object();
        private Thread _thread;
        private bool _disposed = false;
        private ManualResetEvent _eventTerminate = new ManualResetEvent(false);
        private RegChangeNotifyFilter _regFilter = RegChangeNotifyFilter.Key | RegChangeNotifyFilter.Attribute |
                                                   RegChangeNotifyFilter.Value | RegChangeNotifyFilter.Security;
        #endregion
        public RegistryMonitor(RegistryKey registryKey)
        {
            InitRegistryKey(registryKey.Name);
        }
        public RegistryMonitor(string name)
        {
            if (name == null || name.Length == 0)
                throw new ArgumentNullException("name");
            InitRegistryKey(name);
        }
        public RegistryMonitor(RegistryHive registryHive, string subKey)
        {
            InitRegistryKey(registryHive, subKey);
        }
        public RegChangeNotifyFilter RegChangeNotifyFilter
        {
            get { return _regFilter; }
            set
            {
                lock (_threadLock)
                {
                    if (IsMonitoring)
                        throw new InvalidOperationException("Monitoring thread is already running");
                    _regFilter = value;
                }
            }
        }
        #region Initialization
        private void InitRegistryKey(RegistryHive hive, string name)
        {
            switch (hive)
            {
                case RegistryHive.ClassesRoot:
                    _registryHive = HKEY_CLASSES_ROOT;
                    break;
                case RegistryHive.CurrentConfig:
                    _registryHive = HKEY_CURRENT_CONFIG;
                    break;
                case RegistryHive.CurrentUser:
                    _registryHive = HKEY_CURRENT_USER;
                    break;
                case RegistryHive.DynData:
                    _registryHive = HKEY_DYN_DATA;
                    break;
                case RegistryHive.LocalMachine:
                    _registryHive = HKEY_LOCAL_MACHINE;
                    break;
                case RegistryHive.PerformanceData:
                    _registryHive = HKEY_PERFORMANCE_DATA;
                    break;
                case RegistryHive.Users:
                    _registryHive = HKEY_USERS;
                    break;
                default:
                    throw new InvalidEnumArgumentException("hive", (int)hive, typeof(RegistryHive));
            }
            _registrySubName = name;
        }
        private void InitRegistryKey(string name)
        {
            var nameParts = name.Split('\\');
            switch (nameParts[0])
            {
                case "HKEY_CLASSES_ROOT":
                case "HKCR":
                    _registryHive = HKEY_CLASSES_ROOT;
                    break;
                case "HKEY_CURRENT_USER":
                case "HKCU":
                    _registryHive = HKEY_CURRENT_USER;
                    break;
                case "HKEY_LOCAL_MACHINE":
                case "HKLM":
                    _registryHive = HKEY_LOCAL_MACHINE;
                    break;
                case "HKEY_USERS":
                    _registryHive = HKEY_USERS;
                    break;
                case "HKEY_CURRENT_CONFIG":
                    _registryHive = HKEY_CURRENT_CONFIG;
                    break;
                default:
                    _registryHive = IntPtr.Zero;
                    throw new ArgumentException($"The registry hive { nameParts[0] }  is not supported", "value");
            }
            _registrySubName = string.Join("\\", nameParts, 1, nameParts.Length - 1);
        }
        #endregion
        public bool IsMonitoring
        {
            get { return _thread != null; }
        }
        public void Start()
        {
            if (_disposed)
                throw new ObjectDisposedException(null, "This instance is already disposed");
            lock (_threadLock)
            {
                if (!IsMonitoring)
                {
                    _eventTerminate.Reset();
                    _thread = new Thread(new ThreadStart(MonitorThread));
                    _thread.IsBackground = true;
                    _thread.Start();
                }
            }
        }
        public void Stop()
        {
            if (_disposed)
                throw new ObjectDisposedException(null, "This instance is already disposed");
            lock (_threadLock)
            {
                var thread = _thread;
                if (thread != null)
                {
                    _eventTerminate.Set();
                    thread.Join();
                }
            }
        }
        private void Dispose(bool disposing)
        {
            if (disposing)
                GC.SuppressFinalize(this);
            Stop();
        }
        public void Dispose()
        {
            var Truth = true;
            Dispose(Truth);
        }
        private void MonitorThread()
        {
            try
            {
                ThreadLoop();
            }
            catch (Exception e) { OnError(e); }
            _thread = null;
        }
        private void ThreadLoop()
        {
            IntPtr registryKey;
            int result = RegOpenKeyEx( _registryHive, _registrySubName, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_NOTIFY,out registryKey);
            if (result != 0)
                throw new Win32Exception(result);
            try
            {
                var _eventNotify = new AutoResetEvent(false);
                var waitHandles = new WaitHandle[] { _eventNotify, _eventTerminate };
                while (!_eventTerminate.WaitOne(0, true))
                {
                    result = RegNotifyChangeKeyValue(registryKey, true, _regFilter, _eventNotify.SafeWaitHandle.DangerousGetHandle(), true);
                    if (result != 0) throw new Win32Exception(result);
                    if (WaitHandle.WaitAny(waitHandles) == 0)
                    {
                        OnRegChanged();
                    }
                }
            }
            finally
            {
                if (registryKey != IntPtr.Zero)
                    RegCloseKey(registryKey);
            }
        }
    }
    [Flags]
    public enum RegChangeNotifyFilter
    {
        Key = 1,
        Attribute = 2,
        Value = 4,
        Security = 8,
    }
}

Теперь само сканирование: (Создал отдельный класс RegMon)

Список для проверки изменение в ветках реестра:

static List<string> RegScan = new List<string>()
{
    @"HKEY_CLASSES_ROOT\exefile\shell\runas\command",
    @"HKEY_CLASSES_ROOT\zapfile\shell\open\command",
    @"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.exe",
    @"HKEY_CLASSES_ROOT\.exe",
    @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SafeBoot",
    @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options",
    @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon",
    @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows",
    @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
    @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
};

Массив RegistryMonitor

Старт проверки:

public static void StartRegistryMonitor()
{
    if (registryMonitors != null) return;
    registryMonitors = new RegistryMonitor[RegScan.Count];
    for (int i = 0; i < RegScan.Count; i++)
    {
        Console.WriteLine($"Проверка ветки реестра:  {RegScan[i]}");
        registryMonitors[i] = new RegistryMonitor(RegScan[i]);
        registryMonitors[i].RegChanged += OnRegistryChanged;
        registryMonitors[i].Start();
    }
}

Уведомление об изменение в ветках реестра:

static void OnRegistryChanged(object sender, EventArgs args)
{
   Console.WriteLine("Зафиксировано изменение в реестре.");
}

Запускаю сканирование так:

Task.Factory.StartNew(() => RegMon.StartRegistryMonitor());
Console.Read();

При запуске казалось бы всё работает нормально как и хотелось, но оказалось что он реагирует на любой раздел в реестре а не в определённых ветках реестра из List<string> RegScan.

Проблема оказалось в том что если в списке RegScan добавить по определению ветки реестра HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run и.т.д то он реагирует на все разделы в реестре, если убрать этот раздел, то всё работает как нужно.

P.S: Полагаю что косяк в самом классе RegistryUtils.RegistryMonitor.cs

Подскажите что можно заменить чтобы чтобы мой класс реагировал и на другие ветки в разделах реестра.

READ ALSO
Блокируется iFrame на любом сайте

Блокируется iFrame на любом сайте

Создал простую страничку: http://timegraphics/embed?v=1&id=4

345
Как определить есть ли полоса прокрутки у div&#39;a?

Как определить есть ли полоса прокрутки у div'a?

На разных страницах есть один и тот же блок фиксированной высотыК примеру:

360
javascript (callback) need help

javascript (callback) need help

Помогите разобраться где я допустил ошибку или может быть вообще все неправильно написалНужно чтобы получилась такая последовательность:

269
Как работать с JS-шаблонизаторами?

Как работать с JS-шаблонизаторами?

ПриветВ проекте возникла необходимость использовать JS-шаблонизаторы, но я я понятия не имею, как их использовать даже после изучения документации

283