SZ Я же написал как, скопировать. Суть снова вызвать оригинальную функцию передав ей параметры переданные в перехваченную, классический wrapper. Шаманства с продвинутыми техниками конечно хорошо, но не стоит с ними перебарщивать, что можно сделать просто, лучше и делать просто.
ТЛС, имхо не сильно поможет, т.к. для рекурсивно вызываемых ф-ий всё равно придётся делать список. По мне так легче всего поступить так: Имеем функцию funk и адрес возврата из неё addr_ret в начало ф-ии вставляем стаб push addr1 ret По addr1 находится код, который меняет адрес возврата из funk на addr2 и генерирует код по этому адресу следующего вида: push addr_ret call SomeFunk ; это и есть наша ф-ия перехватчик add3: В итоге имеем: при выходе из funk управление попадёт на addr2, а потом на SomeFunk, которой передан в качестве параметра адрес возврата addr_ret, на который следует подменить addr3, который лежит в стеке. Не забываем освободить память, которая занимается сгенерированным стабом.
Нашёл семпл с манипуляцией i31: http://files.virustech.org/indy/Code/NtIcp/ Старший бит ссылки взводится: Код (Text): bts LDR_DATA_TABLE_ENTRY.EntryPoint[eax],31 ; +0x80000000 Обрабатывается #AV, старший бит сбрасывается в контексте: Код (Text): btr [edi].regEip,31 Но там довольно сложный код.
Clerk Спасибо, пробовал ваш метод с таблицей ссылок, работает. Правда, приходится маяться с тем, чтобы не повредить регистры. Сейчас возникла другая проблема. Задача - в одной из развилок сделать так, чтобы при выборе одного условия в определенную переменную писалось 0, при выборе другого - 1. Вроде бы простая задача, но выполнить ее без вылета не получается. Вот начало функции, в которой осуществляется перехват, в 49D5FA нужно присвоить 0, в 49D614 1: Код (Text): _text:0049D540 ; void __cdecl UI_SaberDrawBlade(int, int, int, int) _text:0049D540 UI_SaberDrawBlade proc near ; CODE XREF: sub_0_49E1B0+140p _text:0049D540 _text:0049D540 ;Описание переменных var_XX _text:0049D540 _text:0049D540 sub esp, 0BCh _text:0049D546 push ebx _text:0049D547 mov ebx, eax _text:0049D549 xor eax, eax _text:0049D54B push ebp _text:0049D54C push esi _text:0049D54D mov [esp+0C8h+var_84], eax _text:0049D551 mov esi, edx _text:0049D553 mov [esp+0C8h+var_80], eax _text:0049D557 mov eax, [esi+108h] _text:0049D55D test al, 0Ch _text:0049D55F push edi _text:0049D560 mov edi, ecx _text:0049D562 mov [esp+0CCh+var_88], 0 _text:0049D56A jz short loc_0_49D57D ;Здесь был код, не относящийся к делу _text:0049D5DD loc_0_49D5DD: ; CODE XREF: UI_SaberDrawBlade+6Cj _text:0049D5DD ; UI_SaberDrawBlade+83j _text:0049D5DD mov eax, [esp+0D4h+var_4] _text:0049D5E4 cmp eax, edx _text:0049D5E6 jge loc_0_49E07D _text:0049D5EC test byte ptr [esi+108h], 4 _text:0049D5F3 jz short loc_0_49D614 _text:0049D5F5 cmp eax, 2 _text:0049D5F8 jge short loc_0_49D614 _text:0049D5FA ;Здесь нужно присвоить переменную 0 _text:0049D5FA mov edx, dword_0_F871DC _text:0049D600 push 40h _text:0049D602 lea ecx, [esp+0D8h+var_48] _text:0049D609 push ecx _text:0049D60A push offset aUi_saber_color ; "ui_saber_color" _text:0049D60F call dword ptr [edx+34h] _text:0049D612 jmp short loc_0_49D62C _text:0049D614 ; --------------------------------------------------------------------------- _text:0049D614 _text:0049D614 ;Здесь нужно присвоить переменную 1 _text:0049D614 loc_0_49D614: ; CODE XREF: UI_SaberDrawBlade+B3j _text:0049D614 ; UI_SaberDrawBlade+B8j _text:0049D614 mov ecx, dword_0_F871DC _text:0049D61A push 40h _text:0049D61C lea eax, [esp+0D8h+var_48] _text:0049D623 push eax _text:0049D624 push offset aUi_saber2_color ; "ui_saber2_color" _text:0049D629 call dword ptr [ecx+34h] _text:0049D62C _text:0049D62C loc_0_49D62C: ; CODE XREF: UI_SaberDrawBlade+D2j Как мне это сделать?
Zlyden Про какую переменную вы говорите ? 0xF871DC это не переменная, а ссылка на массив методов(ссылок на процедуры). Можно поправить смещение в ветвлении на +4 байта, или поправить адрес массива на +4 байта(_text:0049D614: mov ecx,0xF871DC + 4).
Clerk 0xF871DC не причем, переменная моя собственная, в коде программы ее нет. Т.е. моя функция, вызываемая позже, должна знать, что произошло в этом ветвлении, и для этого я выделил глобальную переменную, в которую записывается 0 или 1.
Zlyden Ну у меня есть некоторые способности, но не на столько обширные чтобы читать ваши мысли.. Описывайте подробно задачу.
Программа запускается и патчится в памяти. Пишу на С++, в винде. Функцию, вызываемую из UI_SaberDrawBlade, я полностью заменил, но для работе новой функции нужны некоторые данные, а именно - номер прорисовываемого лезвия (0 либо 1). Этот номер определяется в развилке, начинающейся по адресу 0049D5EC. Правда, результат функция нигде не сохраняет, а лишь берет соответствующие номеру данные. Последний метод, который я попробовал - записывать переход в начало блоков инструкций, соответствующих своей ветке. Т.е., по адресу 0049D5FA начинается блок инструкций, соответствующий варианту 0, а в блоке 0049D614 - вариант для 1. Я попробовал сделать так - размер первой инструкции у обоих блоков (mov edx, dword_0_F871DC для 0 и mov ecx, dword_0_F871DC для 1) равен 6 байтам, т.е. равен размеру инструкции call (far). Поэтому я записал вместо первых инструкций call на мои функции, в которых я сохранял номер лезвия, затем повторял стертую инструкцию и retn. Т.е. Выглядело для 0 это так: Код (Text): _text:0049D5FA call my_function ; раньше была mov edx, dword_0_F871DC _text:0049D600 push 40h Код (Text): my_function: xor eax, eax mov uisnum, eax mov edx, ds:0F871DCh retn Вроде бы простой способ, ошибиться невозможно, но мне удалось - вызов UI_SaberDrawBlade вызывает вылет программы.
Zlyden Замените метод в таблице 0xF871DC[0x34], две части кода 0x49D5FA и 0x49D614 одинаковы. Затем в хэндлере определяйте откуда был произведён вызов по адресу возврата, либо по контексту.
sizeof.'mov edx, ds:0F871DCh' == 6 байт, sizeof.'call my_function' == 5 байт. Байт после инструкции 'call my_function' заменен на nop или оставлен как есть? Если оставлен, то надо заменить. И что показывает отладчик?
Mika0x65 Я использую call_far (0x15ff), она длиннее на один байт. Плюс раньше я использовал два push/ret для перехода на мой код и обратно, все равно программа вылетала Если бы он у меня был... Пробовал я ставить SoftIce, 4.2.7 и 4.0.5, патчил и так и сяк - ошибка 31. Попробую попозже за WinDBG взяться. Clerk Спасибо, попробую.
Zlyden А по адресу, куда ссылается call far [0xXXXXXXXX] лежит корректный селектор:смещение? Без переходов между кольцами защиты? И селектор должен следовать за смещением, а не наоборот. И почему WinDbg? Это драйвер? Если это приложение из третьего кольца, можно использовать OllyDbg.
Mika0x65 Спасибо! Оказалось, некорректный. Глупая ошибка, забыл инициализировать байт. Исправил, все заработало
Есть вопрос. Я сделал успешный перехват данных из DLL на Windows, теперь необходимо перехватывать те же данные из Shared Library на Linux. Для DLL я нашел адреса при помощи IDA и работал по ним, но вряд ли в линуксе так же, с их PIC. Хотя бы потому, что необходимо найти, где в памяти Shared Library теперь будет располагаться. Перехватываемая Shared Library и моя висят в памяти одного процесса. Мне нужно вызвать из этой Shared Library несколько функций и заменить значения нескольких переменных.
У меня вопрос, а возможно ли изменить атрибуты какого то куска в секции кода так VirtualProtect(addr,1,PAGE_READONLY,&old) или VirtualProtect(addr,1,PAGE_NOACCESS,&old) вообщем смысл, чтобы убрать у этого куска права выполнения для генерации исключения когда eip будет указывать на этот адрес, с последующим перехватом в своем обработчике. как ни пытался сделать, получаю 0xc0000005 при вызове VirtualProtect. upd кажется понял вызов VirtualProtect срабатывает, но он устанавливает права для всей страницы, а не конкретно по нужному адресу. то есть кроме хардварных бряков, трюков с перехватом, без модификации кода нету upd2 разве что копировать всю страницу и фиксить в коде относительные адреса, и перенаправлять на нее управление из обработчика исключений
Всем доброго времени суток. Возможно ли, только с помощью правки секции импорта в exe-файле - подгрузить свою DLL и затем вызвать из нее сво(ю)(и) функц(ию)(ии) ? У меня ответ на этот вопрос примерно следующий: если функций в секции импорта немного, то можно, а если много, то можно, но это будет долго, нудно и "овчинка выделки не стоит" и нужно применять какой-нибудь более быстрый вариант. А то может я где-то "недогоняю" и сделать такое в любом случае несложно и недолго? Интересует именно грамотный вариант, а не просто патч IAT, от которого у кого-то этот exe-файл запустится, а у кого-то нет.
f13nd, слишком лаконично, и как следствие - я не понял)) Идея такая пришла после прочтения статьи @Thetrik'а.
GRAFik, Сам то понял что спросил? > если функций в секции импорта немного, то можно, а если много, то можно, но это будет долго Опиаты походу.