Заметка для тех кто по каким-либо причинам заинтересовался разработкой статических распаковщиков.
После-того когда отработал код по детектированию пакера и далее следует стадия распаковки, то первым же вопросом, как правило, является : "А каким должен быть размер результирующего файла?", ведь если это криптор, то можно один в один и работать на уровне RvaToRaw\RawToRva , а если применялся алгоритм сжатия?
На этот вопрос можно ответить довольно просто: а как же оно выполняется тогда? Тогда ответ: "Потому что в памяти занимает конечный размер указанный в PE->OptionalHeader.SizeOfImage" будет подсказкой.
Действительно, какие бы мы не применяли алгоритмы сжатия в пакере, в памяти все равно не больше SizeOfImage. Как вывод, если мы виделим размер файла в SizeOfImage байт, то этого достаточно. Замечу, что необходимо выравнять значение SizeOfImage в большую сторону на значение PE->OptionalHeader.SectionAllignment.
Как правило, результирующий файл принято создавать так:
1) Запомнить смещение до оверлея в оригинальном файле - OverlayOffs
2) Выполнить размапливание - UnmapPEFile()
Сначала поясню п.2. Результат этого процесса можно сравнить с "дампингом", когда мы открываем виртуальное адресное пространство процесса, находим нужный нам образ и "дампим". Здесь же немного по-другому, но очень похоже, вот последовательность действий:
1) Создать файл размером в SizeOfImage;
2) Скопировать заголовок;
3) Каждую секцию записать в файл иммитируя действия системного загрузчика, но базовым адресом считать смещение 0x0, вместо привычных нам 0x400000, 0x7E000000, etc;
4) Переписывание секции сопровождается обновлением описателя этой секции;
После выполнения этих действий получим условно названный "дамп". Отличие этого дампа от привычного нам получаемого в результате запуска процесса в том, что здесь не выполняется код, т.е. стаб пакера не отработал и данные секций еще "не попорчены".
Этот процесс выполняют по двум причинам:
1) Знаем точный окончательный размер
2) Есть вероятность и довольно большая что упакованы не все данные, а только не значительная часть.
После процесса распаковки(возможно работы декомпрессора, фильтрации, востановления релоков, импортов и т.д.) когда размер может измениться, т.е. в файл чтото добавлено, мы зная смещение оверлея просто его дописываем.
После-того когда отработал код по детектированию пакера и далее следует стадия распаковки, то первым же вопросом, как правило, является : "А каким должен быть размер результирующего файла?", ведь если это криптор, то можно один в один и работать на уровне RvaToRaw\RawToRva , а если применялся алгоритм сжатия?
На этот вопрос можно ответить довольно просто: а как же оно выполняется тогда? Тогда ответ: "Потому что в памяти занимает конечный размер указанный в PE->OptionalHeader.SizeOfImage" будет подсказкой.
Действительно, какие бы мы не применяли алгоритмы сжатия в пакере, в памяти все равно не больше SizeOfImage. Как вывод, если мы виделим размер файла в SizeOfImage байт, то этого достаточно. Замечу, что необходимо выравнять значение SizeOfImage в большую сторону на значение PE->OptionalHeader.SectionAllignment.
Как правило, результирующий файл принято создавать так:
1) Запомнить смещение до оверлея в оригинальном файле - OverlayOffs
2) Выполнить размапливание - UnmapPEFile()
Сначала поясню п.2. Результат этого процесса можно сравнить с "дампингом", когда мы открываем виртуальное адресное пространство процесса, находим нужный нам образ и "дампим". Здесь же немного по-другому, но очень похоже, вот последовательность действий:
1) Создать файл размером в SizeOfImage;
2) Скопировать заголовок;
3) Каждую секцию записать в файл иммитируя действия системного загрузчика, но базовым адресом считать смещение 0x0, вместо привычных нам 0x400000, 0x7E000000, etc;
4) Переписывание секции сопровождается обновлением описателя этой секции;
После выполнения этих действий получим условно названный "дамп". Отличие этого дампа от привычного нам получаемого в результате запуска процесса в том, что здесь не выполняется код, т.е. стаб пакера не отработал и данные секций еще "не попорчены".
Этот процесс выполняют по двум причинам:
1) Знаем точный окончательный размер
2) Есть вероятность и довольно большая что упакованы не все данные, а только не значительная часть.
После процесса распаковки(возможно работы декомпрессора, фильтрации, востановления релоков, импортов и т.д.) когда размер может измениться, т.е. в файл чтото добавлено, мы зная смещение оверлея просто его дописываем.
2 комментария:
написал большой коммент и похерил =\
в двух словах - отталкиватся от данных в хидере опасно, необходимо детектить пакер и исходить из его алгоритма, используя минимальное число ресурсов =)
2 izl3sa :
Ты прав, что на хидер не стоит закладываться, но ты не понял о чем это я посте ;)
Я не в коим случае не исключаю стадию детекта пакера и правил хорошего тона по разработке анпакера. Эта заметка всего-лишь попытка донести мысль до людей, начинающих, о том с чего начать создание результирующего файла;)
Отправить комментарий