Blog. Just Blog

Быстрый поиск

Введите фрагмент названия статьи для поиска

Запуск задания cron с интервалом меньше 60 секунд

31.08.2022 | Категория: Web-мастеру и не только | Автор: ManHunter

Формат crontab

Как известно из документации, минимальный интервал запуска заданий в cron равен 1 минуте. Причина такого ограничения понятна, минутный интервал нужен, чтобы не перегрузить систему параллельными задачами в случае некорректных настроек. А мне понадобилось запускать определенный процесс каждые 20 секунд. Да, можно было бы написать промежуточный скрипт, который запускался бы раз в минуту по планировщику, а потом запускал процессы с нужными интервалами. Но есть более красивое решение средствами самого cron. Для того чтобы какое-либо задание запускалось каждые 20 секунд, в файле crontab нужно сделать 3 записи, что-то типа такого:

####################################################
# Запуск задания каждые 20 секунд
####################################################

* * * * * /usr/local/bin/php -f /path/to/script.php
* * * * * (sleep 20 ; /usr/local/bin/php -f /path/to/script.php)
* * * * * (sleep 40 ; /usr/local/bin/php -f /path/to/script.php)

Теперь каждую минуту будет запускаться пакет из трех заданий, но самое первое стартует незамедлительно, второе запустится через 20 секунд, а третье только через 40 секунд. Таким образом исходная задача будет решена. А, например, для запуска заданий с интервалом в 30 секунд понадобятся только две записи, и пауза перед вторым заданием, соответственно, будет 30 секунд.

Просмотров: 185 | Комментариев: 2

Отслеживание загрузки dll в память процесса

13.05.2021 | Категория: Образ мышления: Assembler | Автор: ManHunter
Ранее я уже рассказывал, как можно легко и просто получить список динамических библиотек, загруженных в ваш процесс. Сегодня расскажу о возможности отслеживания загрузки и выгрузки DLL. Начиная с Windows Vista, появилась функция LdrRegisterDllNotification. С ее помощью в приложении регистрируется callback-функция, которая будет вызываться каждый раз, как только в ваше приложение будет загружена DLL или какая-то DLL будет выгружена из его адресного пространства. Установка обработчика выполняется одной командой:
  1.         ; Зарегистрировать обработчик загрузки и выгрузки DLL
  2.         invoke  LdrRegisterDllNotification,0,LdrDllNotification,NULL,Cookie
  3.         or      eax,eax
  4.         jnz     loc_error
Важное замечание. Как показала практика, в callback-функции не должно быть никаких открытий окон, вывода сообщений и прочих взаимодействий с интерфейсом. Это может привести к зацикливанию и падению приложения во время загрузки UI-библиотек.
  1. LDR_DLL_NOTIFICATION_REASON_LOADED   = 1
  2. LDR_DLL_NOTIFICATION_REASON_UNLOADED = 2
  3.  
  4. struct NOTIFICATION_DATA
  5.     Flags       dd ?
  6.     FullDllName dd ?
  7.     BaseDllName dd ?
  8.     DllBase     dd ?
  9.     SizeOfImage dd ?
  10. ends
  11.  
  12. proc LdrDllNotification NotificationReason:DWORD,\
  13.         NotificationData:DWORD,Context:DWORD
  14.  
  15.         pusha
  16.         mov     eax,[NotificationReason]
  17.         ; EAX -> действие с DLL
  18.         ; LDR_DLL_NOTIFICATION_REASON_LOADED = загружена
  19.         ; LDR_DLL_NOTIFICATION_REASON_UNLOADED = выгружена
  20.  
  21.         ; Получить полный путь до файла DLL
  22.         mov     eax,[NotificationData]
  23.         mov     eax,[eax+NOTIFICATION_DATA.FullDllName]
  24.         mov     eax,[eax+4]
  25.         ; EAX -> полное имя файла DLL
  26.  
  27.         ; Получить базовый адрес DLL
  28.         mov     eax,[NotificationData]
  29.         mov     eax,[eax+NOTIFICATION_DATA.DllBase]
  30.         ; EAX -> DllBase библиотеки
  31.  
  32.         popa
  33.         ret
  34. endp
При каждом вызове в callback-функцию передается причина вызова - загрузка или выгрузка DLL, а также заполненная структура NOTIFICATION_DATA, в которой содержится полный путь и имя файла библиотеки, базовый адрес загрузки и размер загружаемого образа. Зная эти данные, можно проверить, что за DLL пытаются подгрузить в наш процесс и принять соответствующие меры. Например, при попытке подгрузить в процесс модуль мониторинга, можно отключить некоторые ветки алгоритма или исказить выдаваемые данные, а можно просто завершить работу приложения. Если пойти дальше, то теоретически можно даже модифицировать в памяти загруженную библиотеку, нейтрализовав в ней то, чего она не должна делать с вашим процессом. Просторы для фантазии безграничны.

Читать статью целиком »
Просмотров: 774 | Комментариев: 1

Перезапуск приложения в случае его аварийного завершения

23.03.2021 | Категория: Образ мышления: Assembler | Автор: ManHunter

Перезапуск приложения в случае его аварийного завершения

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

Читать статью целиком »
Просмотров: 935 | Комментариев: 5

Как узнать, что приложение запущено через ярлык

29.11.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Очередная развлекушка на Ассемблере. Давайте узнаем, была ли наша программа запущена через .lnk-файл, то есть через ярлык, или же напрямую через Проводник, файловый менеджер или другой процесс. Для этого надо получить структуру STARTUPINFO, а затем проверить, установлен ли флаг STARTF_TITLEISLINKNAME в поле dwFlags.
  1.         STARTF_TITLEISLINKNAME = 0x800
  2.  
  3.         ; Получить информацию запуска
  4.         mov     [sinfo.cb],sizeof.STARTUPINFO
  5.         invoke  GetStartupInfo,sinfo
  6.  
  7.         ; Флаг установлен?
  8.         test    [sinfo.dwFlags],STARTF_TITLEISLINKNAME
  9.         jz      @f
  10.         ; Да, запуск выполнен через ярлык
  11.         ...
  12. @@:
  13.         ; Нет, прямой запуск
  14.         ...
Ранее этот флаг относился к недокументированным, сейчас в MSDN появилось его нормальное описание. Итак, если флаг STARTF_TITLEISLINKNAME установлен, то программа была запущена через ярлык, а в параметре lpTitle структуры STARTUPINFO содержится указатель на строку с полным путем к .lnk-файлу, через который был произведен запуск.

Читать статью целиком »
Просмотров: 709 | Комментариев: 0

Управление редактором реестра из своего приложения

27.05.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Наверняка вы слышали о программе RegJump от SysInternals, ныне принадлежащая Microsoft. При помощи этой программы вы можете открыть regedit сразу же на нужной ветке реестра. Мне стало очень интересно, как она это делает. Дизассемблер в руки, отладчик в боевую готовность и вперед!

Вот что мне удалось накопать. Я оставил только самый важный код, попутно упростив и оптимизировав его. Оригинальный RegJump сперва пытается найти запущенный regedit по наименованию класса окна, если такого нет, то пытается запустить regedit из системной папки. Так или иначе, вся работа выполняется с найденным окном. У меня подразумевается, что редактор реестра уже запущен.
  1. section '.data' data readable writeable
  2.  
  3. ; Классы окон для поиска
  4. szClass db 'RegEdit_RegEdit',0
  5. szList  db 'SysTreeView32',0
  6. ; Название ветки реестра
  7. szReg   db '\HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\',0
Наименование ветки реестра, куда надо перейти, переводится в верхний регистр, а в начало и конец строки прицепляется символ "\". Традиционные сокращения типа "HKLM" разворачиваются в полноценные наименования веток реестра "HKEY_LOCAL_MACHINE" и т.п. Я надеюсь, с подобным преобразованием строки у вас проблем возникнуть не должно. У меня строка сразу приведена в должный вид.

Хэндл процесса необходим для синхронизации пользовательского ввода с окном приложения, поскольку все управление regedit выполняется через эмуляцию нажатий клавиш в списке. Для "своей" копии regedit, которая запущена RegJump, используется результат выполнения функции CreateProcess, для запущенного ранее экземпляра хэндл получается через пару функций GetWindowThreadProcessId и OpenProcess. Особых привилегий для этого не надо.
  1.         ; Найти окно редактора реестра
  2.         invoke  FindWindow,szClass,NULL
  3.         or      eax,eax
  4.         jz      loc_exit
  5.         mov     [hRWnd],eax
  6.  
  7.         ; Найти список в окне редактора реестра
  8.         invoke  FindWindowEx,[hRWnd],NULL,szList,NULL
  9.         or      eax,eax
  10.         jz      loc_exit
  11.         mov     [hWnd],eax
  12.  
  13.         ; Получить хэндл процесса-владельца
  14.         invoke  GetWindowThreadProcessId,[hRWnd],ProcessId
  15.         invoke  OpenProcess,PROCESS_QUERY_INFORMATION,0,[ProcessId]
  16.         or      eax,eax
  17.         jz      loc_exit
  18.         mov     [hProcess],eax
  19.  
  20.         ; Активировать окно редактора реестра
  21.         invoke  ShowWindow,[hRWnd],SW_RESTORE
  22.         invoke  SetForegroundWindow,[hRWnd]
  23.         ; Установить фокус на список
  24.         invoke  SetFocus,[hWnd]
  25.         invoke  WaitForInputIdle,[hProcess],-1
  26.  
  27.         ; Вот тут непонятно :(
  28.         invoke  SendMessage,[hRWnd],WM_COMMAND,10288h,0
  29.         invoke  WaitForInputIdle,[hProcess],-1
  30.  
  31.         ; Перейти на верхний уровень списка
  32.         mov     ebx,30
  33. @@:
  34.         invoke  SendMessage,[hWnd],WM_KEYDOWN,VK_LEFT,0
  35.         invoke  WaitForInputIdle,[hProcess],-1
  36.         sub     ebx,1
  37.         jnz     @b
  38.  
  39.         ; Указатель на строку в названием ветки реестра
  40.         mov     esi,szReg
  41. loc_loop:
  42.         lodsb
  43.         or      al,al
  44.         jz      loc_exit_clean
  45.  
  46.         cmp     al,'\'
  47.         jne     @f
  48.         ; Открыть ветку списка
  49.         invoke  SendMessage,[hWnd],WM_KEYDOWN,VK_RIGHT,0
  50.         invoke  WaitForInputIdle,[hProcess],-1
  51.         jmp     loc_loop
  52. @@:
  53.         movzx   eax,al
  54.         ; Поиск строки в списке
  55.         invoke  SendMessage,[hWnd],WM_CHAR,eax,0
  56.         invoke  WaitForInputIdle,[hProcess],-1
  57.         jmp     loc_loop
  58. loc_exit_clean:
  59.         invoke  CloseHandle,[hProcess]
  60.  
  61. loc_exit:
Когда все нужные окна найдены и хэндл процесса получен, начинается эмуляция нажатий клавиш. Сперва выполняется переход на самый верхний уровень списка. Судя по коду, Марк Руссинович предположил, что глубже 30-го уровня списка зайти невозможно, что ж, ему виднее. Затем начинается обработка строки с нужным названием ветки реестра. Строка обрабатывается посимвольно, когда встретится символ "\", то эмулируется нажатие стрелки вправо для открытия нужного уровня списка и перехода на него. Именно для этого исходная строка дополняется в начале и в конце этим символом. Строковые символы из строки передаются в поиск, тем самым определяя следующий уровень списка. Как видите, никаких ракетных технологий, но лично мне было очень интересно посмотреть на решение этой задачи от одного из признанных знатоков внутренностей Windows.

Читать статью целиком »
Просмотров: 1123 | Комментариев: 6

prev 01 02 03 04 05
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2022
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.12 сек. / MySQL: 3 (0.0512 сек.) / Память: 5 Mb
Наверх