Программа, внедряющая библиотеку
Я тут подумал, как бы попроще внедрить свою библиотеку в адресное пространство чужого процесса. Использовать CreateRemoteThread? - её нет в Windows98. Предложенный Рихтером метод замены команд в точке входа - слишком сложен и неудобен. Проще выделить блок памяти в чужом адресном пространстве, скопировать туда вызов LoadLibrary, и манипулировать контекстом потока. Но выделить память - её нужно возвращать. А когда? - вот тут проблема. И тут меня осенило - а есть же стек! Там наверняка найдётся лишних байт 300 - имя библиотеки + вызов LoadLibrary. И мучиться с доступом не надо - стек доступен для чтения/выполнения/записи во всех версиях Windows. А прибить память можно add esp, xxx. Главное, чтобы kernel32.dll был спроецирован по одному и тому же адресу - но это соблюдается у всех процессов. Что ж, вот что у меня получилось. Программа внедряет библиотеку dll.dll (должна быть в той же папке) в программу, указанную пользователем.
.386
.model flat
include include\windows.inc
include include\kernel32.inc
include include\comdlg32.inc
.code
_start:
xor ebx,ebx ;В ebx будет 0
push offset written
push offset librname ;Сюда поместят полное имя
push 260
push offset dllname ;Короткое имя
call GetFullPathName ;Получаем полное имя внедряемой библиотеки
mov byte ptr filename, bl
push offset fop ;Пусть пользователь выберет
call GetOpenFileName ;что нужно запускать
test eax,eax ;Если не выбрал - выйдем
jz exit
mov eax, LoadLibrary ;Сохраним адрес LoadLibrary
mov loadlibraddr, eax ;в копируемом блоке
mov stinfo.cb, size stinfo
push offset procinfo
push offset stinfo
push ebx
push ebx
push CREATE_SUSPENDED ;Запускаем программу, выбранную
push ebx ;пользователем в
push ebx ;остановленном состоянии
push ebx
push offset filename
push ebx
call CreateProcess
or eax, eax ;Если не запускается -
jz exit ;- выйдем
mov ProcCont.ContextFlags, CONTEXT_CONTROL
push offset ProcCont ;Получим значения
push procinfo.hThread ;регистров остановленного
call GetThreadContext ;главного потока
mov eax, ProcCont.regEip ;Вот откуда мы будем продолжать
mov entry, eax ;после загрузки библиотеки
mov eax, ProcCont.regEsp ;Уменьшим стек потока на размер
sub eax, ProcSize-4 ;внедряемого кода
mov ProcCont.regEip, eax ;И установим eip на
sub eax, 4 ;эту область
mov ProcCont.regEsp, eax
push offset written
push ProcSize ;Записываем туда
push offset ProcToExec ;нашу небольшую
push eax ;программу
push procinfo.hProcess ;Она находится у
call WriteProcessMemory ;нас в данных
push procinfo.hProcess ;Описатель процесса
call CloseHandle ;больше не нужен
push offset ProcCont
push procinfo.hThread ;Записываем изменённые
call SetThreadContext ;регистры
push procinfo.hThread
call ResumeThread ;Запускаем поток!
push procinfo.hThread
call CloseHandle ;Закрываем описатель
exit: push eax
call ExitProcess ;Завершаем нашу программу
data segment 'DATA'
assume cs:data ;Нужно для кода в данных
filter db 'Программы',0,'*.exe',0,0 ;Фильтр для GetOpenFileName
dllname db 'dll.dll',0 ;Имя нашей библтотеки
align 4
fop OPENFILENAME <size fop,0,?,offset filter,0,0,0,offset filename,\
260,0,0,0,0,\
OFN_HIDEREADONLY or OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_EXPLORER,\
?,?,0,0,0,0>
;Далее идёт программка, выполняемая в чужом стеке
;Так как неизвестно, где она, нельзя пользоваться offset xxx
ProcToExec: ;esp при входе указывает сюда
entry dd 0
pushad ;а eip сюда
pushfd ;ОБЯЗАТЕЛЬНО всё сохраняем
call templab ;Эквивалентно mov eax,
templab: pop eax ;offset templab
add eax, (offset librname-offset templab)
push eax ;Имя нашей библиотеки
call dword ptr [eax-4] ;call LoadLibraryA
popfd ;Всё восстанавливаем
popad
ret 120h ;ret (ProcSize-4), я посмотрел из листинга
;Это ключевая команда. Она :
;а) переходит по адресу, указанному в entry
;б) очищает стек, занятый программой
align 4
loadlibraddr dd 0 ;Адрес LoadLibraryA
librname db 260 dup(?) ;Полное имя нашей библиотеки
ProcSize = $ - offset ProcToExec
.data?
stinfo STARTUPINFO <>
procinfo PROCESS_INFORMATION <>
ProcCont CONTEXT <> ;Контекст главного потока
written dd ? ;Временная переменная
filename db 260 dup(?) ;Имя запускаемой программы
end _start