Практика

Для примера сделаем программулину, которая автоматом убирает «Ярлык для» при создании ярлыка (да я знаю, что надоел со своими ярлыками :)). Чтобы попасть в адресное пространство explorer’a используем мой извращенный 🙂 метод инжектирования в процесс без использования библиотек. Его описание есть в ссылках. Тем не менее, код внедрения с того момента стал более компактным, логичным и грамотным. Теперь я сам делаю релокэйшены и к data’e можно обращаться напрямую. Также я правлю попорченную таблицу импорта => invoke работает, господа 😉 Код всего этого безобразия приводить здесь не буду (много места), но он будет в примерах к статье. Все остальное
прокомментировано и не должно вызывать проблем, тем не менее, если что-то непонятно – всегда обращайтесь ко мне на мыло.

; ## ANTI LNKS ###
;
Убирает "Ярлык для" при создании ярлыка explorer'ом. Пример к статье "Перехват вызовов СОМ методов"
;
Компилировать: вот фаил
MakeIt.bat:

;--------------------------------------- Start of MakeIt.bat ----------------------------------
comment ~
@echo off
echo Compiling resources
echo ###################
brcc32.exe res\1.rc

if exist 1.obj del 1.obj
if exist 1.exe del 1.exe
echo Compiling obj file
echo ################### 
c:\masm32\bin\ml /c /coff /nologo 1.asm
echo Compliling exe file
echo ################### 
c:\masm32\bin\Link /SUBSYSTEM:WINDOWS /MERGE:.rdata=.text /SECTION:.text,ERW /FIXED:NO 1.obj res\1.res

dir 1.*

pause
~
;---------------------------------------- End of MakeIt.bat -----------------------------------
; ### Directives ###
.386 
.model flat, stdcall 
option casemap :none 

; ### Includes and Libs ###
include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\ole32.inc

include CRT_API.asm ; Внедрение в чужой процесс
include comhooks.asm ;
Перехват сом методов
include shlobj.inc ;
Интерфейсы IShellLink, IPersistFile

includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\ole32.lib

; ### PROTOS ###
ThreadProc proto lpParameter: DWORD 

; ### CONSTS ###
IDD_DIALOG1 equ 101
MM_CLOSE equ WM_QUIT
MM_SET equ WM_USER+2
MM_LOAD equ WM_USER+3 

; ### DATA ###
.data 
szDisabled db "All lnks must be without 'Ярлык для' string ;)",0
szEnabled db "All lnks must be with 'Ярлык для' string",0
szCapt db "Antishit :)",0
szProgman db "Progman",0
hProgman dd 0
ThreadId dd 0
msg MSG <>
oldFunc dd 0
szBuf db 255 dup(0)
szBuf1 db 255 dup(0) 
wcFin dw 255 dup(0)

szTemp db "Ярлык для ",0
size_szTemp equ $-szTemp

CLSID_ShellLink GUID <0021401H, 0000H, 0000H, \
<0C0H, 00H, 00H, 00H, 00H, 00H, 00H, 046H>>
IID_IShellLink GUID <00214EEH, 0000H, 0000H, \ 
<0C0H, 00H, 00H, 00H, 00H, 00H, 00H, 046H>>
IID_IPersistFile GUID <000010BH, 0000H, 0000H, \ 
<0C0H, 00H, 00H, 00H, 00H, 00H, 00H, 046H>>

ppf dd 0
psl dd 0 

; ### CODE ###
.code 

; Функция, которая будет выполнятся вместо IShellLink.IPersistFile.Save
NIPersistFileSave proc a: DWORD, b: DWORD, cd: DWORD 
;
Переводим параметр в ANSII
invoke WideCharToMultiByte, CP_ACP, 0, b, -1, offset szBuf, 255, 0,0
;
Ищем есть ли слова "Ярлык для" в создаваемом
файле (если нет - в еах 0)

invoke InString, 1, offset szBuf, offset szTemp
;
Убираем Ярлык для, ...
lea ebx, szBuf
add ebx, eax
add ebx, size_szTemp-2 
;
копируя все, что до этих слов в буфер и...
invoke lstrcpyn, offset szBuf1, offset szBuf, eax
;
соединяя с тем, что после них.
invoke lstrcat, offset szBuf1, ebx
;
Переводим результат в UNICODE
invoke MultiByteToWideChar, CP_ACP, 0, offset szBuf1, -1, offset wcFin, 255
;
Снимаем на время хук
invoke TableCOMHook, ppf, IPersistFile.Save, oldFunc, 0
;
и вызываем IShellLink.IPersistFile.Save с нужными нам параметрами 😉
coinvoke a, IPersistFile, Save, offset wcFin, cd 
push eax 
;
Сново ставим хук.
invoke TableCOMHook, ppf, IPersistFile.Save, offset NIPersistFileSave, offset oldFunc 
pop eax
ret
NIPersistFileSave endp

DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.if uMsg==WM_CLOSE 
;
Уходя не забудем удалиться и из explorer'a
invoke PostThreadMessage, ThreadId, MM_CLOSE,0,0
invoke ExitProcess, 0
.elseif uMsg==WM_COMMAND
.if lParam!=0
mov edx,wParam 
mov ax, dx 
shr edx,16 
.if (dx==BN_CLICKED)&&(ax==IDOK)
;
Если юзер сказал не надо "Ярлык для" - так оно и будет 
invoke PostThreadMessage, ThreadId, MM_SET,0,0 
.elseif (dx==BN_CLICKED)&&(ax==IDCANCEL)
;
Если че - отменяем все 😉 
invoke PostThreadMessage, ThreadId, MM_LOAD,0,0
.endif
.endif
.else
mov eax, FALSE
ret
.endif
mov eax, TRUE
ret
DlgProc endp 

; Эта процедура будет выполняться в адресном пространстве explorer'a
ThreadProc proc lpParameter: DWORD 
;
Инициализируем СОМ
invoke CoInitialize, NULL
;
Создаем объект от интерфейса IShellLink (или получаем на него указатель, если он уже создан)
invoke CoCreateInstance, offset CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, offset IID_IShellLink, offset psl
;
Запрашиваем объект по образу и подобию IPersistFile
coinvoke psl, IShellLink, QueryInterface, offset IID_IPersistFile, offset ppf
;
Цикл обработки сообщений, посланных потоку
___loooop: 
invoke GetMessage, offset msg,0,0,0
;
Если пришло MM_CLOSE=WM_QUIT, уходим
test eax, eax
jz bye
invoke TranslateMessage, offset msg
invoke DispatchMessage, offset msg
.if (msg.message==MM_SET) 
;
Если основная прога сказала нам установить хук - так и будет 🙂
invoke TableCOMHook, ppf, IPersistFile.Save, offset NIPersistFileSave, offset oldFunc
invoke MessageBox,0,offset szDisabled,offset szCapt,MB_OK
.elseif (msg.message==MM_LOAD) 
;
Если же сказала восстановить все, чтобы как было - мы восстановим
invoke TableCOMHook, ppf, IPersistFile.Save, oldFunc, 0
invoke MessageBox,0,offset szEnabled,offset szCapt,MB_OK
.endif

jmp ___loooop
bye: 
;
Уходя всегда восстанавливаем 😉
invoke TableCOMHook, ppf, IPersistFile.Save, oldFunc, 0
;
Закрываем за собой дверь
coinvoke ppf, IPersistFile, Release
coinvoke psl, IShellLink, Release
invoke CoUninitialize 
;
Завершаем поток, выгружая так же себя из адресного пространства 
call GetCurrModBase
invoke FreeLibraryAndExitThread, eax, 0

ThreadProc endp

start:
;
Находим окно Progman, которое принадлежит explorer'у 
invoke FindWindow, offset szProgman,0
mov hProgman, eax 
;
Внедряемся в процесс
invoke ECreateRemoteThreadNt, eax, 0,offset ThreadProc, 0,0
.if eax>4 
;
Узнаем ThreadID вновь
созданного потока в explorer'e

assume eax: PTR CRT_RES
mov eax, [eax].ThreadID
mov ThreadId, eax 
;
Показываем пользователю диалог 
invoke GetModuleHandle, 0
invoke DialogBoxParam, eax, IDD_DIALOG1,NULL, offset DlgProc, 0
.endif 
;
Уходим 
invoke ExitProcess, 0
end start

Сслыки:
1) Сайт Ernest’а Murphy http://ourworld.compuserve.com/homepages/ernies_world/a.htm 
2) Эрик Хармон «Разработка COM-приложений в среде Delphi»
3) Нетривиальные возможности хуков (http://www.xakep.ru/post/20126/default.htm
и http://www.xakep.ru/post/20141/default.htm).

Исходники

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии