15 августа 2012 г.

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

А вот и вторая часть про пакер/криптор.

Так как у нас все данные из старого файла будут находиться в одной секции, необходимо их склеить, потом закриптовать/упаковать и выяснить размер. Я не стал писать функцию криптования или упаковки, так как это достаточно просто, да и лень что то стало, ограничился только склеиванием и измерением размера. В любом случае, тут не нужно файловое выравнивание и секция получается меньше, чем в оригинальном файле.
Немножко кода:

4,5,6 пункты у меня объедены в один, так как кода достаточно мало там и 4ый пункт не содержит склейки и криптования упаковки, так как это будет делаться дальше.
    add        eax, 1Eh ; зарезервируем немножно места под тех инфу
    add        eax, UNPACKSIZE ; добавим размер анпакера
    invoke    GetAlignUp, eax, fAlig ; вычислим получившйся размер с файловым выравниванием
    mov        imgSize, eax ; сохраним размер образа в imgSize, 
    add        fileSize, eax ; прибавим к вычисленному размеру файлу размер образа
    mov        eax, fAlig ; скопируем в eax величину выравнивания
    add        fileSize, eax ; прибавим величину выравнивания для резервирования места под IAT

7. Создаем и маппируем новый фаил с необходимым размером.
    invoke    CreateFile, offset outfilename,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_WRITE, NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, 0 ; создаем фаил
    mov        hOpenfile, eax ; записываем его хендл
    
    invoke    CreateFileMapping, eax, NULL,PAGE_READWRITE, 0, fileSize , NULL ; мапируем с необходимым размером fileSize 
    mov        hOFMap, eax ; записываем хэндл
    invoke    MapViewOfFile, eax, FILE_MAP_WRITE, 0, 0, 0 ; делаем проекцию
    mov        houtfile, eax ; сохраняем указатель на начало нового файла
    
    invoke    crPEHeader, hinfile, houtfile ; крадем PE заголовок

8. Крадем заголовок из оригинального файла.
crPEHeader    proc psrcPEHeader:DWORD, pdstPEHeader:DWORD
;###############################
;    in - psrcPEHeader = src header
;    in - pdstPEHeader = dst header
;    out - eax = start PE header
;    out    - ecx = size PE header
;###############################
LOCAL    hinfSize:DWORD ; локальная переменная
    mov        eax, psrcPEHeader ; источник заголовка
    mov        ebx, pdstPEHeader ; место куда будем писать заголовок
    xor        ecx, ecx ; обнуляем ecx
    mov        cx, WORD PTR [eax+IMAGE_DOS_HEADER.e_lfanew] ; записываем в cx размер DOS заголовка
    add        eax, ecx ; прибавляем к eax размер DOS заголовка
    add        ebx, ecx ; прибавляем к ebx размер DOS заголовка
    add        ecx, IMAGE_FILE_HEADER+4h ; прибавляем IMAGE_FILE_HEADER
    add        cx, WORD PTR [eax+IMAGE_FILE_HEADER.SizeOfOptionalHeader+4h] ; прибавляем к ecx размер SizeOfOptionalHeader
    mov        hinfSize, ecx ; копируем в локальную переменную полный размер заголовка
    mov        esi, psrcPEHeader ; в esi - источник
    mov        edi, pdstPEHeader ; в edi - получатель
    rep        movsb ; копируем 1 к 1 заголовок
    xor        ecx, ecx ; обнуляем ecx
    mov        ecx, hinfSize ; копируем в ecx размер из локальной переменной
    mov        eax, ebx ; копируем в eax указатель на начало заголовка в файле получателе
    ret        ; готово
crPEHeader endp

9. Создаем секции,  учитывая размер из упаковываемого файла.
    mov        ebx, secCount ; в ebx записываем количество секций
    mov        WORD PTR [eax+IMAGE_FILE_HEADER.NumberOfSections+4h], bx ; записываем количество секий в новый PE заголовок
    add        eax, FULL_IMAGE_FILE_HEADER ; прибавим полный размер IMAGE_FILE_HEADER
    mov        optHeader, eax ; сохраним указатель на опциональный заголовок
    mov        ebx, secCount ; в ebx записываем количество секций (наверно оно тут не нада)
    dec        ebx ; уменьшим на 1 ebx
    imul    ebx, ebx, SECSTRUCSIZE ; вычисляем размер структуры SECSTRUCSIZE 
    add        ebx, secMem ; прибавим к этому указатель на secMem
    
    invoke    GetAlignUp, DWORD PTR [ebx], DWORD PTR [eax+IMAGE_OPTIONAL_HEADER.SectionAlignment] ; вычислим размер с выравниванием секций
    add        eax, DWORD PTR [ebx+4h] ; прибавим к результату выравнивания размер секции
    mov        ebx, houtfile ; скопируем в ebx указатель на начало файла
    add        ebx, pehSize ; прибавим к нему заголовок и окажемся в начале таблицы секций
    
    mov        DWORD PTR [sSection.vSize], eax ; в структуру занесем размер секции
    mov        eax, optHeader ; занесем в eax указатель на начало опционального заголовка
    mov        eax, DWORD PTR [eax+IMAGE_OPTIONAL_HEADER.SectionAlignment] ; перекинем в eax показатель выравниания секции
    mov        DWORD PTR [sSection.vAddr],eax ; в ячейку виртуального адреса структуры занесем оказатель выравниания секции
    mov        eax, codeStart ; в eax занесем указатель на начало кода
    mov        DWORD PTR [sSection.rAddr],eax ; в RWA адрес занесем указатель на начало кода
    
    
    invoke    crSecTableItem, ebx, offset namesec, DWORD PTR [sSection.vSize], DWORD PTR [sSection.vAddr], 0h, DWORD PTR [sSection.rAddr], IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_CNT_CODE or IMAGE_SCN_MEM_WRITE ; создаем запись в таблице секций
    mov        eax, DWORD PTR [sSection.vSize] ; в eax копируем виртуальный размер
    add        eax, DWORD PTR [sSection.vAddr] ; складываем с виртуальным адресом
    mov        DWORD PTR [sSection.vAddr], eax ; теперь это виртуальный адрес следующей секции
    mov        eax, optHeader ; занесем в eax указатель на начало опционального заголовка
    invoke    GetAlignUp, imgSize, DWORD PTR [eax+IMAGE_OPTIONAL_HEADER.SectionAlignment] ; вычислим размер с выраванием
    mov        DWORD PTR [sSection.vSize], eax ; теперь это виртуальный размер
    mov        eax, optHeader ; занесем в eax указатель на начало опционального заголовка
    invoke    GetAlignUp, imgSize, fAlig ; получим размер образа наших данных с файловым выравниванием
    mov        DWORD PTR [sSection.rSize], eax ; теперь это RWA размер
    
    add        ebx, 28h ; сместим указатель на следующую строку в таблице секций
    invoke    crSecTableItem, ebx, offset namesec, DWORD PTR [sSection.vSize], DWORD PTR [sSection.vAddr], DWORD PTR [sSection.rSize], DWORD PTR [sSection.rAddr], IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_CNT_CODE or IMAGE_SCN_MEM_WRITE ; создаем запись в таблице секций
    mov        eax, optHeader ; занесем в eax указатель на начало опционального заголовка
    mov        ecx,DWORD PTR [sSection.vAddr] ; в ecx занесем виртуальный адрес предыдущей секции
    mov        DWORD PTR [eax+IMAGE_OPTIONAL_HEADER.BaseOfCode], ecx ; правим базу кода в PE заголовке
    mov        eax, DWORD PTR [sSection.vAddr] ; в eax копируем виртуальный адрес
    add        eax, DWORD PTR [sSection.vSize] ; складываем с виртуальным размером
    mov        DWORD PTR [sSection.vAddr], eax ; теперь это адрес следующей секции
    mov        eax, DWORD PTR [sSection.rSize] ; в eax RWA размер
    add        eax, DWORD PTR [sSection.rAddr] ; складываем с RWA адресом
    mov        DWORD PTR [sSection.rAddr], eax ; теперь это начало следующей секции в файле
    mov        edx, fAlig ; записываем в edx файловое выравнивание
    mov        DWORD PTR [sSection.rSize], edx ; записываем в размер в файле
    
    add        ebx, 28h ; сместим указатель на следующую строку в таблице секций
    invoke    crSecTableItem, ebx, offset namesec, DWORD PTR [sSection.vSize], DWORD PTR [sSection.vAddr], DWORD PTR [sSection.rSize], DWORD PTR [sSection.rAddr], IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_CNT_CODE or IMAGE_SCN_MEM_WRITE ; создаем запись в таблице секций

Процедурка crSecTableItem
crSecTableItem proc    uses eax ebx ecx esi edi pEndSec:DWORD, pNameSec:DWORD, vSize:DWORD, vAddr:DWORD, rSize:DWORD, rAddr:DWORD, charac:DWORD
    mov        ebx, pEndSec ; копируем в ebx начало секции
    mov        ecx, 8 ; в 1 поле у нас 8 байт для текстового указателя
    mov        edi, ebx ; копируем в edi указатель на начало секции
    mov        esi, pNameSec ; в esi указатель на начало названия
nextChr: ; метка на следующий цикл
    .if    BYTE PTR [esi] == 0 ; если в esi 0, значит буквы закончились
        jmp    endName ; выходим на метку endName
    .endif
    movsb ; копируем байт
    loop    nextChr ; повторяем пока не пройдет 8 итераций или не выйдем по if
endName: 
    mov        eax, vSize ; копируем виртуальный размер в eax
    mov        DWORD PTR [ebx+8h], eax ; записываем его в ячейку VirtualSize
    mov        eax, vAddr ; копируем виртуальный адрес в eax
    mov        DWORD PTR [ebx+0Ch], eax ; записываем его в ячейку SizeOfRawData
    mov        eax, rSize ; копируем реальный размер в eax
    mov        DWORD PTR [ebx+10h], eax ; записываем его в ячейку PointerToRawData
    mov        eax, rAddr ; копируем реальный адрес в eax
    mov        DWORD PTR [ebx+14h], eax ; записываем реальный адрес
    mov        eax, charac ; копируем в eax атрибуты секции
    mov        DWORD PTR [ebx+24h], eax ; записываем в ячейку Characteristics
    ret
crSecTableItem endp

Ну и на сегодня все, дальнейшее описанике приптора будет в следующих частях. Вот ссылка на первую часть.

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

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