21 августа 2012 г.

Пишем пакер, ну или основу криптора. (Часть 3)

Итак третья часть зловещей пьесы про пакер/криптор. Предыдущие 1 глава и 2 глава.
Что у нас осталось, необходимо доделать секции, разместить информацию в PE заголовке, создать таблицу импорта, закопировать все данные и декриптора, ну и написать сам декриптор.

Начнем потихоньку.

Доделываем таблицу секций и размещаем информацию об ней в PE заголовке.
    mov        importSec, eax ; запоминаем где начинается секция импорта
    mov        ebx, DWORD PTR [sSection.vAddr] ; пишем виртуальный адрес секции
    add        ebx, DWORD PTR [sSection.vSize] ; складываем его с виртуальным размером
    mov        eax, optHeader ; в eax копируем указатель на опциональный заголовок
    mov        DWORD PTR [eax+IMAGE_OPTIONAL_HEADER.SizeOfImage], ebx ; в размер образа записываем собственно размер
    mov        ebx, DWORD PTR [sSection.vAddr] ; копируем в ebx виртуальный адрес
    mov        DWORD PTR [eax+IMAGE_OPTIONAL_HEADER.BaseOfData], ebx ; в базу пишем получившийся виртуальный адрес

    add        eax, IMAGE_OPTIONAL_HEADER.DataDirectory+8h ; прибавляем к указателю eax размер до DataDirectory
    mov        ebx, DWORD PTR [sSection.vAddr] ; в ebx копируем начало импорт секции
    mov        DWORD PTR [eax], ebx ; записываем в Import Directory RWA получившийся виртуальный адрес

Создаем таблицу импорта для работы распаковщика/декриптора.
    mov        eax, importSec
    add        eax, houtfile
    invoke    createImport, ebx, eax

Процедура createImport
createImport    proc uses eax ebx edi esi ecx vSecAddr:DWORD, rSecAddr:DWORD
LOCAL pFunc:DWORD
    mov        ebx, rSecAddr ; пишем в ebx реальный адрес где будет находится import секция
    add        ebx, 0Ch ; прибавляем 12 байт, до поля Name RWA
    mov        eax, vSecAddr ; запишем в eax виртуальный адрес секции
    add        eax, 34h ; прибавим к виртуальному адресу 52 байта, это 2 раза структура 5*4Byte(одна пустая) + таблица IAT из 2х 4 байтовых записей + 1х4байта пустая 
    mov        DWORD PTR [ebx], eax ; запишем в поле Name RWA где находиться название kernel32.dll 
    mov        edi, rSecAddr ; запишем в edi реальное нахождение секции
    add        edi, 34h ; снова прибавим 52 байта
    mov        ecx, sizeof _kernel32 ; вычислим размер строки "kernel32.dll" и запишем ее в ecx
    mov        esi, offset _kernel32 ; в esi положим указатель на строку "kernel32.dll"
    rep        movsb ; копируем строку в фаил
    mov        pFunc, edi ; запомним где находиться указатель уже на функции импорта
    
    add        ebx, 4h ; прибавим к ebx 4 байта, чтобы перейти на поле указывающее на IAT
    mov        eax, vSecAddr ; в eax занесем виртуальный адрес
    add        eax, SLOADL ; прибавим константу в 40 байт чтобы был указатель на таблицу IAT
    mov        DWORD PTR [ebx], eax ; записываем в поле IAT указатель на IAT
    
    mov        ebx, rSecAddr ; помещаем в ebx реальный адрес таблицы импорта
    add        ebx, SLOADL ; прибавляем к нему теже 40 байт
    mov        eax, edi ; копируем указатель из edi в eax
    sub        eax, rSecAddr ; отнимаем от eax реальный адрес и получаем необходимое смещение
    add        eax, vSecAddr ; прибавляем его к виртуальному, чтобы получить адрес IAT таблицы виртуальной
    mov        DWORD PTR [ebx], eax ; записываем его в фаил
    
    add     edi, 2h ; прибавм к edi 2байта Hintа
    mov        ecx, sizeof    _loadlibrary ; вычисляем размер строки с loadlibrary
    mov        esi, offset _loadlibrary ; копируем в esi указатель на строку с loadlibrary
    rep        movsb ; копируем строчку в упакованный фаил
    
    dec        edi ; уменьшаем edi на 1
    add        ebx, 4h ; прибавляем к ebx 4 байта, чтобы перейти на следующую позицию в IAT
    mov        eax, edi ; в eax копируем указатель на следующий элемент IAT
    sub        eax, rSecAddr ; отнимаем реальный адрес, получаем смещение
    add        eax, vSecAddr ; прибавляем виртуальный адрес
    mov        DWORD PTR [ebx], eax ; копируем виртуальное смещение на следующую функцию
    
    add     edi, 2h ; прибавляем к edi 2 байта Hintа
    mov        ecx, sizeof _getprocaddress ; вычисляем размер строки с именем getprocaddress
    mov        esi, offset _getprocaddress ; копируем в esi указатель на имя getprocaddress
    rep        movsb ; записываем строчку в фаил
    
    ret
createImport endp

Копируем всякие данные в упакованный фаил:
    mov        ebx, hinfile ; в ebx копируем указатель на начало упаковываемого фаила
    add        ebx, pehSize ; прибавляем к ebx размер PE заголовка
    mov        ecx, secCount ; в ecx копируем количество секций
    mov        edi, houtfile ; в edi копируем адрес упакованного файла
    add        edi, pehSize ; прибавляем к edi размер PE заголовке
    mov        edi, DWORD PTR [edi+14h] ; вычисляем адрес первой секции в упакованном файле
    add        edi, houtfile ; прибавляем к нему адрес упакованного файла
    mov        edx, edi ; копируем в edx idi
    xor        eax, eax ; обнуляем eax
writecode:
    mov        esi, DWORD PTR [ebx+14h] ; в esi копируем адрес секции жертвы
    add        esi, hinfile ; прибавляем адрес замапированнного файла жертвы
    push    ecx ; сохраним ecx в стеке
    mov        ecx, DWORD PTR [ebx+8h] ; занесем в ecx реальный размер секции
    rep        movsb ; копируем всю секцию
    pop        ecx ; востановим ecx
    add        ebx, 28h ; прибавим 40 байт до следующей секции
    loop    writecode ; повторим пока все секции не кончатся
    mov        eax, edi ; скопируем в eax указатель на конец скопированного кода
    sub        eax, edx ; отнимим от eax edx чтобы получить адрес смещения на код распаковщика/декриптора
    mov        ebx, optHeader ; скопируем в ebx адрес опционального заголовка PE
    add        eax, DWORD PTR [ebx+IMAGE_OPTIONAL_HEADER.BaseOfCode] ; прибавим к eax адрес базы кода
    mov        DWORD PTR [ebx+IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint], eax ; запишем в точку входа адрес с которого начинается распаковщик/декриптор
    mov        esi, offset unpack ; в esi занесем указатель на функцию распаковки/декриптора
    mov        ecx, UNPACKSIZE ; в ecx занесем размер функции распаковки/декриптора
    rep        movsb ; копируем код распаковки/декриптора

Ну вот и все на сегодня, в следующей и последней части, я опишу тех поля которые понадобяться для распаковки и анпакер/декриптор который нужен будет для нармальной работы файла который будет запакован.
Предыдущие части про упаковщик/криптор можно почитать в Главе1 и Главе2.

Комментариев нет:

Отправить комментарий