Зачарованные функции 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?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.