Ну хватит разглагольствовать, смотри MsgProc и ECreateRemoteThread:

ECreateRemoteThreadNt proc USES ebx ecx esi hWind: HANDLE, dwStackSize: DWORD, lpStartAddress: DWORD, dwCreationFlags: DWORD
local ThreadID : DWORD 
local HookH : HHOOK 
local hEvent : HANDLE 
local pLastBase : DWORD 
local margs : CREATE_THREAD_ARGS
local FM : HANDLE 
local MVF : DWORD
;
Заполняем структуру параметров CreateThread’у 
push dwStackSize
pop margs.dwStackSize
push lpStartAddress
pop margs.lpStartAddress
push dwCreationFlags
pop margs.dwCreationFlags
;
Создаем файл, проецируемый в память… 
invoke CreateFileMapping, INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof CREATE_THREAD_ARGS, SADD(«FM_CRT_HOOK»)
mov FM, eax 
.if FM==0
mov eax, -3 
ret
.endif
invoke MapViewOfFile, FM, FILE_MAP_WRITE, 0, 0, sizeof CREATE_THREAD_ARGS
mov MVF, eax
.if MVF==NULL 
invoke CloseHandle, FM
mov eax, -4 
ret
.endif 
;
Передаем параметры 
invoke MemCopy, addr margs, MVF, sizeof CREATE_THREAD_ARGS 
;
Узнаем поток, в который будем внедряться 
invoke GetWindowThreadProcessId, hWind, NULL 
mov ThreadID, eax 
.if ThreadID==NULL 
invoke CloseHandle, FM
mov eax, -1
ret 
.endif 
invoke GetModuleHandle, NULL
mov pLastBase, eax 
;
Для синхронизации, чтобы не выгрузиться раньше выполнения LoadLibrary в ловушке…
invoke CreateEvent, NULL, FALSE, FALSE, SADD(«EVENT_CRT_HOOK»)
mov hEvent, eax 
;
Ставим локальный хук… Параметр, в котором должен быть базовый адрес библиотеки
invoke SetWindowsHookEx, WH_GETMESSAGE, addr MsgProc, pLastBase, ThreadID
mov HookH, eax 
.if HookH==NULL 
invoke CloseHandle, FM
mov eax, -2
ret
.endif 
;
Отсылаем сообщение, чтобы вызвалась MsgProc 
invoke PostMessage, hWind, WM_USER+50, lpStartAddress, pLastBase
;
Ждем пока не выполниться LoadLibrary 
invoke WaitForSingleObject, hEvent, INFINITE
invoke UnhookWindowsHookEx, HookH 
;
Узнаем результат из того же MMF’a 
mov eax,[MVF]
dodata <CRT_RES !<!>>
mov esi, ecx
invoke MemCopy, eax, esi, sizeof CRT_RES 
mov eax, esi
push eax 
;
Закрываем за собой дверь
invoke UnmapViewOfFile, MVF
invoke CloseHandle, FM 
invoke CloseHandle, hEvent 
pop eax
ret
ECreateRemoteThreadNt endp 


Теперь MsgProc:

MsgProc proc STDCALL USES ebx esi edi ecx code: DWORD, wparam: WPARAM, lparam: LPARAM 
local LL : DWORD
local szModName: DWORD
local CT : DWORD
local FM : HANDLE
local lpThreadID : DWORD 
local hEvent : HANDLE
local lpvar : DWORD
.if code==HC_ACTION 
assume edi: PTR MSG 
mov edi, lparam
.if [edi].message==WM_USER+50 
;
Увеличиваем счетчик блокировок нашего модуля, дабы не произошло AV
;
Находим LoadLibrary… 
dodata <db «LoadLibraryA»,0>
push ecx
dodata <db «kernel32.dll»,0>
push ecx 
call EGetProcAddress 
mov LL, eax 

; Находим GetModuleFileName 
dodata <db «GetModuleFileNameA»,0>
push ecx
dodata <db «kernel32.dll»,0>
push ecx
call EGetProcAddress
mov esi, eax

; Вызываем GetModuleFileName
push 126
dodata <db 126 dup(0)>
mov szModName, ecx
push ecx
call GetCurrModBase 
push eax
call esi 

; Вызываем LoadLibrary на наш модуль… 
push szModName
call LL 

; Для синхронизации
;
Находим OpenEvent 
dodata <db «OpenEventA»,0> 
push ecx
dodata <db «kernel32.dll»,0>
push ecx
call EGetProcAddress 

; Вызываем OpenEvent 
dodata <db «EVENT_CRT_HOOK»,0>
push ecx
push TRUE
push EVENT_ALL_ACCESS
call eax 
mov hEvent, eax

; Create’им thread 😉
;
Находим CreateThread
dodata <db «CreateThread»,0>
push ecx
dodata <db «kernel32.dll»,0>
push ecx 
call EGetProcAddress 
mov CT, eax 

; Получаем параметры 
;
Находим OpenFileMapping
dodata <db «OpenFileMappingA»,0>
push ecx
dodata <db «kernel32.dll»,0>
push ecx
call EGetProcAddress

; Вызываем OpenFileMapping
dodata <db «FM_CRT_HOOK»,0>
push ecx
push FALSE
push FILE_MAP_WRITE 
call eax 
cmp eax, 0
jz exit
mov ebx, eax

; Находим MapViewOfFile
dodata <db «MapViewOfFile»,0>
push ecx
dodata <db «kernel32.dll»,0>
push ecx
call EGetProcAddress 

; Вызываем MapViewOfFile 
push sizeof CREATE_THREAD_ARGS
push 0
push 0 
push FILE_MAP_WRITE
push ebx
call eax 
cmp eax, 0
jz exit 
mov esi, eax 

assume esi: PTR CREATE_THREAD_ARGS 
;
Вызываем CreateThread 
lea eax, lpThreadID 
push eax 
push [esi].dwCreationFlags 
push NULL
;
Узнаем смещение ThreadProc’a
;
Вычитаем из старого адреса старую базу 
mov ebx, [edi].wParam
sub ebx, [edi].lParam 
;
Теперь вычисляем новый адрес 
call GetCurrModBase
add ebx, eax 
push ebx 
push [esi].dwStackSize
push NULL 
call CT 
;
Возвращаем результат
assume esi: PTR CRT_RES
push lpThreadID 
pop [esi].ThreadID
push eax
pop [esi].hThread
call GetCurrModBase
push eax
pop [esi].hModule 
; Находим SetEvent
dodata <db «SetEvent»,0> 
push ecx
dodata <db «kernel32.dll»,0> 
push ecx 
call EGetProcAddress 

; Вызываем SetEvent, чтобы продолжить основную прогу… 
push hEvent
call eax

.endif 
.endif 
exit:
ret
MsgProc endp 

Для удобства я объявил пару структур:

CREATE_THREAD_ARGS struct ; Параметры; смысл и название идентичны параметрам CT
dwStackSize dd 0
lpStartAddress dd 0
dwCreationFlags dd 0
CREATE_THREAD_ARGS ends

CRT_RES struct ; Результат, возвращаемый ECreateRemoteThread

hModule dd 0 ; база нашего модуля в чужом адресном пространстве
ThreadID dd 0 ; Индификатор нового потока
hThread dd 0 ; Хэндл нового потока
CRT_RES ends


Практика.

Что я сделал в качестве примера использования EcreateRemoteThread()??? Банальный
MessageBoxA. Но так как сообщение заставляет прогу «застыть», то мы можем протестировать – не происходит ли досрочная выгрузка нашего модуля. Если происходит, то возврат из MBA будет указывать
в никуда, появиться Access Violation. Это ты сможешь пронаблюдать, если уберешь из MsgProc’a LoadLibraryA. Рассмотрим текст главного модуля примера, который я написал. Тут все просто:

;— Start of MakeIt.bat —
; @echo off
;
; if exist 1.obj del 1.obj
; if exist 1.exe del 1.exe
;
; c:\masm32\bin\ml /c /coff /nologo 1.asm
; c:\masm32\bin\Link /SUBSYSTEM:WINDOWS /FIXED:NO /MERGE:.rdata=.text /SECTION:.text,ERW 
; 1.obj
;
; dir 1.*
;
; pause
;— End of MakeIt.bat —

.386 
.model flat, stdcall 
option casemap :none 

include c:\masm32\include\windows.inc ; Куча структур и еще много разной полезной хрени
include c:\masm32\include\user32.inc ;
Разные MessageBox()’ов и SetWindowsHookEx()’ов
include c:\masm32\include\kernel32.inc ;
ExitProcess, GetModuleHandle и т.д.
include c:\masm32\macros\macros.asm ;
Макросы 
include ..\include\API_Emul.asm ;
Эмуляция апи функций+пару макросов by me 😉
include ..\include\CRT_API.asm ;
CreateRemoteThread() by me 😉


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

.code 
ThreadProc proc 
;
Находим MessageBox 
dodata <db «MessageBoxA»,0>
push ecx
dodata <db «user32.dll»,0>
push ecx
call EGetProcAddress

; Показываем MB
push MB_OK
dodata <db «GOTCHA!!!»,0>
push ecx 
push ecx
push 0
call eax 

; Завершаем поток
dodata <db «ExitThread»,0>
push ecx
dodata <db «kernel32.dll»,0>
push ecx
call EGetProcAddress

push 0
call eax 
ret 
ThreadProc endp 

start: 
main proc 
invoke FindWindow, NULL, SADD(«Калькулятор»)
;
Идентификатор окна в первом параметре
;
Второй параметр — размер стэка нового потока , делаем его дефолтным
(1Мб)

;
Третий – Точка входа потока в ГЛАВНОМ модуле.
;
Для примера возьмем его suspend’нутым
(4ый параметр)

invoke ECreateRemoteThreadNt, eax, 0,ThreadProc,CREATE_SUSPENDED 
;
Результат в виде структуры CRT_RES
assume eax: PTR CRT_RES
.if (eax>0) && ([eax].hThread!=NULL) 
;
В CRT_RES уже есть hThread, но он не имеет прав на приостановку/восстановление
invoke OpenThread, THREAD_SUSPEND_RESUME, FALSE, [eax].ThreadID 
;
Запускаем поток
invoke ResumeThread, eax 
.endif 
invoke ExitProcess, 0 
ret 
main endp 
end start

Ну вот, тут все прокомментировано и должно быть понятно.

Если ты думаешь, что это все, что может этот подход к хукам, ты ошибаешься… Можно делать поистине удивительные вещи с этой фишкой! Мы с ZeroIce’ом пораскинули мозгами и пришли к выводу, что довольно легко можно сделать свой код ВООБЩЕ невидимым… То бишь ни в списке процессов, ни в списке потоков, ни в списке модулей, он светиться не будет! Как это сделать? Просто! Все по старой схеме, только вместо создания потока и увеличения счетчика модуля делаем VirtualAlloc и копируем в зарезервированную область нужный код! А потом передаем
туда управление. А если сделать его еще и полиморфиком ;). Только тут, конечно, есть недостаток. Поток, в который мы внедрились, приостановиться на время выполнения нашего внедренного кода, но ведь можно и сделать
так, чтобы эта фишка происходила по определенному событию… Например, реализовать перехват АПИ через изменение таблицы импорта, а наш код будет покоиться, пока не произойдет вызов перехватываемой АПИ ;). Реализацию этого фишкаря оставлю тебе… В то же время в папке 9х ты найдешь пример резервирования памяти в чужом процессе и копирования
туда кода, установление атрибута исполнения и т.д.
Но передача туда управления не произойдет! У нас другая тема, реализация перехвата АПИ – тоже избитая тема, ссылка в конце статьи+читай у Рихтера…


Инструменты

Для тестирования кода на платформе 9х использовался MS Windows ME+OllyDbg v1.09d
Для тестирования кода на платформе NT использовался MS Windows XP Professional(build 2600 без sp)+SoftIce
В качестве компилятора везде выступал masm32v8.0 by Hutch

 

Ссылки
1) Где купить Рихтера? Например http://www.books.ru/shop/books/8283
или http://www.books-shop.com/book89.html
или  http://www.mistral.ru/content/38168.shtml
(А ты че думал??? Электронный вариант? Черта с
два… Не для этого Рихтер работал, чтобы ты
на халяву его талмуд скатал)
2) masm32 by Hutch http://www.movsd.com/masmdl.htm
3) Описание таблицы экспорта http://www.wasm.ru/article.php?article=1002007
4) Эмуляция GetProcAddress’a http://www.wasm.ru/article.php?article=searchapi
5) Нахождение базы kernel’a http://sbvc.host.sk/articles/9.html

Greetzzzzz

Спасибо Four-F’у, который додумался, что все
это работает только из-за релоков. Если бы
не он, я бы, наверное, до сих пор делал бы /DEBUG
:).

Спасибо ZeroIce’у, который часто указывал
мне на баги и ошибки в моих примерах.

Исходники

Оставить мнение

Check Also

Windows 10 против шифровальщиков. Как устроена защита в обновленной Windows 10

Этой осенью Windows 10 обновилась до версии 1709 с кодовым названием Fall Creators Update …