Зачарованные функции main и WinMain
От: BioUnit Россия  
Дата: 21.03.08 00:01
Оценка:
Вот столкнулся с волшебством...

Есть код:
#pragma comment(linker,"/SECTION:.text,EWR")

__declspec(naked)
void stub()
{
    __asm ret 
}

int main()
{
    stub();

    unsigned char* p = (unsigned char*)main;
    for(int i=-8; i<8; i++) {
        p[i] = 0xDD;
    }

    return 0;
}

Функция stub введена лишь для того, чтоб секция кода начиналась не с функции main.

Что по идее должно произойти: должны затереться 8 байт до функции main и 8 байт внутри её.

Проверяю...

Дамп памяти до выполнения цикла:
0x00401008  cc cc cc cc cc cc cc cc e8 eb ff ff ff b9 dd dd

Дамп памяти после:
0x00401008  dd dd dd dd dd dd dd dd e8 dd dd dd dd dd dd dd

Не верю своим глазам, ячейка 0x00401010 (e8) не затерлась. Это первый байт функции main.

Добавляю после цикла сброс кеша:
FlushInstructionCache(GetCurrentProcess(), 0, 0);
Ноль эмоций, дамп тот же.

Делаю другой эксперимент (теперь stub нужен чтоб не затиралась start):
#pragma comment(linker,"/SECTION:.text,EWR")
#pragma comment(linker,"/ENTRY:start")

int main();

__declspec(naked)
void start()
{
    __asm int 3

    register unsigned char* p;
    p = (unsigned char*)main;
    for(int i=-8; i<8; i++) {
        p[i] = 0xDD;
    }

    __asm ret 
}

__declspec(naked)
void stub()
{
    __asm ret 
}

int main()
{
    stub();
    stub();
    return 0;
}

Получаю такое же неубиваемое e8 !
Проверяю с FlushInstructionCache, дамп без изменений.

Ставлю еще один эксперимент,- добавляю функцию WinMain. Причем это просто имя, т.к. сигнатура функции иная (нет параметров, тет WINAPI, не подключаю windows.h), и приложение оставляю консольным:
#pragma comment(linker,"/SECTION:.text,EWR")
#pragma comment(linker,"/ENTRY:start")

int WinMain();
int main();

__declspec(naked)
void start()
{
    __asm int 3

    register unsigned char* p;

    p = (unsigned char*)main;
    for(int i=-8; i<8; i++) {
        p[i] = 0xDD;
    }

    p = (unsigned char*)WinMain;
    for(int i=-8; i<8; i++) {
        p[i] = 0xBB;
    }

    __asm ret 
}

__declspec(naked)
void stub()
{
    __asm ret 
}

int main()
{
    stub();
    stub();
    stub();
    return 0;
}

int WinMain()
{
    stub();
    stub();
    return 0;
}

Компилятор возмущается
warning C4007: 'WinMain' : must be '__stdcall'
но проект собирается.

Запускаю...

Дамп до:
0x00401048  cc cc cc cc cc cc cc cc e8 eb ff ff ff e8 e6 ff    // main

0x00401068  cc cc cc cc cc cc cc cc e8 cb ff ff ff e8 c6 ff    // WinMain

Дамп после:
0x00401048  dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd    // main

0x00401068  bb bb bb bb bb bb bb bb e8 bb bb bb bb bb bb bb    // WinMain

Аллилуя! main затерлась, но теберь "болезни" подвержена функция WinMain !

Перемещаю WinMain относительно main вперед по коду. Все равно недозатирается WinMain.

Делаю "контрольный в голову" — переименовываю WinMain в WunMoon. Повторяется картина, как во втором эксперименте, т.е. вновь не затирается main.

Так что за странность такая?
Что за волшебные имена main и WinMain?
Re: Зачарованные функции main и WinMain
От: BioUnit Россия  
Дата: 21.03.08 00:06
Оценка:
Забыл добавить: все это в MSVC 2005, на чем либо ином не проверял.
Re[2]: Зачарованные функции main и WinMain
От: 8bit  
Дата: 21.03.08 06:46
Оценка:
Здравствуйте, BioUnit, Вы писали:

смотрел на VS2005 express, в релизе, все прекрасно затирается.
Re[3]: Зачарованные функции main и WinMain
От: BioUnit Россия  
Дата: 21.03.08 07:24
Оценка:
Здравствуйте, 8bit, Вы писали:

8>смотрел на VS2005 express, в релизе, все прекрасно затирается.


Первый пример у меня сегодня тоже заработал... сам по себе...
Остальные все так же не работают.
Re[4]: Зачарованные функции main и WinMain
От: 8bit  
Дата: 21.03.08 10:44
Оценка:
Здравствуйте, BioUnit, Вы писали:

BU>Первый пример у меня сегодня тоже заработал... сам по себе...

BU>Остальные все так же не работают.

Попробовал самый последний пример, все ок.
Через что смотрите? Я через ollydbg.
Re[5]: Зачарованные функции main и WinMain
От: BioUnit Россия  
Дата: 21.03.08 15:03
Оценка:
Здравствуйте, 8bit, Вы писали:

8>Попробовал самый последний пример, все ок.

8>Через что смотрите? Я через ollydbg.

До этого пробовал стандартный идущий с MSVS.
Сегодня попробовал отлаживаться в IDA, и действительно все затирается.
Значит, это только проблема MSVS деббагера...
Но для чего ему лочить эти несчастные байты?
Re[6]: Зачарованные функции main и WinMain
От: CreatorCray  
Дата: 21.03.08 15:09
Оценка: 6 (1) +1
Здравствуйте, BioUnit, Вы писали:

BU>Значит, это только проблема MSVS деббагера...

BU>Но для чего ему лочить эти несчастные байты?
возможно он туда подставляет точки останова и в дебугере показывает те значения, которые там были или же после отработки функции снимает точки останова, возвращая прежние значения.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Зачарованные функции main и WinMain
От: Аноним  
Дата: 21.03.08 15:46
Оценка: 6 (1)
под дебагом запускаете небойсь? дык дебагер ставит брякпоинт на точку входа в программу. Брякпоинт — это int 3, опкод cc. Когда дебагер приходит в какой либо брякпоинт, он восстанавливает предыдущее значение во всех остальных брякпоинтах включая начало main, т.е. записывает туда изначаьный байт, который был там до вашего мегапатча. А вообще откровенно говоря фигней вы какой то страдаете.
Re[7]: Зачарованные функции main и WinMain
От: BioUnit Россия  
Дата: 21.03.08 17:28
Оценка:
Здравствуйте, CreatorCray, Вы писали:

CC>Здравствуйте, BioUnit, Вы писали:


BU>>Значит, это только проблема MSVS деббагера...

BU>>Но для чего ему лочить эти несчастные байты?
CC>возможно он туда подставляет точки останова и в дебугере показывает те значения, которые там были или же после отработки функции снимает точки останова, возвращая прежние значения.

Да, похоже, что это как-то связано с брейкпоинтами. Только не понятно, почему дебаггер реагирует именно на имена функций, причем не на экспортируемые, а на те, что в дебагинфо. И почему он отдает предпочтение WinMain.
Re[2]: Зачарованные функции main и WinMain
От: BioUnit Россия  
Дата: 21.03.08 17:30
Оценка:
Здравствуйте, Аноним, Вы писали:

А>под дебагом запускаете небойсь? дык дебагер ставит брякпоинт на точку входа в программу. Брякпоинт — это int 3, опкод cc. Когда дебагер приходит в какой либо брякпоинт, он восстанавливает предыдущее значение во всех остальных брякпоинтах включая начало main, т.е. записывает туда изначаьный байт, который был там до вашего мегапатча. А вообще откровенно говоря фигней вы какой то страдаете.


Если бы Вы внимательно почитали топик и посмотрели бы код, то заметили бы, что точка входа в программу совсем не main, и уж тем более не WinMain.
Возможно дебаггер и ставит брейкпоинты в начало main или WinMain, но делает он это странным образом — основываясь лишь на имени функции, а не на её сигнатуре, информацией о том, является ли она входной точкой, а в случае существования двух имен main и WinMain отдает предпочтение WinMain. И делает это только дебаггер идущий с MSVS.

Надеюсь, я не очень испортил Вам жизнь своей "фигней".
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.