Orion9

|
Posted: Thu Mar 12, 2026 00:35 Post subject: |
|
|
И все-таки я спросил у болвана, как можно скрыть окно до его появления. Два-три запроса, и он выдал вполне вменяемый код установки хука на Autohotkey v2. Почему Autohotkey? Потому что его проще всего переводить на язык Autorun.
 Hidden text | Code: | #Requires AutoHotkey v2.0
; 1. Получаем адрес функции ShowWindow в user32.dll
pShowWindow := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", "user32.dll", "Ptr"), "AStr", "ShowWindow", "Ptr")
; 2. Сохраняем оригинальные 12 байт (для x64)
OriginalBytes := Buffer(12)
DllCall("RtlMoveMemory", "Ptr", OriginalBytes, "Ptr", pShowWindow, "Ptr", 12)
; 3. Создаем "Callback" — нашу функцию на языке AHK, которая заменит оригинал
; В v2 CallbackCreate создает адрес в памяти, который можно вызвать как функцию
MyDetour := CallbackCreate(DetouredShowWindow, "Fast", 2)
; 4. Подготавливаем патч (Machine Code для x64 JMP)
; mov rax, <address> ; jmp rax
Patch := Buffer(12)
NumPut("UChar", 0x48, Patch, 0) ; MOV RAX...
NumPut("UChar", 0xB8, Patch, 1)
NumPut("Ptr", MyDetour, Patch, 2) ; Адрес нашего колбэка
NumPut("UChar", 0xFF, Patch, 10) ; JMP...
NumPut("UChar", 0xE0, Patch, 11) ; ...RAX
; 5. Применяем патч
InstallHook() {
DllCall("VirtualProtect", "Ptr", pShowWindow, "Ptr", 12, "UInt", 0x40, "UInt*", &OldProtect := 0)
DllCall("RtlMoveMemory", "Ptr", pShowWindow, "Ptr", Patch, "Ptr", 12)
DllCall("VirtualProtect", "Ptr", pShowWindow, "Ptr", 12, "UInt", OldProtect, "UInt*", &OldProtect)
}
; Наша функция-заменитель
DetouredShowWindow(hWnd, nCmdShow) {
; Принудительно скрываем (SW_HIDE = 0)
forcedCmd := 0
; Чтобы вызвать оригинал, нужно временно снять патч
DllCall("VirtualProtect", "Ptr", pShowWindow, "Ptr", 12, "UInt", 0x40, "UInt*", &OldProtect := 0)
DllCall("RtlMoveMemory", "Ptr", pShowWindow, "Ptr", OriginalBytes, "Ptr", 12)
; Вызов оригинала
result := DllCall("user32\ShowWindow", "Ptr", hWnd, "Int", forcedCmd)
; Возвращаем патч обратно
DllCall("RtlMoveMemory", "Ptr", pShowWindow, "Ptr", Patch, "Ptr", 12)
DllCall("VirtualProtect", "Ptr", pShowWindow, "Ptr", 12, "UInt", OldProtect, "UInt*", &OldProtect)
return result
}
; Активируем перехват
InstallHook()
; ТЕСТ: Попробуем показать блокнот. Он создастся, но ShowWindow(hWnd, 5) превратится в (hWnd, 0)
Run "notepad.exe",,, &PID
WinWait "ahk_pid " PID
MsgBox "Попытка показать окно заблокирована хуком!" |
 Hidden text | Code: | Как это работает (Пошагово):
Поиск адреса: Мы находим, где в памяти процесса находится функция ShowWindow из user32.dll.
Сохранение оригинала: Мы копируем первые 12 байт функции в массив originalBytes, чтобы иметь возможность восстановить их или выполнить оригинал.
Запись JMP: Мы перезаписываем начало функции ShowWindow инструкцией перехода на наш адрес DetouredShowWindow. Теперь любой вызов ShowWindow в этом процессе приведет к нам.
Модификация: Внутри нашей функции мы игнорируем то, что хочет программа, и передаем в систему SW_HIDE.
Важные ограничения "Raw" метода:
Архитектура: Данный пример написан под x64 (использует 12-байтовый переход через RAX). Для x86 код патча будет короче (5 байт через 0xE9).
Потокобезопасность: Если другой поток вызовет ShowWindow в тот микромомент, когда хук временно снят для вызова оригинала, он проскочит незамеченным. Именно поэтому профессиональные библиотеки (MinHook, Detours) используют "трамплины" — выделяют отдельный участок памяти, где лежат оригинальные байты + переход на середину функции, чтобы никогда не снимать хук.
Хотите, чтобы я объяснил, как работает механизм трамплина, чтобы избежать постоянного снятия/установки патча в памяти?
Разбор механики в AHK:
CallbackCreate: Самая важная часть. Она превращает функцию скрипта в адрес памяти, понятный для процессора.
Buffer: В AHK v2 заменяет старые манипуляции с переменными через VarSetCapacity. Это безопасный способ работать с сырыми байтами.
NumPut: Записывает опкоды ассемблера (0x48, 0xB8 и т.д.) прямо в буфер патча.
VirtualProtect: Необходим, так как по умолчанию страницы памяти с кодом защищены от записи. |
Ниже обновленный модуль autorun.cfg. Если кто-то хочет попробовать, можно подключить к мини-сборке, которую я выкладывал на предыдущей странице. Но код еще нужно пересматривать.
 Hidden text | Code: | Pragma AutorunBlockUnload
pShowWindow = DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandleA", "Str", "user32.dll", "Ptr"), "Str", "ShowWindow", "Ptr")
nSize = auX64 ? 12 : 8
gBuff = Buffer(nSize)
gBuff.Zero()
DllCall("RtlMoveMemory", "Ptr", gBuff.Ptr, "Ptr", pShowWindow, "Ptr", nSize)
MyDetour = Callback("DetouredShowWindow", "hwnd;int")
Patch = Buffer(nSize)
Patch.Zero()
Patch.SetNum(0, "UChar", 0x48, _
"UChar", 0xB8, _
"Ptr", MyDetour.Ptr, _
"UChar", 0xFF, _
"UChar", 0xE0)
OldProtect = 0
Func InstallHook()
DllCall("VirtualProtect", "Ptr", pShowWindow, "dword", nSize, "UInt", 0x40, "UInt*", @OldProtect)
DllCall("RtlMoveMemory", "Ptr", pShowWindow, "Ptr", Patch.Ptr, "Ptr", nSize)
DllCall("VirtualProtect", "Ptr", pShowWindow, "dword", nSize, "UInt", OldProtect, "UInt*", @OldProtect)
EndFunc
Func RemoveHook()
DllCall("VirtualProtect", "Ptr", pShowWindow, "dword", nSize, "UInt", 0x40, "UInt*", @OldProtect)
DllCall("RtlMoveMemory", "Ptr", pShowWindow, "Ptr", gBuff.Ptr, "Ptr", nSize)
DllCall("VirtualProtect", "Ptr", pShowWindow, "dword", nSize, "UInt", OldProtect, "UInt*", @OldProtect)
EndFunc
Func DetouredShowWindow(hWnd, nCmdShow)
forcedCmd = 0
DllCall("VirtualProtect", "Ptr", pShowWindow, "dword", nSize, "UInt", 0x40, "UInt*", @OldProtect)
DllCall("RtlMoveMemory", "Ptr", pShowWindow, "Ptr", gBuff.Ptr, "Ptr", nSize)
If WinGetClass(hwnd) = "TNASTYNAGSCREEN" Then nCmdShow = 0
result = DllCall("user32\ShowWindow", "Ptr", hWnd, "Int", nCmdShow)
# Возвращаем патч обратно
DllCall("RtlMoveMemory", "Ptr", pShowWindow, "Ptr", Patch.Ptr, "Ptr", nSize)
DllCall("VirtualProtect", "Ptr", pShowWindow, "dword", nSize, "UInt", OldProtect, "UInt*", @OldProtect)
return result
EndFunc
LoadLibrary Plugins\TCFS2Tools.dll
LoadLibrary Plugins\Autorun_Tweaks.dll
LoadLibrary Plugins\Autorun_Sysinfo.dll
LoadLibrary Plugins\Autorun_Runtime.dll
LoadLibrary Plugins\Autorun_Process.dll
LoadLibrary Plugins\Autorun_RegExp.dll
InstallHook()
NagScreen()
RemoveHook()
Pragma Include %COMMANDER_PATH%\Ini\Autorun\InfoHeader.aucfg
Pragma Include %COMMANDER_PATH%\Ini\Autorun\Test.aucfg
Pragma Include %COMMANDER_PATH%\Ini\Autorun\Functions.aucfg |
|
|