Скрэмблер UPX своими руками

Одной из функций PeStubOEP является скрэмблер сигнатур различных упаковщиков. Попробуем написать скрэмблер UPX. Если кто-то забыл, то напомню, что если запустить UPX с ключом -d, он распакует упакованный файл, но только в случае если сигнатура не повреждена. Также мы научимся изменять имена секций, так как не очень-то весело видеть подобное:

Код:
.UPX0 сюда UPX кладет информацию из .tls

.UPX1 здесь располагается весь упакованный код и данные программы

.rsrc ресурсы

Нам понадобится только информация о расположении PE-заголовка и адрес начала секций. Так вот, несмотря на то, что многие любят ломать DOS-заголовок, по смещению &H3C всегда находится адрес на начало PE-заголовка (его там нет только если программа была написана под DOS). Теперь, когда уже найден адрес начала PE-заголовка, найдем адрес начала описания секций. Как ни странно, описание секций всегда начинается со смещения (PeOffset+&HF9), где PeOffset - адрес начала PE-заголовка. Осталось только определить число секций, а оно хранится по смещению (PeOffset+6) в основном PE-заголовке. Теперь, когда все найдено, не мешало бы разобраться со структурой описания секций. Приведу ее вариант для VB:

Код:
Public Type pe_section_header

section_name As String * 8 ' Имя секции [8 байт]

section_size As Long ' Размер секции в памяти

section_rva As Long ' Адрес загрузки секции в памяти

section_size2 As Long ' Размер секции в файле

section_start As Long ' Смещение начала секции в файле

reserved As String * 12

section_flags As Long ' Флаги секции

End Type

Структуры, подобные приведенной выше, идут одна за другой, а их количество равно числу секций в файле.

Нижеприведенная структура идентична для UPX 1.24 и 1.90, а также вряд ли поменяется в следующих версиях упаковщика, и я думаю, что можно смело пользоваться данной структурой. Так вот, сама структура содержит в себе поля, необходимые для нормальной распаковки файлов UPX'ом и всегда начинается с "UPX!". Этим мы и воспользуемся для нахождения адреса начала сигнатуры.

Код:
Public Type UPX_STRUCT

upxMagic As String * 4 ' Символы "UPX!"

upxVersion As Byte ' Версия UPX'а (например: 0C значит 1.24, 0D - 1.90)

upxFormat As Byte ' Определяет формат файла (PE, ELF, DOS и т.д.) PE - 09

upxMethod As Byte ' Метод сжатия (если NRV или UCL, то 02)

upxLevel As Byte ' Степень сжатия (от 0 до 10)

upxU_adler As Long ' CRC части экзешника в распакованном виде

upxC_adler As Long ' CRC части экзешника в запакованном виде

upxU_len As Long ' Размер части экзешника в распакованном виде

upxC_len As Long ' Размер части экзешника в запакованном виде

upxU_file_size As Long ' Размер распакованного экзешника.

upxFilter As Integer ' Метод распаковки

upxCRC As Byte ' CRC сигнатуры

End Type

Теперь у нас есть все необходимое для написания собственного скрэмблера. Полученных знаний вполне достаточно, чтобы переименовать все секции в файле, например на ".sux", и стереть все данные из UPX-сигнатуры. Для начала запустим Visual Basic 6.0, создадим новый проект, удалим из него форму и добавим модуль (наша программа будет работать с командной строкой). Ниже я приведу простейшую реализацию этой задачи. Для того чтобы не повторятся, я убрал объявления вышеописанных структур:

Код:
Public sSections() As pe_section_header

Private Sub Main()

sFileName = Command$

If sFileName = "" Then MsgBox "Вы не передали имя файла в командной строке", _

vbCritical, "Ошибка": Exit Sub

If Left$(sFileName, 1) = Chr(34) Then sFileName = Mid$(sFileName, 2, _

Len(sFileName) - 2)

Dim sPeOffset As Long, sFindUPX As String * 5000, sUPX As UPX_STRUCT, _

sNumberSections As Integer

FileCopy sFileName, Left$(sFileName, Len(sFileName) - 3) & "bak"

sFile = FreeFile

Open sFileName For Binary As #sFile

Get #sFile, &H3C + 1, sPeOffset

Get #sFile, sPeOffset + 7, sNumberSections

sSectionsStart = sPeOffset + &HF9 'ищем сигнатуру UPX в первых 5000 байт программы

Get #sFile, 1, sFindUPX

sFind = InStr(1, sFindUPX, "UPX!")

If sFind > 0 Then

Get #sFile, sFind, sUPX 'заполняем все поля ерундой

sUPX.upxMagic = "GPcH": sUPX.upxVersion = 0

sUPX.upxC_adler = 0: sUPX.upxC_len = 0

sUPX.upxCRC = &HFF: sUPX.upxFilter = 0

sUPX.upxFormat = 0: sUPX.upxMethod = 0

sUPX.upxU_adler = 0: sUPX.upxU_file_size = 0

sUPX.upxU_len = 0: sUPX.upxVersion = 11

Put #sFile, sFind, sUPX

Else

MsgBox "Ошибка: файл '" & sFileName & "' не содержит сигнатуру UPX", _

vbCritical, "Скрамблер UPX": Close #sFile: Exit Sub

End If

ReDim sSections(sNumberSections - 1)

Get #sFile, sSectionsStart, sSections

For i = 0 To sNumberSections - 1

sSections(i).section_name = ".sux"

Next

Put #sFile, sSectionsStart, sSections

Close #sFile

MsgBox "Файл '" & sFileName & "' успешно обработан", vbInformation, "Скрамблер UPX"

End Sub

Вот, собственно, и все. Не удивляйся, что к каждому смещению при считывании прибавляется единица - это особенности Visual Basic'а.

Источник