Необходимо определить точку входа в процедуру из самой процедуры, причем функция должна быть на C++ с ассемблерными вставками. Вызов других функций, как и обращение к переменным (кроме локальных) недопустим. Варианты вроде: "Написать на чистом ассемблере, передавать через параметры, с помощью глобальных переменных, через таблицу импорта" не подходят. У кого какие будут мысли? Может быть, после вызова процедуры, точку входа можно получить из каких то регистров? -------------------- С уважением Евгений.
Смотри на имя функции как на переменную которая хранит адрес точки входа этой функции. напр. Код (Text): int Func(int param) { DWORD* Address = (DWORD*)Func; // В Address адрес начала функции return 0; }
Приношу свои извинения за неточную формулировку вопроса. Дело в том, что я хочу данную функцию копировать в другое (системное) адресное пространство, и оттуда ее выполнять. Как я понимаю, в этом случае данный код теряет свою актуальность т.к. в Address будет содержаться указатель на мою функцию в индивидуальном адресном пространстве, что неминуемо приведет к BSOD, или я не прав?
Udzhen И да, и нет. А что нужно-то? Скопировать код своей функции в другой процесс? Так смотри статьи и примеры по внедрению своего кода. Который должен быть независим от расположения в адресном пространстве (PIC). Определить адрес своего кода (функции) уже в другом процессе? Читай там же, найдёшь вроде классического call @F; @@: pop ebp; etc.
Хочу осуществить перехват Native API без драйвера. Для этого: осуществляю вход в Ring0 с мощью модификации GDT, перехват осуществляю заменой адреса экспортируемой функции в SST на адрес своего обработчика, функцию - обработчик копирую в Ring0 область памяти выделенную с помощью ExAllocatePool. Проблема же заключается в том, что функции-обработчику необходимо как-то передать адрес перехватываемой функции... Я решил выделить под функцию на 3 байта больше памяти, скопировать функцию в выделенную память со смещением в 3 байта от начала выделенной памяти, а в первые 3 байта скопировать адрес перехватываемой функции. Соответственно доступ к этой своеобразной "переменной" можно осуществить так: Код (Text): InterceptorFunc(...) { PDWORD pdwOriginalAddress = reinterpret_cast<PDWORD>(&InterceptorFunc) - 0x03; } Но вот будет ли &InterceptorFunc действительно точкой входа в процедуру? Ведь код скопирован в другое адресное пространство! P.S. А статьи обязательно поищу и почитаю. -------------------- С уважением Евгений.
Нет, конечно. "Адрес функции" компилятор сделает просто константой, недействительной при другом адресе кода. Определи последний программно. Но наверняка есть лучшие методы.
Udzhen Дык в чем проблема-то. Абсолютный адрес в некоторой точке @1 определяется как заметил IceStudent классическим методом через call @1; @1: pop eax. Остается только определить относительное смещение delta точки @1 от точки входа в процедуру. Это можно сделать по разному: 1) если процедура написана и не будет изменяться, то можно опредилить delta заранее "ручками-глазками" в отладчике или дизассемблере и забить как константу в sub eax,delta 2) если встроенный асм поддерживает вычисление разности адресов, то пишем просто sub eax,@1-InterceptorFunc (обычные асмы вычисляют разности без проблем, а вот например дельфи в этих случаях капризничает и выдает ошибку) 3) если не получается по способу 2, то придется хитрить задав разность в инструкции jcc\jmp\call, например так Код (Text): call @1 call InterceptorFunc ;call rel32 @1: pop eax ;адрес возврата на call InterceptorFunc add eax,5 ;адрес @1 add eax,[eax-4] ;добавляем смещение из call InterceptorFunc PS: Извиняюсь, в попыхах add eax,5 забыл. Думал раскритикуют в пух и прах, а тут тишина и покой, крепко глазки закрой
Простите за offline, сейчас нахожусь в деревне, а WAP не везде есть. IceStudent Конечно я имел ввиду: Код (Text): InterceptorFunc(...) { PDWORD pdwOriginalAddress = reinterpret_cast<PDWORD>(&InterceptorFunc) - sizeof(PDWORD); } leo Компилятор у меня Microsoft Visual Studio .NET 2003 Enterprise Architect. Код как я понимаю, для него должен выглядеть так: Код (Text): #pragma optimize("", off) // Отключаем оптимизацию NTSTATUS InterceptorFunc(...) { // Здесь пролог функции __asm { call pointer; pointer: pop eax; // Здесь, как я понимаю, в регистре eax абсолютный адрес delta точки pointer sub eax, pointer - InterceptorFunc; // В eax теперь вроде должен находится адрес точки входа функции } // Здесь эпилог } // Это для вычисления размера процедуры InterceptorFunc (к вопросу EntryPoint не относится) // SIZE_T size = reinterpret_cast<SIZE_T>(&InterceptorFuncEnd) - reinterpret_cast<SIZE_T>(&InterceptorFunc); void InterceptorFuncEnd(void) { return; } #pragma optimize("", on) // Включаем оптимизацию Уважаемый leo, Вы имели ввиду подобное решение? Может быть, кто-нибудь предложит еще какие то варианты? P.S. К сожалению, нет студии под рукой, и проверить код не чем. Я в асме не силен, и до критики мне как до ... ---------------------- С уважением Евгений.
Udzhen Да, правильно. В целом код рабочий, только нужно уточнить синтаксис - может для гарантии использовать offset pointer, offset InterceptorFunc (как в VS не знаю, в масме вроде все равно, а вот дельфи без offset отказывается компилить). Ну и лишний регистр незачем занимать (компилер лишние push\pop вставит), можно просто Код (Text): sub eax, offset pointer add eax, offset InterceptorFunc PS: О, не заметил что ты подправил код. Думаю, раз изменил на непосредственную разность pointer-InterceptorFunc, то в VS это работает
leo Код изменил, что бы показать, что вычисление разности pointer-InterceptorFunc происходит на этапе компиляции (эквивалентно способу №1 "ручками-глазками"). Но сегодня проверил, и оказалось, что VS не поддерживает вычисление разности адресов в ассемблерных вставках, поэтому пришлось сделать так: Код (Text): #pragma optimize("", off) // Отключаем оптимизацию NTSTATUS InterceptorFunc(...) { PDWORD pdwOriginalAddress; // Указатель на перехватываемую функцию __asm { call pointer; pointer: pop eax; sub eax, offset pointer; // В принципе директиву offset можно убрать, компилятор ее вставляет сам add eax, offset InterceptorFunc; // В регистре eax теперь абосолютный адрес InterceptorFunc sub eax, 0x04; mov pdwOriginalAddress, [eax]; } ... return STATUS_SUCCESS; } // Это для вычисления размера процедуры InterceptorFunc (к вопросу EntryPoint не относится) // SIZE_T size = reinterpret_cast<SIZE_T>(&InterceptorFuncEnd) - reinterpret_cast<SIZE_T>(&InterceptorFunc); void InterceptorFuncEnd(void) { return; } #pragma optimize("", on) // Включаем оптимизацию Код прекрасно работает, но неприятно, что при каждом вызове функции происходят лишние вычисления. Всем спасибо за участие, проблема решена! P.S. Но тему не закрываю, жду интересных решений. ---------------------- С уважением Евгений.
Udzhen > "неприятно, что при каждом вызове функции происходят лишние вычисления" Ну во-первых, ничего страшного в этом нет. Во-вторых, ты сам так поставил задачу "определить точку входа в процедуру из самой процедуры", хотя как я понимаю в твоем случае можно поступить иначе - при копировании процедуры перебить значение адреса по фиксированному смещению на другое значение Код (Text): @1: mov eax,[offset InterceptorFunc - 4] ; HEX: 8B 05 XXXXXXXX @2: mov pdwOriginalAddress, eax ; HEX: 89 ... Адреса InterceptorFunc в разных адресных пространствах известны, поэтому достаточно определить смещение метки @1 или @2 от начала процедуры и записать новое значение адреса по смещению @1+2 или @2-4. Определить смещение можно заранее "ручками-глазками" по дизассемблерному листингу или в рантайме найти поиском значения dword(&InterceptorFunc-4) с проверкой байтов окружения (в приведенном случае 8Bh,05h перед и 89h после искомого дворда). Хотя поиск и займет некоторое время, но выполняется он один раз во время копирования процедуры
leo Я хотел этим сказать, что производить вычисления разности адресов каждый раз при вызове функции, против вычисления этой разности на этапе компиляции не рационально (с идеалистической точки зрения). А мысль патчить функцию после копирования пришла ко мне первым делом. Просто хочется как-то все это универсализировать! Как ты сам понимаешь толку от кода, который не может обращаться к переменным и функциям, сохранять данные и взаимодействовать с другим кодом совсем не много. ---------------------- С уважением Евгений.