Как воспрепятствовать закрытию окна другого приложения?

Тема в разделе "WASM.WIN32", создана пользователем WishMaster, 29 июл 2008.

  1. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    Скажем, у меня открыт стандартный Notepad и я хочу воспрепятствовать его закрытию пользователем. Первая идея – это пробовать отлавливать сообщения, посылаемые окну Блокнота и если это WM_CLOSE, то не пересылать их дальше. Вот код (Блокнот должен был блокироваться при нажатии на кнопку ButtonLock):

    Код (Text):
    1. WNDPROC OldWindowProc;
    2. HWND NotepadHandle;
    3.  
    4. LRESULT CALLBACK NewWindowProc(HWND hWnd, UINT msg, WPARAM w, LPARAM l)
    5.   {
    6.     if (msg == 0x0010) {MessageBox(NULL, "Нельзя закрывать!", "", MB_OK); return(0);}
    7.     else return CallWindowProc((FARPROC)OldWindowProc, hWnd, msg, w, l);
    8.   }
    9.  
    10. void __fastcall TForm1::ButtonLockClick(TObject *Sender)
    11. {
    12.   NotepadHandle = FindWindow(NULL, "Безымянный - Блокнот");
    13.   OldWindowProc = (WNDPROC)SetWindowLong(NotepadHandle, GWL_WNDPROC, (long)NewWindowProc);
    14.   RaiseLastWin32Error();
    15. }
    Функция SetWindowLong() выдает ошибку: “System Error. Code: 5. Отказано в доступе.” Это запрещено с точки зрения безопасности? Потому как для окна моей программы этот код работает нормально (не дает ей закрыться). Как можно это обойти?

    Как воспрепятствовать закрытию Блокнота? Блокировать кнопку закрытия окна не предлагать – в любой программе есть либо своя кнопка закрытия, либо меню Файл-Выход. Кроме того, я обратил также внимание на то, что событие WM_CLOSE вызывается не всегда. Например, при вызове функции Form->Close() оно почему-то не срабатывает. А обрабатывать WM_DESTROY уже позно – когда оно срабатывает окно уже пропадает с экрана (по крайней мере у меня так было).

    Жду ваших размышлений :)
     
  2. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    ну дык не может же быть WndProc в другой программе, он должен быть в адресном пространстве того же процесса

    грузи dll
     
  3. zhindos

    zhindos New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2008
    Сообщения:
    142
    С чего бы вдруг SetWindowLong изменять WndProc на ту, которая находится в адресном пространстве другого процесса? (Read MSDN :)
    По сути: находишь в USER32.dll (как правило проецируется на один и тот же адрес во всех процессах) ф-ию DestroyWindow, заменяешь первые 3 байта на С2 04 00 ... должно сработать
    ЗЫ. C Builder is like delphi - full shit!!!
     
  4. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Я хотел однажды заюзать тоже этот сервис дабы подменить обработчик. Оказалось что можно вызывать только в текущем процессе. Попробуй использовать ловушки.
     
  5. zhindos

    zhindos New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2008
    Сообщения:
    142
    Любой способ сделать так, чтобы код новой WndProc оказался в адресном пространстве другого процесса...

    ЗЫ. А с DestroyWindow я ступил - закрываться то окно не будет, а вот всякий код освобождения ресурсов перед вызовом этой ф-ии я не учел... :dntknw:
     
  6. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    WishMaster ты сорвал JackPot ) "Вчера 23:23:23"
     
  7. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    Если загрузить функцию из dll, SetWindowLong() поменяет ее на обработчик событий окна другого приложения?
    Но ведь ловушки, на сколько понимаю, позволят мне лишь "констатировать факт" закрытия окна другого приложения, а не воспрепятствовать этому.
    dll?
    =)
     
  8. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    Да dll и с ловушками тоже dll. Напиши тот же код и скомпиль его как библеотеку, а потом заинжекти блокнот в хлам )))
     
  9. Prince

    Prince New Member

    Публикаций:
    0
    Регистрация:
    9 июл 2008
    Сообщения:
    71
    WishMaster
    2FED уже ответил ведь - dll, либо какой-то другой инжект твоего кода в память процесса
    rtfm
     
  10. zhindos

    zhindos New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2008
    Сообщения:
    142
    WishMaster
    dll?

    Вообще говоря, не обязательно, можно выделить в другом процессе блок памяти, присвоить страницам атрибут PAGE_EXECUTE_READWRITE, записать туда твой WndProc, затем найти какой-нибудь способ вызвать SetWindowLong с указателем на выделенный тобою блок(новый WndProc) потоком того процесса и that's all... :)))))))))))))))
    Но это довольно стремно, поэтому лучше все-таки dll. Если не любишь ловушки - можно ч-з удаленный поток:

    Создаешь удаленный поток(CreateRemoteThread) в нужном тебе процессе, в качестве стартовой ф-ии указываешь LoadLibrary(но не напрямую, а узнаешь ч-з GetProcAddress ее вирт. адрес), в качестве параметра ф-ии(LoadLibrary) передаешь указатель на строку, содержащую имя inject-dll-ки(но в адресном пр-ве того процесса, а не своего - выдел. память - VirtualAllocEx, осв. - VirtualFreeEx).
    В самой dll-ке у тебя находится новый WndProc, а в DllMain - код его изменения...

    ЗЫ. Да и мало ли какие способы можно еще придумать... :)
     
  11. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    NtUserSetWindowLong -> xxxSetWindowLong -> xxxSetWindowData:
    Код (Text):
    1. case GWLP_WNDPROC:  // See similar case DWLP_DLGPROC
    2.         /*
    3.          * Hide the window proc from other processes
    4.          */
    5.         if (PpiCurrent() != GETPTI(pwnd)->ppi) {
    6.             RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING,
    7.                 "SetWindowLong: Window owned by another process %#p", pwnd);
    8.             return 0;
    9.         }
    Патчить win32k придётся. Просто заинжектиться, найти адрес оконного обработчика и хукнуть его, например сплайсингом.
    [Либо из контекста процесса куда выполняется инжект заюзать SetWindowLong.]
     
  12. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    И всё ради того чтобы блокнот жил :lol:
     
  13. Twister

    Twister New Member

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    720
    Адрес:
    Алматы
    CrystalIC
    Как ты собираешься патчить win32k из юзермода? А если есть возможность просто заинжектиться, то почему бы не воспользоваться уже предложенным SetWindowLong(), а не гемороиться со сплайсом?

    WishMaster
    Давай начнем по порядку.
    Какой смысл защищать окно от закрытия, если процесс можно спокойно прибить с помощью TerminateProcess()?
    Теперь в обратную сторону: даже если ты защитишь процесс от завершения (способов море, но они все смотрят в ядро), но процесс имеет окно, то _ни что_ не спасет этот процесс от GUI-хака через то же самое окно. Способов тоже много - есть общие, есть заточенные под конкретное приложение.
    Мало того. Окно, в отличие от процесса или потока, нельзя скрыть от перечисления. Тут не поможет способ, заюзаный в HideToolz от ms-rem'а или в RkU от EP_X0FF - способ, основанный на перехвате NtUserBuildHwndList(). Не поможет и исключение окна из многосвязных списков - такое окно просто будет нерабочим. Была когда-то мысль перехватывать обращение к страницам памяти, в которых расположены списки окон и для всех процессов, кроме ядра, csrss и "оболочки" поставлять фэйковые страницы со списками без защищаемого окна. Но посоветовавшись с тем же EP_X0FF я понял, что этой технике не уйти дальше PoC, а из-за сложностей в реализации за нее вообще не стоит браться. Короче говоря - окно нельзя скрыть, а если его видно, то его можно прибить. При чем прибивается окно (а в большинстве случаев, по вытекающей, и процесс) даже без вылазок в ядро, из юзермода.
     
  14. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    Дело было так :) В панельку моего приложения с помощью SetParent насильно запхнут MS Word. Я хочу, чтобы пользователь не мог его закрыть. В крайнем случае - отловить событие разрушение этого окна Ворда и сразу же создать там новый. Примерно так :) Но лучше конечно было бы не дать его закрыть.
    В принципе мне нужно было бы защитить его от закрытия через кнопку закрытия, из меню, ну может еще как-то - но только от закрытия так сказать натуральным способом. Если его убивают через Диспетчер задач - то это уже проблемы пользователя.
     
  15. a1ss

    a1ss New Member

    Публикаций:
    0
    Регистрация:
    18 ноя 2007
    Сообщения:
    120
    Тогда не проще подумать, как спрятать кнопку закрытия? Тем же SetWindowLong например. ИМХО не искушенному юзверю просто так дочернее окно не закрыть.
     
  16. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    Меню "Файл-Выход" тоже прятать?
     
  17. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    Плюс если в этом Ворде будет открыто два документа - один в моем приложении, а второй просто как обычный документ с Парентом в виде Десктопа, то при закрытии документа в моем приложении закроется все окно ворда, и ворд останется только на десктопе, а я останусь при своих интересах :) Для этого я и хочу отслеживать события с тем окном ворда, которое открыто в моем приложении и в крайнем случае реагировать на WM_DESTROY созданием нового окна Ворда.
     
  18. a1ss

    a1ss New Member

    Публикаций:
    0
    Регистрация:
    18 ноя 2007
    Сообщения:
    120
    Ну это еще проще :)

    Тогда инжекть длл, ИМХО тему уже раскрыли.
     
  19. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    Сделал так:

    Код длл-ки:

    Код (Text):
    1. #include <windows.h>
    2. #include <vcl.h>
    3. #pragma argsused
    4.  
    5. //Pointer to a CWPSTRUCT.
    6. PCWPSTRUCT pWndStruct;
    7. //---------------------------------------------------------------------------
    8.  
    9. extern "C" __declspec(dllexport) LRESULT CALLBACK CallWordWndProc (int, WPARAM, LPARAM);
    10.  
    11. //---------------------------------------------------------------------------
    12.  
    13. int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
    14. {
    15.         return 1;
    16. }
    17. //---------------------------------------------------------------------------
    18.  
    19. LRESULT CALLBACK CallWordWndProc(int nCode, WPARAM wParam, LPARAM lParam)
    20. {
    21.   if (nCode == HC_ACTION)
    22.     {
    23.       //The hook procedure must process the message.
    24.       pWndStruct = (PCWPSTRUCT)lParam;
    25.       if (pWndStruct->message == WM_NCDESTROY)
    26.         {
    27.           //MessageBox(NULL, "Window is destroying", "DLL Message", MB_OK);
    28.           Variant d = Variant::CreateObject("Word.Application");
    29.           d.OlePropertySet("Visible", true);
    30.         }  
    31.     }
    32.   //For Windows NT/XP/2003 hhk parameter of CallNextHookEx() function ignored.
    33.   return CallNextHookEx(NULL, nCode, wParam, lParam);
    34. }
    Код формы:

    Код (Text):
    1. #include <vcl.h>
    2. #pragma hdrstop
    3.  
    4. #include "Unit1.h"
    5. //---------------------------------------------------------------------------
    6. #pragma package(smart_init)
    7. #pragma resource "*.dfm"
    8. TForm1 *Form1;
    9.  
    10. Variant WordApp;
    11. HWND WordHandle;
    12. typedef LRESULT CALLBACK (__stdcall *CallWordWndProc)(int, WPARAM, LPARAM);
    13. CallWordWndProc pCallWordWndProc1;
    14. HINSTANCE hLib;
    15. HHOOK WordWndHook;
    16.  
    17. //---------------------------------------------------------------------------
    18. __fastcall TForm1::TForm1(TComponent* Owner)
    19.         : TForm(Owner)
    20. {
    21.   hLib = NULL;
    22.   pCallWordWndProc1 = NULL;
    23.   WordWndHook = NULL;
    24. }
    25. //---------------------------------------------------------------------------
    26.  
    27. void __fastcall TForm1::ButtonLockClick(TObject *Sender)
    28. {
    29.   WordApp = Variant::CreateObject("Word.Application");
    30.   WideString WordCaption = WordApp.OlePropertyGet("Caption");
    31.   WordApp.OlePropertySet("Caption", "123");
    32.   WordHandle = FindWindow(NULL, "123");
    33.   WordApp.OlePropertySet("Caption", WordCaption);
    34.   WordApp.OlePropertySet("Visible", true);
    35.  
    36.   hLib = LoadLibrary("Project2.dll");
    37.   if (hLib)
    38.     {
    39.       pCallWordWndProc1 = (CallWordWndProc)GetProcAddress(hLib, "CallWordWndProc");
    40.       if (pCallWordWndProc1)
    41.         {
    42.           WordWndHook = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)pCallWordWndProc1, hLib, GetWindowThreadProcessId(WordHandle, NULL));
    43.         }
    44.     }
    45. }
    46. //---------------------------------------------------------------------------
    47. void __fastcall TForm1::FormDestroy(TObject *Sender)
    48. {
    49.   if (WordWndHook) UnhookWindowsHookEx(WordWndHook);
    50.   if (hLib) FreeLibrary(hLib);
    51. }
    52. //---------------------------------------------------------------------------
    При нажатии на ButtonLock запускается Ворд. При закрытии Ворда должен запускаться новый. Какого-то хрена событие WM_NCDESTROY срабатывает 16 раз (столько новых Вордов у меня открывается). С событием WM_DESTROY аналогично. Событие WM_CLOSE не отлавливается, если выходить через меню. В чем проблема?
     
  20. zhindos

    zhindos New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2008
    Сообщения:
    142
    А если бы оно сработало 1600 раз? :)
    У тебя же для каждого окна (кнопки, edit-а и т.д) потока, куда ты инсталлишь хук, перехватывается WM_NCDESTROY
    Поэтому просто в ф-ии - обработчике хука замени старый WndProc на новый (для главного окна Wordа) (но т-ко один раз!!!), где у тебя будет соответствующая обработка твоих WM_CLOSE, WM_NCDESTROY и т.д