• XSS.stack #1 – первый литературный журнал от юзеров форума

Размещение функции в памяти

coree

(L2) cache
Пользователь
Регистрация
27.12.2021
Сообщения
303
Решения
1
Реакции
116
Гарант сделки
1
Депозит
0.0006
Допустим, у меня есть кусок кода (функция), которую я копирую (!) в памяти по другому адресу (прохожусь циклом пока не встречу ret и пишу это в массив а потом копирую). Эта функция должна работать в качестве хука (я подменяю ее адресом адрес того что мне надо хукнуть), но соответственно ВСЕ вызовы внутри функции ломаются из-за (как я понял) сегментации данных (вызов оригинальной функции соответственно тоже). Так вот вопрос, что в таком случае делать, чтобы вызовы не сбивались?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Так вот вопрос, что в таком случае делать, чтобы вызовы не сбивались?
Во-первых, функция не обязательно заканчивается инструкцией ret, эта инструкция может быть и где-то в середине функции. Во-вторых, функция либо должна быть позиционно независимой сама по себе, либо ты должен дизассемблировать все ее инструкции и поменять все относительные адреса, указывающие вне функции, и абсолютные адреса, указывающие внутрь нее. В-третьих, зачем тебе переносить оригинальную функцию целиком, если ты можешь перенести только первые интсрукции, которые перетирает сплайсинг хук, а за ними поставить джамп на условно третью или четвертую инструкцию оригинальной функции (для этого в любом случае нужен дизассемблер длин).
 
Хорошо, отвечу. Функция заканчивается ret-ом так как это моя собственная функция, она вида
Код:
int hooked_func(argument){
    original_func(argument);
    return 0;
}
где адрес original_func я получаю по ходу работы моей программы, условным GetProcAddr. Т.е. я переношу не оригинальную функцию, а свой "хук".
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Т.е. я переношу не оригинальную функцию, а свой "хук
Во-первых, зачем? А потом, ну так посмотри в дизассемблерный листинг этой функции и найди те инструкции, о которых я говорил раньше. Или под отладчиком запусти.

Я опять же предполагаю, что ты не просто копируешь функцию хер пойми куда, а выделил исполняемую память и записываешь функцию по правильному выравниванию. Вообще, задавать абстрактные вопросы по коду без самого кода имеет смысла чуть менее чем ноль...
 
Пожалуйста, обратите внимание, что пользователь заблокирован
if you could add English version of your question we can help you ,
what did i understand you wanna hook some function and execute your code lets say you try hooking
MessageBoxA and from hooked function you intercapt args and change it or spoof it then ? what is the problem
 
Пример кода будет сложно привести, он достаточно объемный, а сократить никак - смысл теряется. Почему я копирую функцию в память? Смотри, у меня такая штука что я не могу выделять память и туда копировать, мой основной код выгружается сразу же после срабатывания. Поэтому я делаю так: загружаю длл с помощью LoadLibraryA, получаю адрес .text секции и пишу свою хук-функцию туда. Все адреса у меня есть которые нужны, с этим всё ок.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
я не могу выделять память
Из-за антивируса? VirtualAlloc так то куда проще использовать.

Все адреса у меня есть которые нужны, с этим всё ок
Ну если ты уверен, что в инструкциях твоей функции проблем нет, то, возможно, проблема в выравнивании. Это надо погуглить, я точно не скажу, но вангую, что функция на x86 должна быть выровнена на границу в 4 байта (и в 16 байт на x64).

И потом, ты уверен, что твоя функция не адресует каких-то данных в твоем коде, который, как ты говоришь, был выгружен.
 
Из-за антивируса?
Из-за того что код выгружается. Соответственно вся выделенная память освобождается, а мне надо чтобы она дальше висела после выгрузки. Там проблема в вызовах которые
Код:
call dword ptr ds:<смещение в сегменте памяти>
, конкретно из-за ds:смещение я не могу корректно после копирования вызвать функцию. Потому что ds:смещение указывает на переменную (прототип функции), в которой адрес экспортируемой функции. А после копирования все это сбивается.
 
чтобы адресса не сбивались,пиши функцию как шелкод
Если мне ее писать как шеллкод, то придется снова искать все адреса и шеллкод получится размером чуть ли не с сам исполняемый модуль)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Из-за того что код выгружается. Соответственно вся выделенная память освобождается, а мне надо чтобы она дальше висела после выгрузки.
Воу-воу, давайка с этого момента поподробнее. Та память, которую ты выделил с помощью VirtualAlloc никуда не девается, пока ей кто-нибудь не сделает VirtualFree. Как и в случае с кучей, но куча неисполняемая по умолчанию.

Потому что ds:смещение указывает на переменную (прототип функции), в которой адрес экспортируемой функции. А после копирования все это сбивается
Ну я тебе об этом и говорил. Тебе надо эти инструкции поправить при переносе функции.

Если мне ее писать как шеллкод, то придется снова искать все адреса и шеллкод получится размером чуть ли не с сам исполняемый модуль
Захардкодь какой то адрес, а при копировании перезапиши его действительным адресом.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Очевидно же, в функции есть или call или еще что, что меняется если переместить ее по другому адресу.
Или пиши шк, или смотри, что у тебя там базозависимое и правь.
 
Тебе надо эти инструкции поправить при переносе функции.
А как это все выправить то? Там же надо получается менять оффсет учитывая сегмент...

Насчёт виртуалаллока, он не подходит ещё тем что вообще лучше функций для триггера антивируса вызывать поменьше (да и вообще поменьше, исполнение в контексте очень нестабильного процесса), память уже загруженной длл выглядит менее подозрительно.
Даже moneta64 говорит что rwx/rx commit reserve секция памяти это странно).

У меня есть вот какая мысль, можно написать простенький шеллкод который будет просто пушить аргументы, а затем делать так:
Код:
mov edx, <0x*****>
call edx
Вот этот адрес 0x***** можно костыльно перезаписать поиском по паттерну, типа для примера выставить адрес mov edx, 0xDEADBEEF, а потом просто memcpy скопировать его туда вместо DEADBEEF. Похоже на то как ты сказал, как думаешь, сильно ли костыльно?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Похоже на то как ты сказал, как думаешь, сильно ли костыльно?
Ну я до сих пор не понял, что тебе нужно и зачем, но как бы я такое решение и предлагал, тут вряд ли можно что-то сделать не костыльно.

память уже загруженной длл выглядит менее подозрительно
Кроме того, что тебе нужно будет поменять права страницы с read-execute на read-write-execute, что тоже знатный триггер для антивируса.

триггера антивируса вызывать поменьше
Сделай один блок разделяемой памяти с двумя отображениями: read-execute и read-write, пиши данные во второй. Это менее палевно, чем сделать VirtualAlloc.
 
Обычно антивирус не чекает уже загруженные в процесс длл, особенно полностью легитимные. Это своего рода dll hollowing)
 
Ну я до сих пор не понял, что тебе нужно и зачем, но как бы я такое решение и предлагал, тут вряд ли можно что-то сделать не костыльно.
Хочет наверное раскидать хуки по кодовым секциям легитимных длл в АП процесса.

Ответ один, пиши шеллкод в качестве обработчика. Если беспокоишься о ограниченном адресном пространстве в секции легитимной длл делай через прослойки.
"mov edx,... call edx" сломает стек и передаваемые параметры простому прологу хука в виде например NewCloseHandle(HANDLE) {} не дойдут и потеряются на стеке.
Смотри в сторону джампов вроде "mov eax,... jmp eax" чтоб стек не двигался.

UPD: Знаешь еще как прикольно можно делать. Двойные джампы. Поясню. Точки входа с системные функции выровнены и между ними либо нопы, либо инт3. На точку входа ставишь шорт джамп на 5 байт назад, а там второй лонг джамп на твой код. Для большинства АВ или анализаторов это не выглядит хуком.
 
Последнее редактирование:
Если я не ошибаюсь, когда мы делаем джампами надо будет рассчитывать и вручную пушить адрес возврата чтобы он из ret смог выбраться?
 
Если я не ошибаюсь, когда мы делаем джампами надо будет рассчитывать и вручную пушить адрес возврата чтобы он из ret смог выбраться?
Нет. Адрес возврата уже лежит на вершине стека и твой ret в твоем хуке все вернет на место. Джампы придется считать, да, но там математика за 3 класс
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Обычно антивирус не чекает уже загруженные в процесс длл, особенно полностью легитимные.
Он чекает VirtualProtect ровно столько же, сколько он чекает VirtualAlloc.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх