Pull to refresh

Comments 18

Разместите вторую gif-ку покадрово, пожалуйста.
Эх. Помню я как-то я журнале ZX-формат соревновались у кого меньше байт будет для плавной гасилки экрана. Вот были времена, когда программу в 21 байт укладывали.
А где текст самой программы? Наверняка, общими усилиями сможем сделать меньше
Ещё не всё прочитал, но навскидку:

Существующие примеры программ размером 268 байт не содержат ни одной секции, и фактически, целиком помещаются внутри заголовка PE, для загрузки которого Windows выделяет одну страницу памяти (4КБ).
Для загрузки заголовка выделяется ALIGN_UP(SizeOfHeaders, max(SectionAlignment, PAGE_SIZE)). Так что можно поставить SizeOfHeaders больше страницы и без секций обойтись.

На WinXP моя программа, к сожалению, не работает: та отказывается загружать программы, у которых в каталоге менее 0xD записей.
Там просто часть кода поддержки совместимости смотрит на Directories[DEBUG].Size, не проверяя, что DEBUG действительно есть. Если выставить соответствующий dword в нуль, всё будет работать.
Минуточку. На XP SP3 оно вполне работает. (DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size у вас хоть и не 0, но 3, но пока оно меньше 0x1C, это нормально.) При отсутствии IMAGE_DIRECTORY_ENTRY_IAT = 0xC в XP есть засада, что таблица импорта должна быть в какой-нибудь секции, не в заголовке, но это проблема, только если делать программу целиком в заголовке без секций.
Как-то странно оно работает. Один и тот же файл запускаю — то запускается нормально, то выскакивает «Application Error: The application failed to initialize properly (0xc000007b). Click on OK to terminate the application.»
Поди, опять что-нибудь связанное с файловым кэшем.

(Всё равно спасибо за подсказку! Исправил пост, чтобы указать, что на WinXP программа иногда работает.)
У меня на виртуалке запускается совершенно стабильно. Ошибка явно от юзермодного загрузчика, ему на файловый кэш должно быть ну совсем пофиг.
WinDbg на машине есть?
WinDbg есть, но не помогает — ошибка вываливается ещё до DbgBreakPoint внутри LdrpInitializeProcess:



Не исключено, что это шалит стоящий на машине антивирус (Symantec), но с ним я сделать ничего не могу — машина не моя, я только запустил программу.
У WinDbg в настройках можно включить Debug -> Event filters -> Create process -> enabled, перезагрузить процесс, сделать bu ntdll!LdrInitializeThunk, g, и отлаживать совсем с начала.

Но у меня появилась мысль, что может быть не так.
часть таблицы импорта (последние 0x16 её байт нулевые, и в файле не хранятся)
Если честно добить файл нулями, проблема будет воспроизводиться?
Окей, исключение прилетает отсюда:

ntdll!_LdrpInitialize+0x178:
7c84a446 57              push    edi
7c84a447 e85e530100      call    ntdll!LdrpInitializationFailure (7c85f7aa)
7c84a44c 57              push    edi
7c84a44d e890e0fdff      call    ntdll!RtlRaiseStatus (7c8284e2)
7c84a452 cc              int     3

Выше по стеку вызовов — только ntdll!KiUserApcDispatcher+0x25

Если честно добить файл нулями, проблема будет воспроизводиться?

Да.
Естественно. LdrpInitializeProcess возвращает 0xC000007B, а уже верхний уровень бросает исключение.
Тупой способ выяснить, откуда оно — после останова на LdrInitializeThunk выполнить команду
r;t;z(eax!=c000007b)
подождать, посмотреть, где остановилось, и посмотреть команды перед этим — чтобы понять, почему управление дошло до этой ветки кода.
Более интеллектуальный — настроить символы
.sympath SRV*c:\symcache*http://msdl.microsoft.com/download/symbols
.reload
(папку c:\symcache потом можно почистить), поставить bp ntdll!LdrpSnapIAT, дождаться второго срабатывания (первый вызов — для kernel32 -> ntdll) и запустить команду выше уже с этого момента.
При отсутствии IMAGE_DIRECTORY_ENTRY_IAT = 0xC в XP есть засада, что таблица импорта должна быть в какой-нибудь секции, не в заголовке, но это проблема, только если делать программу целиком в заголовке без секций.

Возвращаясь к старой теме: у меня на Windows 10, если нет секций и загружается только заголовок, то импорты не резолвятся. Получается, что программу без секций вообще нет смысла делать: десять лишних IMAGE_DATA_DIRECTORY занимают намного больше места, чем одна IMAGE_SECTION_HEADER.
Для загрузки заголовка выделяется ALIGN_UP(SizeOfHeaders, max(SectionAlignment, PAGE_SIZE)). Так что можно поставить SizeOfHeaders больше страницы и без секций обойтись.

А можно пример? А то у меня с SizeOfHeaders больше 0x1000 прога напрочь отказывается загружаться.
На XP и семёрке, казалось бы, никаких проблем: yadi.sk/d/4yHs4lWioPtmW
В восьмёрке добавили несколько странную проверку, что EntryPoint должна быть либо 0, либо не меньше SizeOfHeaders, причём 0 для exe-шника — валидное значение (MZ = dec ebp, pop edx), так что можно так: yadi.sk/d/jY0Tn_lSoPvGc
Но вообще формула выше — таки только для ветки с SectionAlignment >= PAGE_SIZE, на ветке с SectionAlignment < PAGE_SIZE весь файл просто маппится одним куском, так что можно просто сделать ImageSize побольше и даже не менять SizeOfHeaders: yadi.sk/d/c_Oc3oyooPwS8
если хотя бы одна секция объявлена, то FileAlignment должен быть не меньше 0x200, а SectionAlignment должен быть 0x1000

Строго говоря, можно. Например, если размеры всех секций кратны 0x1000, то проблем не будет и при SectionAlignment, меньшем размера страницы. (Вообще-то, соответствующий код в подсистеме WOW64 писался не под энтузиастов минимизации вроде нас с вами, а ровно под такую ситуацию. Конкретно — эмуляция x86 на Itanium, где винда использует размер страницы 0x2000.) Но не очень полезно — если честно записывать все дополняющие нули в файл, то о минимизации размера можно забыть, а если не писать, то винда от такой наглости может даже в BSOD выпасть. (ЕМНИП починили где-то между XP SP1 и SP2. Это к вопросу о винтажности. Хотя, конечно, истинно винтажная система — Windows 95.)
Sign up to leave a comment.

Articles