Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Вычисление размера функции


Автор: nadge 3.1.2008, 01:13
Доброе время суток!

Кусок программы (тестовый пока):

Код

void __declspec(naked) angy_StartOfHappyCode(void)
{
}

void HappyCode()
{    
    MESSAGEBOX pMessageBox=(MESSAGEBOX)0x99999999;

    pMessageBox(0,0,0,0);


}

void __declspec(naked) angy_EndOfHappyCode(void)
{
}


Далее в одной из функций пишу:
Код

DWORD dwCodeSize=((DWORD)&angy_EndOfHappyCode) - ((DWORD)&angy_StartOfHappyCode);


И в dwCodeSize получаю очень большое (явно неверное) значение. Идея взята (практически дословно) из BO2k, там прекрасно работает. Уже час бьюсь, так и не разобрался.

Где ошибка?

З.Ы. Подозреваю, что где-то в опциях компиляции, но никак не могу понять, где именно. Оптимизации вроде все по отключал. Среда: VS 2005.

Автор: MAKCim 3.1.2008, 01:37
nadge
с чего ты взял, что код функций располагается последовательно?

Автор: nadge 3.1.2008, 04:26
MAKCim, я видел работающий пример, идентичный моему - http://www.bo2k.com/, файл исходника называется process_hop.cpp. (Здесь код не привожу т.к. все полностью как у меня.)


ОК, переформулирую вопрос иначе. Что нужно сделать, чтобы код располагался последовательно?

Автор: pompei 3.1.2008, 06:58
Ни чё нельзя!!!

Автор: W4FhLF 3.1.2008, 08:32
Единственное верное решение: использовать дизассемблер длин машинных инструкций:

Код

#include "LDasm.h"
#include "windows.h"
#include "stdio.h"

void HappyCode()
{    
    MessageBox(0,0,0,0);
}

int main(int argc, char* argv[])
{
    unsigned int dwCodeSize = SizeOfProc(&HappyCode);
    printf("%lu bytes", dwCodeSize);
    return 0;
}



Проект в аттаче.


Автор: W4FhLF 3.1.2008, 08:33
Цитата(nadge @  3.1.2008,  04:26 Найти цитируемый пост)
Что нужно сделать, чтобы код располагался последовательно?


Это невозможно сделать в рамках стандартных компиляторов. 

Автор: Damarus 3.1.2008, 09:43
Цитата(W4FhLF @  3.1.2008,  08:32 Найти цитируемый пост)
Единственное верное решение: использовать дизассемблер длин машинных инструкций:

Относительно верное smile В результате оптимизации в функции может быть несколько инструкций ret.

Автор: W4FhLF 3.1.2008, 10:13
Damarus, верно, поэтому перед использованием всё-таки надо пихнуть программу в дизассемблер smile 

Автор: MAKCim 3.1.2008, 10:31
не знаю как в PE
но элемент таблицы символов ELF файла может содержать размер символа (функции)
при обычных настройках компилятора/компоновщика эта информация генерируется
в процессе работы программы ее можно получить
кроме того, почему нельзя сделать так

Автор: W4FhLF 3.1.2008, 10:54
Цитата(nadge @  3.1.2008,  04:26 Найти цитируемый пост)
MAKCim, я видел работающий пример, идентичный моему - http://www.bo2k.com/, файл исходника называется process_hop.cpp. (Здесь код не привожу т.к. все полностью как у меня.)


Кстати, ты наверное компилировал в debug? Попробуй в release. 

Ещё можно так:

Код

#include "windows.h"
#include "stdio.h"

void HappyCode()
{    
    MessageBox(0,0,0,0);
    __asm
    {
        nop
        int 3
        nop
        int 3
    }
}

int main(int argc, char* argv[])
{
    
    PCHAR dwCodeEnd = (PCHAR)HappyCode;
    while (*(PULONG)dwCodeEnd != 0xCC90CC90)
        ++dwCodeEnd;

    ULONG dwCodeSize = (ULONG)(dwCodeEnd - (PCHAR)HappyCode);
    // dwCodeSize += 5; (размер ассемблерной вставки и инструкции ret)
    printf("%lu bytes\n", dwCodeSize);
    return 0;
}

Автор: MAKCim 3.1.2008, 11:11
W4FhLF
забыл учесть размер leave (или ручного аналога)

Автор: W4FhLF 3.1.2008, 11:28
MAKCim, в моём случае его небыло.

Автор: nadge 3.1.2008, 16:07
Цитата
Это невозможно сделать в рамках стандартных компиляторов. 

Ну, в вышеприведенном BO2k как-то же сделали?

Цитата
Кстати, ты наверное компилировал в debug? Попробуй в release. 

И так и так, хотя release не особо тщательно проверял. Перепроверю.

Цитата
Ещё можно так:

Кстати, хороший вариант. 

Только в моем случае довольно неудобный, т.к. функций таких будет штук 30, если не больше. 






Автор: W4FhLF 3.1.2008, 17:03
Цитата(nadge @  3.1.2008,  16:07 Найти цитируемый пост)
Ну, в вышеприведенном BO2k как-то же сделали?


Знаю только, что VS _обычно_ не меняет порядок, но даже если порядок не меняется между процедурами может идти мусор, так что этот способ не рулит. 


Цитата(nadge @  3.1.2008,  16:07 Найти цитируемый пост)
Только в моем случае довольно неудобный, т.к. функций таких будет штук 30, если не больше. 


Но разве удобней пихать туеву кучу пустышек вместо этого? 

Note: Зачем нужна "angy_StartOfHappyCode"? Можно сразу брать &HappyCode.

Автор: nadge 3.1.2008, 17:25
Цитата
Но разве удобней пихать туеву кучу пустышек вместо этого? 

Note: Зачем нужна "angy_StartOfHappyCode"? Можно сразу брать &HappyCode.

Предполагалось написать примерно так:

Код

void __declspec(naked) angy_StartOfHappyCode(void)
{
}

void HappyFunc1()
{    
   // тут какой-то код
}

void HappyFunc2()
{    
   // тут какой-то код
}

void HappyFunc3()
{    
   // тут какой-то код
}

void HappyFunc4()
{    
   // тут какой-то код
}

void HappyFunc5()
{    
   // тут какой-то код
}

void HappyFunc6()
{    
   // тут какой-то код
}

void __declspec(naked) angy_EndOfHappyCode(void)
{

}

Т.е. весь код должен быть вместе, а не каждая ф-ция по-отдельности. В таком случае пустышки весьма удобны хотя бы для наглядности.


Автор: W4FhLF 3.1.2008, 18:15
Какова задача в общем?

Автор: MAKCim 3.1.2008, 18:31
Цитата(W4FhLF @  3.1.2008,  11:28 Найти цитируемый пост)
MAKCim, в моём случае его небыло. 

хочешь сказать, что ret был сгенерирован до твоего кода?

Автор: nadge 3.1.2008, 20:12
Цитата
Какова задача в общем?

Создать (относительно большой) базонезависимый код для запуска его в адресном пр-ве другого процесса, куда его сперва нужно будет скопировать.

С деталями написания самого кода более-менее разобрался, а вот такая, как мне казалось, простая функция, как его копирование не получается.


Автор: W4FhLF 3.1.2008, 21:20
Цитата(MAKCim @  3.1.2008,  18:31 Найти цитируемый пост)
хочешь сказать, что ret был сгенерирован до твоего кода?


может я что-то не так понял?

Код

00401000   .  PUSH    0                                ; /Style = MB_OK|MB_APPLMODAL
00401002   .  PUSH    0                                ; |Title = NULL
00401004   .  PUSH    0                                ; |Text = NULL
00401006   .  PUSH    0                                ; |hOwner = NULL
00401008   .  CALL    DWORD PTR DS:[<&USER32.MessageBo>; \MessageBoxW
0040100E   .  NOP
0040100F   .  INT3
00401010   .  NOP
00401011   .  INT3
00401012   .  RETN



Цитата(nadge @  3.1.2008,  20:12 Найти цитируемый пост)
С деталями написания самого кода более-менее разобрался, а вот такая, как мне казалось, простая функция, как его копирование не получается.


Пользуйся лучше способом с поиском сигнатуры, это самый оптимальный вариант, имхо. 
Вообще, всё зависит от твоей реализации базонезависимого кода, ибо там тонкостей достаточно много. Если ты решил ещё и вызовы процедур делать в нём(своих же), то всё усложняется, тут конечно было бы идеально, если бы ты в том процессе расположил процедуры именно так(относительно друг друга), как они расположены в твоём процессе, ибо иначе придётся тебе править операнды вручную. 

Автор: nadge 3.1.2008, 22:02
Мой вариант (с расположением функций в той последовательности, что в исходнике) хорош в первую очередь своей простотой. Базонезависимый код будет большой, по этому не хочется ни на что отвлекаться (например, на предложенные сигнатуры), чтобы не собирать потом ошибки. К тому же последовательное расположение ф-ций сильно упростит из взаимный вызов (который там очень важен, хотя и решается созданием массива с адресами ф-ций и глобальных переменных).


Самое интересное другое - ведь получается же такая штука в приведенном мною примере с back orifice 2k. Там тот же VC++ используется. Опции компилятора изучал, переносил в свою программу - не помогло.




Автор: dumb 3.1.2008, 23:52
Цитата(nadge @  3.1.2008,  22:02 Найти цитируемый пост)
Базонезависимый код будет большой
развей мои сомнения - приведи небольшой кусок из твоего "базонезависимого кода".

Автор: Любитель 4.1.2008, 00:36
Цитата(Damarus @  3.1.2008,  09:43 Найти цитируемый пост)
Относительно верное  В результате оптимизации в функции может быть несколько инструкций ret.

Не только. А если это не cdecl функция? smile 99% она на retn будет заканчиваться.

Added: точнее, если stdcall, по крайней мере.

Цитата(W4FhLF @  3.1.2008,  21:20 Найти цитируемый пост)
может я что-то не так понял?

Просто у функции нет параметров smile

Добавлено @ 00:40
Цитата(W4FhLF @  3.1.2008,  17:03 Найти цитируемый пост)
Знаю только, что VS _обычно_ не меняет порядок

Угу. Да и большинство компилеров. Но (!) в дебаге будет сгенерена табличка стабов вида jmp <функция> - они и будут вызываться кругом. Нафига это не помню - но где-то когда-то читал разъяснение.

Цитата(nadge @  3.1.2008,  22:02 Найти цитируемый пост)
хорош в первую очередь своей простотой

И плох сомнительностью своей работы smile Впрочем всё-таки отталкиваться ИМХО лучше от него, но учитывать его потенциальную нестабильность smile Так чё насчёт релиза?

Автор: nadge 4.1.2008, 01:04
Цитата
Впрочем всё-таки отталкиваться ИМХО лучше от него, но учитывать его потенциальную нестабильность

Про нестабильность - это точно.

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

Пока не могу сказать, что проблема решена - надо еще потестировать. Но вроде все ОК. 

Цитата
Так чё насчёт релиза?

Всмысле, собрать как релиз? Само по себе это не помогло. Хотя щас все так собираю, для отладки пользуюсь софтайсом.

Автор: Любитель 4.1.2008, 01:16
Цитата(nadge @  4.1.2008,  01:04 Найти цитируемый пост)
Само по себе это не помогло.

И не должно... Просто с дебагом по идее вообще не прокатит, из-за этих стабов для функций.

Автор: _n0 13.2.2008, 00:55
Актуально сейчас или нет, но изложу ещё один вариант. Он будет несколько корректнее в плане того, чтобы перенести весь необходимый код.
Целевые функции стоит выделить в отдельную секцию (используя #pragma code_seg либо #pragma section).
Чтобы это счатье выдрать -  чуть больше работы нужно будет, чем в уже приводившихся способах, зато надёжней. Просто напросто нужно пробежаться по PE-заголовку образа в памяти и получить адрес и размер секции. Её и копируем в нужный процесс. Относительное расположение в ней элементов можно найти разностью адреса функции в нашем процессе и уже вычисленного адреса секции.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)