Ну хватит разглагольствовать, смотри 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’у, который часто указывал
мне на баги и ошибки в моих примерах.

Исходники

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

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

    Подписаться

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