C++ и ПОЛНОСТЬЮ динамические функции
У меня проблема с объездными путями. Обходы, как вы все знаете, могут перемещаться только между 5 байтами пространства (то есть вызовом 'jmp' и адресом 4 байта). Из-за этого невозможно иметь функцию 'hook' в классе (метод), вы не можете предоставить указатель 'this', потому что просто не хватает места ( здесь проблема более подробно объяснена). Поэтому я целый день проводил мозговой штурм в поисках решения, и теперь я хочу, чтобы вы подумали об этом, чтобы не начинать 3-5-дневный проект, не зная, возможно ли это или нет.
Изначально у меня было 3 цели, я хотел, чтобы функции "ловушки" были методами класса, я хотел, чтобы весь подход был объектно-ориентированным (без статических функций или глобальных объектов) и, что самое худшее / сложное, был полностью динамичным. Это мое (в теории) решение; при сборке можно изменять функции во время выполнения (идеальным примером является любой обходной метод). Так как я могу динамически изменять функции, разве я не могу создавать их динамически? Например; Я выделяю память, скажем, ~30 байт (через malloc/new). Разве нельзя было бы просто заменить все байты двоичными числами, соответствующими различным операторам сборки (например, 0xE9 - это "jmp"), а затем вызвать адрес напрямую (так как он будет содержать функцию)?
ПРИМЕЧАНИЕ: я заранее знаю возвращаемое значение и все аргументы всех функций, которые я хочу обойти, и, поскольку я использую GCC, соглашение thiscall практически идентично соглашению _cdecl.
Так что это моя мысль / реализация в ближайшее время; Я создаю класс "Функция". Этот конструктор принимает различное количество аргументов (кроме первого аргумента, который описывает возвращаемое значение целевой функции).
Каждый аргумент является описанием аргументов, которые получит хук (размер и указатель или нет). Допустим, я хочу создать класс Function для int * RandomClass::IntCheckNum(short arg1);
, Тогда мне просто нужно сделать так:Function func(Type(4, true), Type(4, true), Type(2, false));
, Где "Тип" определяется как Type(uint size, bool pointer)
, Затем через сборку я мог бы динамически создать функцию (примечание: все это будет использовать соглашение о вызовах _cdecl), так как я могу вычислить количество аргументов и общий размер.
РЕДАКТИРОВАТЬ: с примером, Type(4, true)
это возвращаемое значение (int*), скондType(4, true)
это указатель RandomClass 'this' и Type(2, false)
описывает первый аргумент (короткий arg1).
С этой реализацией я мог бы легко иметь методы класса в качестве обратных вызовов, но это потребовало бы большого количества ассемблерного кода (с которым я даже не особенно опытен). В конце концов, единственной не динамической вещью были бы методы в моем классе обратного вызова (что также потребовало бы до и после обратного вызова).
Итак, я хотел знать; Это возможно? Сколько работы это потребует, и я над головой?
РЕДАКТИРОВАТЬ: Извините, если я представил все немного нечетко, но если есть что-то, что вы хотите более подробно объяснить, спросите!
EDIT2: я также хотел бы знать, могу ли я найти шестнадцатеричные значения для всех операторов сборки где-нибудь? Список поможет тонну! И / или если есть возможность как-то "сохранить" асм (""); код по адресу памяти (в чем я сильно сомневаюсь).
1 ответ
То, что вы описываете, обычно называется "громовым" и довольно часто применяется. Исторически самой распространенной целью было отображение 16-битного и 32-битного кода (путем автоматического создания новой 32-битной функции, которая вызывает существующую 16-битную или наоборот). Я полагаю, что некоторые компиляторы C++ генерируют аналогичные функции для настройки указателей базового класса на указатели подкласса в множественном наследовании.
Это, безусловно, кажется жизнеспособным решением вашей проблемы, и я не предвижу никаких серьезных проблем. Просто убедитесь, что вы выделяете память с любыми флагами, необходимыми в вашей операционной системе, чтобы убедиться, что память является исполняемой (большинство современных ОС по умолчанию выделяют неисполняемую память).
Эта ссылка может оказаться полезной, особенно если вы работаете в Win32: http://www.codeproject.com/Articles/16785/Thunking-in-Win32-Simplifying-Callbacks-to-Non-sta
Что касается нахождения шестнадцатеричных значений сборочных операций, лучшая справка, о которой я знаю, - это Приложение к руководству ассемблера NASM (и я не просто говорю это, потому что помогал писать). Копия доступна здесь: http://www.posix.nl/linuxassembly/nasmdochtml/nasmdoca.html