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

Отслеживание загрузки dll в память процесса
13.05.2021 | Категория: Образ мышления: Assembler | Автор: ManHunter
Ранее я уже рассказывал, как можно легко и просто получить список динамических библиотек, загруженных в ваш процесс. Сегодня расскажу о возможности отслеживания загрузки и выгрузки DLL. Начиная с Windows Vista, появилась функция LdrRegisterDllNotification. С ее помощью в приложении регистрируется callback-функция, которая будет вызываться каждый раз, как только в ваше приложение будет загружена DLL или какая-то DLL будет выгружена из его адресного пространства. Установка обработчика выполняется одной командой:Code (Assembler) : Убрать нумерацию
- ; Зарегистрировать обработчик загрузки и выгрузки DLL
- invoke LdrRegisterDllNotification,0,LdrDllNotification,NULL,Cookie
- or eax,eax
- jnz loc_error
Code (Assembler) : Убрать нумерацию
- LDR_DLL_NOTIFICATION_REASON_LOADED = 1
- LDR_DLL_NOTIFICATION_REASON_UNLOADED = 2
- struct NOTIFICATION_DATA
- Flags dd ?
- FullDllName dd ?
- BaseDllName dd ?
- DllBase dd ?
- SizeOfImage dd ?
- ends
- proc LdrDllNotification NotificationReason:DWORD,\
- NotificationData:DWORD,Context:DWORD
- pusha
- mov eax,[NotificationReason]
- ; EAX -> действие с DLL
- ; LDR_DLL_NOTIFICATION_REASON_LOADED = загружена
- ; LDR_DLL_NOTIFICATION_REASON_UNLOADED = выгружена
- ; Получить полный путь до файла DLL
- mov eax,[NotificationData]
- mov eax,[eax+NOTIFICATION_DATA.FullDllName]
- mov eax,[eax+4]
- ; EAX -> полное имя файла DLL
- ; Получить базовый адрес DLL
- mov eax,[NotificationData]
- mov eax,[eax+NOTIFICATION_DATA.DllBase]
- ; EAX -> DllBase библиотеки
- popa
- ret
- endp
Читать статью целиком »
Просмотров: 1616 | Комментариев: 1

Перезапуск приложения в случае его аварийного завершения
23.03.2021 | Категория: Образ мышления: Assembler | Автор: ManHunter

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

Как узнать, что приложение запущено через ярлык
29.11.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Очередная развлекушка на Ассемблере. Давайте узнаем, была ли наша программа запущена через .lnk-файл, то есть через ярлык, или же напрямую через Проводник, файловый менеджер или другой процесс. Для этого надо получить структуру STARTUPINFO, а затем проверить, установлен ли флаг STARTF_TITLEISLINKNAME в поле dwFlags.Code (Assembler) : Убрать нумерацию
- STARTF_TITLEISLINKNAME = 0x800
- ; Получить информацию запуска
- mov [sinfo.cb],sizeof.STARTUPINFO
- invoke GetStartupInfo,sinfo
- ; Флаг установлен?
- test [sinfo.dwFlags],STARTF_TITLEISLINKNAME
- jz @f
- ; Да, запуск выполнен через ярлык
- ...
- @@:
- ; Нет, прямой запуск
- ...
Читать статью целиком »
Просмотров: 1080 | Комментариев: 0

Управление редактором реестра из своего приложения
27.05.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Наверняка вы слышали о программе RegJump от SysInternals, ныне принадлежащая Microsoft. При помощи этой программы вы можете открыть regedit сразу же на нужной ветке реестра. Мне стало очень интересно, как она это делает. Дизассемблер в руки, отладчик в боевую готовность и вперед!Вот что мне удалось накопать. Я оставил только самый важный код, попутно упростив и оптимизировав его. Оригинальный RegJump сперва пытается найти запущенный regedit по наименованию класса окна, если такого нет, то пытается запустить regedit из системной папки. Так или иначе, вся работа выполняется с найденным окном. У меня подразумевается, что редактор реестра уже запущен.
Code (Assembler) : Убрать нумерацию
- section '.data' data readable writeable
- ; Классы окон для поиска
- szClass db 'RegEdit_RegEdit',0
- szList db 'SysTreeView32',0
- ; Название ветки реестра
- szReg db '\HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\',0
Хэндл процесса необходим для синхронизации пользовательского ввода с окном приложения, поскольку все управление regedit выполняется через эмуляцию нажатий клавиш в списке. Для "своей" копии regedit, которая запущена RegJump, используется результат выполнения функции CreateProcess, для запущенного ранее экземпляра хэндл получается через пару функций GetWindowThreadProcessId и OpenProcess. Особых привилегий для этого не надо.
Code (Assembler) : Убрать нумерацию
- ; Найти окно редактора реестра
- invoke FindWindow,szClass,NULL
- or eax,eax
- jz loc_exit
- mov [hRWnd],eax
- ; Найти список в окне редактора реестра
- invoke FindWindowEx,[hRWnd],NULL,szList,NULL
- or eax,eax
- jz loc_exit
- mov [hWnd],eax
- ; Получить хэндл процесса-владельца
- invoke GetWindowThreadProcessId,[hRWnd],ProcessId
- invoke OpenProcess,PROCESS_QUERY_INFORMATION,0,[ProcessId]
- or eax,eax
- jz loc_exit
- mov [hProcess],eax
- ; Активировать окно редактора реестра
- invoke ShowWindow,[hRWnd],SW_RESTORE
- invoke SetForegroundWindow,[hRWnd]
- ; Установить фокус на список
- invoke SetFocus,[hWnd]
- invoke WaitForInputIdle,[hProcess],-1
- ; Вот тут непонятно :(
- invoke SendMessage,[hRWnd],WM_COMMAND,10288h,0
- invoke WaitForInputIdle,[hProcess],-1
- ; Перейти на верхний уровень списка
- mov ebx,30
- @@:
- invoke SendMessage,[hWnd],WM_KEYDOWN,VK_LEFT,0
- invoke WaitForInputIdle,[hProcess],-1
- sub ebx,1
- jnz @b
- ; Указатель на строку в названием ветки реестра
- mov esi,szReg
- loc_loop:
- lodsb
- or al,al
- jz loc_exit_clean
- cmp al,'\'
- jne @f
- ; Открыть ветку списка
- invoke SendMessage,[hWnd],WM_KEYDOWN,VK_RIGHT,0
- invoke WaitForInputIdle,[hProcess],-1
- jmp loc_loop
- @@:
- movzx eax,al
- ; Поиск строки в списке
- invoke SendMessage,[hWnd],WM_CHAR,eax,0
- invoke WaitForInputIdle,[hProcess],-1
- jmp loc_loop
- loc_exit_clean:
- invoke CloseHandle,[hProcess]
- loc_exit:
Читать статью целиком »
Просмотров: 1705 | Комментариев: 6

Запуск ограниченного количества копий программы
23.05.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
В комментариях к статье о запрете запуска нескольких копий программы пару лет назад был задан очень правильный вопрос: как реализовать запуск ограниченного числа копий программы больше одного? Сейчас я могу ответить на этот вопрос полноценной статьей. Настоятельно рекомендую сперва прочитать изначальную статью, чтобы не дублировать здесь теоретические выкладки. Для наглядности почти все методы остаются прежними, меняться будут только условия их использования.Первый способ использует shared-память, общую для всех копий данного приложения. В ней находится счетчик, который каждая копия увеличивает на 1 при запуске и уменьшает на 1 при завершении своей работы. При старте выполняется проверка на количество ранее запущенных копий. Счетчик достиг максимального значения - пожалуйте на выход.
Code (Assembler) : Убрать нумерацию
- ; Расшаренная секция, общая для всех копий данного приложения
- section '.shared' data readable writeable shareable
- started dd 0 ; Количество запущенных копий
- ; Сегмент кода
- section '.code' code readable executable
- cmp [started],3 ; Уже запущено три экземпляра программы?
- jae already_started ; Да, на выход
- ; +1 к счетчику копий
- ; Префикс LOCK используется для предотвращения возможных конфликтов
- ; на многопроцессорных машинах
- lock add [started],1
- ; Нормальный запуск программы
- ...
- ...
- ...
- ; -1 от счетчика копий
- lock sub [started],1
- jmp loc_exit
- already_started:
- ; Выход из программы
- ...
- loc_exit:
Читать статью целиком »
Просмотров: 1490 | Комментариев: 3
