Sokolov
Привет. Ну так...
Ilyas
http://www.spbk-spo.com/new/povt/Prog_assembler.pdf
Вот ещё
Kirill
Начни с x86, для неё полно литературы. Потом разберись, что изменилось с введением x64. Глобальных отличий не так уж и много
Anonymous
Ребят, где взять инфу про переход в legacy режим для архитектуры x86-64?
Anonymous
Стоп. В x86-64 проц начинает работать в реальном режиме?
Anonymous
Конечно
Anonymous
Отлично
Anonymous
Нет, режимы работы у x86-64 это real, protected и long mode
Anonymous
Ну ещё SMM есть
🦥Alex Fails
А тут вррде про насм выкладывали
void *
ага, и кажется, аж три раза
Endor Flame
А можно книжку по насму?
Ned
Ned
Anonymous
IB
Anonymous
Anonymous
Ребят, вообщем то из комментариев все ясно.
Anonymous
Это код для перехвата функции recv()
Anonymous
Проблема с передачей ареса функции, т.к. компиль заменяет ставит относительный прыжок, и когда иньекция
jmp before_recv + 0x3
проведена, там уже не верный адрес before_recv
Dmitry
а зачем так извращаться вообще?
Anonymous
Перехват API
Anonymous
Пречем перехат такой хитрожопый, чтоб поставить коллбэк
Dmitry
ну создай отдельный буфер, пять байтов, в первый байт ставь 0xE9, в последние четыре байта - относительный адрес того куда нужно перепрыгнуть, и копирни этот буфер в начало recv
Anonymous
На который попадет управление после выполения recv()
Dmitry
относительный адрес легко пересчитать
Dmitry
да как-то все хардкорно сделано, можно универсальный вариант
Anonymous
"в последние четыре байта - относительный адрес того куда нужно перепрыгнуть", а не абсолютный не?
Anonymous
Относительный компиль и сейчас сам туда пихает
Dmitry
подожди
Dmitry
я просто не понимаю, зачем изврат с before_recv и code_inject. т.е. зачем это кодить отдельным кодом.
смотри, техника очень простая на самом деле
Anonymous
А, 0xE9 это ж относительный прыжок, хорошо, как ты предлагаешь пересчитать относительный адрес?
Dmitry
1) создаём буфер - OriginalRecv. ну, динамически его где-нибудь выделяем, пусть где-то на 32 байта, хватит.
2) с помощью дизассемблера длин последовательно вычисляем длины первых инструкций перехватываемой функции, пока суммарная длина считанных инструкций не будет больше или равна 5. допустим, их длина равна N. ну пусть это будут mov edi, edi / push ebp / mov ebp, esp. скопируем их в OriginalRecv в начало.
3) в конец буфера OriginalRecv пишем 0xE9, а потом четыре байта - ОТНОСИТЕЛЬНЫЙ адрес recv + N.
4) в начало recv() пишем 0xE9 а затем относительный адрес своего hook_recv(). плюс пять.
5) если надо вызвать оригинал - вызываем OriginalRecv.
Dmitry
как относительный адрес пересчитать?
допустим у тебя есть recv() по адресу X
и "куда перепрыгнуть" по адресу Y.
пересчитываешь по формуле X-Y+5.
Anonymous
Суть в том чтобы подменить адрес возврата у recv()
Anonymous
Запихнуть туда push callback_after_recv
Dmitry
хм
Anonymous
Эта функция будет написана на плюсах
Anonymous
В ней парсер и редактор пакетов
Dmitry
а почему не сделать hook_recv(), в котором ты будешь вызывать оригинальный recv(), а потом делать свои вещи?
Dmitry
ну это как-то более общепринято что ли
Dmitry
сейчас
Anonymous
Можно и так
Anonymous
Но с подменой адреса возврата, не надо будет заново аргументы для функции на стеке переносить
Anonymous
callback вызовется с уже готовым стеком, ему не надо аргументы ложить
Dmitry
так тебе их и так не нужно переносить, ну, в смысле, не нужно с этим ебаться.
смотри, у тебя в самом начале recv() будет jmp hook_recv.
то есть, твой hook_recv() получает все аргументы от recv().
потом когда тебе нужно вызвать оригинальный recv(), ты зовешь (через call само собой) OriginalRecv(), поскольку ты его зовешь из C, и прототип у тебя _stdcall, он сам все пихнет в стек и вызовет. а поскольку функция stdcall, она сама за собой все подчистит.
Dmitry
все равно не вижу проблемы
Anonymous
Хотя есть конечно небольшой подвох, управление не сразу перейдет на коллбэк, а на код, который подсунет новый адрес возврата (оригинальный адрес возврата recv()) и только потом вызовет функцию на плюсах
Dmitry
ну вот тем более, у тебя хардкорный вариант
Dmitry
вот ты напишешь int _stdcall hook_recv(int, char*, int, int) { }
а в начало recv запихнешь jmp hook_recv И ВСЁ
где тут нужно париться с аргументами в стеке?
Anonymous
Ну, хоть и хардовый вариант, но проблема не в нем, он то работает, тут все же с адресом проблема, сейчас попробую зафиксить как ты предложил
Dmitry
ну у тебя плюс ещё всё жестко захардкожено
Dmitry
вот эти mov edi, edi / push ebp / mov ebp, esp
Anonymous
Это оригинальный код начала recv()
Anonymous
5 байт
Dmitry
а если тебе другую функцию нужно перехватить? а если x64? а если (ну это конечно маловероятно) майкрософт поменяет первые байты?
Dmitry
я знаю
Dmitry
просто хардкодить - плохо :)
Anonymous
Ну, на перехват других функций я и не расчитывал)
Dmitry
лучше собирать самому этот before_recv, дизассемблируя начало recv
Anonymous
Ну это понятно, просто как бэ костыль
Dmitry
ну если так то да
Dmitry
но send тебе точно понадобится :)
Dmitry
а WSARecv? :)
Anonymous
sock 2.0 ?
Dmitry
ну да, WSARecv дохрена ж где юзается
Dmitry
ему лет дохренища
Anonymous
Но не в данном случае)
Dmitry
а, то есть под конкретную программу решение
Anonymous
Ага
Anonymous
Спасибо вообщем 👍
Lev
слышал на ассемблере плагины к diablo 2 пишут
Anonymous
Парни, опять вопрос не по окладу. Скажите как электрик электрику. В электротехнике величина обратно пропорцинальная мощности?
Anonymous
Частота? Рабочая частота генератора
Anonymous
Не?
Anonymous
В коде на C++ компилятору встречается такая конструкция:
int ret = ((int(*)(unsigned int, unsigned char *, int, int))&*original_recv.buff)(s, buff, len, flags);
преобразование буфера к указателю на функцию и вызов.
Но компиль не знает что эта функция __stdcall, функция будет известна лишь на этапе рантайма и после того как из функции произойдет выход
ret 0x10
компиль ставит
add esp, 0x10
т.е. к функции __stdcall он применяет еще и метод вызова __cdecl.
Можно ли как-то компиль заранее уведомить о этом что это указатель на функцию __stdcall, чтоб он стек второй раз не чистил после выхода из нее?
🦥Alex Fails
В коде на C++ компилятору встречается такая конструкция:
int ret = ((int(*)(unsigned int, unsigned char *, int, int))&*original_recv.buff)(s, buff, len, flags);
преобразование буфера к указателю на функцию и вызов.
Но компиль не знает что эта функция __stdcall, функция будет известна лишь на этапе рантайма и после того как из функции произойдет выход
ret 0x10
компиль ставит
add esp, 0x10
т.е. к функции __stdcall он применяет еще и метод вызова __cdecl.
Можно ли как-то компиль заранее уведомить о этом что это указатель на функцию __stdcall, чтоб он стек второй раз не чистил после выхода из нее?
int ret = ((int(__stdcall*)(unsigned int, unsigned char *, int, int))&*original_recv.buff)(s, buff, len, flags);