Блокируем Ctrl-Alt-Del
Доброго времени суток. На многих форумах программистов очень часто встречается вопрос «Как заблокировать комбинацию клавиш Ctrl-Alt-Del?». В этой статье я расскажу, как можно реально заблокировать комбинацию клавиш Ctrl-Alt-Del без каких-либо извращений с заменой файлов и прочего. Статья не рассчитана на новичков, читатель этой статьи как минимум должен знать, что такое инжект и запуск удалённых потоков.
Первое что хотелось бы сказать — это то, что комбинация клавиш Ctrl-Alt-Del предназначена не только для вызова диспетчера задач. В первую очередь она предназначена для вызова окна процесса Winlogon, в котором у нас имеется возможность завершить текущий сеанс, завершить работу компьютера, и, разумеется, вызвать диспетчер задач. Те, кто ставил в WinXP настройки повышенной безопасности, тем знакомо вот это окно.
Итак, блокировка замена или удаление либо замена его на свой файл самого диспетчера задач Windows (файл taskmgr.exe в системной папке windows) просто делает невозможным его вызов, но по-прежнему (при определённых настройках) комбинация Ctrl-Alt-Del работает и вышеуказанное окно безопасности по-прежнему выводится. А вызвать диспетчер задач можно также через комбинацию клавиш Ctrl-Shift-Esc без вывода этого окна.
Сначала подумаем, как можно заблокировать диспетчер задач Windows. Многим сразу придёт в голову идея об удалении или замене файла taskmgr.exe. Во-первых это не так просто так как в Windows XP введена система защиты файлов и при любом изменении её системных файлов она их сразу восстановит. Резервные копии важных файлов находятся в папке system32dllcache. Папка system32 и system32dllcache взаимно связаны и восстанавливаются, друг от друга удаление из system32dllcache влечёт восстановление из system32. Поэтому надо удалять (или заменять) файл taskmgr.exe из обеих папок одновременно. Ладно, мы удалили (или заменили) этот файл, но радость не долгая, выводится сообщение о повреждении системных файлов Windows и просьба вставить диск с дистрибутивом для обновления системы. В принципе и это тоже можно обойти. К чему я веду? К тому, что замена или удаление файлов это не вариант, да и «через жопу» это получается.
Более внимательные пользователи заметят, что диспетчер задач Windows не запускается два раза, т.е. если он уже запущен, то во второй раз он уже не запустится. И возникает идея о скрытии окна диспетчера, окно скрыто, а он работает и в результате, как ни нажимай Ctrl-Alt-Del или Ctrl-Shift-Esc мы ничего не получим. Следующий код блокирует и разблокирует диспетчер задач Windows.
uses shellapi; procedure TForm1.Button1Click(Sender: TObject); var TDWH:THandle; begin TDWH:=FindWindow(nil,'Диспетчер задач Windows'); if TDWH=0 then ShellExecute(0,'open','taskmgr.exe',nil,nil,SW_HIDE) else ShowWindow(TDWH,SW_HIDE); end; procedure TForm1.Button2Click(Sender: TObject); var TDWH:THandle; begin TDWH:=FindWindow(nil, 'Диспетчер задач Windows'); ShowWindow(TDWH,SW_SHOWNORMAL); end;
Всё очень просто. Также вдобавок можно перемещать окно диспетчера далеко за пределы экрана. Итак, задача блокировки диспетчера задач успешно решена. Но наша цель это комбинация клавиш Ctrl-Alt-Del или Ctrl-Shift-Esc.
Первая идея, которая возникает, когда надо перехватить комбинации клавиш Ctrl-Alt-Del или Ctrl-Shift-Esc — это воспользоваться стандартным механизмом хуков. Но те, кто уже пытался так сделать, скажут, что через стандартный механизм хуков нельзя перехватить ни одну из важных комбинаций. И возникает такое ощущение, что эти комбинации можно перехватить разве что, написав драйвер-фильтр режима ядра. Но есть другой способ.
Итак, наша цель — это процесс winlogon.exe, этот процесс управляет входом пользователей в систему и выходом из нее. Процесс winlogon.exe один из основных процессов отвечающих за безопасность системы. Этот процесс нельзя завершить из диспетчера задач, но можно завершить любой другой сторонней программой. Вот только после завершения winlogon.exe сразу буден сгенерирован BSOD.
Итак, процесс winlogon.exe очень важен. В нём находится окно с заголовком «SAS window» и классом «SAS Window class» именно этому и только этому окну посылается сообщение WM_HOTKEY, когда были нажаты комбинации Ctrl-Alt-Del или Ctrl-Shift-Esc и ещё несколько важных комбинаций. Найти это окно через функцию FindWindow нельзя, вернее можно, но только будучи в контексте процесса winlogon. Из обычной программы найти это окно нельзя.
Итак, наша задача подменить оконную функцию окна «SAS window» и отлавливать в нём сообщения WM_HOTKEY, если нажаты эти волшебные комбинации, то просто не вызываем оригинальную оконную функцию. Но чтобы, всё это сделать, нам надо быть в контексте процесса winlogon. Самый простой способ — это внедрить в него нашу DLL. Вот собственно и код этой DLL
library HookDLL; uses Windows,Messages; var OldWndProc: pointer; ThreadID:DWORD; const CtrlAltDel_CODE = (VK_DELETE shl 16) or (MOD_CONTROL or MOD_ALT); CtrlShiftEsc_CODE = (VK_ESCAPE shl 16) or (MOD_CONTROL or MOD_SHIFT); function GethWnd: HWND; begin result:= FindWindow('SAS Window class','SAS window'); end; function NewWndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin if msg=WM_HOTKEY then begin if (lParam=CtrlAltDel_CODE) or (lParam = CtrlShiftEsc_CODE) then result:= 0 else result:= CallWindowProc(OldWndProc, hWnd, Msg, wParam, lParam); end else result:= CallWindowProc(OldWndProc, hWnd, Msg, wParam, lParam); end; procedure SetWndProc(hWnd: HWND); begin OldWndProc:= pointer(SetWindowLong(hWnd, GWL_WNDPROC, cardinal(@NewWndProc))); end; procedure UnSetWndProc(hWnd: HWND); begin SetWindowLong(hWnd, GWL_WNDPROC, cardinal(OldWndProc)); end; function HookThread(PARAM1:DWORD):DWORD; stdcall; var ThrID:DWORD; begin Result:=0; SetWndProc(GethWnd); sleep(60*1000); UnSetWndProc(GethWnd); sleep(10); CreateThread(nil,0,GetProcAddress(GetModuleHandle('kernel32'),'FreeLibrary'),pointer(hInstance),0,ThrID); end; begin CreateThread(nil,0,@HookThread,nil,0,ThreadID); end.
Код этой DLL блокирует комбинации ровно на минуту, потом DLL выгружается из памяти winlogon. Так же можно изменить функцию NewWndProc так чтобы перенаправить заблокированные комбинации на другие, также можно заблокировать любую комбинацию клавиш которую нельзя перехватить через стандартный механизм хуков. А вот и код, который загрузит нашу DLL в процесс winlogon.
function Start(ProcessID: Cardinal; DllFileName: string): Boolean; var hProcess, hTh: THandle; BytesWritten, ThreadID, DllNameLen: Cardinal; LoadLibraryProc, MemPtr: Pointer; ExitCode: DWord; begin Result := false; SetDebugPriv(); hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE,true, ProcessID); if hProcess = 0 then exit; DllNameLen := Length(DllFileName) + 1; MemPtr := VirtualAllocEx(hProcess, nil, DllNameLen, MEM_COMMIT, PAGE_READWRITE); if MemPtr nil then begin //3 if WriteProcessMemory(hProcess, MemPtr, PChar(DllFileName), DllNameLen, BytesWritten) then begin //2 LoadLibraryProc := GetProcAddress(GetModuleHandle('kernel32.dll'), 'LoadLibraryA'); hTh := CreateRemoteThread(hProcess, nil, 0, LoadLibraryProc, MemPtr, 0, ThreadID); if hTh 0 then begin //1 if (WaitForSingleObject(hTh, INFINITE) = WAIT_OBJECT_0) and GetExitCodeThread(hTh, ExitCode) then Result := ExitCode 0; CloseHandle(hTh); end; //1 end; //2 VirtualFreeEx(hProcess, MemPtr, 0, MEM_RELEASE); end; //3 CloseHandle(hProcess); end;
Эта процедура принимает ID процесса winlogon и путь к нашей DLL. Разумеется, до этого надо позаботиться о получении привилегии «SeDebugPrivilege» чтобы можно было открыть процесс winlogon c нужным нам доступом. Полный код программы и DLL смотрите в архиве с исходниками в конце статьи.
Итак, блокировка Ctrl-Alt-Del и Ctrl-Shift-Esc реализована. Но некоторым не нравится использование DLL. И как всегда возникает вопрос «А можно ли всё сделать без DLL». Ну, разумеется, можно все это сделать и без DLL, через инжект нашего кода в процесс winlogon.
Итак, приступим. Нам надо будет внедрить в процесс winlogon код, который будет находить окно и изменять оконную процедуру целевого окна и код самой оконной процедуры. Разумеется, внедряемый код должен быть базонезависимым, так как мы заранее не знаем, по какому адресу мы его скопируем, и ему нужны адреса используемых им API функций. На Delphi сделать это будет уже проблематично. И поэтому сделаем мы это на ассемблере, так как на нём проще всего написать базонезависимый код. Сначала приведу код, который будет выполняться в контексте процесса winlogon
section '.remcode' code executable readable writeable ;---------------------------------------- ; REMOTE CODE START --------------------- ;---------------------------------------- RemoteCodeStart: call .delta .delta: pop ebp sub ebp, .delta lea eax, [ebp+SAS_WndTitle] push eax lea eax, [ebp+SAS_WndClass] push eax call [ebp+pFindWindowA] mov [ebp+SAS_WndHandle], eax test eax, eax jnz @f jmp .thrend @@: lea eax, [ebp+NewWindowProc] push eax push GWL_WNDPROC push [ebp+SAS_WndHandle] call [ebp+pSetWindowLongA] mov [ebp+OldWindowProc], eax push 10000 call [ebp+pSleep] push [ebp+OldWindowProc] push GWL_WNDPROC push [ebp+SAS_WndHandle] call [ebp+pSetWindowLongA] .thrend: push 0 call [ebp+pExitThread] proc NewWindowProc hwnd, wmsg, wparam, lparam call .delta .delta: pop eax sub eax, .delta ; delta offset -> eax cmp [wmsg], WM_HOTKEY jnz .continue cmp [lparam], CtrlAltDel_CODE jz .exit_proc cmp [lparam], CtrlShiftEsc_CODE jz .exit_proc .continue: push [lparam] push [wparam] push [wmsg] push [hwnd] push [eax+OldWindowProc] call [eax+pCallWindowProcA] jmp .return .exit_proc: xor eax, eax .return: ret endp SAS_WndClass db 'SAS Window class',0 SAS_WndTitle db 'SAS window',0 SAS_WndHandle dd 0 OldWindowProc dd 0 pFindWindowA dd 0 pSetWindowLongA dd 0 pCallWindowProcA dd 0 pExitThread dd 0 pSleep dd 0 RemoteCodeEnd: RemoteCodeSize equ RemoteCodeEnd-RemoteCodeStart ;---------------------------------------- ; REMOTE CODE END ----------------------- ;----------------------------------------
В начале обоих процедур мы сначала вычисляем дельта-смещение, дельта смещение нам нужно, для того чтобы узнать, на сколько отличаются адреса переменных перемещённых с нашим кодом от тех адресов, которые поставил нам компилятор во время компиляции. Зная, дельта-смещение мы можем спокойно обращаться к переменным, не боясь возникновения ошибок доступа к памяти. Приводить полный код программы, я думаю, смысла не имеет, поэтому только приведу код, который подготавливает переменные, копирует код и запускает поток в процессе winlogon
invoke OpenProcess, PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE, FALSE, [proc_entry.th32ProcessID] mov [WinlogonProcHandle], eax test eax, eax jnz @f jmp .exit @@: mov eax, [FindWindow] mov [pFindWindowA], eax mov eax, [SetWindowLong] mov [pSetWindowLongA], eax mov eax, [ExitThread] mov [pExitThread], eax mov eax, [CallWindowProc] mov [pCallWindowProcA], eax mov eax, [Sleep] mov [pSleep], eax invoke VirtualAllocEx, [WinlogonProcHandle], 0, RemoteCodeSize, MEM_COMMIT+MEM_RESERVE, PAGE_EXECUTE_READWRITE mov [RemoteThreadBaseAddress], eax invoke WriteProcessMemory, [WinlogonProcHandle], eax, RemoteCodeStart, RemoteCodeSize, Writed invoke CreateRemoteThread, [WinlogonProcHandle], 0, 0, [RemoteThreadBaseAddress], 0, 0, RemoteThreadID .exit: invoke ExitProcess, 0
Сначала мы открываем процесс winlogon с нужным нам уровнем доступа (код получения привилегий и получения ID winlogon я не привёл). Потом заполняем переменные, в которых будут храниться адреса используемых API функций, потом выделяем кусок памяти в процессе winlogon, потом копируем туда код, который будет выполняться в его контексте, потом запускаем удалённый поток. Полный код программы приведён в архиве с исходниками к этой статье.
Наступил статьи конец, кто дочитал тот молодец. Итог, мы написали две программы-каркаса, которые блокируют комбинацию Ctrl-Alt-Del.
я удалил фаил «Tackmpgr.exe»ща все не открываеться!!!а у меня такая фишка типо если удалишь!!то он удаляет его вообще а не в карзину!!!!как щас можно востанновить или заменяить чем то!!!!а можно с другого комьпьютера его скапировать????
Спасибо за статью , она довольно полезна для «юнных» злоумышленников , и мне в том числе 🙂
на счёт Диспетчера задач , я считаю Вам можно добавить отключение оннного в реестре , также , имея старые версии Windows(XP SP2)( взломанные ) диспетчер задач открывался столько раз сколько я нажимал (Ctrl + Alt + Delete) , незнаю правильно это или нет но на данной сборке( сейчас SP3 loner) он действительно открывается всего 1 раз.
ещё замутил такой «баг» : если поместить в системный диск ( С по стандарту) файлик program.exe то при нажатии Ctrl + Alt + Delete (Ctrl-Shift-Esc) у меня вместо диспетчера задач выполняется именно этот файл , но при перезагрузке системы ( следующий вход в виндовс) выдаётся «предупреждение» с предложением переименовать файл , разумеется можно его отвергнуть , наверное можно отловить и скрыть , или не показывать , возможно зависит от моей сборки windows , однако говорю то , что я заметил 😀
Также был рассмотрен метод открытия файла с привелегиями , запрещающего запись/чтение его для других программ, также и запуска )
И как вывод , я думаю что использовав вышеперечисленные методы можно » окончательно» лишить пользователя данного tool’a
С уважением , Lime (http://programmersforum.ru/)
Спасибо за полезную информацию в который раз !!!
Спасибо большое очень нужно для дальнейшего
еще вместо удаления taskmgr.exe можно его в реестре запретить черезDisabletaskmgr
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe]
«Debugger»=»\»C:\\PROGRAM FILES\\PROCESS EXPLORER\\PROCEXP.EXE\»»
я тут этого не видел, но может кому понадобится
и тут я поняла как много я ещё не знаю… 😳 😥 😳
Люди,подскажите пожалуйста как это в Delphi7 программу внедрить,например,чтобы кнопочка на форме
весь этот ассемблерчик выполняла.Если можно,покажите исходничек. 🙂
в этой же самой статье написано, что реализовать такое на Delphi будет проблематично, но возможно если захотеть, но я не хочу.
У кого-нибудь получалось заблокировать диспетчер задач под Windows 7. А то у меня ни вариант с реестром, ни с DLL не прокатывают?
проще всего через xxx.bat код:
@echo off
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System /v DisableTaskMgr /t REG_DWORD /d 1 /f >nul
del %0 >nul
Нужно просто скопировать этот код в блокнот и сохранить его с расширением .BAT после запустить.
reg add……… — блокирует Alt+Ctrl+Del и Ctrl+Shift+Esc
del %0>nul… — удаляет себя (т.е. xxx.bat).
А чтобы включить обратно (Alt+Ctrl+Del и Ctrl+Shift+Esc) изменить в конц строчке reg add……………/d 1 /f>nul на …/d 0 /f>nul
ничего непонятно. Вечно ваши описания идут сплошняком без обьяснений как что называется, Это всё пишется в одном файле? Как файл называть чтобы вообще ничего не менять? Чтобы скопировал код к себе он заработал и начал править….
К сожалению, представленный материал не работает на windows 7. А было бы очень интересно, узнать, как это там сделать.