Определение границ функции

Тема в разделе "LANGS.C", создана пользователем wsd, 2 дек 2008.

  1. _Aspire

    _Aspire New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2008
    Сообщения:
    62
    Кто нибудь может привести пример кода, в котором после компиляции функции идут в другом порядке?

    [add] VS C++
     
  2. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    crypto
    Повторюсь - функция не обязана заканчиваться выходом. Применительно к примеру выше:

    Код (Text):
    1. function() {
    2. if(<..>) {
    3.    for(;;) {   
    4.       print "Уррааа!"
    5.    }
    6. }
    7. <код>
    8. <характерная конструкция>
    9. return;
    10. }
    имеет только один выход. И запросто преобразуется в

    Код (Text):
    1. function() {
    2. if(!<..>) {
    3.    <код>
    4.    <характерная конструкция>
    5.    return;
    6. }
    7. for(;;) {  
    8.    print "Уррааа!"
    9. }
    10. }
    По-настоящему прочувствовать все многообразие code flow можно только написав или попытавшись написать декомпилятор :)
     
  3. DEEP

    DEEP Андрей

    Публикаций:
    0
    Регистрация:
    27 апр 2008
    Сообщения:
    491
    Адрес:
    г. Владимир
    Вставлю-ка и я свои пять копеек =)

    Вот все говорят - лови RETN, лови RETN... А если наоборот ловить не выход из функции, а следующий за ним идентификатор начала следующей? Насколько мне позволяют судить мои практически никакие знания С, в случае не-VOID функции она должна начинаться с PUSH EBP + MOV EBP,ESP т.е. подготовки кадра стэка. Может быть, можно сыграть на этом?

    зы. Да, грабли есть и здесь.
    1. А вдруг это вообще последняя функция? Тогда, видимо, придётся проверять на ведущие нули в сегменте - если их больше некоего количества - значит функций больше нету.
    2. Если всё же у функции нет парамов. Тут возможны лишь две ситуации: две функции разделяет или RETN, или JMP на вечный цикл. Как обрабатывать этот случай - пока не знаю) Скорее всего, компиль всё-таки вставляет между функциями хоть один байт "мусора" типа INT3 (встречалось мне пару раз при дизасмее сишного кода) или db 00, хотя хз, если честно.
     
  4. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    wsd
    А чем "мусор" между функциями хуже твоих 7-11 байт мусора push eax и т.д. Свой мусор ближе к телу ? :)

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

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Stiver
    так если мы сигнатурим последний RET, то соответственно все промежуточные реты
    туда войдут. а зачем сигнатурить промежуточные реты?
    т.е. текстуально последний рет включает весь набор ретов.
     
  6. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    leo
    если доки по этому вопросу молчат - будем доверять "естественному" :)
     
  7. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    А если функция соптимизируется с thunk'ами?
     
  8. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    KeSqueer
    Тогда кердык или пиши сборщик, который будет все эти куски склеивать в буфере.
     
  9. only

    only New Member

    Публикаций:
    0
    Регистрация:
    21 окт 2008
    Сообщения:
    147
    вставляется уникальная сигнатура в начале функции и в самом конце (6-10 байт хотябы)
    отключается оптимизация
    динамически находятся адреса
    дальше немного анализа, чтобы получить реальные конец и начало функций
    100 раз уже делал проблем не было
     
  10. trupac

    trupac New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    7
    как тривиально... KISS
    давайте воспользуемся указателями и их свойством работы с сырой памятью, что позволит нам покопаться в стеке.
    вся суть приёма состоит в том что мы передадим функции первым параметром указатель, прямо перед которым в стеке будет лежать адрес возврата. в общем, тут не паханое поле возможностей, так что моя пляска с указателями далеко не самый лучший вариант, но для примера, в общем то, я думаю, сгодится.
    Код (Text):
    1. #include "iostream"
    2. #include "iomanip"
    3.  
    4. using namespace std;
    5. // тихая злоба... мелким что лень было namespace std по дефолту поставить?
    6.  
    7. void drosophila(unsigned long *);
    8.  
    9. int main() {
    10.    unsigned long tmp, *ptr_tmp = &tmp;
    11.    cin >> tmp;
    12.    drosophila(ptr_tmp);
    13.    return 0;
    14. }
    15.  
    16. void drosophila(unsigned long * tmp) {
    17.    unsigned long ptr_tmp = tmp[-2];
    18.    cout << hex << ptr_tmp << endl;
    19.  
    20.  
    21.    char xxx[128];
    22.    cout << "Write any text: ";
    23.    cin >> xxx;
    24. // три строки бреда нужны для того что бы мягкая поделка не превратила функцию в inline, любителям const привет!
    25. }
     
  11. trupac

    trupac New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    7
    и с чего бы это я решил что нужно адрес возврата получить?.. извиняюсь. немножко не туда забрёл. сейчас подумаю как можно исправить.

    кстати а нельзя ли под конец функции просто считать eip и сделать поправку на размер мусора оставленного компилятором?
     
  12. only

    only New Member

    Публикаций:
    0
    Регистрация:
    21 окт 2008
    Сообщения:
    147
    trupac
    Трезвый?
     
  13. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Работает :))
    Код (Text):
    1. unsigned int lpEnd_myFunc;
    2. int myFunc(void)
    3. {
    4.     __asm {
    5.         lea eax, end_myFunc
    6.         mov [lpEnd_myFunc], eax
    7.     }
    8.     printf("myFunc: begin = 0x%p, end = 0x%x, size = 0x%x byte \n", &myFunc, lpEnd_myFunc, lpEnd_myFunc - (unsigned int)&myFunc);
    9.   return 0;
    10.   end_myFunc:;
    11. }
     
  14. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Y_Mur
    Да, но только один нюанс - по лабелю вычислять можно только внутри
    этой функции, т.к. он локален внутри неё и снаружи не доступен.
     
  15. _Aspire

    _Aspire New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2008
    Сообщения:
    62
    Y_Mur
    Тоже офигенный вариант )) Будем инжектить функцию, которая кроме того что нам нужно, так, между прочим, еще и какой-то левый код будет выполнять. Так сказать, обфускация )))

    А, кстати, куда она будет записывать значение еах?
     
  16. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    А как в масме низзя :: для глобальности /сам не пробовал/?
     
  17. _Aspire

    _Aspire New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2008
    Сообщения:
    62
    asmfan
    Это просто обращение к глобальной переменной.
     
  18. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    _Aspire
    Кстати вполне рабочий вариант: если в функции есть параметр\ы, который в нормальных условиях не может\не должен принимать некоторых значений (например, указатель), то можно в функции проверять его значение и выдавать в качестве рез-та указатель на метку
     
  19. trupac

    trupac New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    7
    leo
    сонный, но теперь и запить можно.
     
  20. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    или как в #53 всегда класть размер в глобальную переменную ;) правда один "холостой" вызов функции всё равно остаётся, да и для инжекта это наверное не совсем хорошо...