Точка входа функции

Тема в разделе "WASM.BEGINNERS", создана пользователем Udzhen, 23 окт 2005.

  1. Udzhen

    Udzhen New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2005
    Сообщения:
    25
    Адрес:
    Russia
    Необходимо определить точку входа в процедуру из самой процедуры, причем функция должна быть на C++ с ассемблерными вставками. Вызов других функций, как и обращение к переменным (кроме локальных) недопустим.

    Варианты вроде: "Написать на чистом ассемблере, передавать через параметры, с помощью глобальных переменных, через таблицу импорта" не подходят.

    У кого какие будут мысли?

    Может быть, после вызова процедуры, точку входа можно получить из каких то регистров?



    --------------------

    С уважением Евгений.
     
  2. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Смотри на имя функции как на переменную которая хранит адрес точки входа этой функции.



    напр.


    Код (Text):
    1. int Func(int param)
    2. {
    3.    DWORD* Address = (DWORD*)Func;
    4.    // В Address адрес начала функции
    5.    return 0;
    6. }
     
  3. Udzhen

    Udzhen New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2005
    Сообщения:
    25
    Адрес:
    Russia
    Приношу свои извинения за неточную формулировку вопроса.

    Дело в том, что я хочу данную функцию копировать в другое (системное) адресное пространство, и оттуда ее выполнять. Как я понимаю, в этом случае данный код теряет свою актуальность т.к. в Address будет содержаться указатель на мою функцию в индивидуальном адресном пространстве, что неминуемо приведет к BSOD, или я не прав?
     
  4. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Udzhen

    И да, и нет. А что нужно-то? Скопировать код своей функции в другой процесс? Так смотри статьи и примеры по внедрению своего кода. Который должен быть независим от расположения в адресном пространстве (PIC). Определить адрес своего кода (функции) уже в другом процессе? Читай там же, найдёшь вроде классического call @F; @@: pop ebp; etc.
     
  5. Udzhen

    Udzhen New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2005
    Сообщения:
    25
    Адрес:
    Russia
    Хочу осуществить перехват Native API без драйвера.

    Для этого: осуществляю вход в Ring0 с мощью модификации GDT, перехват осуществляю заменой адреса экспортируемой функции в SST на адрес своего обработчика, функцию - обработчик копирую в Ring0 область памяти выделенную с помощью ExAllocatePool. Проблема же заключается в том, что функции-обработчику необходимо как-то передать адрес перехватываемой функции... Я решил выделить под функцию на 3 байта больше памяти, скопировать функцию в выделенную память со смещением в 3 байта от начала выделенной памяти, а в первые 3 байта скопировать адрес перехватываемой функции. Соответственно доступ к этой своеобразной "переменной" можно осуществить так:
    Код (Text):
    1.  
    2. InterceptorFunc(...)
    3. {
    4.    PDWORD pdwOriginalAddress = reinterpret_cast<PDWORD>(&InterceptorFunc) - 0x03;
    5. }
    6.  


    Но вот будет ли &InterceptorFunc действительно точкой входа в процедуру? Ведь код скопирован в другое адресное пространство!



    P.S.

    А статьи обязательно поищу и почитаю.





    --------------------

    С уважением Евгений.
     
  6. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Udzhen





    у тебя будет -12.
     
  7. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine


    Нет, конечно. "Адрес функции" компилятор сделает просто константой, недействительной при другом адресе кода. Определи последний программно. Но наверняка есть лучшие методы.
     
  8. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    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):
    1. call @1
    2. call InterceptorFunc ;call rel32
    3. @1:
    4. pop eax              ;адрес возврата на call InterceptorFunc
    5. add eax,5            ;адрес @1
    6. add eax,[eax-4]      ;добавляем смещение из call  InterceptorFunc
    PS: Извиняюсь, в попыхах add eax,5 забыл. Думал раскритикуют в пух и прах, а тут тишина и покой, крепко глазки закрой ;)
     
  9. Udzhen

    Udzhen New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2005
    Сообщения:
    25
    Адрес:
    Russia
    Простите за offline, сейчас нахожусь в деревне, а WAP не везде есть.



    IceStudent



    Конечно я имел ввиду:
    Код (Text):
    1.  
    2. InterceptorFunc(...)
    3. {
    4.    PDWORD pdwOriginalAddress = reinterpret_cast<PDWORD>(&InterceptorFunc) - sizeof(PDWORD);
    5. }
    6.  




    leo



    Компилятор у меня Microsoft Visual Studio .NET 2003 Enterprise Architect.

    Код как я понимаю, для него должен выглядеть так:
    Код (Text):
    1.  
    2. #pragma optimize("", off)  // Отключаем оптимизацию
    3.  
    4. NTSTATUS InterceptorFunc(...)
    5. {
    6.     // Здесь пролог функции
    7.     __asm
    8.     {
    9.         call pointer;
    10. pointer:
    11.         pop eax;  // Здесь, как я понимаю, в регистре eax абсолютный адрес delta точки pointer
    12.         sub eax, pointer - InterceptorFunc;  // В eax теперь вроде должен находится адрес точки входа функции
    13.     }
    14.     // Здесь эпилог
    15. }
    16.  
    17. // Это для вычисления размера процедуры InterceptorFunc (к вопросу EntryPoint не относится)
    18. // SIZE_T size = reinterpret_cast<SIZE_T>(&InterceptorFuncEnd) - reinterpret_cast<SIZE_T>(&InterceptorFunc);
    19. void InterceptorFuncEnd(void)
    20. {
    21.     return;
    22. }
    23.  
    24. #pragma optimize("", on)  // Включаем оптимизацию
    25.  




    Уважаемый leo, Вы имели ввиду подобное решение?

    Может быть, кто-нибудь предложит еще какие то варианты?



    P.S.

    К сожалению, нет студии под рукой, и проверить код не чем.





    Я в асме не силен, и до критики мне как до ...



    ----------------------

    С уважением Евгений.
     
  10. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Udzhen

    Да, правильно. В целом код рабочий, только нужно уточнить синтаксис - может для гарантии использовать offset pointer, offset InterceptorFunc (как в VS не знаю, в масме вроде все равно, а вот дельфи без offset отказывается компилить). Ну и лишний регистр незачем занимать (компилер лишние push\pop вставит), можно просто
    Код (Text):
    1. sub eax, offset pointer
    2. add eax, offset InterceptorFunc
    PS: О, не заметил что ты подправил код. Думаю, раз изменил на непосредственную разность pointer-InterceptorFunc, то в VS это работает
     
  11. Udzhen

    Udzhen New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2005
    Сообщения:
    25
    Адрес:
    Russia
    leo



    Код изменил, что бы показать, что вычисление разности pointer-InterceptorFunc происходит на этапе компиляции (эквивалентно способу №1 "ручками-глазками"). Но сегодня проверил, и оказалось, что VS не поддерживает вычисление разности адресов в ассемблерных вставках, поэтому пришлось сделать так:
    Код (Text):
    1.  
    2. #pragma optimize("", off)  // Отключаем оптимизацию
    3.  
    4. NTSTATUS InterceptorFunc(...)
    5. {
    6.     PDWORD pdwOriginalAddress;  // Указатель на перехватываемую функцию
    7.  
    8.     __asm
    9.     {
    10.         call pointer;
    11. pointer:
    12.         pop eax;
    13.         sub eax, offset pointer;  // В принципе директиву offset можно убрать, компилятор ее вставляет сам
    14.         add eax, offset InterceptorFunc;  // В регистре eax теперь абосолютный адрес InterceptorFunc
    15.         sub eax, 0x04;
    16.         mov pdwOriginalAddress, [eax];
    17.     }
    18.  
    19.     ...
    20.  
    21.     return STATUS_SUCCESS;
    22. }
    23.  
    24. // Это для вычисления размера процедуры InterceptorFunc (к вопросу EntryPoint не относится)
    25. // SIZE_T size = reinterpret_cast<SIZE_T>(&InterceptorFuncEnd) - reinterpret_cast<SIZE_T>(&InterceptorFunc);
    26. void InterceptorFuncEnd(void)
    27. {
    28.     return;
    29. }
    30.  
    31. #pragma optimize("", on)  // Включаем оптимизацию
    32.  




    Код прекрасно работает, но неприятно, что при каждом вызове функции происходят лишние вычисления.



    Всем спасибо за участие, проблема решена!



    P.S.

    Но тему не закрываю, жду интересных решений.





    ----------------------

    С уважением Евгений.
     
  12. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Udzhen

    > "неприятно, что при каждом вызове функции происходят лишние вычисления"

    Ну во-первых, ничего страшного в этом нет. Во-вторых, ты сам так поставил задачу "определить точку входа в процедуру из самой процедуры", хотя как я понимаю в твоем случае можно поступить иначе - при копировании процедуры перебить значение адреса по фиксированному смещению на другое значение
    Код (Text):
    1. @1: mov eax,[offset InterceptorFunc - 4] ; HEX: 8B 05 XXXXXXXX
    2. @2: mov pdwOriginalAddress, eax          ; HEX: 89 ...
    Адреса InterceptorFunc в разных адресных пространствах известны, поэтому достаточно определить смещение метки @1 или @2 от начала процедуры и записать новое значение адреса по смещению @1+2 или @2-4. Определить смещение можно заранее "ручками-глазками" по дизассемблерному листингу или в рантайме найти поиском значения dword(&InterceptorFunc-4) с проверкой байтов окружения (в приведенном случае 8Bh,05h перед и 89h после искомого дворда). Хотя поиск и займет некоторое время, но выполняется он один раз во время копирования процедуры
     
  13. Udzhen

    Udzhen New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2005
    Сообщения:
    25
    Адрес:
    Russia
    leo



    Я хотел этим сказать, что производить вычисления разности адресов каждый раз при вызове функции, против вычисления этой разности на этапе компиляции не рационально (с идеалистической точки зрения).

    А мысль патчить функцию после копирования пришла ко мне первым делом. Просто хочется как-то все это универсализировать! Как ты сам понимаешь толку от кода, который не может обращаться к переменным и функциям, сохранять данные и взаимодействовать с другим кодом совсем не много.



    ----------------------

    С уважением Евгений.