Ну хватит разглагольствовать, смотри 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

DDoS на Bluetooth. Разбираем трюк, который поможет отключить чужую колонку

На свете существует не так много вещей, которые бесят практически всех без исключения. Это…

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