Вы не можете увеличить размер раздела, не делая недействительными следующие (обычно потому, что это делает недействительными смещения и адреса в этих разделах). Это остается возможным, но это чрезвычайно подвержено ошибкам и не стоит хлопот, когда у вас есть более простое решение.
Как правило, вам просто нужно добавить раздел в конец PE и перейти туда из раздела кода. Обычно в конце раздела кода (кодовая пещера) есть немного места, поэтому вы можете поместить туда свои JMP (или небольшую заглушку кода) для перенаправления в новый раздел. Вы также можете добавить другие новые разделы для данных или новых ресурсов или чего угодно.
Примечание. Я использую два инструмента: проводник CFF в качестве PE-браузера; шестнадцатеричный редактор.
Этот файл довольно специфичен, поэтому добавить новый раздел немного сложнее, чем обычно.
Давайте начнем!
Ниже представлен шестнадцатеричный вид массива IMAGE_SECTION_HEADER
:
Обычно есть место для добавления нового раздела, но в данном конкретном случае его нет... За заголовком последнего раздела сразу следует что-то.
Судя по содержимому, это, вероятно, связанный каталог импорта, что подтверждается в CFF explorer (смещение связанного каталога 0x248):
Связанный каталог импорта сегодня бесполезен, особенно с ASLR, поэтому мы можем обнулить весь каталог (его размер 0xA8 байт, как показано на предыдущем скриншоте):
Вы также можете обнулить RVA связанного каталога импорта в каталогах данных, хотя это не является строго обязательным:
Теперь пришло время добавить новый раздел.
Добавить новый раздел
Сапер поставляется с 3 разделами по умолчанию, поэтому увеличьте количество разделов с 3 до 4:
Перейдите к заголовкам разделов и добавьте новый раздел (вы можете сделать это прямо в проводнике CFF; я назвал свой, .foobar
, будьте осторожны, имена разделов максимум 8 символов и не должны заканчиваться с нулевым байтом):
Вам нужно выбрать два числа:
Необработанный размер нового раздела (я выбрал 0x400); оно должно быть кратным FileAlignment
(в данном случае это 0x200).
Виртуальный размер нового раздела (я выбрал 0x1000); оно должно быть кратно SectionAlignement
(что для этого двоичного файла равно 0x1000).
Теперь нам нужно вычислить два других члена, Virtual Address
и Raw Address
.
Виртуальный адрес
Возьмем пример с первой и второй секцией.
Первый раздел начинается с виртуального адреса 0x1000 и имеет виртуальный размер 0x3A56. Виртуальный адрес следующего раздела должен быть выровнен по SectionAlignement
(0x1000), поэтому расчет (здесь используется python):
>>> def round_up_multiple_of(number, multiple):
num = number + (multiple - 1)
return num - (num % multiple)
>>> hex(round_up_multiple_of(0x1000 + 0x3a56, 0x1000))
'0x5000'
Что дает 0x5000, что правильно (раздел .data начинается с виртуального адреса 0x5000).
Итак, где должен начинаться наш последний раздел?
Раздел .rsrc начинается с адреса 0x6000 и имеет размер 0x19160:
>>> hex(round_up_multiple_of(0x6000 + 0x19160, 0x1000))
'0x20000'
Таким образом, он должен начинаться с виртуального адреса 0x20000. Поместите это число в Virtual Address
.
Необработанный адрес
(Обычно в этом нет необходимости, так как все разделы уже выровнены, последний раздел должен начинаться прямо в конце файла, но мы сделаем это).
Напомним, необработанный адрес — это адрес в файле (а не в памяти).
Начнем с примера (первый и второй раздел):
Необработанный адрес первого раздела — 0x400, а его необработанный размер — 0x3c00. FileAlignement
равно 0x200, таким образом:
>>> hex(round_up_multiple_of(0x400 + 0x3c00, 0x200))
'0x4000'
Второй раздел должен начинаться с файла (его Raw address
) с адреса 0x4000, что правильно.
Таким образом, для нашего нового раздела расчет будет следующим:
- Раздел .rsrc начинается в файле с адреса 0x4200.
- Размер раздела .rsrc в файле 0x19200
FileAligment
is 0x200
Расчет следующий:
>>> hex(round_up_multiple_of(0x4200 + 0x19200, 0x200))
'0x1d400'
Наш последний раздел начинается с необработанного адреса 0x1d400 в файле, который подтверждается шестнадцатеричным редактором:
Заключительные шаги
Требуется последний шаг — вычисление поля SizeOfImage
в заголовке «Необязательный». Согласно спецификации PE это поле:
Размер (в байтах) изображения, включая все заголовки, при загрузке изображения в память. Оно должно быть кратно SectionAlignment.
Следовательно, расчет можно упростить следующим образом: VirtualAddress
+ VirtualSize
последнего раздела, выровненного по SectionAlignment
(0x1000):
>>> hex(round_up_multiple_of(0x20000 + 0x1000, 0x1000))
'0x21000'
Теперь сохраните все ваши изменения в проводнике CFF и выйдите.
Добавление места для нового раздела
Последний шаг — добавить необходимые байты для последней секции. Когда я выбираю Raw size
из 0x400, я вставляю 0x400 байт по адресу Raw Address
(0x1d400) с помощью шестнадцатеричного редактора.
Сохраните файл. Если вы выполнили все шаги, он должен работать (проверено на Win 10) как есть, и вы можете запустить модифицированный исполняемый файл без каких-либо ошибок.
Попробуйте использовать другой необработанный размер для нового раздела, если 0x400 недостаточно.
Теперь у вас есть новый пустой раздел, остальное зависит от вас для изменения кода :)
person
Neitsa
schedule
04.03.2016