Второй день ковыряю, но пока безуспешно. Нигде пока не смог найти описание того в каком же формате хранятся инициализированные данные (".data"). С ресурсами все красиво получилось - шифрование как самих ресурсов, так и строковых названий (где есть), не ломая структуры секции. Но с секцией .data пока глухо. Шифровать целиком - не подходит, но как ее "развернуть"-то?
Очень смешно. В секции с именем .data может храниться даже код, имя секции ничерта не значит. А если речь именно об инициализированных данных - то они хранятся в том формате, который придумал программист. Написал он где-то в глобальной области видимости Code: static int a = 5; И компилятор к данным инициализированным добавил 4 байта (если система x86), и записал в эти 4 байта значение 0x00000005. Написал он: Code: static const char b[] = "Vasya"; И компилятор добавил к секции данных еще 6 байтов, заполнив их значениями 'V','a','s','y','a',0.
Ну это всегда можно проверить через Сегмент.Characteristics (0x00000040 - сегмент инициализированных данных). В общем, этот сегмент не имеет никакого формата и просто грузится в память по указанному адресу? Загрузчик абсолютно ничего с ним не делает, так?
Я открою еще одну тайну - сегментов больше не существует, нет такого понятия. Следующее внезапное открытие - флаг 0x00000040 (IMAGE_SCN_CNT_INITIALIZED_DATA) загрузчиком игнорируется, и я могу записать туда, что это IMAGE_SCN_CNT_CODE, а хранить там данные. Такое впечатление, что вы доверяете всему, что пишут в официальной документации Реальное значение имеют только флаги IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE, IMAGE_SCN_MEM_EXECUTE и парочка других. Наконец, третье открытие - загрузчик ничего не делает вообще ни с какими секциями PE-файла, он их просто грузит по общим правилам. Он может только применить релокации, заполнить таблицу импортов, например. Но загрузчику совершенно насрать, в каких секциях эти самые таблицы лежат, главное, чтобы их читать и писать можно было (а иногда и просто читать).
Ложь, п****ж и провокация. (с) Если в секции ресурсов "испортить" некоторые вещи (иконку приложения или манифест) - система откажется запускать такой файл.
Если манифест испортить - может и откажется, так как через него настраиваются права. А если иконку, то нет. Она просто не будет отображаться. Хорошие упаковщики или крипторы просто создают дубль секции ресурсов только с информацией о версии, манифестами и иконками приложения, а остальное целиком шифруют/упаковывают.
P.S. То же самое касается секции "(TLS) data". Windows не может корректно инициализировать приложение и отказывается его запускать.
Вы, видимо, невнимательно читали то, что я написал выше. А я написал, что "загрузчик ничего не делает вообще ни с какими секциями PE-файла, он их просто грузит по общим правилам". А вы говорите не о секциях, а о таблицах PE-Файла. В одной секции может лежать и таблица импорта, и TLS, и данные, и код, все что угодно. Не беритесь за написание криптора, если не видите отличий между словами сегмент, секция и таблица. Опять-таки, хорошие крипторы делают дубли TLS-таблиц, а потом шифруют все секции целиком, и неважно, в какой из них располагались эти таблицы.
А я у себя сделал шифрование прямо в существующей секции ресурсов, без создания новой (что на порядки проще). Но теперь хочется и разные строки в EXE попрятать. Как это проще всего сделать? Условие: проект на C++ Builder (т.е. EntryPoint нельзя же сменить через #pragma + макросами изначально зашифрованные строки не создать, как это очень удобно делать в MSVC)
А при чем тут EntryPoint и зашифрованные строки?.. Чтобы зашифрованные строки сделать, достаточно всю секцию, содержащую инициализированные данные, зашифровать. Если в ней содержится что-то еще, помимо данных, то соответственно зашифровать нужно только тот кусок, в котором лежат именно данные. Сейчас у меня еще вопрос возник: вы пишете криптор только ради того, чтобы им зашифровать какой-то конкретный exe-файл, который тоже вам принадлежит?
Это я в смысле что 1) В MSVC можно удобно объявлять примерно так: char const_szFilename_Log[] = CRYPT100("\\myfile.txt"); (описывать макрос, думаю, не стоит - главное - нужная нам строка будет объявлена в зашифрованном виде, что удобней предварительно шифрования и объявления в виде массива уже шифрованных байт). 2) В билдере не сменить EntryPoint (и не выключить их рантайм), потому не получится просто зашифровать .data , а сразу "на входе" расшифровать - управление передается на билдеровский код, который крэшится сразу.
Я не пишу криптер. Я просто обрабатываю один свой EXE файл другим EXE файлом Задача - легкое сбивание сигнатур "в два клика" (меняю ключ и пересобираю проект). В секции кода использую метки, чтобы шифровать почти весь код приложения, ресурсы тоже шифрую. Но вот касательно инициализированных данных - пришлось "задуматься". Я могу, конечно, перекинуть все в ресурсы и подтягивать при загрузке, но... как-то это не интересно.
Вирус на C++ Builder? Это мощно, да А перенести макрос в билдер ну никак нельзя? Сменить энтри поинт всегда можно, сначала передавать управление на некий стаб, который будет расшифровывать все что надо, а потом на оригинальную точку входа программы, и программа уже будет иметь расшифрованные данные к этому моменту. Адрес точки входа лежит в IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint, и ничто не мешает его перезаписать.
Вот задумайтесь - после упаковки любого exe-файла UPX'ом в нем остаются только секции UPX0, UPX1 и .rsrc, причем неважно, какие там были секции до этого. Билдеровские exe он жмет так же, ему пофиг на то, где что собрано. Всякие важные таблицы вроде TLS он дублирует. Почему бы не делать так же? Единственная проблема, которая останется - это сделать стаб, который все это будет расшифровывать, а он может через какое-то время начать палиться.
У мсье "о Гуру" ничего кроме вирусов не ассоциируется с сигнатурами? Нет. Он такое не поддерживает (да, меня тоже это удивило, но факт ). Подробнее про макрос я в блоге своем писал (blog.kmint21.com). Спасибо, Кэп. Но, если честно, не хочется с этим завязываться. Даже уже думал просто asm-метку поставить в новой функции WinMain (так останется только адрес входа заменить и все - не нужно будет думать куда "положить" этот "стаб" и на чем его писать). Но и так тоже пока не хотелось заморачиваться. Мне это нужно размножить минимум на 3 проекта (2 на Билдере, 1 на MSVC), потому хотелось как можно проще и надежней чтоб все было. В общем, пока размышляю...
А у чего еще "сигнатуры" могут начать "палиться", кроме как у малвари?) То, что мсье Калинский на главной странице своего сайта торгует кейлоггерами, это подтверждает) Не хочется заморачиваться, нужно проще и надежней - почему бы тогда не воспользоваться готовым решением? Имхо, разбирать устройство таблиц ресурсов - это уже большая заморочка и занимает много времени. Изменить адрес точки входа на свой стаб, написанный хоть на том же ассемблере, который расшифровывает секцию, содержащую данные, а потом передает управление на оригинальную точку входа, не сложнее.
1) Раньше юзал ExeCryptor для "защиты" продуктов. Но теперь все антивирусы научились его распаковывать. А те, кто поленился - кричат что "Crypted" (типа бойтесь). Пообщался с разработчиком одного из "актуальных" на сегодня крипторов, уточнил как они сотрудничают с антивирусными компаниями. Вывод - будут только выкинутые деньги на лицензию. 2) Любое чужое готовое решение будет работать строго до первого попадания сигнатур этого самого "решения" в базы антивирусов. А когда свое - сменил ключик в define.h, нажал .bat-ничек для перебилда-криптовки и все, можно заливать. Хоть несколько раз в день, хоть на автомате настроить аплоад новых версий на сайт. Разница в том, что стаб я не смогу сделать полиморфным, хотя очень бы хотелось. А вот сишный код расшифровщика я замусориваю дефайнами, которые очень просто переопределять и "ломать" сигнатуры. (Например, #define MUSOR GetACP(); а потом этот MUSOR вставляю между строк). Т.е., сделав ассемблерный расшифровщик, я загоню сам себя в угол. См. 1-ю страницу топика.