Как изменить вес exe файла

Как изменить размер exe файла, не мешая его работе? C++ Решение и ответ на вопрос 2857320

1 / 1 / 0

Регистрация: 19.06.2018

Сообщений: 173

1

09.07.2021, 16:04. Показов 1237. Ответов 4


Добрый день, возник вопрос, как изменить размер exe файла на +- 10кб, но при этом, чтобы он работал стабильно.

Добавлено через 4 минуты
Можно изменить метадату файла, но это вероятно не будет занимать 10 кб

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

09.07.2021, 16:04

4

-253 / 68 / 21

Регистрация: 08.05.2021

Сообщений: 289

09.07.2021, 16:46

2

strip <your-file>. Либо винковать что-нибудь.



0



Эксперт С++

3222 / 2481 / 429

Регистрация: 03.05.2011

Сообщений: 5,158

Записей в блоге: 21

09.07.2021, 22:53

3

Вопрос — что вам дадут эти 10 килобайт?
По сабжу: ручная пересборка секций va и rva с удалением пустот из нулевых байт в PE.



0



Just Do It!

3427 / 1897 / 624

Регистрация: 23.09.2014

Сообщений: 6,001

Записей в блоге: 1

11.07.2021, 18:36

4

Цитата
Сообщение от shuraros1
Посмотреть сообщение

Как изменить размер exe файла, не мешая его работе?

вот здесь я игрался:
Добавить текстовый файл в проект в качестве ресурса
там патчился ексешник во время его работы.

ещё такая была тема:
Внедрение картинки в исполняемый файл

как оно там влияет на работоспособность, то я хз,
лично у меня во время моих тестов артефактов обнаружено не было.



0



587 / 561 / 91

Регистрация: 29.05.2015

Сообщений: 3,615

13.07.2021, 23:58

5

Просто дописать какие-нибудь байты в конец файла не получится?



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

13.07.2021, 23:58

Помогаю со студенческими работами здесь

Как уменьшить размер EXE файла?
Люди, подскажите, пожалуйста, что можно отключить, чтобы скомпилённый экзешник стал немного…

Как уменьшить размер exe файла?
Всем привет, начал изучать c++ и меня очень смутило то, что exe файл даже простого hello world…

Как уменьшить размер exe-файла?
Создал элементарную программку на lazarus. Прога — только одна форма и одна кнопка, а exe весит 14…

Как уменьшить размер exe-файла?
Exe весит 10 мб. , не могу понять почему. Сначала думал что фоновые картинки и кнопки ( кнопками…

Как изменить размер текста в зависимости от его длины в кнопке?
У меня есть кнопка, с каждым кликом по ней у нее меняется текст. Но бывает, что текст большой длины…

Как изменить размер фонта у виджета и всех его детишек?
QDialog *mw = new QDialog();
mw-&gt;font().setPixelSize(16);
Дает error:
passing `const QFont’…

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

5

  • Download unchanged project — 16K
  • Download project reduced with these techniques — 9K

    Introduction

    A few days back I was assigned a challenging task of writing a Win32 application performing tasks (as defined by our client). But the client required that the final exe file size to be less than 50K. With this kind of size limit we immediately had to give up an MFC based solution, a tough decision to make in most cases :). I am very comfortable with MFC and never had bothered about final file size. But for this specific project I had to dig into pure Win32 SDK to get things done. The project was started and the first prototype was sized about 36K and everyone was happy. But problems were raised when we started implementing the user requirements and one day we found that the size of the exe file in release mode had exceeded the 50K limit. And when the final product was about to be shipped the size had reached about 72K. We were thinking about re-nagotiating the size limit with our client. Fortunately I posted a question on one of the Microsoft news threads and got some prompt replies. I tried to test the instructions that I received from the news thread on my application, and the result were simply amazing, my file size reduced to 35K resulting in about 50% files size reduction. We were happy and so was our client :)

    So what are those magic tricks? Actually all you have to do is to instruct compiler to leave out unnecessary code from your application. If you create a simple HelloWorld Win32 Application from the app wizard and compile it in release mode, the resulting exe file size is 24K. Too much for a simple «Hello World» application. Now, perform the following steps:

    1. Create another similar project workspace, i.e. another «Hello World» project.
    2. Select active build configuration to be «Win32 Release».
    3. Open project setting and select the «Link» tab. Remove all the library file names from the «Object/library modules:» edit box and type «MSVCRT.LIB kernel32.lib user32.lib». Press OK and compile, the final exe file size is reduced to 16K. You might get a linker warning like «LINK : warning LNK4098: default lib "LIBC" conflicts with use of other libs; use /NODEFAULTLIB:library«. This can be avoided by clicking «Ignore all default libraries» from the Link tab of Project Settings.
    4. The further magic is done by using /ALIGN linker option. You can see MSDN for further details about this linker option. Again go to the «Project Settings», «Link» tab. Type /ALIGN:4096 in the Project Options edit box. Press OK and rebuild your project. The size is further reduced to 3K. The compiler generates a linker warning «LINK : warning LNK4108: /ALIGN specified without /DRIVER or /VXD; image may not run«. If you have followed my instructions properly, your exe file should run properly. I played around with the /ALIGN linker directive and figured out that if you use /ALIGN:4096 the produced exe file runs properly.

    That’s it, we have reduced size of our Hello World app from 24K to 3K. There are some other options that you can try in this regard:

    1. You can run some symbol stripper utility on the final exe file. It helps reducing size in many cases. One such utility can be found at neoworx.com.
    2. There is a utility named ASPack, this utility also helps in compressing your exe files up to 50%.

    MFC

    I haven’t yet tried these tricks with MFC projects, so results are unpredictable. But that should not stop you from trying these options on MFC projects.

  • This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.

  • Download unchanged project — 16K
  • Download project reduced with these techniques — 9K

    Introduction

    A few days back I was assigned a challenging task of writing a Win32 application performing tasks (as defined by our client). But the client required that the final exe file size to be less than 50K. With this kind of size limit we immediately had to give up an MFC based solution, a tough decision to make in most cases :). I am very comfortable with MFC and never had bothered about final file size. But for this specific project I had to dig into pure Win32 SDK to get things done. The project was started and the first prototype was sized about 36K and everyone was happy. But problems were raised when we started implementing the user requirements and one day we found that the size of the exe file in release mode had exceeded the 50K limit. And when the final product was about to be shipped the size had reached about 72K. We were thinking about re-nagotiating the size limit with our client. Fortunately I posted a question on one of the Microsoft news threads and got some prompt replies. I tried to test the instructions that I received from the news thread on my application, and the result were simply amazing, my file size reduced to 35K resulting in about 50% files size reduction. We were happy and so was our client :)

    So what are those magic tricks? Actually all you have to do is to instruct compiler to leave out unnecessary code from your application. If you create a simple HelloWorld Win32 Application from the app wizard and compile it in release mode, the resulting exe file size is 24K. Too much for a simple «Hello World» application. Now, perform the following steps:

    1. Create another similar project workspace, i.e. another «Hello World» project.
    2. Select active build configuration to be «Win32 Release».
    3. Open project setting and select the «Link» tab. Remove all the library file names from the «Object/library modules:» edit box and type «MSVCRT.LIB kernel32.lib user32.lib». Press OK and compile, the final exe file size is reduced to 16K. You might get a linker warning like «LINK : warning LNK4098: default lib "LIBC" conflicts with use of other libs; use /NODEFAULTLIB:library«. This can be avoided by clicking «Ignore all default libraries» from the Link tab of Project Settings.
    4. The further magic is done by using /ALIGN linker option. You can see MSDN for further details about this linker option. Again go to the «Project Settings», «Link» tab. Type /ALIGN:4096 in the Project Options edit box. Press OK and rebuild your project. The size is further reduced to 3K. The compiler generates a linker warning «LINK : warning LNK4108: /ALIGN specified without /DRIVER or /VXD; image may not run«. If you have followed my instructions properly, your exe file should run properly. I played around with the /ALIGN linker directive and figured out that if you use /ALIGN:4096 the produced exe file runs properly.

    That’s it, we have reduced size of our Hello World app from 24K to 3K. There are some other options that you can try in this regard:

    1. You can run some symbol stripper utility on the final exe file. It helps reducing size in many cases. One such utility can be found at neoworx.com.
    2. There is a utility named ASPack, this utility also helps in compressing your exe files up to 50%.

    MFC

    I haven’t yet tried these tricks with MFC projects, so results are unpredictable. But that should not stop you from trying these options on MFC projects.

  • This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.

    Уменьшение размера исполняемого файла в Lazarus

    Cоздаваемые в Lazarus исполняемые файлы имеют довольно большой размер. Причин несколько. Во-первых, в exe-файле сохраняется вся отладочная информация. Во вторых — создаваемый exe-файл оптимизирован под скорость выполнения, а не под размер.

    Чтобы уменьшить размер исполняемого файла необходимо в свойствах проекта (Проект — Параметры проекта) включить 4 ключа компиляции:

    1) Вкладка Генерация кода: установить флажок «Умная компоновка» (-СХ);
    2) Вкладка Компоновка: установить флажок «Умная компоновка» (-ХХ);
    3) Вкладка Компоновка: установить флажок «Использовать внешний файл отладочных символов GDB»(-Xg);
    4) Вкладка Компоновка: установить флажок «Вырезать символы из исполняемого файла»(-Xs).

    Уменьшение размера исполняемого файла в Lazarus

    Эта настройка позволяет сократить размер исполняемого файла в несколько раз. (Пустой проект с 12 МБ сокращается до 1 МБ).

    Однако, можно еще сократить размер, если воспользоваться утилитами strip.exe и upx.exe. Первая вырезает из файла отладочную информацию, вторая сжимает запускаемый файл. Удобно создать bat-файл

    compress.bat

    и запускать сжатие одной командой:

    Утилиты прикреплены ниже.

    Прикрепленный файл Размер
    Утилиты компрессии exe-файла Lazarus 401.35 кб

    Комментарии

    Здравствуйте,создал проект написал программу на лазарус,потом выставил и убрал все галочки для удаления отладочной инфы, сохранил и собрал проект ..но размер файла как был мегабайтный так ничего и не изменилось..
    что я делаю не так?
    и второй вопрос: скачал я утилиты компрессии exe-файла лазарус и как ими пользоваться?
    если есть возможность объясните мне эти два вопроса по шагам
    с Уважением Юрий

    CompactGUI — легко сжимаем тяжёлые программы и игры

    CompactGUI — это графический интерфейс для системной утилиты compact.exe, который предлагается использовать нам с вами для сжатия тяжёлых программ, игр или просто объёмных папок и файлов. Программа очень проста в использовании: в большинстве случаев пользователю достаточно указать путь к нужной папке и воспользоваться кнопкой Compress folder.

    CompactGUI — легко сжимаем тяжёлые программы и игры

    CompactGUI — легко сжимаем тяжёлые программы и игры

    Опытным пользователям CompactGUI предоставляет возможность выбрать один из четырёх доступных алгоритмов сжатия, воспользоваться или отказаться от функция сжатия подпапок, скрытых и системных файлов. Программа умеет автоматически выключать или перезагружать компьютер по завершении операции сжатия и уведомлять пользователя о результатах работы. Для большего удобства CompactGUI можно интегрировать в контекстное меню Проводника.

    CompactGUI — легко сжимаем тяжёлые программы и игры

    CompactGUI — легко сжимаем тяжёлые программы и игры

    Объём освобождаемого дискового пространства может отличаться в зависимости от выбранного алгоритма сжатия. В ходе тестирования мы легко умерили «вес» папки, в которую установлены некоторые популярные приложения Adobe (Fireworks, Dreamweaver, Premier) почти в два раза: с 3,1 до 1,5 ГБ. Никакого ущерба для скорости загрузки приложений или надёжности их использования на нашей тестовой системе (Intel Core i3/16 ГБ DDR3/120 ГБ SSD) мы не заметили вообще. Заметим, что использовать compact.exe на откровенно слабых машинах с небольшим объёмом оперативной памяти не рекомендует сама Microsoft.

    CompactGUI — легко сжимаем тяжёлые программы и игрыCompactGUI — легко сжимаем тяжёлые программы и игры

    Распространяется программа бесплатно, с открытым исходным кодом, новейшая версия всегда доступна на официальной странице на GitHub . Русский язык для интерфейса в текущей версии не поддерживается.

    Что такое ASPack?

    ASPack – усовершенствованная программа-упаковщик, предназначенная для сжатия исполняемых файлов EXE под Win32 и защиты от непрофессионального реверс-инжиниринга.

    Решение уменьшает размер файлов и библиотек под Windows до 70% (степень сжатия выше стандарта ZIP на 10-20%), a также сокращает время загрузки таких приложений в локальных сетях и Интернет.

    ASPack также защищает программы от непрофессионального анализа и декомпиляции. Приложения, сжатые при помощи ASPack, являются автономными и запускаются так же, как и до сжатия, без потери времени и ухудшения производительности.

    Я хочу создать фиктивный EXE-файл Win32, который намного больше, чем должен быть. Таким образом, по умолчанию размер стандартного Win32 EXE-файла составляет 80 КБ. Мне нужен 5 МБ для тестирования других утилит.

    Первая идея — добавить ресурс, но, как оказалось, встроенные ресурсы — это не то же самое, что 5 МБ кода, когда дело доходит до выделения памяти. Я думаю, что могу сослаться на большую библиотеку и получить огромный EXE-файл? Если нет, возможно, написать несколько тысяч подобных методов, таких как AddNum1, AddNum2 и т. Д., И т. Д.?

    Любые простые идеи очень ценятся.

    19 ответы

    Используйте большой массив постоянная данные, такие как явные строки:

    char *dummy_data[] = {
        "blajkhsdlmf..(long script-generated random string)..",
        "kjsdfgkhsdfgsdgklj..(etc...)...jldsjglkhsdghlsdhgjkh",
    };
    

    В отличие от переменных данных, постоянные данные часто попадают в тот же раздел памяти, что и фактический код, хотя это может зависеть от компилятора или компоновщика.

    Редактировать: Я протестировал следующее, и он работает в Linux:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
        int i, j;
    
        puts("char *dummy_data[] = {");
        for (i = 0; i < 5000; i++) {
            fputs("    "", stdout);
            for (j = 0; j < 1000; j++) putchar('a' + rand() % 26);
            puts("",");
        }
        puts("};");
        return 0;
    }
    

    И этот код, и его вывод компилируются чисто.

    ответ дан 01 окт ’10, 21:10

    А как насчет простого определения большого статического массива символов?

    char const bigarray[5*1024*1024] = { 1 };
    

    См. Также мой другой ответ в этой ветке, где я предлагаю статически связываться с большими библиотеками. Это, безусловно, приведет к появлению реального кода, если вы просто укажете достаточно кода библиотек.

    РЕДАКТИРОВАТЬ: добавлена ​​ненулевая инициализация, так как данные, содержащие только нули, обрабатываются оптимизированным способом компилятором / компоновщиком.

    РЕДАКТИРОВАТЬ: добавлена ​​ссылка на мой другой ответ.

    РЕДАКТИРОВАТЬ: добавлен квалификатор const, поэтому большой массив будет помещен в код многими компиляторами.

    ответ дан 05 окт ’10, 15:10

    char big[5*1024*1024] = {1};
    

    Вам необходимо инициализировать его значением, отличным от 0, иначе компилятор / компоновщик может его оптимизировать.

    ответ дан 01 окт ’10, 16:10

    ответ дан 12 апр.

    Заполните EXE-файл NOP на ассемблере.

    ответ дан 05 окт ’10, 14:10

    Как насчет того, чтобы просто добавить двоичные нули в конец .exe?

    ответ дан 01 окт ’10, 16:10

    Вы можете создавать большие статические массивы фиктивных данных. Это увеличило бы размер вашего exe, хотя это был бы не настоящий код.

    ответ дан 01 окт ’10, 16:10

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

    Итак, путь:

    • перейдите в http://lipsum.org/
    • генерировать много текста
    • добавить cpp в вашу программу
    • добавить статическую константную строку, которая будет иметь сгенерированный текст в качестве значения
    • компилировать
    • проверьте размер.

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

    Добавленный размер должен быть легко угаданным.

    ответ дан 01 окт ’10, 16:10

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

    ответ дан 01 окт ’10, 16:10

    Используйте Boost и скомпилируйте исполняемый файл с отладочной информацией.

    ответ дан 01 окт ’10, 16:10

    Напишите программу, генерирующую много кода.

    printf("000000000");
    printf("000000001");
    // ...
    printf("010000000");
    

    ответ дан 01 окт ’10, 16:10

    Признаюсь, я парень Linux / UNIX. Можно ли статически связать исполняемый файл в Windows? Затем вы можете ссылаться на некоторые тяжелые библиотеки и увеличивать размер кода настолько, насколько хотите, без написания большого количества кода самостоятельно.

    Еще одна идея, которую я задумал, читая ваш комментарий к моему первому ответу, — это добавить нули в ваш файл. Как уже было сказано, я не эксперт по Windows, так что это может не сработать.

    ответ дан 01 окт ’10, 16:10

    Добавьте изображение размером 5 МБ (BMP).

    ответ дан 01 окт ’10, 17:10

    После того, как вы выполните все перечисленные здесь методы, выполните компиляцию с флагом отладки и с максимальным флагом оптимизации (gcc -g -O3).

    ответ дан 05 окт ’10, 14:10

    Если ничего не помогает, вы все равно можете создать исходный файл на языке ассемблера, в котором у вас есть соответствующее количество db операторы, испускающие байты в сегмент кода, и связывают полученный объект кода с вашей программой как extern "C" { ... }.

    Возможно, вам придется поиграть с компилятором / компоновщиком, чтобы помешать компоновщику оптимизировать этот фиктивный объект «кода».

    ответ дан 01 окт ’10, 16:10

    Используйте #define для определения множества макросов, содержащих строку огромной длины, и используйте эти макросы внутри вашей программы во многих местах.

    ответ дан 01 окт ’10, 16:10

    Вы могли сделать это:

    REM generate gibberish of the desired size
    dd if=/dev/random of=entropy count=5000k bs=1
    REM copy the entropy to the end of the file
    copy /b someapp.exe + entropy somefatapp.exe
    

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

    Как правило, вы можете скопировать столько информации, сколько хотите, в конец exe. Весь код / ​​ресурсы хранятся как смещения от начала файла, поэтому увеличение его размера не должно повлиять на него.

    (Я предполагаю, что у вас есть dd в Windows. Если нет, получите).

    ответ дан 01 окт ’10, 18:10

    Напишите генератор кода, который генерирует произвольные случайные функции. Единственный трюк в этом случае — убедиться, что он не будет оптимизирован, и с отдельной компиляцией, которая не должна быть сложной.

    ответ дан 01 окт ’10, 21:10

    Статически привяжите wxWidgets к вашему приложению. Он мгновенно станет размером 5 МБ.

    ответ дан 01 окт ’10, 21:10

    Не тот ответ, который вы ищете? Просмотрите другие вопросы с метками

    c++
    winapi
    executable
    crt

    or задайте свой вопрос.

    Малый объем оперативной памяти и устройств долговременного хранения информации на персональных компьютерах в прошлом накладывал весьма жесткие ограничения на размер программ. Сегодня подобной проблемы не существует. Однако и сейчас иногда важно максимально уменьшить размер exe-модуля разрабатываемого приложения.

    Как уменьшить размер exe

    Вам понадобится

    • — исходный код;
    • — компилятор, линкер;
    • — компрессоры PE-модулей, такие как UPX, Themida.

    Инструкция

    Соберите release-версию исполняемого модуля приложения. Выберите в настройках проекта в IDE соответствующую конфигурацию. Если такой конфигурации нет, создайте ее на основе уже существующей. Измените список опций линкера, убрав и добавив соответствующие директивы. Так, при использовании пакета разработки от Microsoft, следует убрать опцию /debug. Можно также добавить в исходный код директиву:#pragma comment(linker,»/RELEASE»)

    Сконфигурируйте проект так, чтобы максимально избежать линковки исполняемого модуля со статическими библиотеками. Используйте разделяемые версии соответствующих библиотек. К примеру, можно исключить код библиотек времени исполнения C и C++, заменив опцию линкера /ML или /MT (статические одно- и многопоточные библиотеки) на /MD (многопоточная CRT DLL).

    Рассмотрите вариант слияния различных секций exe-модуля в одну. Данный метод не даст заметного результата, если файл достаточно велик, но при исходном объеме модуля в 20-30 килобайт, выигрыш может оказаться существенным. Опция /merge линкера позволяет объединить секции. Можно задать ее через параметры проекта:/merge:.text=.data /merge:.reloc=.data /merge:.rdata=.dataили при помощи pragma-директив в исходном коде:#pragma comment(linker,»/merge:.text=.data»)#pragma comment(linker,»/merge:.reloc=.data»)#pragma comment(linker,»/merge:.rdata=.data»)#pragma comment(linker,»/merge:.idata=.data»)Также имеет смысл определить атрибуты результирующей секции:#pragma comment(linker,»/section:.data,rwe»)

    Уменьшите размер exe путем установки минимального значения величины блоков, по границам которых выравниваются секции. Используйте опцию линкера /filealign, заданную через редактирование свойств проекта или директиву pragma:#pragma comment(linker,»/filealign:0x200″)Данный способ пригоден для маленьких модулей.

    Попытайтесь уменьшить размер exe-файла, производя его сборку с параметрами оптимизации, направленной на сокращение объема машинного кода. Замените опции компилятора /O2 или /Od на /O1.

    Замените стандартную заглушку DOS в exe-модуле на собственную, которая будет иметь минимальный объем. Используйте опцию линкера /stub:#pragma comment(linker,»/stub:mystub.exe»)Здесь mystub.exe — имя исполняемого файла DOS, код которого будет добавлен в exe-модуль в качестве заглушки.

    Рассмотрите вариант указания собственной точки входа в приложение. Это позволит исключить инициализирующий код статических библиотек времени исполнения. Используйте опцию линкера /entry, например:#pragma comment(linker,»/entry:MyStartup») void MyStartup(){    ::MessageBox(NULL, «Hello!», «Message!», MB_OK);}

    Примените утилиты упаковки, такие как UPX, ASPack, Themida, PECompact к готовому exe-файлу. Данные модуля подвергнутся компрессии. Их распаковка будет осуществляться в память после запуска приложения. Этот метод дает хорошие результаты в отношении объемных exe-файлов, содержащих в себе большое количество статических данных с низкой энтропией (например, DIB-растры в секции ресурсов).

    В интернетах есть несколько старых статей (тыц, тыц) про то, как уменьшить размер exe-файла, который генерирует Visual C++. Я взялся проверить актуальность рецептов, которые там приводятся, для Visual Studio 2010.

    Задачу я взял классическую: найти 10 самых популярных слов в текстовом файле. Мой исходный файл был размером 73728 байт.

    Начало

    Вот мое изначальное решение, написанное за 8 минут и заработавшее со второй компиляции:

    #include <fstream>
    #include <iostream>
    #include <map>
    #include <string>
    #include <boost/format.hpp>
    using namespace std;

    int main()
    {
        try {
            string s = «input.txt»;
            ifstream inf(s.c_str(), ios::binary);
            if (inf.good()) {
                string word;
                map<string, int> wc;
                while (inf >> word) {
                    ++wc[word];
                }
                inf.close();
                vector< pair<int, string> > wcvec;
                for (auto i = wc.begin(), iend = wc.end(); i != iend; ++i) {
                    wcvec.push_back(make_pair(i->second, i->first));
                }
                sort(wcvec.begin(), wcvec.end());
                for (size_t i = wcvec.size() — 1, j = 0; i >= 0 && j < 10; —i, ++j) {
                    cout << boost::format(«%6d %sn«) % wcvec[i].first % wcvec[i].second;
                }
            } else {
                throw runtime_error(«No such file»);
            }
        } catch (exception& e) {
            cerr << e.what() << endl;
        } catch (…) {
            cerr << «Unknown error» << endl;
        }
    }

    VC2010 в конфигурации Release выдал exe-файл размером 73728 байт. Посмотрим внутрь, что там столько жрет:

    Заголовок 0x400
    .text 0xC400 = 50176 байт В этой секции находится код
    .rdata 0x3A00 строки, манглированные имена
    .data 0x0A00 еще немного манглированных имен
    .rsrc 0x0200 манифест
    .reloc 0x1200 рассказ загрузчику как менять адреса в программе, если файл загружен не по тому адресу, по какому ожидал линкер

    Наш файл зависит от библиотек рантайма Visual C: msvcp100.dll, msvcr100.dll (10.0 здесь это версия, XP SP2 в стандартной поставке имеет только до 7.0), и, как и каждый исполнимый файл в системе, от kernel32.dll (тот, в свою очередь всегда тянет за собой ntdll.dll).

    В памяти программа занимает максимум 2.5 мегабайта на входном файле в полмегабайта. В адресное пространство мапятся нужные dll, кодовые страницы и .nls, по странице (4 KB) жрут переменные окружения, параметры процесса, PEB и TIB, 574 страницы съедает heap и, вопреки опасениям, стек выделяется не весь сразу, а по мере надобности, в пике 3 страницы на сам стек и 1 на его guard page.

    Сборка

    Для начала попробуем уменьшить файл ключами компилятора и линкера. Я провел небольшое исследование, воспользовавшись, в том числе, утилитой, которая собирала программу, перебирая найденные ключи. Каких-то 8000 exe-файлов за ночь сборки, и я уже могу поделиться результатами :)

    Опции компилятора:

    1. /Os — Favor small code;
    2. /GS- — Buffer security check off (default /GS), это те самые __security_check_cookie;
    3. /Oy — Omit frame pointers (default /Oy-);

    Опции компилятора, которые иногда помогают:

    1. /O1 — Minimize size (default /O2 maximize speed);
    2. /Ob2 — Inline function expansion. Теоретически, должно помогать, если есть много функций, которые вызываются только один раз, либо маленьких функций, которые вызываются один-два раза. Еще можно указать компилятору использовать интринсики вместо вызовов функций для некоторых функций с помощью прагмы вида #pragma intrinsic(memset, strlen, memcpy);
    3. /Oi — Enable intrinsic functions;
    4. /Gy- — отключить Enable function-level linking (default /Gy);
    5. /arch:SSE2 — включает расширенный набор инструкций за счет того, что программа перестает исполняться на старых процессорах (до Pentium 4);

    Опции линкера:

    1. /MANIFEST:NO — отключает манифест;
    2. /MERGE:.rdata=.data /MERGE:.text=.data — сливает .text и .rdata в одну секцию;
    3. /ALIGN:16 — устанавливает минимальное выравнивание секции;
    4. Убрать /DEBUG — удаляет из exe-файла информацию о соответствующем PDB-файле;
    5. /DYNAMICBASE:NO /FIXED (default /DYNAMICBASE) — запрещает релоки и убивает их секцию (прощай, ASLR в Vista+, плюс, очевидно, не подходит для .dll);

    Опасные (отключают механизмы языка):

    1. /ENTRY:»main» — меняет точку входа и отключает всю инициализацию, осуществляющуюся перед вызовом main (это ___security_init_cookie и ___tmainCRTStartup);
    2. /NODEFAULTLIB (использовать вместе с /GS-) — отключает все дефолтные библиотеки со всеми средствами языка. Верный способ получить ошибки линковки, если используется что-то кроме WinAPI;
    3. Убрать /EHsc — запретить Enable C++ exceptions (еще можно заменить их другими механизмами (SEH, extern C functions), но пользы от этого замечено не было);
    4. /GR- — выключить RTTI.

    Вдоволь поперебирав, я обнаружил, что оптимальный размер достигается, если установить все опции из 1-й и 3-й группы, плюс первую и последнюю из 4-й. Это 42544 байт. Отладка такого файла превращается в экстремально сложное занятие, так что все последующие манипуляции следует проделывать сначала над конфигурацией Debug :)

    Отмечу, что с теми же опциями + /NODEFAULTLIB минимальный hello world с одним MessageBoxA занимает 640 байт (против 7186 байт в Release по дефолту и 28160 в Debug).

    Теперь пара слов о том, что НЕ работает или не нужно:

    • Незачем убирать из .lib для линкера лишнее, он справляется сам;
    • Незачем отключать совместимость с DEP (/NXCOMPAT:NO);
    • #define WIN32_LEAN_AND_MEAN — стрипает windows.h, которого тут нет;
    • #pragma comment(linker, "/SECTION:.data,EWRX") — во-первых, надо EWR, во-вторых, все равно не нужно, линкер ругается, но линкует;
    • #pragma comment(linker, "/FILEALIGN:512") — директива была недокументированная и ее убрали;
    • #pragma comment(linker, "/ALIGN:512") — по неведомой причине такая прагма бьет PE-файл, надо выставлять SectionAlignment в свойствах проекта, который действует на тот же ключ;
    • #pragma comment(linker,"/merge:.rsrc=.data") или .reloc=.data — согласно MSDN, you shouldn’t merge .rsrc, .reloc, or .pdata into other sections и линкер отказывается это делать;
    • #pragma comment(linker, "/opt:nowin98") — перекрывается /ALIGN;
    • #pragma optimize("gsy", on) — делает то же самое, что /Og (deprecated) /Os /Oy и, в принципе, является самым простым и безопасным способом уменьшить размер exeшника одной строчкой, но я уже разобрал ключи в отдельности.

    Код

    Воспользовавшись Function list в одном известном дизассемблере и самописным скриптом, взвесим различные смысловые части кода в изначальном файле:

    Init and deinit 889
    main 1832
    Exceptions 4537
    RTTI 82
    Runtime checks 527
    PE functions 332
    Float arithmetics 222
    Memory allocation 413
    Locks 12
    8846
    std memory fns 1524
    std::allocator 368
    std::exception types 152
    std::iostream 2022
    Locale and facets 700
    std::fstream 528
    std bufs 3142
    std::map 400
    std::_Tree 2992
    std::vector 1984
    std::basic_string 3607
    std::char_traits 128
    std::pair 400
    std::sort 4192
    std::heap 993
    std comparisons 160
    23292
    boost::format 4128
    boost::io 9216
    boost::optional 48
    boost::base_from_member 64
    boost::exception 4184
    boost::detail 234
    17874
    Overall: 50012

    Легко видеть, что boost, который здесь почти ничего не делает (чего не смог бы сделать банальный printf), занимает почти треть кода. Заменяем, 42544 → 19744 байт.

    Сказал Э, скажи Ю. Заменим весь iostream на fopen, printf и K°. 10865 байт.

    Уберем sort и vector, заменив на insertion sort в простом массиве размера 10. 8336 байт.

    Заменим map на unordered_map. 8896 байт. Ой, я пошутил, откатимся обратно. Внезапно хэш-таблица, которую бы я писал, если бы фашисты отобрали у меня STL, оказалась толще красно-черного дерева.

    Выпилим исключения, все равно они здесь почти ничего не делают, и заменим на обработку ошибок в старом мерзком си-стиле. 8112 байта.

    Да, поддержку C++ исключений теперь можно и отключить. 7360 байт. Все, больше ничего не смог придумать :)

    Теперь можно расслабиться и проверить энтропию. Популярнейший упаковщик исполнимых файлов UPX пожал исходный файл до 32256 байт, с исправленным не справился из-за /align; проставил /align:512, upx пожал до 6144 байт, но побил файл. 7z пожал исходный файл до 29591 байт, а исправленный до 3955 байт. Есть еще простор для сжатия :)

    Напомню, исходный код был написан за 8 минут, а оптимизация ключей компилятора и линкера с последующим переписыванием в более компактный вид заняла 18 часов.

    UPD: По совету xproger и wizzard0 попробовал Crinkler, хитрый линкер для интрописателей. Как линкеру, ему нужен .obj, который генерирует студия в одну из папок проекта. Для начала следует собрать проект с отключенной Whole program optimization (/GL, оно немного увеличит студийный exe), затем исполнить команду вида:

    crinkler.exe /ENTRY:main /SUBSYSTEM:CONSOLE /COMPMODE:SLOW kernel32.lib user32.lib msvcrt.lib msvcprt.lib main.obj

    Подумав минуту, Crinkler выплюнет exe размером 3907 байт, который вообще не сжимается 7z! Теперь, думаю, простор для сжатия закончился :)

    Ссылки:
    Как сделать 133-байтный PE
    Как сделать 45-байтный ELF

    Понравилась статья? Поделить с друзьями:
  • Как изменить верхнюю шторку на самсунг
  • Как изменить верхнюю шторку на андроид
  • Как изменить верхнюю шторку на xiaomi
  • Как изменить верхнюю шторку на miui 12
  • Как изменить верхнюю шторку айфон