у меня такая идея: цепляться к какой-нить часто-вызываемой API функции целевого процесса, сплайсингом делать трамплин на код (который вызовет необходимую функцию, уберет трамплин с начала API функции, и вызовет оригинал)... таким образом алгоритм сводится к следующему: - найти адрес часто-вызываемой API функции в контексте целевого процесса - сохранить первые 5 байт часто-вызываемой API функции в памяти целевого процесса - динамически сформировать внедряемый код - записать внедряемый код в целевой процесс - приостановить процесс, записать трамплин в начало API функции, возобновить процесс все нормально работает, кроме двух вещей))) 1) как найти адрес ну допустим GetMessage в чужом процессе... можно канеш записать в чужой процесс GetProcAddress и ExitThread, затем выполнить их CreateRemoteThread'ом, но это - возвращение к тому, от чего я пытаюсь уйти... 2) я довольно сильно туповат в ассемблере, поэтому не могу нормально сформировать код (который вызовет необходимую функцию, уберет трамплин с начала API функции, и вызовет оригинал)... сейчас я делаю так: Код (Text): // В заголовке файла // Опкоды некоторых команд ассемблера #define ASM_PUSH 0x68 #define ASM_CALL 0x15FF #define ASM_RET 0xC3 // Структура для формирования кода typedef struct _INJECTOR_RUNFUNCEX { BYTE PushFuncCom; // Команда - push (записать в стек адрес параметра) DWORD PushFuncArg; // Параметр - адрес параметров функции WORD CallFuncCom; // Команда - call (выполнить функцию с таким параметром) DWORD CallFuncArg; // Параметр - адрес функции // ВСТАВИТЬ ВОССТАНОВЛЕНИЕ ПЕРВЫХ 5 БАЙТ ОРИГИНАЛЬНОЙ ФУНКЦИИ WORD CallOrigCom; // Команда - call (выполнить оригинальную функцию) DWORD CallOrigArg; // Параметр - адрес функции } INJECTOR_RUNFUNCEX, *PINJECTOR_RUNFUNCEX; // И уже в функции // Формируем внедряемый код INJECTOR_RUNFUNCEX InjData; InjData.PushFuncCom = ASM_PUSH; InjData.PushFuncArg = (DWORD)paramadr; InjData.CallFuncCom = ASM_CALL; InjData.CallFuncArg = (DWORD)funcadr; InjData.CallOrigCom = ASM_CALL; InjData.CallFuncArg = (DWORD)target_adr; // Записываем внедряемый код PVOID my_adr = InjectMemoryEx(hProc, &InjData, sizeof(INJECTOR_RUNFUNCEX)); if(my_adr == NULL) { return false; } // Если не удалось внедрить код то есть к моему стыду я не знаю, как правильно (грамотно) восстановить эти первые 5 байт... всем заранее спасибо за ответы! ЗЫ просьба ногами не пинать)) ЗЗЫ мне хотелось бы реализовать именно этот метод (делаю я это исключительно в самообразовательных целях), про всякие там GetThreadContext/SetThreadContext и другие альтернативы я в курсе...
Сохраняй их в шелл-коде, а писать просто (mov byte ptr[address],[byte]), ты же уже в контексте целевого процесса. На сях можно так: *(BYTE*)[указатель]=[byte], ну или массив байтеков создавай.
есть идея по поводу поиска адреса функции... загрузить нужную DLL себе, получить адрес функции у себя... вычесть из адреса функции адрес загрузки DLL, получить смещение... в чужом процессе уже оперировать со смещением относительно начала загрузки DLL... но возникает вопрос: как получить адрес загрузки DLL в чужом процессе... это видимо надо в заголовке секции экспорта копаться?
блин... это канеш отличная идея, но тк я не силен в ассемблере, шелл-коды остаются для меня загадочным понятием... то есть, я делаю так? Код (Text): BYTE Mov1Com = 0x"шелл-код команды mov" // Не подскажешь код этой команды DWORD Mov1Arg1 = &target_adr[0]; // target_adr[0] - адрес 1ого байта API функции BYTE Mov1Arg2 = byte5[0]; // Сохраненный первый байт и так для каждого из 5 байт? а не возникнет ли проблем с защитой страницы? всмыле не надо ли вызывать VirtualProtectEx перед записью?
Надо. Шеллкод должен сам находить нужные ему апи-функции. Стандартный способ - получение из PEB'а адресов загрузки ntdll и kernel32. Дальше уже используешь LoadLibrary и GetPrcoAddress(или свой аналог с парсером экспорта).
Rel [0x7FFE0304] Crc32 o Peb.Ldr:PPEB_LDR_DATA o MemoryMappedFilenameInformation Перемап кодовой секции.
Rel В своем процессе просто GetModuleHandle, т.к. хэндл модуля это и есть его базовый адрес. В чужом можно через toolhelp CreateToolhelp32Snapshot + Module32First\Next или psapi EnumProcessModules + GetModuleBaseName (+ GetModuleInformation до кучи) Причем если речь идет о user32.dll, то 1) скорее всего она грузится во все процессы по одному адресу, 2) по крайней мере в XP для всех популярных функций предусмотрен hot-patch, т.е. функция начинается с двухбайтового нопа mov edi,edi (для замены на короткий джамп), перед которым зарезервированы 5 нопов 90h для замены на длинный джамп. Это позволяет не сохранять и не восстанавливать исходные байты функции - просто делаешь двойной джамп на свою функ-у, которая делает свое "грязное дело" и передает управление на адрес исходной функ-и + 2 байта
leo На сколько помню слепки исполняются посредством RtlQueryProcessDebugInformation(), этот функционал использует удалённые потоки. Гарантировано. Ядро использует глобальные ссылки в этот модуль.
Clerk Утверждение кажется очень логичным, однако, например, в висте64 user32.dll может быть промаплена и по другому адресу (в отличие от ntdll.dll и kernel32.dll): Код (Text): >frilocs64.exe user32.dll WinVer: 6.0.6001 sp1, SuiteMask: 274, x64 process: 1, wow64: 0 Using base of [user32.dll] library as default ImageBase Default ImageBase for test: 0000000077A60000 Current process: Fixups applied: 1 ImageBase (default): 0000000140000000 ImageBase (actual): 000000013F190000 ------------------------------------------------------------------------------- CASE 0: IMAGE_FILE_RELOCS_STRIPPED = 0 Base Relocations Directory ZEROED = 0 ------------------------------------------------------------------------------- Trying to create a child process... SUCCESS Listing currently mapped views: 0000000076F10000: 1\Users\John\AppData\Local\Temp\1\vuvetcwhrahsuhxb.exe 0000000077C60000: 1\Windows\System32\ntdll.dll Total mapped views: 2 Listing mapped views again: 0000000076F10000: 1\Users\John\AppData\Local\Temp\1\vuvetcwhrahsuhxb.exe 0000000077A60000: 1\Windows\System32\user32.dll 0000000077B30000: 1\Windows\System32\kernel32.dll 0000000077C60000: 1\Windows\System32\ntdll.dll ... Child process exit status: 0x00000000 Child process: Fixups applied: 1 ImageBase (default): 0000000077A60000 ImageBase (actual): 0000000076F10000 ------------------------------------------------------------------------------- CASE 1: IMAGE_FILE_RELOCS_STRIPPED = 0 Base Relocations Directory ZEROED = 1 ------------------------------------------------------------------------------- Trying to create a child process... SUCCESS Listing currently mapped views: 0000000077520000: 1\Users\John\AppData\Local\Temp\1\hcsgwadetehsdxtq.exe 0000000077C60000: 1\Windows\System32\ntdll.dll Total mapped views: 2 Listing mapped views again: 0000000077520000: 1\Users\John\AppData\Local\Temp\1\hcsgwadetehsdxtq.exe 0000000077A60000: 1\Windows\System32\user32.dll 0000000077B30000: 1\Windows\System32\kernel32.dll 0000000077C60000: 1\Windows\System32\ntdll.dll ... Child process exit status: 0x00000000 Child process: Fixups applied: 0 ImageBase (default): 0000000077A60000 ImageBase (actual): 0000000077520000 ------------------------------------------------------------------------------- CASE 2: IMAGE_FILE_RELOCS_STRIPPED = 1 Base Relocations Directory ZEROED = 0 ------------------------------------------------------------------------------- Trying to create a child process... SUCCESS Listing currently mapped views: 0000000077A60000: 1\Users\John\AppData\Local\Temp\1\xbqqabexaqhudcxg.exe 0000000077C60000: 1\Windows\System32\ntdll.dll Total mapped views: 2 Listing mapped views again: 0000000000140000: 1\Windows\System32\user32.dll 0000000077A60000: 1\Users\John\AppData\Local\Temp\1\xbqqabexaqhudcxg.exe 0000000077B30000: 1\Windows\System32\kernel32.dll 0000000077C60000: 1\Windows\System32\ntdll.dll ... Child process exit status: 0x00000000 Child process: Fixups applied: 0 ImageBase (default): 0000000077A60000 ImageBase (actual): 0000000077A60000 ------------------------------------------------------------------------------- CASE 3: IMAGE_FILE_RELOCS_STRIPPED = 1 Base Relocations Directory ZEROED = 1 ------------------------------------------------------------------------------- Trying to create a child process... SUCCESS Listing currently mapped views: 0000000077A60000: 1\Users\John\AppData\Local\Temp\1\qavcbsebetwwceed.exe 0000000077C60000: 1\Windows\System32\ntdll.dll Total mapped views: 2 Listing mapped views again: 0000000000680000: 1\Windows\System32\user32.dll 0000000077A60000: 1\Users\John\AppData\Local\Temp\1\qavcbsebetwwceed.exe 0000000077B30000: 1\Windows\System32\kernel32.dll 0000000077C60000: 1\Windows\System32\ntdll.dll ... Child process exit status: 0x00000000 Child process: Fixups applied: 0 ImageBase (default): 0000000077A60000 ImageBase (actual): 0000000077A60000 (Один должен обращать внимание на два последних кейса). Конечно, если есть гарантия, что к моменту вызова ZwMapViewOfSection регион для отображения нужной длл свободен, то вполне можно посчитать, что длл промапится по тому же адресу, что и в другом процессе – ядро старается отображать такие регионы по одному и тому же адресу на время жизни секции (из-за неких сортов оптимизации?). Rel Можешь также взглянуть на пример того, как ^листать виды^. Там пара строчек всего.
спасибо большое а ответы! сейчас проблема больше в формировании внедряемого кода... сплайсинг проходит без проблем, поиск импортированной функции в другом процессе тоже (копаюсь в PE заголовке)... но код никак не хочет выполняться... пробывал так: 1) просто "байпасить функцию": Код (Text): ret работает... 2) выполнить другую функцию, вместо этой Код (Text): call funcadr ret вылезает косяк "эксесвайолейтинг" на чтение... по всей видимости закрадывается в стек какой-то косяк, в результате которого он пытается вернуть управление не туда... и я не могу понять почему... обе функции (и подменяемая и та, на которую подменяю: void и без параметров), вроде никаких изменений в стеке для вызова функции-подменки я производить не должен, но почему же тогда проблема в стеке возникает... загадка)))
Интересно, что скрывается за "call funcadr" ? Не забывай, что call м.б. либо относительным (E8) - тогда funcadr д.б. = смещению вызываемой функции относительно команды следующей за call. Либо прямым косвенным (FF 15) - тогда funcadr д.б. = адресу дворда, в котором записан адрес вызываемой функции. А ты небось напрямую адрес своей функции подставляешь
да... я именно так и делаю))) ну во всяком случае с кодом я угадал))) (FF 15) завтра попробую, это я чет в справочнике не доглядел(((( спасибо!
ну все работает теперь)) правда ещё пришлось саму структуры взять в Код (Text): #pragma pack(push, 1) . . . #pragma pack(pop) так и не понял зачем и почему, но работает))) господа, а как мне правильно составить восстановление пяти первых байт? можно сделать так: Код (Text): mov <адрес начала функции>, <сохраненный байт1> mov <адрес начала функции + 1>, <сохраненный байт2> mov <адрес начала функции + 2>, <сохраненный байт3> mov <адрес начала функции + 3>, <сохраненный байт4> mov <адрес начала функции + 4>, <сохраненный байт5> или делать 1 mov с dword'ами и 1 mov с байтом... может есть лучше вариант?... но я чет никак не могу подобрать нужный опкод команды mov для этого... подскажите пожалуйста))) Virtual Protect'ом решил в своем процессе права на 5 байт не восстанавливать, чтобы во внедряемом коде два раза не вызывать эту функцию... то есть старые права на страницу будет восстанавливать именно внедренный код...
да... movsb - это канеш хорошо... но как мне записать в кодах вот это: Код (Text): mov ecx, 05h mov esi, offset adr1 mov edi, offset adr2 rep movsb пытался накопать коды в справочниках, но чет не могу понять это((( http://faydoc.tripod.com/cpu/rep.htm допустим по данным этого справочника, чтобы выполнить rep movsb мне надо в структуру записать Код (Text): BYTE rep = 0xF3; BYTE movsb = 0xA4 это верно?)) http://faydoc.tripod.com/cpu/mov.htm а как быть с командами mov, заполняющими регистры?
Ну е мае возьми ассемблер, скомпилируй свой шеллкод и посмотри что получится. Спрашивать тут опкоды каждой инструкции - это уже борщ (с фасолью).